1010import time
1111import unicodedata
1212from typing import Any
13- from typing import Collection
13+ from typing import Generator
14+ from typing import Iterable
1415from typing import MutableMapping
1516from typing import Sequence
1617
@@ -57,20 +58,20 @@ def _full_msg(
5758
5859
5960def filter_by_include_exclude (
60- names : Collection [str ],
61+ names : Iterable [str ],
6162 include : str ,
6263 exclude : str ,
63- ) -> list [str ]:
64+ ) -> Generator [str , None , None ]:
6465 include_re , exclude_re = re .compile (include ), re .compile (exclude )
65- return [
66+ return (
6667 filename for filename in names
6768 if include_re .search (filename )
6869 if not exclude_re .search (filename )
69- ]
70+ )
7071
7172
7273class Classifier :
73- def __init__ (self , filenames : Collection [str ]) -> None :
74+ def __init__ (self , filenames : Iterable [str ]) -> None :
7475 self .filenames = [f for f in filenames if os .path .lexists (f )]
7576
7677 @functools .lru_cache (maxsize = None )
@@ -79,40 +80,39 @@ def _types_for_file(self, filename: str) -> set[str]:
7980
8081 def by_types (
8182 self ,
82- names : Sequence [str ],
83- types : Collection [str ],
84- types_or : Collection [str ],
85- exclude_types : Collection [str ],
86- ) -> list [str ]:
83+ names : Iterable [str ],
84+ types : Iterable [str ],
85+ types_or : Iterable [str ],
86+ exclude_types : Iterable [str ],
87+ ) -> Generator [str , None , None ]:
8788 types = frozenset (types )
8889 types_or = frozenset (types_or )
8990 exclude_types = frozenset (exclude_types )
90- ret = []
9191 for filename in names :
9292 tags = self ._types_for_file (filename )
9393 if (
9494 tags >= types and
9595 (not types_or or tags & types_or ) and
9696 not tags & exclude_types
9797 ):
98- ret .append (filename )
99- return ret
100-
101- def filenames_for_hook (self , hook : Hook ) -> tuple [str , ...]:
102- names = self .filenames
103- names = filter_by_include_exclude (names , hook .files , hook .exclude )
104- names = self .by_types (
105- names ,
98+ yield filename
99+
100+ def filenames_for_hook (self , hook : Hook ) -> Generator [str , None , None ]:
101+ return self .by_types (
102+ filter_by_include_exclude (
103+ self .filenames ,
104+ hook .files ,
105+ hook .exclude ,
106+ ),
106107 hook .types ,
107108 hook .types_or ,
108109 hook .exclude_types ,
109110 )
110- return tuple (names )
111111
112112 @classmethod
113113 def from_config (
114114 cls ,
115- filenames : Collection [str ],
115+ filenames : Iterable [str ],
116116 include : str ,
117117 exclude : str ,
118118 ) -> Classifier :
@@ -121,7 +121,7 @@ def from_config(
121121 # this also makes improperly quoted shell-based hooks work better
122122 # see #1173
123123 if os .altsep == '/' and os .sep == '\\ ' :
124- filenames = [ f .replace (os .sep , os .altsep ) for f in filenames ]
124+ filenames = ( f .replace (os .sep , os .altsep ) for f in filenames )
125125 filenames = filter_by_include_exclude (filenames , include , exclude )
126126 return Classifier (filenames )
127127
@@ -148,7 +148,7 @@ def _run_single_hook(
148148 verbose : bool ,
149149 use_color : bool ,
150150) -> tuple [bool , bytes ]:
151- filenames = classifier .filenames_for_hook (hook )
151+ filenames = tuple ( classifier .filenames_for_hook (hook ) )
152152
153153 if hook .id in skips or hook .alias in skips :
154154 output .write (
@@ -250,7 +250,7 @@ def _compute_cols(hooks: Sequence[Hook]) -> int:
250250 return max (cols , 80 )
251251
252252
253- def _all_filenames (args : argparse .Namespace ) -> Collection [str ]:
253+ def _all_filenames (args : argparse .Namespace ) -> Iterable [str ]:
254254 # these hooks do not operate on files
255255 if args .hook_stage in {
256256 'post-checkout' , 'post-commit' , 'post-merge' , 'post-rewrite' ,
0 commit comments