@@ -67,7 +67,7 @@ def _is_case_sensitive(flavour):
6767#
6868
6969@functools .lru_cache ()
70- def _make_selector (pattern_parts , case_sensitive ):
70+ def _make_selector (pattern_parts , flavour , case_sensitive ):
7171 pat = pattern_parts [0 ]
7272 child_parts = pattern_parts [1 :]
7373 if not pat :
@@ -78,19 +78,21 @@ def _make_selector(pattern_parts, case_sensitive):
7878 cls = _ParentSelector
7979 elif '**' in pat :
8080 raise ValueError ("Invalid pattern: '**' can only be an entire path component" )
81- else :
81+ elif _is_wildcard_pattern ( pat ) or case_sensitive != _is_case_sensitive ( flavour ) :
8282 cls = _WildcardSelector
83- return cls (pat , child_parts , case_sensitive )
83+ else :
84+ cls = _PreciseSelector
85+ return cls (pat , child_parts , flavour , case_sensitive )
8486
8587
8688class _Selector :
8789 """A selector matches a specific glob pattern part against the children
8890 of a given path."""
8991
90- def __init__ (self , child_parts , case_sensitive ):
92+ def __init__ (self , child_parts , flavour , case_sensitive ):
9193 self .child_parts = child_parts
9294 if child_parts :
93- self .successor = _make_selector (child_parts , case_sensitive )
95+ self .successor = _make_selector (child_parts , flavour , case_sensitive )
9496 self .dironly = True
9597 else :
9698 self .successor = _TerminatingSelector ()
@@ -100,37 +102,55 @@ def select_from(self, parent_path):
100102 """Iterate over all child paths of `parent_path` matched by this
101103 selector. This can contain parent_path itself."""
102104 path_cls = type (parent_path )
105+ is_dir = path_cls .is_dir
106+ exists = path_cls .exists
103107 scandir = path_cls ._scandir
104- if not parent_path . is_dir ():
108+ if not is_dir (parent_path ):
105109 return iter ([])
106- return self ._select_from (parent_path , scandir )
110+ return self ._select_from (parent_path , is_dir , exists , scandir )
107111
108112
109113class _TerminatingSelector :
110114
111- def _select_from (self , parent_path , scandir ):
115+ def _select_from (self , parent_path , is_dir , exists , scandir ):
112116 yield parent_path
113117
114118
115119class _ParentSelector (_Selector ):
116120
117- def __init__ (self , name , child_parts , case_sensitive ):
118- _Selector .__init__ (self , child_parts , case_sensitive )
121+ def __init__ (self , name , child_parts , flavour , case_sensitive ):
122+ _Selector .__init__ (self , child_parts , flavour , case_sensitive )
119123
120- def _select_from (self , parent_path , scandir ):
124+ def _select_from (self , parent_path , is_dir , exists , scandir ):
121125 path = parent_path ._make_child_relpath ('..' )
122- for p in self .successor ._select_from (path , scandir ):
126+ for p in self .successor ._select_from (path , is_dir , exists , scandir ):
123127 yield p
124128
125129
130+ class _PreciseSelector (_Selector ):
131+
132+ def __init__ (self , name , child_parts , flavour , case_sensitive ):
133+ self .name = name
134+ _Selector .__init__ (self , child_parts , flavour , case_sensitive )
135+
136+ def _select_from (self , parent_path , is_dir , exists , scandir ):
137+ try :
138+ path = parent_path ._make_child_relpath (self .name )
139+ if (is_dir if self .dironly else exists )(path ):
140+ for p in self .successor ._select_from (path , is_dir , exists , scandir ):
141+ yield p
142+ except PermissionError :
143+ return
144+
145+
126146class _WildcardSelector (_Selector ):
127147
128- def __init__ (self , pat , child_parts , case_sensitive ):
148+ def __init__ (self , pat , child_parts , flavour , case_sensitive ):
129149 flags = re .NOFLAG if case_sensitive else re .IGNORECASE
130150 self .match = re .compile (fnmatch .translate (pat ), flags = flags ).fullmatch
131- _Selector .__init__ (self , child_parts , case_sensitive )
151+ _Selector .__init__ (self , child_parts , flavour , case_sensitive )
132152
133- def _select_from (self , parent_path , scandir ):
153+ def _select_from (self , parent_path , is_dir , exists , scandir ):
134154 try :
135155 # We must close the scandir() object before proceeding to
136156 # avoid exhausting file descriptors when globbing deep trees.
@@ -151,18 +171,18 @@ def _select_from(self, parent_path, scandir):
151171 name = entry .name
152172 if self .match (name ):
153173 path = parent_path ._make_child_relpath (name )
154- for p in self .successor ._select_from (path , scandir ):
174+ for p in self .successor ._select_from (path , is_dir , exists , scandir ):
155175 yield p
156176 except PermissionError :
157177 return
158178
159179
160180class _RecursiveWildcardSelector (_Selector ):
161181
162- def __init__ (self , pat , child_parts , case_sensitive ):
163- _Selector .__init__ (self , child_parts , case_sensitive )
182+ def __init__ (self , pat , child_parts , flavour , case_sensitive ):
183+ _Selector .__init__ (self , child_parts , flavour , case_sensitive )
164184
165- def _iterate_directories (self , parent_path , scandir ):
185+ def _iterate_directories (self , parent_path , is_dir , scandir ):
166186 yield parent_path
167187 try :
168188 # We must close the scandir() object before proceeding to
@@ -178,18 +198,18 @@ def _iterate_directories(self, parent_path, scandir):
178198 raise
179199 if entry_is_dir and not entry .is_symlink ():
180200 path = parent_path ._make_child_relpath (entry .name )
181- for p in self ._iterate_directories (path , scandir ):
201+ for p in self ._iterate_directories (path , is_dir , scandir ):
182202 yield p
183203 except PermissionError :
184204 return
185205
186- def _select_from (self , parent_path , scandir ):
206+ def _select_from (self , parent_path , is_dir , exists , scandir ):
187207 try :
188208 yielded = set ()
189209 try :
190210 successor_select = self .successor ._select_from
191- for starting_point in self ._iterate_directories (parent_path , scandir ):
192- for p in successor_select (starting_point , scandir ):
211+ for starting_point in self ._iterate_directories (parent_path , is_dir , scandir ):
212+ for p in successor_select (starting_point , is_dir , exists , scandir ):
193213 if p not in yielded :
194214 yield p
195215 yielded .add (p )
@@ -839,7 +859,7 @@ def glob(self, pattern, *, case_sensitive=None):
839859 pattern_parts .append ('' )
840860 if case_sensitive is None :
841861 case_sensitive = _is_case_sensitive (self ._flavour )
842- selector = _make_selector (tuple (pattern_parts ), case_sensitive )
862+ selector = _make_selector (tuple (pattern_parts ), self . _flavour , case_sensitive )
843863 for p in selector .select_from (self ):
844864 yield p
845865
@@ -856,7 +876,7 @@ def rglob(self, pattern, *, case_sensitive=None):
856876 pattern_parts .append ('' )
857877 if case_sensitive is None :
858878 case_sensitive = _is_case_sensitive (self ._flavour )
859- selector = _make_selector (("**" ,) + tuple (pattern_parts ), case_sensitive )
879+ selector = _make_selector (("**" ,) + tuple (pattern_parts ), self . _flavour , case_sensitive )
860880 for p in selector .select_from (self ):
861881 yield p
862882
0 commit comments