@@ -34,6 +34,23 @@ def _is_case_sensitive(parser):
3434 return parser .normcase ('Aa' ) == 'Aa'
3535
3636
37+ def _parse_path (path ):
38+ """
39+ Split the path into a 2-tuple (anchor, parts), where *anchor* is the
40+ uppermost parent of the path (equivalent to path.parents[-1]), and
41+ *parts* is a reversed list of parts following the anchor.
42+ """
43+ split = path .parser .split
44+ path = str (path )
45+ parent , name = split (path )
46+ names = []
47+ while path != parent :
48+ names .append (name )
49+ path = parent
50+ parent , name = split (path )
51+ return path , names
52+
53+
3754class PathGlobber (_GlobberBase ):
3855 """
3956 Class providing shell-style globbing for path objects.
@@ -115,7 +132,7 @@ def root(self):
115132 @property
116133 def anchor (self ):
117134 """The concatenation of the drive and root, or ''."""
118- return self . _stack [0 ]
135+ return _parse_path ( self ) [0 ]
119136
120137 @property
121138 def name (self ):
@@ -193,8 +210,8 @@ def relative_to(self, other, *, walk_up=False):
193210 """
194211 if not isinstance (other , PurePathBase ):
195212 other = self .with_segments (other )
196- anchor0 , parts0 = self . _stack
197- anchor1 , parts1 = other . _stack
213+ anchor0 , parts0 = _parse_path ( self )
214+ anchor1 , parts1 = _parse_path ( other )
198215 if anchor0 != anchor1 :
199216 raise ValueError (f"{ str (self )!r} and { str (other )!r} have different anchors" )
200217 while parts0 and parts1 and parts0 [- 1 ] == parts1 [- 1 ]:
@@ -216,8 +233,8 @@ def is_relative_to(self, other):
216233 """
217234 if not isinstance (other , PurePathBase ):
218235 other = self .with_segments (other )
219- anchor0 , parts0 = self . _stack
220- anchor1 , parts1 = other . _stack
236+ anchor0 , parts0 = _parse_path ( self )
237+ anchor1 , parts1 = _parse_path ( other )
221238 if anchor0 != anchor1 :
222239 return False
223240 while parts0 and parts1 and parts0 [- 1 ] == parts1 [- 1 ]:
@@ -232,7 +249,7 @@ def is_relative_to(self, other):
232249 def parts (self ):
233250 """An object providing sequence-like access to the
234251 components in the filesystem path."""
235- anchor , parts = self . _stack
252+ anchor , parts = _parse_path ( self )
236253 if anchor :
237254 parts .append (anchor )
238255 return tuple (reversed (parts ))
@@ -257,23 +274,6 @@ def __rtruediv__(self, key):
257274 except TypeError :
258275 return NotImplemented
259276
260- @property
261- def _stack (self ):
262- """
263- Split the path into a 2-tuple (anchor, parts), where *anchor* is the
264- uppermost parent of the path (equivalent to path.parents[-1]), and
265- *parts* is a reversed list of parts following the anchor.
266- """
267- split = self .parser .split
268- path = str (self )
269- parent , name = split (path )
270- names = []
271- while path != parent :
272- names .append (name )
273- path = parent
274- parent , name = split (path )
275- return path , names
276-
277277 @property
278278 def parent (self ):
279279 """The logical parent of the path."""
@@ -301,11 +301,6 @@ def is_absolute(self):
301301 a drive)."""
302302 return self .parser .isabs (str (self ))
303303
304- @property
305- def _pattern_str (self ):
306- """The path expressed as a string, for use in pattern-matching."""
307- return str (self )
308-
309304 def match (self , path_pattern , * , case_sensitive = None ):
310305 """
311306 Return True if this path matches the given pattern. If the pattern is
@@ -343,8 +338,8 @@ def full_match(self, pattern, *, case_sensitive=None):
343338 if case_sensitive is None :
344339 case_sensitive = _is_case_sensitive (self .parser )
345340 globber = self ._globber (pattern .parser .sep , case_sensitive , recursive = True )
346- match = globber .compile (pattern . _pattern_str )
347- return match (self . _pattern_str ) is not None
341+ match = globber .compile (str ( pattern ) )
342+ return match (str ( self ) ) is not None
348343
349344
350345
@@ -500,29 +495,25 @@ def iterdir(self):
500495 """
501496 raise UnsupportedOperation (self ._unsupported_msg ('iterdir()' ))
502497
503- def _glob_selector (self , parts , case_sensitive , recurse_symlinks ):
504- if case_sensitive is None :
505- case_sensitive = _is_case_sensitive (self .parser )
506- case_pedantic = False
507- else :
508- # The user has expressed a case sensitivity choice, but we don't
509- # know the case sensitivity of the underlying filesystem, so we
510- # must use scandir() for everything, including non-wildcard parts.
511- case_pedantic = True
512- recursive = True if recurse_symlinks else _no_recurse_symlinks
513- globber = self ._globber (self .parser .sep , case_sensitive , case_pedantic , recursive )
514- return globber .selector (parts )
515-
516498 def glob (self , pattern , * , case_sensitive = None , recurse_symlinks = True ):
517499 """Iterate over this subtree and yield all existing files (of any
518500 kind, including directories) matching the given relative pattern.
519501 """
520502 if not isinstance (pattern , PurePathBase ):
521503 pattern = self .with_segments (pattern )
522- anchor , parts = pattern . _stack
504+ anchor , parts = _parse_path ( pattern )
523505 if anchor :
524506 raise NotImplementedError ("Non-relative patterns are unsupported" )
525- select = self ._glob_selector (parts , case_sensitive , recurse_symlinks )
507+ if case_sensitive is None :
508+ case_sensitive = _is_case_sensitive (self .parser )
509+ case_pedantic = False
510+ elif case_sensitive == _is_case_sensitive (self .parser ):
511+ case_pedantic = False
512+ else :
513+ case_pedantic = True
514+ recursive = True if recurse_symlinks else _no_recurse_symlinks
515+ globber = self ._globber (self .parser .sep , case_sensitive , case_pedantic , recursive )
516+ select = globber .selector (parts )
526517 return select (self )
527518
528519 def rglob (self , pattern , * , case_sensitive = None , recurse_symlinks = True ):
0 commit comments