@@ -25,6 +25,23 @@ def _is_case_sensitive(parser):
25
25
return parser .normcase ('Aa' ) == 'Aa'
26
26
27
27
28
+ def _explode_path (path ):
29
+ """
30
+ Split the path into a 2-tuple (anchor, parts), where *anchor* is the
31
+ uppermost parent of the path (equivalent to path.parents[-1]), and
32
+ *parts* is a reversed list of parts following the anchor.
33
+ """
34
+ split = path .parser .split
35
+ path = str (path )
36
+ parent , name = split (path )
37
+ names = []
38
+ while path != parent :
39
+ names .append (name )
40
+ path = parent
41
+ parent , name = split (path )
42
+ return path , names
43
+
44
+
28
45
class PathGlobber (_GlobberBase ):
29
46
"""
30
47
Class providing shell-style globbing for path objects.
@@ -50,7 +67,6 @@ class PurePathBase:
50
67
51
68
__slots__ = ()
52
69
parser = posixpath
53
- _globber = PathGlobber
54
70
55
71
def with_segments (self , * pathsegments ):
56
72
"""Construct a new path object from any number of path-like objects.
@@ -82,7 +98,7 @@ def root(self):
82
98
@property
83
99
def anchor (self ):
84
100
"""The concatenation of the drive and root, or ''."""
85
- return self . _stack [0 ]
101
+ return _explode_path ( self ) [0 ]
86
102
87
103
@property
88
104
def name (self ):
@@ -160,8 +176,8 @@ def relative_to(self, other, *, walk_up=False):
160
176
"""
161
177
if not isinstance (other , PurePathBase ):
162
178
other = self .with_segments (other )
163
- anchor0 , parts0 = self . _stack
164
- anchor1 , parts1 = other . _stack
179
+ anchor0 , parts0 = _explode_path ( self )
180
+ anchor1 , parts1 = _explode_path ( other )
165
181
if anchor0 != anchor1 :
166
182
raise ValueError (f"{ str (self )!r} and { str (other )!r} have different anchors" )
167
183
while parts0 and parts1 and parts0 [- 1 ] == parts1 [- 1 ]:
@@ -183,8 +199,8 @@ def is_relative_to(self, other):
183
199
"""
184
200
if not isinstance (other , PurePathBase ):
185
201
other = self .with_segments (other )
186
- anchor0 , parts0 = self . _stack
187
- anchor1 , parts1 = other . _stack
202
+ anchor0 , parts0 = _explode_path ( self )
203
+ anchor1 , parts1 = _explode_path ( other )
188
204
if anchor0 != anchor1 :
189
205
return False
190
206
while parts0 and parts1 and parts0 [- 1 ] == parts1 [- 1 ]:
@@ -199,7 +215,7 @@ def is_relative_to(self, other):
199
215
def parts (self ):
200
216
"""An object providing sequence-like access to the
201
217
components in the filesystem path."""
202
- anchor , parts = self . _stack
218
+ anchor , parts = _explode_path ( self )
203
219
if anchor :
204
220
parts .append (anchor )
205
221
return tuple (reversed (parts ))
@@ -224,23 +240,6 @@ def __rtruediv__(self, key):
224
240
except TypeError :
225
241
return NotImplemented
226
242
227
- @property
228
- def _stack (self ):
229
- """
230
- Split the path into a 2-tuple (anchor, parts), where *anchor* is the
231
- uppermost parent of the path (equivalent to path.parents[-1]), and
232
- *parts* is a reversed list of parts following the anchor.
233
- """
234
- split = self .parser .split
235
- path = str (self )
236
- parent , name = split (path )
237
- names = []
238
- while path != parent :
239
- names .append (name )
240
- path = parent
241
- parent , name = split (path )
242
- return path , names
243
-
244
243
@property
245
244
def parent (self ):
246
245
"""The logical parent of the path."""
@@ -268,11 +267,6 @@ def is_absolute(self):
268
267
a drive)."""
269
268
return self .parser .isabs (str (self ))
270
269
271
- @property
272
- def _pattern_str (self ):
273
- """The path expressed as a string, for use in pattern-matching."""
274
- return str (self )
275
-
276
270
def match (self , path_pattern , * , case_sensitive = None ):
277
271
"""
278
272
Return True if this path matches the given pattern. If the pattern is
@@ -293,7 +287,7 @@ def match(self, path_pattern, *, case_sensitive=None):
293
287
return False
294
288
if len (path_parts ) > len (pattern_parts ) and path_pattern .anchor :
295
289
return False
296
- globber = self . _globber (sep , case_sensitive )
290
+ globber = PathGlobber (sep , case_sensitive )
297
291
for path_part , pattern_part in zip (path_parts , pattern_parts ):
298
292
match = globber .compile (pattern_part )
299
293
if match (path_part ) is None :
@@ -309,9 +303,9 @@ def full_match(self, pattern, *, case_sensitive=None):
309
303
pattern = self .with_segments (pattern )
310
304
if case_sensitive is None :
311
305
case_sensitive = _is_case_sensitive (self .parser )
312
- globber = self . _globber (pattern .parser .sep , case_sensitive , recursive = True )
313
- match = globber .compile (pattern . _pattern_str )
314
- return match (self . _pattern_str ) is not None
306
+ globber = PathGlobber (pattern .parser .sep , case_sensitive , recursive = True )
307
+ match = globber .compile (str ( pattern ) )
308
+ return match (str ( self ) ) is not None
315
309
316
310
317
311
@@ -463,29 +457,25 @@ def iterdir(self):
463
457
"""
464
458
raise NotImplementedError
465
459
466
- def _glob_selector (self , parts , case_sensitive , recurse_symlinks ):
467
- if case_sensitive is None :
468
- case_sensitive = _is_case_sensitive (self .parser )
469
- case_pedantic = False
470
- else :
471
- # The user has expressed a case sensitivity choice, but we don't
472
- # know the case sensitivity of the underlying filesystem, so we
473
- # must use scandir() for everything, including non-wildcard parts.
474
- case_pedantic = True
475
- recursive = True if recurse_symlinks else _no_recurse_symlinks
476
- globber = self ._globber (self .parser .sep , case_sensitive , case_pedantic , recursive )
477
- return globber .selector (parts )
478
-
479
460
def glob (self , pattern , * , case_sensitive = None , recurse_symlinks = True ):
480
461
"""Iterate over this subtree and yield all existing files (of any
481
462
kind, including directories) matching the given relative pattern.
482
463
"""
483
464
if not isinstance (pattern , PurePathBase ):
484
465
pattern = self .with_segments (pattern )
485
- anchor , parts = pattern . _stack
466
+ anchor , parts = _explode_path ( pattern )
486
467
if anchor :
487
468
raise NotImplementedError ("Non-relative patterns are unsupported" )
488
- select = self ._glob_selector (parts , case_sensitive , recurse_symlinks )
469
+ if case_sensitive is None :
470
+ case_sensitive = _is_case_sensitive (self .parser )
471
+ case_pedantic = False
472
+ elif case_sensitive == _is_case_sensitive (self .parser ):
473
+ case_pedantic = False
474
+ else :
475
+ case_pedantic = True
476
+ recursive = True if recurse_symlinks else _no_recurse_symlinks
477
+ globber = PathGlobber (self .parser .sep , case_sensitive , case_pedantic , recursive )
478
+ select = globber .selector (parts )
489
479
return select (self )
490
480
491
481
def rglob (self , pattern , * , case_sensitive = None , recurse_symlinks = True ):
0 commit comments