mirror of
https://github.com/python/cpython.git
synced 2025-07-19 17:25:54 +00:00
GH-104996: Defer joining of pathlib.PurePath()
arguments. (GH-104999)
Joining of arguments is moved to `_load_parts`, which is called when a normalized path is needed.
This commit is contained in:
parent
f5df347fcf
commit
ffeaec7e60
2 changed files with 29 additions and 17 deletions
|
@ -195,10 +195,10 @@ def _select_unique(paths):
|
||||||
yielded = set()
|
yielded = set()
|
||||||
try:
|
try:
|
||||||
for path in paths:
|
for path in paths:
|
||||||
raw_path = path._raw_path
|
path_str = str(path)
|
||||||
if raw_path not in yielded:
|
if path_str not in yielded:
|
||||||
yield path
|
yield path
|
||||||
yielded.add(raw_path)
|
yielded.add(path_str)
|
||||||
finally:
|
finally:
|
||||||
yielded.clear()
|
yielded.clear()
|
||||||
|
|
||||||
|
@ -247,9 +247,9 @@ class PurePath:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = (
|
__slots__ = (
|
||||||
# The `_raw_path` slot stores an unnormalized string path. This is set
|
# The `_raw_paths` slot stores unnormalized string paths. This is set
|
||||||
# in the `__init__()` method.
|
# in the `__init__()` method.
|
||||||
'_raw_path',
|
'_raw_paths',
|
||||||
|
|
||||||
# The `_drv`, `_root` and `_tail_cached` slots store parsed and
|
# The `_drv`, `_root` and `_tail_cached` slots store parsed and
|
||||||
# normalized parts of the path. They are set when any of the `drive`,
|
# normalized parts of the path. They are set when any of the `drive`,
|
||||||
|
@ -306,10 +306,11 @@ class PurePath:
|
||||||
paths = []
|
paths = []
|
||||||
for arg in args:
|
for arg in args:
|
||||||
if isinstance(arg, PurePath):
|
if isinstance(arg, PurePath):
|
||||||
path = arg._raw_path
|
|
||||||
if arg._flavour is ntpath and self._flavour is posixpath:
|
if arg._flavour is ntpath and self._flavour is posixpath:
|
||||||
# GH-103631: Convert separators for backwards compatibility.
|
# GH-103631: Convert separators for backwards compatibility.
|
||||||
path = path.replace('\\', '/')
|
paths.extend(path.replace('\\', '/') for path in arg._raw_paths)
|
||||||
|
else:
|
||||||
|
paths.extend(arg._raw_paths)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
path = os.fspath(arg)
|
path = os.fspath(arg)
|
||||||
|
@ -320,13 +321,8 @@ class PurePath:
|
||||||
"argument should be a str or an os.PathLike "
|
"argument should be a str or an os.PathLike "
|
||||||
"object where __fspath__ returns a str, "
|
"object where __fspath__ returns a str, "
|
||||||
f"not {type(path).__name__!r}")
|
f"not {type(path).__name__!r}")
|
||||||
paths.append(path)
|
paths.append(path)
|
||||||
if len(paths) == 0:
|
self._raw_paths = paths
|
||||||
self._raw_path = ''
|
|
||||||
elif len(paths) == 1:
|
|
||||||
self._raw_path = paths[0]
|
|
||||||
else:
|
|
||||||
self._raw_path = self._flavour.join(*paths)
|
|
||||||
|
|
||||||
def with_segments(self, *pathsegments):
|
def with_segments(self, *pathsegments):
|
||||||
"""Construct a new path object from any number of path-like objects.
|
"""Construct a new path object from any number of path-like objects.
|
||||||
|
@ -356,7 +352,14 @@ class PurePath:
|
||||||
return drv, root, parsed
|
return drv, root, parsed
|
||||||
|
|
||||||
def _load_parts(self):
|
def _load_parts(self):
|
||||||
drv, root, tail = self._parse_path(self._raw_path)
|
paths = self._raw_paths
|
||||||
|
if len(paths) == 0:
|
||||||
|
path = ''
|
||||||
|
elif len(paths) == 1:
|
||||||
|
path = paths[0]
|
||||||
|
else:
|
||||||
|
path = self._flavour.join(*paths)
|
||||||
|
drv, root, tail = self._parse_path(path)
|
||||||
self._drv = drv
|
self._drv = drv
|
||||||
self._root = root
|
self._root = root
|
||||||
self._tail_cached = tail
|
self._tail_cached = tail
|
||||||
|
@ -687,10 +690,17 @@ class PurePath:
|
||||||
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,
|
||||||
a drive)."""
|
a drive)."""
|
||||||
# ntpath.isabs() is defective - see GH-44626 .
|
|
||||||
if self._flavour is ntpath:
|
if self._flavour is ntpath:
|
||||||
|
# ntpath.isabs() is defective - see GH-44626.
|
||||||
return bool(self.drive and self.root)
|
return bool(self.drive and self.root)
|
||||||
return self._flavour.isabs(self._raw_path)
|
elif self._flavour is posixpath:
|
||||||
|
# Optimization: work with raw paths on POSIX.
|
||||||
|
for path in self._raw_paths:
|
||||||
|
if path.startswith('/'):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return self._flavour.isabs(str(self))
|
||||||
|
|
||||||
def is_reserved(self):
|
def is_reserved(self):
|
||||||
"""Return True if the path contains one of the special names reserved
|
"""Return True if the path contains one of the special names reserved
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Improve performance of :class:`pathlib.PurePath` initialisation by
|
||||||
|
deferring joining of paths when multiple arguments are given.
|
Loading…
Add table
Add a link
Reference in a new issue