@@ -99,7 +99,7 @@ class PathGlobber(_GlobberBase):
99
99
@staticmethod
100
100
def concat_path (path , text ):
101
101
"""Appends text to the given path."""
102
- return path .with_segments (path . _raw_path + text )
102
+ return path .with_segments (str ( path ) + text )
103
103
104
104
105
105
class PurePathBase :
@@ -112,9 +112,9 @@ class PurePathBase:
112
112
"""
113
113
114
114
__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
118
119
119
# The '_resolving' slot stores a boolean indicating whether the path
120
120
# is being processed by `PathBase.resolve()`. This prevents duplicate
@@ -124,11 +124,14 @@ class PurePathBase:
124
124
parser = ParserBase ()
125
125
_globber = PathGlobber
126
126
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} " )
127
+ def __init__ (self , arg , * args ):
128
+ paths = [arg ]
129
+ paths .extend (args )
130
+ for path in paths :
131
+ if not isinstance (path , str ):
132
+ raise TypeError (
133
+ f"path should be a str, not { type (path ).__name__ !r} " )
134
+ self ._raw_paths = paths
132
135
self ._resolving = False
133
136
134
137
def with_segments (self , * pathsegments ):
@@ -141,7 +144,19 @@ def with_segments(self, *pathsegments):
141
144
def __str__ (self ):
142
145
"""Return the string representation of the path, suitable for
143
146
passing to system calls."""
144
- return self ._raw_path
147
+ paths = self ._raw_paths
148
+ if len (paths ) == 1 :
149
+ return paths [0 ]
150
+ elif paths :
151
+ # Join path segments from the initializer.
152
+ path = self .parser .join (* paths )
153
+ # Cache the joined path.
154
+ paths .clear ()
155
+ paths .append (path )
156
+ return path
157
+ else :
158
+ paths .append ('' )
159
+ return ''
145
160
146
161
def as_posix (self ):
147
162
"""Return the string representation of the path with forward (/)
@@ -166,7 +181,7 @@ def anchor(self):
166
181
@property
167
182
def name (self ):
168
183
"""The final path component, if any."""
169
- return self .parser .split (self . _raw_path )[1 ]
184
+ return self .parser .split (str ( self ) )[1 ]
170
185
171
186
@property
172
187
def suffix (self ):
@@ -202,7 +217,7 @@ def with_name(self, name):
202
217
split = self .parser .split
203
218
if split (name )[0 ]:
204
219
raise ValueError (f"Invalid name { name !r} " )
205
- return self .with_segments (split (self . _raw_path )[0 ], name )
220
+ return self .with_segments (split (str ( self ) )[0 ], name )
206
221
207
222
def with_stem (self , stem ):
208
223
"""Return a new path with the stem changed."""
@@ -242,17 +257,17 @@ def relative_to(self, other, *, walk_up=False):
242
257
anchor0 , parts0 = self ._stack
243
258
anchor1 , parts1 = other ._stack
244
259
if anchor0 != anchor1 :
245
- raise ValueError (f"{ self . _raw_path !r} and { other . _raw_path !r} have different anchors" )
260
+ raise ValueError (f"{ str ( self ) !r} and { str ( other ) !r} have different anchors" )
246
261
while parts0 and parts1 and parts0 [- 1 ] == parts1 [- 1 ]:
247
262
parts0 .pop ()
248
263
parts1 .pop ()
249
264
for part in parts1 :
250
265
if not part or part == '.' :
251
266
pass
252
267
elif not walk_up :
253
- raise ValueError (f"{ self . _raw_path !r} is not in the subpath of { other . _raw_path !r} " )
268
+ raise ValueError (f"{ str ( self ) !r} is not in the subpath of { str ( other ) !r} " )
254
269
elif part == '..' :
255
- raise ValueError (f"'..' segment in { other . _raw_path !r} cannot be walked" )
270
+ raise ValueError (f"'..' segment in { str ( other ) !r} cannot be walked" )
256
271
else :
257
272
parts0 .append ('..' )
258
273
return self .with_segments ('' , * reversed (parts0 ))
@@ -289,17 +304,17 @@ def joinpath(self, *pathsegments):
289
304
paths) or a totally different path (if one of the arguments is
290
305
anchored).
291
306
"""
292
- return self .with_segments (self ._raw_path , * pathsegments )
307
+ return self .with_segments (* self ._raw_paths , * pathsegments )
293
308
294
309
def __truediv__ (self , key ):
295
310
try :
296
- return self .with_segments (self ._raw_path , key )
311
+ return self .with_segments (* self ._raw_paths , key )
297
312
except TypeError :
298
313
return NotImplemented
299
314
300
315
def __rtruediv__ (self , key ):
301
316
try :
302
- return self .with_segments (key , self ._raw_path )
317
+ return self .with_segments (key , * self ._raw_paths )
303
318
except TypeError :
304
319
return NotImplemented
305
320
@@ -311,7 +326,7 @@ def _stack(self):
311
326
*parts* is a reversed list of parts following the anchor.
312
327
"""
313
328
split = self .parser .split
314
- path = self . _raw_path
329
+ path = str ( self )
315
330
parent , name = split (path )
316
331
names = []
317
332
while path != parent :
@@ -323,7 +338,7 @@ def _stack(self):
323
338
@property
324
339
def parent (self ):
325
340
"""The logical parent of the path."""
326
- path = self . _raw_path
341
+ path = str ( self )
327
342
parent = self .parser .split (path )[0 ]
328
343
if path != parent :
329
344
parent = self .with_segments (parent )
@@ -335,7 +350,7 @@ def parent(self):
335
350
def parents (self ):
336
351
"""A sequence of this path's logical parents."""
337
352
split = self .parser .split
338
- path = self . _raw_path
353
+ path = str ( self )
339
354
parent = split (path )[0 ]
340
355
parents = []
341
356
while path != parent :
@@ -347,7 +362,7 @@ def parents(self):
347
362
def is_absolute (self ):
348
363
"""True if the path is absolute (has both a root and, if applicable,
349
364
a drive)."""
350
- return self .parser .isabs (self . _raw_path )
365
+ return self .parser .isabs (str ( self ) )
351
366
352
367
@property
353
368
def _pattern_str (self ):
0 commit comments