@@ -198,14 +198,13 @@ def __repr__(self):
198
198
return "<{}.parents>" .format (type (self ._path ).__name__ )
199
199
200
200
201
- class PurePath :
202
- """Base class for manipulating paths without I/O .
201
+ class _PurePathBase :
202
+ """Base class for pure path objects .
203
203
204
- PurePath represents a filesystem path and offers operations which
205
- don't imply any actual filesystem I/O. Depending on your system,
206
- instantiating a PurePath will return either a PurePosixPath or a
207
- PureWindowsPath object. You can also instantiate either of these classes
208
- directly, regardless of your system.
204
+ This class *does not* provide several magic methods that are defined in
205
+ its subclass PurePath. They are: __fspath__, __bytes__, __reduce__,
206
+ __hash__, __eq__, __lt__, __le__, __gt__, __ge__. Its initializer and path
207
+ joining methods accept only strings, not os.PathLike objects more broadly.
209
208
"""
210
209
211
210
__slots__ = (
@@ -227,29 +226,17 @@ class PurePath:
227
226
# for the first time. It's used to implement `_str_normcase`
228
227
'_str' ,
229
228
230
- # The `_str_normcase_cached` slot stores the string path with
231
- # normalized case. It is set when the `_str_normcase` property is
232
- # accessed for the first time. It's used to implement `__eq__()`
233
- # `__hash__()`, and `_parts_normcase`
234
- '_str_normcase_cached' ,
235
-
236
- # The `_parts_normcase_cached` slot stores the case-normalized
237
- # string path after splitting on path separators. It's set when the
238
- # `_parts_normcase` property is accessed for the first time. It's used
239
- # to implement comparison methods like `__lt__()`.
240
- '_parts_normcase_cached' ,
241
-
242
- # The `_hash` slot stores the hash of the case-normalized string
243
- # path. It's set when `__hash__()` is called for the first time.
244
- '_hash' ,
245
-
246
229
# The '_resolving' slot stores a boolean indicating whether the path
247
230
# is being processed by `_PathBase.resolve()`. This prevents duplicate
248
231
# work from occurring when `resolve()` calls `stat()` or `readlink()`.
249
232
'_resolving' ,
250
233
)
251
234
pathmod = os .path
252
235
236
+ def __init__ (self , * paths ):
237
+ self ._raw_paths = paths
238
+ self ._resolving = False
239
+
253
240
def with_segments (self , * pathsegments ):
254
241
"""Construct a new path object from any number of path-like objects.
255
242
Subclasses may override this method to customize how new path objects
@@ -444,7 +431,7 @@ def relative_to(self, other, /, *_deprecated, walk_up=False):
444
431
warnings ._deprecated ("pathlib.PurePath.relative_to(*args)" , msg ,
445
432
remove = (3 , 14 ))
446
433
other = self .with_segments (other , * _deprecated )
447
- elif not isinstance (other , PurePath ):
434
+ elif not isinstance (other , _PurePathBase ):
448
435
other = self .with_segments (other )
449
436
for step , path in enumerate (chain ([other ], other .parents )):
450
437
if path == self or path in self .parents :
@@ -468,7 +455,7 @@ def is_relative_to(self, other, /, *_deprecated):
468
455
warnings ._deprecated ("pathlib.PurePath.is_relative_to(*args)" ,
469
456
msg , remove = (3 , 14 ))
470
457
other = self .with_segments (other , * _deprecated )
471
- elif not isinstance (other , PurePath ):
458
+ elif not isinstance (other , _PurePathBase ):
472
459
other = self .with_segments (other )
473
460
return other == self or other in self .parents
474
461
@@ -487,7 +474,7 @@ def joinpath(self, *pathsegments):
487
474
paths) or a totally different path (if one of the arguments is
488
475
anchored).
489
476
"""
490
- return self .with_segments (self , * pathsegments )
477
+ return self .with_segments (* self . _raw_paths , * pathsegments )
491
478
492
479
def __truediv__ (self , key ):
493
480
try :
@@ -497,7 +484,7 @@ def __truediv__(self, key):
497
484
498
485
def __rtruediv__ (self , key ):
499
486
try :
500
- return self .with_segments (key , self )
487
+ return self .with_segments (key , * self . _raw_paths )
501
488
except TypeError :
502
489
return NotImplemented
503
490
@@ -555,7 +542,7 @@ def match(self, path_pattern, *, case_sensitive=None):
555
542
"""
556
543
Return True if this path matches the given pattern.
557
544
"""
558
- if not isinstance (path_pattern , PurePath ):
545
+ if not isinstance (path_pattern , _PurePathBase ):
559
546
path_pattern = self .with_segments (path_pattern )
560
547
if case_sensitive is None :
561
548
case_sensitive = _is_case_sensitive (self .pathmod )
@@ -570,6 +557,35 @@ def match(self, path_pattern, *, case_sensitive=None):
570
557
match = _compile_pattern (pattern_str , sep , case_sensitive )
571
558
return match (str (self )) is not None
572
559
560
+
561
+ class PurePath (_PurePathBase ):
562
+ """Base class for manipulating paths without I/O.
563
+
564
+ PurePath represents a filesystem path and offers operations which
565
+ don't imply any actual filesystem I/O. Depending on your system,
566
+ instantiating a PurePath will return either a PurePosixPath or a
567
+ PureWindowsPath object. You can also instantiate either of these classes
568
+ directly, regardless of your system.
569
+ """
570
+
571
+ __slots__ = (
572
+ # The `_str_normcase_cached` slot stores the string path with
573
+ # normalized case. It is set when the `_str_normcase` property is
574
+ # accessed for the first time. It's used to implement `__eq__()`
575
+ # `__hash__()`, and `_parts_normcase`
576
+ '_str_normcase_cached' ,
577
+
578
+ # The `_parts_normcase_cached` slot stores the case-normalized
579
+ # string path after splitting on path separators. It's set when the
580
+ # `_parts_normcase` property is accessed for the first time. It's used
581
+ # to implement comparison methods like `__lt__()`.
582
+ '_parts_normcase_cached' ,
583
+
584
+ # The `_hash` slot stores the hash of the case-normalized string
585
+ # path. It's set when `__hash__()` is called for the first time.
586
+ '_hash' ,
587
+ )
588
+
573
589
def __new__ (cls , * args , ** kwargs ):
574
590
"""Construct a PurePath from one or several strings and or existing
575
591
PurePath objects. The strings and path objects are combined so as
@@ -600,8 +616,7 @@ def __init__(self, *args):
600
616
"object where __fspath__ returns a str, "
601
617
f"not { type (path ).__name__ !r} " )
602
618
paths .append (path )
603
- self ._raw_paths = paths
604
- self ._resolving = False
619
+ super ().__init__ (* paths )
605
620
606
621
def __reduce__ (self ):
607
622
# Using the parts tuple helps share interned path parts
@@ -719,7 +734,7 @@ class PureWindowsPath(PurePath):
719
734
# Filesystem-accessing classes
720
735
721
736
722
- class _PathBase (PurePath ):
737
+ class _PathBase (_PurePathBase ):
723
738
"""Base class for concrete path objects.
724
739
725
740
This class provides dummy implementations for many methods that derived
@@ -733,8 +748,6 @@ class _PathBase(PurePath):
733
748
such as paths in archive files or on remote storage systems.
734
749
"""
735
750
__slots__ = ()
736
- __bytes__ = None
737
- __fspath__ = None # virtual paths have no local file system representation
738
751
739
752
@classmethod
740
753
def _unsupported (cls , method_name ):
@@ -1341,7 +1354,7 @@ def as_uri(self):
1341
1354
self ._unsupported ("as_uri" )
1342
1355
1343
1356
1344
- class Path (_PathBase ):
1357
+ class Path (_PathBase , PurePath ):
1345
1358
"""PurePath subclass that can make system calls.
1346
1359
1347
1360
Path represents a filesystem path but unlike PurePath, also offers
@@ -1351,8 +1364,6 @@ class Path(_PathBase):
1351
1364
but cannot instantiate a WindowsPath on a POSIX system or vice versa.
1352
1365
"""
1353
1366
__slots__ = ()
1354
- __bytes__ = PurePath .__bytes__
1355
- __fspath__ = PurePath .__fspath__
1356
1367
as_uri = PurePath .as_uri
1357
1368
1358
1369
def __init__ (self , * args , ** kwargs ):
0 commit comments