21
21
re_pattern_t = re_pattern_type = type (re .compile ("" ))
22
22
23
23
24
- if hasattr (enum , "auto" ): #PY36+
25
- enum_auto = enum .auto
26
- elif not ty .TYPE_CHECKING : #PY35
27
- _counter = 0
28
-
29
- def enum_auto () -> int :
30
- global _counter
31
- _counter += 1
32
- return _counter
24
+ enum_auto = enum .auto
33
25
34
26
35
27
O_DIRECTORY = getattr (os , "O_DIRECTORY" , 0 ) # type: int
36
28
37
29
38
- HAVE_FWALK = hasattr (os , "fwalk" ) # type: bool
39
- HAVE_FWALK_BYTES = HAVE_FWALK and sys .version_info >= (3 , 7 ) # type: bool
30
+ HAVE_FWALK : bool = hasattr (os , "fwalk" )
31
+ HAVE_FWALK_BYTES = HAVE_FWALK and sys .version_info >= (3 , 7 )
40
32
41
33
42
34
class Matcher (ty .Generic [ty .AnyStr ], metaclass = abc .ABCMeta ):
43
35
"""Represents a type that can match on file paths and decide whether they
44
36
should be included in some file scanning/adding operation"""
45
37
__slots__ = ("is_binary" ,)
46
- #is_binary: bool
47
-
38
+
48
39
def __init__ (self , is_binary : bool = False ) -> None :
49
- self .is_binary = is_binary # type: bool
40
+ self .is_binary : bool = is_binary
50
41
51
42
@abc .abstractmethod
52
43
def should_descend (self , path : ty .AnyStr ) -> bool :
@@ -111,8 +102,8 @@ def should_report(self, path: ty.AnyStr, *, is_dir: bool) -> utils.Literal_False
111
102
return False
112
103
113
104
114
- MATCH_ALL = MatchAll () # type : MatchAll[str]
115
- MATCH_NONE = MatchNone () # type : MatchNone[str]
105
+ MATCH_ALL : MatchAll [str ] = MatchAll ()
106
+ MATCH_NONE : MatchNone [str ] = MatchNone ()
116
107
117
108
118
109
class GlobMatcher (Matcher [ty .AnyStr ], ty .Generic [ty .AnyStr ]):
@@ -136,11 +127,7 @@ class emulates. If your are accustomed the globing on real Unix shells
136
127
pasting it into a real shell works this may be why.
137
128
"""
138
129
__slots__ = ("period_special" , "_sep" , "_pat" , "_dir_only" )
139
- #period_special: bool
140
- #_sep: ty.AnyStr
141
- #_pat: ty.List[ty.Optional[re_pattern_t[ty.AnyStr]]]
142
- #_dir_only: bool
143
-
130
+
144
131
def __init__ (self , pat : ty .AnyStr , * , period_special : bool = True ):
145
132
"""
146
133
Arguments
@@ -153,14 +140,14 @@ def __init__(self, pat: ty.AnyStr, *, period_special: bool = True):
153
140
shells allow one to disable this behaviour
154
141
"""
155
142
super ().__init__ (isinstance (pat , bytes ))
156
-
157
- self .period_special = period_special # type: bool
158
-
159
- self ._sep = utils .maybe_fsencode (os .path .sep , pat ) # type: ty.AnyStr
160
- dblstar = utils .maybe_fsencode ("**" , pat ) # type: ty.AnyStr
161
- dot = utils .maybe_fsencode ("." , pat ) # type: ty.AnyStr
162
- pat_ndot = utils .maybe_fsencode (r"(?![.])" , pat ) # type: ty.AnyStr
163
-
143
+
144
+ self .period_special : bool = period_special
145
+
146
+ self ._sep : ty . AnyStr = utils .maybe_fsencode (os .path .sep , pat )
147
+ dblstar = utils .maybe_fsencode ("**" , pat )
148
+ dot = utils .maybe_fsencode ("." , pat )
149
+ pat_ndot = utils .maybe_fsencode (r"(?![.])" , pat )
150
+
164
151
# Normalize path separator
165
152
if os .path .altsep :
166
153
pat = pat .replace (utils .maybe_fsencode (os .path .altsep , pat ), self ._sep )
@@ -174,9 +161,9 @@ def __init__(self, pat: ty.AnyStr, *, period_special: bool = True):
174
161
# (TBH, I find it hard to see how that is useful, but everybody does it
175
162
# and it keeps things consistent overall – something to only match files
176
163
# would be nice however.)
177
- self ._dir_only = pat .endswith (self ._sep ) # type: bool
178
-
179
- self ._pat = [] # type : ty.List[ty.Optional[re_pattern_t[ty.AnyStr]]]
164
+ self ._dir_only : bool = pat .endswith (self ._sep )
165
+
166
+ self ._pat : ty .List [ty .Optional [re_pattern_t [ty .AnyStr ]]] = [ ]
180
167
for label in pat .split (self ._sep ):
181
168
# Skip over useless path components
182
169
if len (label ) < 1 or label == dot :
@@ -193,7 +180,6 @@ def __init__(self, pat: ty.AnyStr, *, period_special: bool = True):
193
180
"an issue if you need this!" .format (os .fsdecode (label ))
194
181
)
195
182
else :
196
- #re_expr: ty.AnyStr
197
183
if not isinstance (label , bytes ):
198
184
re_expr = fnmatch .translate (label )
199
185
else :
@@ -308,32 +294,30 @@ class ReMatcher(Matcher[ty.AnyStr], ty.Generic[ty.AnyStr]):
308
294
own matcher with a proper :meth:`Matcher.should_descend` method.
309
295
"""
310
296
__slots__ = ("_pat" ,)
311
- #_pat: re_pattern_t[ty.AnyStr]
312
-
297
+
313
298
def __init__ (self , pat : ty .Union [ty .AnyStr , "re_pattern_t[ty.AnyStr]" ]):
314
- self ._pat = re .compile (pat ) # type: re_pattern_t[ty.AnyStr]
315
-
299
+ self ._pat : "re_pattern_t[ty.AnyStr]" = re .compile (pat )
300
+
316
301
super ().__init__ (not (self ._pat .flags & re .UNICODE ))
317
302
318
303
def should_descend (self , path : ty .AnyStr ) -> bool :
319
304
return True
320
305
321
306
def should_report (self , path : ty .AnyStr , * , is_dir : bool ) -> bool :
322
- suffix = utils .maybe_fsencode (os .path .sep , path ) if is_dir else type (path )() # type: ty.AnyStr
307
+ suffix : ty . AnyStr = utils .maybe_fsencode (os .path .sep , path ) if is_dir else type (path )()
323
308
return bool (self ._pat .match (path + suffix ))
324
309
325
310
326
311
class MetaMatcher (Matcher [ty .AnyStr ], ty .Generic [ty .AnyStr ]):
327
312
"""Match files and directories by delegating to other matchers"""
328
313
__slots__ = ("_children" ,)
329
- #_children: ty.List[Matcher[ty.AnyStr]]
330
-
314
+
331
315
def __init__ (self , children : ty .List [Matcher [ty .AnyStr ]]):
332
316
assert len (children ) > 0
333
317
super ().__init__ (children [0 ].is_binary )
334
-
335
- self ._children = children # type : ty.List[Matcher[ty.AnyStr]]
336
-
318
+
319
+ self ._children : ty .List [Matcher [ty .AnyStr ]] = children
320
+
337
321
def should_descend (self , path : ty .AnyStr ) -> bool :
338
322
return any (m .should_descend (path ) for m in self ._children )
339
323
@@ -350,13 +334,12 @@ class NoRecusionAdapterMatcher(Matcher[ty.AnyStr], ty.Generic[ty.AnyStr]):
350
334
scanner and hence provides ``recursive=False`` semantics.
351
335
"""
352
336
__slots__ = ("_child" ,)
353
- #_child: Matcher[ty.AnyStr]
354
-
337
+
355
338
def __init__ (self , child : Matcher [ty .AnyStr ]):
356
339
super ().__init__ (child .is_binary )
357
-
358
- self ._child = child # type : Matcher[ty.AnyStr]
359
-
340
+
341
+ self ._child : Matcher [ty .AnyStr ] = child
342
+
360
343
def should_descend (self , path : ty .AnyStr ) -> bool :
361
344
return False
362
345
@@ -367,8 +350,9 @@ def should_report(self, path: ty.AnyStr, *, is_dir: bool) -> bool:
367
350
368
351
if ty .TYPE_CHECKING :
369
352
_match_spec_t = ty .Union [ty .AnyStr , re_pattern_t [ty .AnyStr ], Matcher [ty .AnyStr ]]
370
- else : # Using `re_pattern_t` here like in the type checking case makes
371
- # sphinx_autodoc_typehints explode # noqa: E114
353
+ else :
354
+ # Using `re_pattern_t` here like in the type checking case makes
355
+ # sphinx_autodoc_typehints explode
372
356
_match_spec_t = ty .Union [ty .AnyStr , re_pattern_t , Matcher [ty .AnyStr ]]
373
357
match_spec_t = ty .Union [
374
358
ty .Iterable [_match_spec_t [ty .AnyStr ]],
@@ -404,16 +388,20 @@ def matcher_from_spec(spec: match_spec_t[ty.AnyStr], *, # type: ignore[misc] #
404
388
elif isinstance (spec , (str , bytes )):
405
389
return GlobMatcher (spec , period_special = period_special )
406
390
elif isinstance (spec , collections .abc .Iterable ) and not isinstance (spec , Matcher ):
407
- spec = ty .cast (ty .Iterable [_match_spec_t [ty .AnyStr ]], spec ) # type: ignore[redundant-cast]
408
-
409
- matchers = [matcher_from_spec (s , # type: ignore[arg-type] # mypy bug
410
- recursive = recursive , period_special = period_special ) for s in spec ]
391
+ matchers : ty .List [Matcher [ty .AnyStr ]] = [
392
+ matcher_from_spec (
393
+ s , # type: ignore[arg-type]
394
+ recursive = recursive ,
395
+ period_special = period_special )
396
+ for s in spec
397
+ ]
398
+
411
399
if len (matchers ) == 0 : # Edge case: Empty list of matchers
412
- return MATCH_NONE # type: ignore[return-value]
400
+ return MatchNone ()
413
401
elif len (matchers ) == 1 : # Edge case: List of exactly one matcher
414
- return matchers [0 ] # type: ignore[return-value] # same mypy bug
402
+ return matchers [0 ]
415
403
else : # Actual list of matchers (plural)
416
- return MetaMatcher (matchers ) # type: ignore[arg-type] # same mypy bug
404
+ return MetaMatcher (matchers )
417
405
else :
418
406
return spec
419
407
@@ -436,10 +424,7 @@ class FSNodeType(enum.Enum):
436
424
437
425
class walk (ty .Generator [FSNodeEntry , ty .Any , None ], ty .Generic [ty .AnyStr ]):
438
426
__slots__ = ("_generator" , "_close_fd" )
439
- #_generator: ty.Generator[FSNodeEntry, ty.Any, None]
440
- #_close_fd: ty.Optional[int]
441
-
442
-
427
+
443
428
def __init__ (
444
429
self ,
445
430
directory : ty .Union [ty .AnyStr , utils .PathLike [ty .AnyStr ], int ],
@@ -482,43 +467,44 @@ def __init__(
482
467
:class:`NoRecusionAdapterMatcher` and hence prevent the scanner from
483
468
doing any recursion.
484
469
"""
485
- self ._close_fd = None # type : ty.Optional[int]
486
-
470
+ self ._close_fd : ty .Optional [int ] = None
471
+
487
472
# Create matcher object
488
- matcher = matcher_from_spec (
489
- match_spec , recursive = recursive , period_special = period_special
490
- ) # type: Matcher[ty.AnyStr] # type: ignore[assignment]
491
-
473
+ matcher = matcher_from_spec ( # type: ignore[type-var]
474
+ match_spec , recursive = recursive , period_special = period_special # type: ignore[arg-type]
475
+ )
476
+
492
477
# Convert directory path to string …
493
478
if isinstance (directory , int ):
494
479
if not HAVE_FWALK :
495
480
raise NotImplementedError ("Passing a file descriptor as directory is "
496
481
"not supported on this platform" )
497
-
498
- self ._generator = self ._walk (
499
- directory , None , matcher , follow_symlinks , intermediate_dirs
500
- ) # type: ty.Generator[FSNodeEntry, ty.Any, None]
482
+
483
+ self ._generator : ty . Generator [ FSNodeEntry , None , None ] = self ._walk (
484
+ directory , None , matcher , follow_symlinks , intermediate_dirs # type: ignore[arg-type]
485
+ )
501
486
else :
502
- #directory_str: ty.AnyStr
503
- if hasattr (os , "fspath" ): #PY36+
504
- directory_str = os .fspath (directory )
505
- elif not ty .TYPE_CHECKING : #PY35
506
- directory_str = utils .convert_path (directory )
507
-
487
+ directory_str = os .fspath (directory )
488
+
508
489
# Best-effort ensure that target directory exists if it is accessed by path
509
490
os .stat (directory_str )
510
491
511
492
# … and possibly open it as a FD if this is supported by the platform
512
493
#
513
494
# Note: `os.fwalk` support for binary paths was only added in 3.7+.
514
- directory_str_or_fd = directory_str # type: ty.Union[ty.AnyStr, int]
495
+ directory_str_or_fd = directory_str
515
496
if HAVE_FWALK and (not isinstance (directory_str , bytes ) or HAVE_FWALK_BYTES ):
516
- self ._close_fd = directory_str_or_fd = os .open (directory_str , os .O_RDONLY | O_DIRECTORY )
517
-
497
+ fd = os .open (directory_str , os .O_RDONLY | O_DIRECTORY )
498
+ self ._close_fd = directory_str_or_fd = fd # type: ignore[assignment]
499
+
518
500
self ._generator = self ._walk (
519
- directory_str_or_fd , directory_str , matcher , follow_symlinks , intermediate_dirs
501
+ directory_str_or_fd ,
502
+ directory_str ,
503
+ matcher , # type: ignore[arg-type]
504
+ follow_symlinks ,
505
+ intermediate_dirs
520
506
)
521
-
507
+
522
508
def __iter__ (self ) -> 'walk[ty.AnyStr]' :
523
509
return self
524
510
@@ -548,7 +534,8 @@ def throw(self, typ: ty.Union[ty.Type[BaseException], BaseException],
548
534
tb : ty .Optional [types .TracebackType ] = None ) -> FSNodeEntry :
549
535
try :
550
536
if isinstance (typ , type ):
551
- return self ._generator .throw (typ , val , tb )
537
+ bt = ty .cast (ty .Type [BaseException ], typ ) # type: ignore[redundant-cast]
538
+ return self ._generator .throw (bt , val , tb )
552
539
else :
553
540
assert val is None
554
541
return self ._generator .throw (typ , val , tb )
@@ -595,8 +582,8 @@ def _walk(
595
582
while directory .endswith (sep ):
596
583
directory = directory [:- len (sep )]
597
584
prefix = (directory if not isinstance (directory , int ) else dot ) + sep
598
-
599
- reported_directories = set () # type : ty.Set[ty.AnyStr]
585
+
586
+ reported_directories : ty .Set [ty .AnyStr ] = set ()
600
587
601
588
# Always report the top-level directory even if nothing therein is matched
602
589
reported_directories .add (utils .maybe_fsencode ("" , sep ))
@@ -616,14 +603,19 @@ def _walk(
616
603
try :
617
604
for result in walk_iter :
618
605
dirpath , dirnames , filenames = result [0 :3 ]
619
- dirfd = result [3 ] if len (result ) > 3 else None # type:ty.Optional[int] # type: ignore[misc]
620
-
606
+
607
+ if len (result ) <= 3 :
608
+ dirfd : ty .Optional [int ] = None
609
+ else :
610
+ # mypy wrongly believes this will produce an index-out-of-range exception.
611
+ dirfd = result [3 ] # type: ignore[misc]
612
+
621
613
# Remove the directory prefix from the received path
622
614
_ , _ , dirpath = dirpath .partition (prefix )
623
615
624
616
# Keep track of reported intermediaries, so that we only check for
625
617
# these at most once per directory base
626
- intermediates_reported = False # type: bool
618
+ intermediates_reported = False
627
619
628
620
for filename , is_dir in self ._join_dirs_and_files (list (dirnames ), filenames ):
629
621
filepath = os .path .join (dirpath , filename )
0 commit comments