@@ -406,6 +406,23 @@ def __rtruediv__(self, key):
406
406
except TypeError :
407
407
return NotImplemented
408
408
409
+ @property
410
+ def _stack (self ):
411
+ """
412
+ Split the path into a 2-tuple (anchor, parts), where *anchor* is the
413
+ uppermost parent of the path (equivalent to path.parents[-1]), and
414
+ *parts* is a reversed list of parts following the anchor.
415
+ """
416
+ split = self .pathmod .split
417
+ path = str (self )
418
+ parent , name = split (path )
419
+ names = []
420
+ while path != parent :
421
+ names .append (name )
422
+ path = parent
423
+ parent , name = split (path )
424
+ return path , names
425
+
409
426
@property
410
427
def parent (self ):
411
428
"""The logical parent of the path."""
@@ -911,60 +928,60 @@ def readlink(self):
911
928
self ._unsupported ("readlink" )
912
929
readlink ._supported = False
913
930
914
- def _split_stack (self ):
915
- """
916
- Split the path into a 2-tuple (anchor, parts), where *anchor* is the
917
- uppermost parent of the path (equivalent to path.parents[-1]), and
918
- *parts* is a reversed list of parts following the anchor.
919
- """
920
- if not self ._tail :
921
- return self , []
922
- return self ._from_parsed_parts (self .drive , self .root , []), self ._tail [::- 1 ]
923
-
924
931
def resolve (self , strict = False ):
925
932
"""
926
933
Make the path absolute, resolving all symlinks on the way and also
927
934
normalizing it.
928
935
"""
929
936
if self ._resolving :
930
937
return self
931
- path , parts = self ._split_stack ()
938
+ path_root , parts = self ._stack
939
+ path = self .with_segments (path_root )
932
940
try :
933
941
path = path .absolute ()
934
942
except UnsupportedOperation :
935
- pass
943
+ path_tail = []
944
+ else :
945
+ path_root , path_tail = path ._stack
946
+ path_tail .reverse ()
936
947
937
948
# If the user has *not* overridden the `readlink()` method, then symlinks are unsupported
938
949
# and (in non-strict mode) we can improve performance by not calling `stat()`.
939
950
querying = strict or getattr (self .readlink , '_supported' , True )
940
951
link_count = 0
941
952
while parts :
942
953
part = parts .pop ()
954
+ if not part or part == '.' :
955
+ continue
943
956
if part == '..' :
944
- if not path . _tail :
945
- if path . root :
957
+ if not path_tail :
958
+ if path_root :
946
959
# Delete '..' segment immediately following root
947
960
continue
948
- elif path . _tail [- 1 ] != '..' :
961
+ elif path_tail [- 1 ] != '..' :
949
962
# Delete '..' segment and its predecessor
950
- path = path . parent
963
+ path_tail . pop ()
951
964
continue
952
- next_path = path . _make_child_relpath (part )
965
+ path_tail . append (part )
953
966
if querying and part != '..' :
954
- next_path ._resolving = True
967
+ path = self .with_segments (path_root + self .pathmod .sep .join (path_tail ))
968
+ path ._resolving = True
955
969
try :
956
- st = next_path .stat (follow_symlinks = False )
970
+ st = path .stat (follow_symlinks = False )
957
971
if S_ISLNK (st .st_mode ):
958
972
# Like Linux and macOS, raise OSError(errno.ELOOP) if too many symlinks are
959
973
# encountered during resolution.
960
974
link_count += 1
961
975
if link_count >= self ._max_symlinks :
962
976
raise OSError (ELOOP , "Too many symbolic links in path" , str (self ))
963
- target , target_parts = next_path .readlink ()._split_stack ()
977
+ target_root , target_parts = path .readlink ()._stack
964
978
# If the symlink target is absolute (like '/etc/hosts'), set the current
965
979
# path to its uppermost parent (like '/').
966
- if target .root :
967
- path = target
980
+ if target_root :
981
+ path_root = target_root
982
+ path_tail .clear ()
983
+ else :
984
+ path_tail .pop ()
968
985
# Add the symlink target's reversed tail parts (like ['hosts', 'etc']) to
969
986
# the stack of unresolved path parts.
970
987
parts .extend (target_parts )
@@ -976,9 +993,7 @@ def resolve(self, strict=False):
976
993
raise
977
994
else :
978
995
querying = False
979
- next_path ._resolving = False
980
- path = next_path
981
- return path
996
+ return self .with_segments (path_root + self .pathmod .sep .join (path_tail ))
982
997
983
998
def symlink_to (self , target , target_is_directory = False ):
984
999
"""
0 commit comments