@@ -385,6 +385,8 @@ def wrapped(pathobjA, pathobjB, *args):
385
385
386
386
listdir = _wrap_strfunc (os .listdir )
387
387
388
+ scandir = _wrap_strfunc (os .scandir )
389
+
388
390
chmod = _wrap_strfunc (os .chmod )
389
391
390
392
if hasattr (os , "lchmod" ):
@@ -429,25 +431,6 @@ def readlink(self, path):
429
431
# Globbing helpers
430
432
#
431
433
432
- @contextmanager
433
- def _cached (func ):
434
- try :
435
- func .__cached__
436
- yield func
437
- except AttributeError :
438
- cache = {}
439
- def wrapper (* args ):
440
- try :
441
- return cache [args ]
442
- except KeyError :
443
- value = cache [args ] = func (* args )
444
- return value
445
- wrapper .__cached__ = True
446
- try :
447
- yield wrapper
448
- finally :
449
- cache .clear ()
450
-
451
434
def _make_selector (pattern_parts ):
452
435
pat = pattern_parts [0 ]
453
436
child_parts = pattern_parts [1 :]
@@ -473,22 +456,26 @@ def __init__(self, child_parts):
473
456
self .child_parts = child_parts
474
457
if child_parts :
475
458
self .successor = _make_selector (child_parts )
459
+ self .dironly = True
476
460
else :
477
461
self .successor = _TerminatingSelector ()
462
+ self .dironly = False
478
463
479
464
def select_from (self , parent_path ):
480
465
"""Iterate over all child paths of `parent_path` matched by this
481
466
selector. This can contain parent_path itself."""
482
467
path_cls = type (parent_path )
483
468
is_dir = path_cls .is_dir
484
469
exists = path_cls .exists
485
- listdir = parent_path ._accessor .listdir
486
- return self ._select_from (parent_path , is_dir , exists , listdir )
470
+ scandir = parent_path ._accessor .scandir
471
+ if not is_dir (parent_path ):
472
+ return iter ([])
473
+ return self ._select_from (parent_path , is_dir , exists , scandir )
487
474
488
475
489
476
class _TerminatingSelector :
490
477
491
- def _select_from (self , parent_path , is_dir , exists , listdir ):
478
+ def _select_from (self , parent_path , is_dir , exists , scandir ):
492
479
yield parent_path
493
480
494
481
@@ -498,13 +485,11 @@ def __init__(self, name, child_parts):
498
485
self .name = name
499
486
_Selector .__init__ (self , child_parts )
500
487
501
- def _select_from (self , parent_path , is_dir , exists , listdir ):
488
+ def _select_from (self , parent_path , is_dir , exists , scandir ):
502
489
try :
503
- if not is_dir (parent_path ):
504
- return
505
490
path = parent_path ._make_child_relpath (self .name )
506
- if exists (path ):
507
- for p in self .successor ._select_from (path , is_dir , exists , listdir ):
491
+ if ( is_dir if self . dironly else exists ) (path ):
492
+ for p in self .successor ._select_from (path , is_dir , exists , scandir ):
508
493
yield p
509
494
except PermissionError :
510
495
return
@@ -516,17 +501,18 @@ def __init__(self, pat, child_parts):
516
501
self .pat = re .compile (fnmatch .translate (pat ))
517
502
_Selector .__init__ (self , child_parts )
518
503
519
- def _select_from (self , parent_path , is_dir , exists , listdir ):
504
+ def _select_from (self , parent_path , is_dir , exists , scandir ):
520
505
try :
521
- if not is_dir (parent_path ):
522
- return
523
506
cf = parent_path ._flavour .casefold
524
- for name in listdir (parent_path ):
525
- casefolded = cf (name )
526
- if self .pat .match (casefolded ):
527
- path = parent_path ._make_child_relpath (name )
528
- for p in self .successor ._select_from (path , is_dir , exists , listdir ):
529
- yield p
507
+ entries = list (scandir (parent_path ))
508
+ for entry in entries :
509
+ if not self .dironly or entry .is_dir ():
510
+ name = entry .name
511
+ casefolded = cf (name )
512
+ if self .pat .match (casefolded ):
513
+ path = parent_path ._make_child_relpath (name )
514
+ for p in self .successor ._select_from (path , is_dir , exists , scandir ):
515
+ yield p
530
516
except PermissionError :
531
517
return
532
518
@@ -537,32 +523,30 @@ class _RecursiveWildcardSelector(_Selector):
537
523
def __init__ (self , pat , child_parts ):
538
524
_Selector .__init__ (self , child_parts )
539
525
540
- def _iterate_directories (self , parent_path , is_dir , listdir ):
526
+ def _iterate_directories (self , parent_path , is_dir , scandir ):
541
527
yield parent_path
542
528
try :
543
- for name in listdir (parent_path ):
544
- path = parent_path ._make_child_relpath (name )
545
- if is_dir (path ) and not path .is_symlink ():
546
- for p in self ._iterate_directories (path , is_dir , listdir ):
529
+ entries = list (scandir (parent_path ))
530
+ for entry in entries :
531
+ if entry .is_dir () and not entry .is_symlink ():
532
+ path = parent_path ._make_child_relpath (entry .name )
533
+ for p in self ._iterate_directories (path , is_dir , scandir ):
547
534
yield p
548
535
except PermissionError :
549
536
return
550
537
551
- def _select_from (self , parent_path , is_dir , exists , listdir ):
538
+ def _select_from (self , parent_path , is_dir , exists , scandir ):
552
539
try :
553
- if not is_dir (parent_path ):
554
- return
555
- with _cached (listdir ) as listdir :
556
- yielded = set ()
557
- try :
558
- successor_select = self .successor ._select_from
559
- for starting_point in self ._iterate_directories (parent_path , is_dir , listdir ):
560
- for p in successor_select (starting_point , is_dir , exists , listdir ):
561
- if p not in yielded :
562
- yield p
563
- yielded .add (p )
564
- finally :
565
- yielded .clear ()
540
+ yielded = set ()
541
+ try :
542
+ successor_select = self .successor ._select_from
543
+ for starting_point in self ._iterate_directories (parent_path , is_dir , scandir ):
544
+ for p in successor_select (starting_point , is_dir , exists , scandir ):
545
+ if p not in yielded :
546
+ yield p
547
+ yielded .add (p )
548
+ finally :
549
+ yielded .clear ()
566
550
except PermissionError :
567
551
return
568
552
0 commit comments