summaryrefslogtreecommitdiffstats
path: root/Lib/pathlib
diff options
context:
space:
mode:
authorBarney Gale <barney.gale@gmail.com>2024-01-06 21:17:51 (GMT)
committerGitHub <noreply@github.com>2024-01-06 21:17:51 (GMT)
commit37bd893a22b784d573b71df5417d855dc32dee62 (patch)
tree1ed89f9e946518beffabe9d10f77f176458f85d1 /Lib/pathlib
parent1e914ad89de707b8a69b03d7b36f5022f4c07c78 (diff)
downloadcpython-37bd893a22b784d573b71df5417d855dc32dee62.zip
cpython-37bd893a22b784d573b71df5417d855dc32dee62.tar.gz
cpython-37bd893a22b784d573b71df5417d855dc32dee62.tar.bz2
GH-113528: Deoptimise `pathlib._abc.PurePathBase.parent` (#113530)
Replace use of `_from_parsed_parts()` with `with_segments()`, and move assignments to `_drv`, `_root`, _tail_cached` and `_str` slots into `PurePath`.
Diffstat (limited to 'Lib/pathlib')
-rw-r--r--Lib/pathlib/__init__.py48
-rw-r--r--Lib/pathlib/_abc.py57
2 files changed, 63 insertions, 42 deletions
diff --git a/Lib/pathlib/__init__.py b/Lib/pathlib/__init__.py
index 765a142..d83f292 100644
--- a/Lib/pathlib/__init__.py
+++ b/Lib/pathlib/__init__.py
@@ -11,6 +11,7 @@ import os
import posixpath
import sys
import warnings
+from _collections_abc import Sequence
try:
import pwd
@@ -31,6 +32,35 @@ __all__ = [
]
+class _PathParents(Sequence):
+ """This object provides sequence-like access to the logical ancestors
+ of a path. Don't try to construct it yourself."""
+ __slots__ = ('_path', '_drv', '_root', '_tail')
+
+ def __init__(self, path):
+ self._path = path
+ self._drv = path.drive
+ self._root = path.root
+ self._tail = path._tail
+
+ def __len__(self):
+ return len(self._tail)
+
+ def __getitem__(self, idx):
+ if isinstance(idx, slice):
+ return tuple(self[i] for i in range(*idx.indices(len(self))))
+
+ if idx >= len(self) or idx < -len(self):
+ raise IndexError(idx)
+ if idx < 0:
+ idx += len(self)
+ return self._path._from_parsed_parts(self._drv, self._root,
+ self._tail[:-idx - 1])
+
+ def __repr__(self):
+ return "<{}.parents>".format(type(self._path).__name__)
+
+
UnsupportedOperation = _abc.UnsupportedOperation
@@ -95,7 +125,6 @@ class PurePath(_abc.PurePathBase):
paths.append(path)
# Avoid calling super().__init__, as an optimisation
self._raw_paths = paths
- self._resolving = False
def __reduce__(self):
# Using the parts tuple helps share interned path parts
@@ -167,6 +196,23 @@ class PurePath(_abc.PurePathBase):
return self._parts_normcase >= other._parts_normcase
@property
+ def parent(self):
+ """The logical parent of the path."""
+ drv = self.drive
+ root = self.root
+ tail = self._tail
+ if not tail:
+ return self
+ return self._from_parsed_parts(drv, root, tail[:-1])
+
+ @property
+ def parents(self):
+ """A sequence of this path's logical parents."""
+ # The value of this property should not be cached on the path object,
+ # as doing so would introduce a reference cycle.
+ return _PathParents(self)
+
+ @property
def name(self):
"""The final path component, if any."""
tail = self._tail
diff --git a/Lib/pathlib/_abc.py b/Lib/pathlib/_abc.py
index 1ce3713..aca2bd5 100644
--- a/Lib/pathlib/_abc.py
+++ b/Lib/pathlib/_abc.py
@@ -2,7 +2,6 @@ import functools
import ntpath
import posixpath
import sys
-from _collections_abc import Sequence
from errno import ENOENT, ENOTDIR, EBADF, ELOOP, EINVAL
from itertools import chain
from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO
@@ -138,35 +137,6 @@ class UnsupportedOperation(NotImplementedError):
pass
-class _PathParents(Sequence):
- """This object provides sequence-like access to the logical ancestors
- of a path. Don't try to construct it yourself."""
- __slots__ = ('_path', '_drv', '_root', '_tail')
-
- def __init__(self, path):
- self._path = path
- self._drv = path.drive
- self._root = path.root
- self._tail = path._tail
-
- def __len__(self):
- return len(self._tail)
-
- def __getitem__(self, idx):
- if isinstance(idx, slice):
- return tuple(self[i] for i in range(*idx.indices(len(self))))
-
- if idx >= len(self) or idx < -len(self):
- raise IndexError(idx)
- if idx < 0:
- idx += len(self)
- return self._path._from_parsed_parts(self._drv, self._root,
- self._tail[:-idx - 1])
-
- def __repr__(self):
- return "<{}.parents>".format(type(self._path).__name__)
-
-
class PurePathBase:
"""Base class for pure path objects.
@@ -442,21 +412,26 @@ class PurePathBase:
@property
def parent(self):
"""The logical parent of the path."""
- drv = self.drive
- root = self.root
- tail = self._tail
- if not tail:
- return self
- path = self._from_parsed_parts(drv, root, tail[:-1])
- path._resolving = self._resolving
- return path
+ path = str(self)
+ parent = self.pathmod.dirname(path)
+ if path != parent:
+ parent = self.with_segments(parent)
+ parent._resolving = self._resolving
+ return parent
+ return self
@property
def parents(self):
"""A sequence of this path's logical parents."""
- # The value of this property should not be cached on the path object,
- # as doing so would introduce a reference cycle.
- return _PathParents(self)
+ dirname = self.pathmod.dirname
+ path = str(self)
+ parent = dirname(path)
+ parents = []
+ while path != parent:
+ parents.append(self.with_segments(parent))
+ path = parent
+ parent = dirname(path)
+ return tuple(parents)
def is_absolute(self):
"""True if the path is absolute (has both a root and, if applicable,