@@ -67,7 +67,7 @@ def _is_case_sensitive(flavour):
67
67
#
68
68
69
69
@functools .lru_cache ()
70
- def _make_selector (pattern_parts , case_sensitive ):
70
+ def _make_selector (pattern_parts , flavour , case_sensitive ):
71
71
pat = pattern_parts [0 ]
72
72
child_parts = pattern_parts [1 :]
73
73
if not pat :
@@ -78,19 +78,21 @@ def _make_selector(pattern_parts, case_sensitive):
78
78
cls = _ParentSelector
79
79
elif '**' in pat :
80
80
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 ) :
82
82
cls = _WildcardSelector
83
- return cls (pat , child_parts , case_sensitive )
83
+ else :
84
+ cls = _PreciseSelector
85
+ return cls (pat , child_parts , flavour , case_sensitive )
84
86
85
87
86
88
class _Selector :
87
89
"""A selector matches a specific glob pattern part against the children
88
90
of a given path."""
89
91
90
- def __init__ (self , child_parts , case_sensitive ):
92
+ def __init__ (self , child_parts , flavour , case_sensitive ):
91
93
self .child_parts = child_parts
92
94
if child_parts :
93
- self .successor = _make_selector (child_parts , case_sensitive )
95
+ self .successor = _make_selector (child_parts , flavour , case_sensitive )
94
96
self .dironly = True
95
97
else :
96
98
self .successor = _TerminatingSelector ()
@@ -100,37 +102,55 @@ def select_from(self, parent_path):
100
102
"""Iterate over all child paths of `parent_path` matched by this
101
103
selector. This can contain parent_path itself."""
102
104
path_cls = type (parent_path )
105
+ is_dir = path_cls .is_dir
106
+ exists = path_cls .exists
103
107
scandir = path_cls ._scandir
104
- if not parent_path . is_dir ():
108
+ if not is_dir (parent_path ):
105
109
return iter ([])
106
- return self ._select_from (parent_path , scandir )
110
+ return self ._select_from (parent_path , is_dir , exists , scandir )
107
111
108
112
109
113
class _TerminatingSelector :
110
114
111
- def _select_from (self , parent_path , scandir ):
115
+ def _select_from (self , parent_path , is_dir , exists , scandir ):
112
116
yield parent_path
113
117
114
118
115
119
class _ParentSelector (_Selector ):
116
120
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 )
119
123
120
- def _select_from (self , parent_path , scandir ):
124
+ def _select_from (self , parent_path , is_dir , exists , scandir ):
121
125
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 ):
123
127
yield p
124
128
125
129
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
+
126
146
class _WildcardSelector (_Selector ):
127
147
128
- def __init__ (self , pat , child_parts , case_sensitive ):
148
+ def __init__ (self , pat , child_parts , flavour , case_sensitive ):
129
149
flags = re .NOFLAG if case_sensitive else re .IGNORECASE
130
150
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 )
132
152
133
- def _select_from (self , parent_path , scandir ):
153
+ def _select_from (self , parent_path , is_dir , exists , scandir ):
134
154
try :
135
155
# We must close the scandir() object before proceeding to
136
156
# avoid exhausting file descriptors when globbing deep trees.
@@ -151,18 +171,18 @@ def _select_from(self, parent_path, scandir):
151
171
name = entry .name
152
172
if self .match (name ):
153
173
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 ):
155
175
yield p
156
176
except PermissionError :
157
177
return
158
178
159
179
160
180
class _RecursiveWildcardSelector (_Selector ):
161
181
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 )
164
184
165
- def _iterate_directories (self , parent_path , scandir ):
185
+ def _iterate_directories (self , parent_path , is_dir , scandir ):
166
186
yield parent_path
167
187
try :
168
188
# We must close the scandir() object before proceeding to
@@ -178,18 +198,18 @@ def _iterate_directories(self, parent_path, scandir):
178
198
raise
179
199
if entry_is_dir and not entry .is_symlink ():
180
200
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 ):
182
202
yield p
183
203
except PermissionError :
184
204
return
185
205
186
- def _select_from (self , parent_path , scandir ):
206
+ def _select_from (self , parent_path , is_dir , exists , scandir ):
187
207
try :
188
208
yielded = set ()
189
209
try :
190
210
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 ):
193
213
if p not in yielded :
194
214
yield p
195
215
yielded .add (p )
@@ -839,7 +859,7 @@ def glob(self, pattern, *, case_sensitive=None):
839
859
pattern_parts .append ('' )
840
860
if case_sensitive is None :
841
861
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 )
843
863
for p in selector .select_from (self ):
844
864
yield p
845
865
@@ -856,7 +876,7 @@ def rglob(self, pattern, *, case_sensitive=None):
856
876
pattern_parts .append ('' )
857
877
if case_sensitive is None :
858
878
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 )
860
880
for p in selector .select_from (self ):
861
881
yield p
862
882
0 commit comments