Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Merge branch 'main' into gh-101362-exclude-anchor-from-parts
  • Loading branch information
barneygale committed Apr 3, 2023
commit f529d5136eb2d9c2e375220d6fc770a8e4771f45
72 changes: 28 additions & 44 deletions Lib/pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,8 @@ class _PathParents(Sequence):
def __init__(self, path):
# We don't store the instance to avoid reference cycles
self._pathcls = type(path)
self._drv = path._drv
self._root = path._root
self._drv = path.drive
self._root = path.root
self._tail = path._tail

def __len__(self):
Expand Down Expand Up @@ -247,7 +247,7 @@ class PurePath(object):
directly, regardless of your system.
"""
__slots__ = (
'_drv', '_root', '_tail',
'_raw_path', '_drv', '_root', '_tail_cached',
'_str', '_hash', '_parts_tuple', '_parts_normcase_cached',
)
_flavour = os.path
Expand Down Expand Up @@ -299,21 +299,20 @@ def _parse_path(cls, path):
parsed = [sys.intern(x) for x in rel.split(sep) if x and x != '.']
return drv, root, parsed

@classmethod
def _from_parts(cls, args):
self = object.__new__(cls)
drv, root, tail = self._parse_parts(args)
def _load_parts(self):
drv, root, tail = self._parse_path(self._raw_path)
self._drv = drv
self._root = root
self._tail = tail
return self
self._tail_cached = tail

@classmethod
def _from_parsed_parts(cls, drv, root, tail):
self = object.__new__(cls)
path = cls._format_parsed_parts(drv, root, tail)
self = cls(path)
self._str = path or '.'
self._drv = drv
self._root = root
self._tail = tail
self._tail_cached = tail
return self

@classmethod
Expand All @@ -330,7 +329,7 @@ def __str__(self):
try:
return self._str
except AttributeError:
self._str = self._format_parsed_parts(self._drv, self._root,
self._str = self._format_parsed_parts(self.drive, self.root,
self._tail) or '.'
return self._str

Expand Down Expand Up @@ -431,12 +430,12 @@ def root(self):
return self._root

@property
def _parts(self):
def _tail(self):
try:
return self._parts_cached
return self._tail_cached
except AttributeError:
self._load_parts()
return self._parts_cached
return self._tail_cached

@property
def anchor(self):
Expand Down Expand Up @@ -497,7 +496,7 @@ def with_name(self, name):
drv, root, tail = f.splitroot(name)
if drv or root or not tail or f.sep in tail or (f.altsep and f.altsep in tail):
raise ValueError("Invalid name %r" % (name))
return self._from_parsed_parts(self._drv, self._root,
return self._from_parsed_parts(self.drive, self.root,
self._tail[:-1] + [name])

def with_stem(self, stem):
Expand All @@ -522,7 +521,7 @@ def with_suffix(self, suffix):
name = name + suffix
else:
name = name[:-len(old_suffix)] + suffix
return self._from_parsed_parts(self._drv, self._root,
return self._from_parsed_parts(self.drive, self.root,
self._tail[:-1] + [name])

def relative_to(self, other, /, *_deprecated, walk_up=False):
Expand Down Expand Up @@ -572,8 +571,8 @@ def parts(self):
try:
return self._parts_tuple
except AttributeError:
if self._drv or self._root:
self._parts_tuple = (self._drv + self._root,) + tuple(self._tail)
if self.drive or self.root:
self._parts_tuple = (self.drive + self.root,) + tuple(self._tail)
else:
self._parts_tuple = tuple(self._tail)
return self._parts_tuple
Expand All @@ -584,22 +583,7 @@ def joinpath(self, *args):
paths) or a totally different path (if one of the arguments is
anchored).
"""
drv1, root1, tail1 = self._drv, self._root, self._tail
drv2, root2, tail2 = self._parse_parts(args)
if root2:
if not drv2 and drv1:
return self._from_parsed_parts(drv1, root2, tail2)
else:
return self._from_parsed_parts(drv2, root2, tail2)
elif drv2:
if drv2 == drv1 or self._flavour.normcase(drv2) == self._flavour.normcase(drv1):
# Same drive => second path is relative to the first.
return self._from_parsed_parts(drv1, root1, tail1 + tail2)
else:
return self._from_parsed_parts(drv2, root2, tail2)
else:
# Second path is non-anchored (common case).
return self._from_parsed_parts(drv1, root1, tail1 + tail2)
return self.__class__(self._raw_path, *args)

def __truediv__(self, key):
try:
Expand All @@ -609,15 +593,15 @@ def __truediv__(self, key):

def __rtruediv__(self, key):
try:
return self._from_parts([key] + self._tail)
return type(self)(key, self._raw_path)
except TypeError:
return NotImplemented

@property
def parent(self):
"""The logical parent of the path."""
drv = self._drv
root = self._root
drv = self.drive
root = self.root
tail = self._tail
if not tail:
return self
Expand Down Expand Up @@ -646,7 +630,7 @@ def is_reserved(self):
# (e.g. r"..\NUL" is reserved but not r"foo\NUL" if "foo" does not
# exist). We err on the side of caution and return True for paths
# which are not considered reserved by Windows.
if self._drv.startswith('\\\\'):
if self.drive.startswith('\\\\'):
# UNC paths are never reserved.
return False
name = self._tail[-1].partition('.')[0].partition(':')[0].rstrip(' ')
Expand All @@ -661,7 +645,7 @@ def match(self, path_pattern):
if not pat_parts:
raise ValueError("empty pattern")
parts = self._parts_normcase
if pat._drv or pat._root:
if pat.drive or pat.root:
if len(pat_parts) != len(parts):
return False
elif len(pat_parts) > len(parts):
Expand Down Expand Up @@ -726,7 +710,7 @@ def _make_child_relpath(self, part):
# This is an optimization used for dir walking. `part` must be
# a single part relative to this path.
tail = self._tail + [part]
return self._from_parsed_parts(self._drv, self._root, tail)
return self._from_parsed_parts(self.drive, self.root, tail)

def __enter__(self):
# In previous versions of pathlib, __exit__() marked this path as
Expand Down Expand Up @@ -833,7 +817,7 @@ def absolute(self):
cwd = self._flavour.abspath(self.drive)
else:
cwd = os.getcwd()
return self._from_parts((cwd,) + self.parts)
return type(self)(cwd, self._raw_path)

def resolve(self, strict=False):
"""
Expand Down Expand Up @@ -1210,12 +1194,12 @@ def expanduser(self):
""" Return a new path with expanded ~ and ~user constructs
(as returned by os.path.expanduser)
"""
if (not (self._drv or self._root) and
if (not (self.drive or self.root) and
self._tail and self._tail[0][:1] == '~'):
homedir = self._flavour.expanduser(self._tail[0])
if homedir[:1] == "~":
raise RuntimeError("Could not determine home directory.")
drv, root, tail = self._parse_parts((homedir,))
drv, root, tail = self._parse_path(homedir)
return self._from_parsed_parts(drv, root, tail + self._tail[1:])

return self
Expand Down
You are viewing a condensed version of this merge commit. You can view the full changes here.