mirror of
https://github.com/python/cpython.git
synced 2025-11-25 04:34:37 +00:00
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`.
This commit is contained in:
parent
1e914ad89d
commit
37bd893a22
2 changed files with 63 additions and 42 deletions
|
|
@ -11,6 +11,7 @@ import os
|
||||||
import posixpath
|
import posixpath
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
|
from _collections_abc import Sequence
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import pwd
|
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
|
UnsupportedOperation = _abc.UnsupportedOperation
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -95,7 +125,6 @@ class PurePath(_abc.PurePathBase):
|
||||||
paths.append(path)
|
paths.append(path)
|
||||||
# Avoid calling super().__init__, as an optimisation
|
# Avoid calling super().__init__, as an optimisation
|
||||||
self._raw_paths = paths
|
self._raw_paths = paths
|
||||||
self._resolving = False
|
|
||||||
|
|
||||||
def __reduce__(self):
|
def __reduce__(self):
|
||||||
# Using the parts tuple helps share interned path parts
|
# Using the parts tuple helps share interned path parts
|
||||||
|
|
@ -166,6 +195,23 @@ class PurePath(_abc.PurePathBase):
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
return self._parts_normcase >= other._parts_normcase
|
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
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"""The final path component, if any."""
|
"""The final path component, if any."""
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import functools
|
||||||
import ntpath
|
import ntpath
|
||||||
import posixpath
|
import posixpath
|
||||||
import sys
|
import sys
|
||||||
from _collections_abc import Sequence
|
|
||||||
from errno import ENOENT, ENOTDIR, EBADF, ELOOP, EINVAL
|
from errno import ENOENT, ENOTDIR, EBADF, ELOOP, EINVAL
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO
|
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
|
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:
|
class PurePathBase:
|
||||||
"""Base class for pure path objects.
|
"""Base class for pure path objects.
|
||||||
|
|
||||||
|
|
@ -442,21 +412,26 @@ class PurePathBase:
|
||||||
@property
|
@property
|
||||||
def parent(self):
|
def parent(self):
|
||||||
"""The logical parent of the path."""
|
"""The logical parent of the path."""
|
||||||
drv = self.drive
|
path = str(self)
|
||||||
root = self.root
|
parent = self.pathmod.dirname(path)
|
||||||
tail = self._tail
|
if path != parent:
|
||||||
if not tail:
|
parent = self.with_segments(parent)
|
||||||
return self
|
parent._resolving = self._resolving
|
||||||
path = self._from_parsed_parts(drv, root, tail[:-1])
|
return parent
|
||||||
path._resolving = self._resolving
|
return self
|
||||||
return path
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def parents(self):
|
def parents(self):
|
||||||
"""A sequence of this path's logical parents."""
|
"""A sequence of this path's logical parents."""
|
||||||
# The value of this property should not be cached on the path object,
|
dirname = self.pathmod.dirname
|
||||||
# as doing so would introduce a reference cycle.
|
path = str(self)
|
||||||
return _PathParents(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):
|
def is_absolute(self):
|
||||||
"""True if the path is absolute (has both a root and, if applicable,
|
"""True if the path is absolute (has both a root and, if applicable,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue