@@ -61,7 +61,7 @@ def isabs(s):
61
61
"""Test whether a path is absolute"""
62
62
s = os .fspath (s )
63
63
sep = _get_sep (s )
64
- return s . startswith ( sep )
64
+ return s [: 1 ] == sep
65
65
66
66
67
67
# Join pathnames.
@@ -80,9 +80,9 @@ def join(a, *p):
80
80
if not p :
81
81
path [:0 ] + sep #23780: Ensure compatible data type even if p is null.
82
82
for b in map (os .fspath , p ):
83
- if b . startswith ( sep ) :
83
+ if b [: 1 ] == sep :
84
84
path = b
85
- elif not path or path . endswith ( sep ) :
85
+ elif not path or path [ - 1 :] == sep :
86
86
path += b
87
87
else :
88
88
path += sep + b
@@ -229,7 +229,7 @@ def expanduser(path):
229
229
tilde = b'~'
230
230
else :
231
231
tilde = '~'
232
- if not path . startswith ( tilde ) :
232
+ if path [: 1 ] != tilde :
233
233
return path
234
234
sep = _get_sep (path )
235
235
i = path .find (sep , 1 )
@@ -311,7 +311,7 @@ def expandvars(path):
311
311
break
312
312
i , j = m .span (0 )
313
313
name = m .group (1 )
314
- if name . startswith ( start ) and name . endswith ( end ) :
314
+ if name [: 1 ] == start and name [ - 1 :] == end :
315
315
name = name [1 :- 1 ]
316
316
try :
317
317
if environ is None :
@@ -331,6 +331,34 @@ def expandvars(path):
331
331
# It should be understood that this may change the meaning of the path
332
332
# if it contains symbolic links!
333
333
334
+ def _normpath_fallback (path ):
335
+ """Normalize path, eliminating double slashes, etc."""
336
+ path = os .fspath (path )
337
+ if isinstance (path , bytes ):
338
+ sep = b'/'
339
+ curdir = b'.'
340
+ pardir = b'..'
341
+ else :
342
+ sep = '/'
343
+ curdir = '.'
344
+ pardir = '..'
345
+ if not path :
346
+ return curdir
347
+ _ , root , tail = splitroot (path )
348
+ comps = []
349
+ for comp in tail .split (sep ):
350
+ if not comp or comp == curdir :
351
+ continue
352
+ if (
353
+ comp != pardir
354
+ or (not root and not comps )
355
+ or (comps and comps [- 1 ] == pardir )
356
+ ):
357
+ comps .append (comp )
358
+ elif comps :
359
+ comps .pop ()
360
+ return (root + sep .join (comps )) or curdir
361
+
334
362
try :
335
363
from posix import _path_normpath
336
364
def normpath (path ):
@@ -340,33 +368,7 @@ def normpath(path):
340
368
return os .fsencode (_path_normpath (os .fsdecode (path ))) or b"."
341
369
return _path_normpath (path ) or "."
342
370
except ImportError :
343
- def normpath (path ):
344
- """Normalize path, eliminating double slashes, etc."""
345
- path = os .fspath (path )
346
- if isinstance (path , bytes ):
347
- sep = b'/'
348
- curdir = b'.'
349
- pardir = b'..'
350
- else :
351
- sep = '/'
352
- curdir = '.'
353
- pardir = '..'
354
- if not path :
355
- return curdir
356
- _ , root , tail = splitroot (path )
357
- comps = []
358
- for comp in tail .split (sep ):
359
- if not comp or comp == curdir :
360
- continue
361
- if (
362
- comp != pardir
363
- or (not root and not comps )
364
- or (comps and comps [- 1 ] == pardir )
365
- ):
366
- comps .append (comp )
367
- elif comps :
368
- comps .pop ()
369
- return (root + sep .join (comps )) or curdir
371
+ normpath = _normpath_fallback
370
372
371
373
372
374
def abspath (path ):
@@ -388,11 +390,11 @@ def realpath(filename, *, strict=False):
388
390
"""Return the canonical path of the specified filename, eliminating any
389
391
symbolic links encountered in the path."""
390
392
filename = os .fspath (filename )
391
- path , ok = _joinrealpath (filename [:0 ], filename , strict , {})
393
+ path , _ = _joinrealpath (filename [:0 ], filename , strict , {})
392
394
return abspath (path )
393
395
394
- # Join two paths, normalizing and eliminating any symbolic links
395
- # encountered in the second path.
396
+ # Join two paths, normalizing and eliminating any symbolic links encountered in
397
+ # the second path. Two leading slashes are replaced by a single slash .
396
398
def _joinrealpath (path , rest , strict , seen ):
397
399
if isinstance (path , bytes ):
398
400
sep = b'/'
@@ -414,22 +416,24 @@ def _joinrealpath(path, rest, strict, seen):
414
416
continue
415
417
if name == pardir :
416
418
# parent dir
417
- if path :
418
- path , name = split (path )
419
- if name == pardir :
420
- path = join (path , pardir , pardir )
421
- else :
419
+ if not path :
420
+ # ..
422
421
path = pardir
422
+ elif basename (path ) == pardir :
423
+ # ../..
424
+ path = join (path , pardir )
425
+ else :
426
+ # foo/bar/.. -> foo
427
+ path = dirname (path )
423
428
continue
424
429
newpath = join (path , name )
425
430
try :
426
431
st = os .lstat (newpath )
432
+ is_link = stat .S_ISLNK (st .st_mode )
427
433
except OSError :
428
434
if strict :
429
435
raise
430
436
is_link = False
431
- else :
432
- is_link = stat .S_ISLNK (st .st_mode )
433
437
if not is_link :
434
438
path = newpath
435
439
continue
@@ -441,12 +445,11 @@ def _joinrealpath(path, rest, strict, seen):
441
445
# use cached value
442
446
continue
443
447
# The symlink is not resolved, so we must have a symlink loop.
444
- if strict :
445
- # Raise OSError(errno.ELOOP)
446
- os .stat (newpath )
447
- else :
448
+ if not strict :
448
449
# Return already resolved part + rest of the path unchanged.
449
450
return join (newpath , rest ), False
451
+ # Raise OSError(errno.ELOOP)
452
+ os .stat (newpath )
450
453
seen [newpath ] = None # not resolved symlink
451
454
path , ok = _joinrealpath (path , os .readlink (newpath ), strict , seen )
452
455
if not ok :
0 commit comments