@@ -99,7 +99,7 @@ class PathGlobber(_GlobberBase):
9999 @staticmethod
100100 def concat_path (path , text ):
101101 """Appends text to the given path."""
102- return path .with_segments (path . _raw_path + text )
102+ return path .with_segments (str ( path ) + text )
103103
104104
105105class PurePathBase :
@@ -112,9 +112,13 @@ class PurePathBase:
112112 """
113113
114114 __slots__ = (
115- # The `_raw_path` slot store a joined string path. This is set in the
116- # `__init__()` method.
117- '_raw_path' ,
115+ # The `_raw_paths` slot stores unjoined string paths. This is set in
116+ # the `__init__()` method.
117+ '_raw_paths' ,
118+
119+ # The `_str` slot stores the string representation of the path,
120+ # computed when `__str__()` is called for the first time.
121+ '_str' ,
118122
119123 # The '_resolving' slot stores a boolean indicating whether the path
120124 # is being processed by `PathBase.resolve()`. This prevents duplicate
@@ -124,11 +128,14 @@ class PurePathBase:
124128 parser = ParserBase ()
125129 _globber = PathGlobber
126130
127- def __init__ (self , path , * paths ):
128- self ._raw_path = self .parser .join (path , * paths ) if paths else path
129- if not isinstance (self ._raw_path , str ):
130- raise TypeError (
131- f"path should be a str, not { type (self ._raw_path ).__name__ !r} " )
131+ def __init__ (self , arg , * args ):
132+ paths = [arg ]
133+ paths .extend (args )
134+ for path in paths :
135+ if not isinstance (path , str ):
136+ raise TypeError (
137+ f"path should be a str, not { type (path ).__name__ !r} " )
138+ self ._raw_paths = paths
132139 self ._resolving = False
133140
134141 def with_segments (self , * pathsegments ):
@@ -138,10 +145,25 @@ def with_segments(self, *pathsegments):
138145 """
139146 return type (self )(* pathsegments )
140147
148+ @property
149+ def _raw_path (self ):
150+ paths = self ._raw_paths
151+ if len (paths ) == 0 :
152+ path = ''
153+ elif len (paths ) == 1 :
154+ path = paths [0 ]
155+ else :
156+ path = self .parser .join (* paths )
157+ return path
158+
141159 def __str__ (self ):
142160 """Return the string representation of the path, suitable for
143161 passing to system calls."""
144- return self ._raw_path
162+ try :
163+ return self ._str
164+ except AttributeError :
165+ self ._str = self ._raw_path
166+ return self ._str
145167
146168 def as_posix (self ):
147169 """Return the string representation of the path with forward (/)
@@ -166,7 +188,7 @@ def anchor(self):
166188 @property
167189 def name (self ):
168190 """The final path component, if any."""
169- return self .parser .split (self . _raw_path )[1 ]
191+ return self .parser .split (str ( self ) )[1 ]
170192
171193 @property
172194 def suffix (self ):
@@ -202,7 +224,7 @@ def with_name(self, name):
202224 split = self .parser .split
203225 if split (name )[0 ]:
204226 raise ValueError (f"Invalid name { name !r} " )
205- return self .with_segments (split (self . _raw_path )[0 ], name )
227+ return self .with_segments (split (str ( self ) )[0 ], name )
206228
207229 def with_stem (self , stem ):
208230 """Return a new path with the stem changed."""
@@ -242,17 +264,17 @@ def relative_to(self, other, *, walk_up=False):
242264 anchor0 , parts0 = self ._stack
243265 anchor1 , parts1 = other ._stack
244266 if anchor0 != anchor1 :
245- raise ValueError (f"{ self . _raw_path !r} and { other . _raw_path !r} have different anchors" )
267+ raise ValueError (f"{ str ( self ) !r} and { str ( other ) !r} have different anchors" )
246268 while parts0 and parts1 and parts0 [- 1 ] == parts1 [- 1 ]:
247269 parts0 .pop ()
248270 parts1 .pop ()
249271 for part in parts1 :
250272 if not part or part == '.' :
251273 pass
252274 elif not walk_up :
253- raise ValueError (f"{ self . _raw_path !r} is not in the subpath of { other . _raw_path !r} " )
275+ raise ValueError (f"{ str ( self ) !r} is not in the subpath of { str ( other ) !r} " )
254276 elif part == '..' :
255- raise ValueError (f"'..' segment in { other . _raw_path !r} cannot be walked" )
277+ raise ValueError (f"'..' segment in { str ( other ) !r} cannot be walked" )
256278 else :
257279 parts0 .append ('..' )
258280 return self .with_segments ('' , * reversed (parts0 ))
@@ -289,17 +311,17 @@ def joinpath(self, *pathsegments):
289311 paths) or a totally different path (if one of the arguments is
290312 anchored).
291313 """
292- return self .with_segments (self ._raw_path , * pathsegments )
314+ return self .with_segments (* self ._raw_paths , * pathsegments )
293315
294316 def __truediv__ (self , key ):
295317 try :
296- return self .with_segments (self ._raw_path , key )
318+ return self .with_segments (* self ._raw_paths , key )
297319 except TypeError :
298320 return NotImplemented
299321
300322 def __rtruediv__ (self , key ):
301323 try :
302- return self .with_segments (key , self ._raw_path )
324+ return self .with_segments (key , * self ._raw_paths )
303325 except TypeError :
304326 return NotImplemented
305327
@@ -311,7 +333,7 @@ def _stack(self):
311333 *parts* is a reversed list of parts following the anchor.
312334 """
313335 split = self .parser .split
314- path = self . _raw_path
336+ path = str ( self )
315337 parent , name = split (path )
316338 names = []
317339 while path != parent :
@@ -323,7 +345,7 @@ def _stack(self):
323345 @property
324346 def parent (self ):
325347 """The logical parent of the path."""
326- path = self . _raw_path
348+ path = str ( self )
327349 parent = self .parser .split (path )[0 ]
328350 if path != parent :
329351 parent = self .with_segments (parent )
@@ -335,7 +357,7 @@ def parent(self):
335357 def parents (self ):
336358 """A sequence of this path's logical parents."""
337359 split = self .parser .split
338- path = self . _raw_path
360+ path = str ( self )
339361 parent = split (path )[0 ]
340362 parents = []
341363 while path != parent :
@@ -347,7 +369,7 @@ def parents(self):
347369 def is_absolute (self ):
348370 """True if the path is absolute (has both a root and, if applicable,
349371 a drive)."""
350- return self .parser .isabs (self . _raw_path )
372+ return self .parser .isabs (str ( self ) )
351373
352374 @property
353375 def _pattern_str (self ):
0 commit comments