8000 GH-100479: Add optional `blueprint` argument to `pathlib.PurePath` by barneygale · Pull Request #100481 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

GH-100479: Add optional blueprint argument to pathlib.PurePath #100481

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
a6fdd0e
Add `pathlib.PurePath.makepath()`; unify path object construction
barneygale Nov 20, 2022
b061747
Fix reST role name.
barneygale Dec 24, 2022
99eb8b1
Move call to `os.getcwd()` back into `Path.cwd()`
barneygale Dec 24, 2022
4759d01
Merge branch 'main' into gh-100479-add-makepath
barneygale Jan 5, 2023
ef6f4c3
Merge branch 'main' into gh-100479-add-makepath
barneygale Apr 3, 2023
595b8ae
Add news blurb.
barneygale Apr 3, 2023
dcfe70a
Merge branch 'main' into gh-100479-add-makepath
barneygale Apr 9, 2023
117fe4b
Add whatsnew entry
barneygale Apr 10, 2023
e75dedc
Merge branch 'main' into gh-100479-add-makepath
barneygale Apr 12, 2023
5a6bd3f
Merge branch 'main' into gh-100479-add-makepath
barneygale Apr 13, 2023
f2f1048
other --> pathsegments
barneygale Apr 24, 2023
3c172fb
Update Lib/pathlib.py
barneygale Apr 24, 2023
4637109
joinpath(*args) --> joinpath(*pathsegments)
barneygale Apr 24, 2023
ae48454
Restore _PathParents
barneygale Apr 25, 2023
e7a8fe3
Add note to `parents` about potential reference cycle.
barneygale Apr 25, 2023
7f12faa
Replace `makepath()` method with `template` initialiser argument.
barneygale Apr 25, 2023
687c764
Apply suggestions from code review
barneygale Apr 25, 2023
d7e326a
Fix docs for other classes.
barneygale Apr 25, 2023
a65d499
Pass template to `super()` to support diamond inheritance.
barneygale Apr 26, 2023
d4b15d7
Fixed missed `template` argument to super().
barneygale Apr 26, 2023
958b183
template --> blueprint
barneygale Apr 27, 2023
1e10188
Merge branch 'main' into gh-100479-add-makepath
barneygale May 2, 2023
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-100479-add-makepath
  • Loading branch information
barneygale committed Apr 3, 2023
commit ef6f4c3b6d75ddfa7064f1fb9f88a1fc0965e645
4 changes: 2 additions & 2 deletions Doc/library/pathlib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ Pure paths provide the following methods and properties:
.. versionchanged:: 3.12
Type changed from a tuple-like immutable sequence to a true tuple.

.. data:: PurePath.parent
.. attribute:: PurePath.parent

The logical parent of the path::

Expand Down Expand Up @@ -551,7 +551,7 @@ Pure paths provide the following methods and properties:

Create a new path object of the same type by combining the *other*
arguments. This method is called whenever a derivative path is created,
such as from :data:`parent` and :meth:`relative_to`. Subclasses may
such as from :attr:`parent` and :meth:`relative_to`. Subclasses may
override this method to pass information to derivative paths, for example::

from pathlib import PurePosixPath
Expand Down
102 changes: 50 additions & 52 deletions Lib/pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def __init__(self, name, child_parts, flavour):

def _select_from(self, parent_path, is_dir, exists, scandir, normcase):
try:
path = parent_path.joinpath(self.name)
path = parent_path._make_child_relpath(self.name)
if (is_dir if self.dironly else exists)(path):
for p in self.successor._select_from(path, is_dir, exists, scandir, normcase):
yield p
Expand Down Expand Up @@ -153,7 +153,7 @@ def _select_from(self, parent_path, is_dir, exists, scandir, normcase):
continue
name = entry.name
if self.match(normcase(name)):
path = parent_path.joinpath(name)
path = parent_path._make_child_relpath(name)
for p in self.successor._select_from(path, is_dir, exists, scandir, normcase):
yield p
except PermissionError:
Expand All @@ -180,7 +180,7 @@ def _iterate_directories(self, parent_path, is_dir, scandir):
if not _ignore_error(e):
raise
if entry_is_dir and not entry.is_symlink():
path = parent_path.joinpath(entry.name)
path = parent_path._make_child_relpath(entry.name)
for p in self._iterate_directories(path, is_dir, scandir):
yield p
except PermissionError:
Expand All @@ -206,7 +206,6 @@ def _select_from(self, parent_path, is_dir, exists, scandir, normcase):
# Public API
#


class PurePath(object):
"""Base class for manipulating paths without I/O.

Expand All @@ -230,7 +229,7 @@ def __new__(cls, *args, **kwargs):
"""
if cls is PurePath:
cls = PureWindowsPath if os.name == 'nt' else PurePosixPath
return super().__new__(cls)
return object.__new__(cls)

def __reduce__(self):
# Using the parts tuple helps share interned path parts
Expand Down Expand Up @@ -270,31 +269,20 @@ def _parse_path(cls, path):
parsed = [sys.intern(x) for x in unfiltered_parsed if x and x != '.']
return drv, root, parsed

@classmethod
def _parse_args(cls, args):
# This is useful when you don't want to create an instance, just
# canonicalize some constructor arguments.
parts = []
for a in args:
if isinstance(a, PurePath):
parts += a._parts
else:
a = os.fspath(a)
if isinstance(a, str):
# Force-cast str subclasses to str (issue #21127)
parts.append(str(a))
else:
raise TypeError(
"argument should be a str object or an os.PathLike "
"object returning str, not %r"
% type(a))
return cls._parse_parts(parts)

def __init__(self, *args):
drv, root, parts = self._parse_args(args)
def _load_parts(self):
drv, root, parts = self._parse_path(self._raw_path)
self._drv = drv
self._root = root
self._parts = parts
self._parts_cached = parts

def _from_parsed_parts(self, drv, root, parts):
path_str = self._format_parsed_parts(drv, root, parts)
path = self.makepath(path_str)
path._str = path_str or '.'
path._drv = drv
path._root = root
path._parts_cached = parts
return path

@classmethod
def _format_parsed_parts(cls, drv, root, parts):
Expand Down Expand Up @@ -477,7 +465,8 @@ 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.makepath(*self._parts[:-1], name)
return self._from_parsed_parts(self.drive, self.root,
self._parts[:-1] + [name])

def with_stem(self, stem):
"""Return a new path with the stem changed."""
Expand All @@ -501,7 +490,8 @@ def with_suffix(self, suffix):
name = name + suffix
else:
name = name[:-len(old_suffix)] + suffix
return self.makepath(*self._parts[:-1], name)
return self._from_parsed_parts(self.drive, self.root,
self._parts[:-1] + [name])

def relative_to(self, other, /, *_deprecated, walk_up=False):
"""Return the relative path to another path identified by the passed
Expand Down Expand Up @@ -565,7 +555,7 @@ def joinpath(self, *args):
paths) or a totally different path (if one of the arguments is
anchored).
"""
return self.makepath(*self._parts, *args)
return self.makepath(self._raw_path, *args)

def __truediv__(self, key):
try:
Expand All @@ -575,7 +565,7 @@ def __truediv__(self, key):

def __rtruediv__(self, key):
try:
return self.makepath(key, *self._parts)
return self.makepath(key, self._raw_path)
except TypeError:
return NotImplemented

Expand All @@ -585,20 +575,19 @@ def parent(self):
drv = self.drive
root = self.root
parts = self._parts
if len(parts) == 1 and (drv or root):
if len(parts) == bool(drv or root):
return self
return self.makepath(*parts[:-1])
return self._from_parsed_parts(drv, root, parts[:-1])

@property
def parents(self):
"""A tuple of this path's logical parents."""
path = self
parent = self.parent
parents = []
while path != parent:
parents.append(parent)
path, parent = parent, parent.parent
return tuple(parents)
drv = self.drive
root = self.root
parts = self._parts
return tuple(
self._from_parsed_parts(drv, root, parts[:idx])
for idx in reversed(range(bool(drv or root), len(parts))))

def is_absolute(self):
"""True if the path is absolute (has both a root and, if applicable,
Expand Down Expand Up @@ -692,11 +681,13 @@ def __init__(self, *args, **kwargs):
def __new__(cls, *args, **kwargs):
if cls is Path:
cls = WindowsPath if os.name == 'nt' else PosixPath
self = super().__new__(cls)
if self._flavour is not os.path:
raise NotImplementedError("cannot instantiate %r on your system"
% (cls.__name__,))
return self
return object.__new__(cls)

def _make_child_relpath(self, part):
# This is an optimization used for dir walking. `part` must be
# a single part relative to this path.
parts = self._parts + [part]
return self._from_parsed_parts(self.drive, self.root, parts)

def __enter__(self):
# In previous versions of pathlib, __exit__() marked this path as
Expand Down Expand Up @@ -751,7 +742,7 @@ def iterdir(self):
special entries '.' and '..' are not included.
"""
for name in os.listdir(self):
yield self.joinpath(name)
yield self._make_child_relpath(name)

def _scandir(self):
# bpo-24132: a future version of pathlib will support subclassing of
Expand Down Expand Up @@ -798,7 +789,12 @@ def absolute(self):
"""
if self.is_absolute():
return self
return self.makepath(os.getcwd(), *self._parts)
elif self.drive:
# There is a CWD on each drive-letter drive.
cwd = self._flavour.abspath(self.drive)
else:
cwd = os.getcwd()
return self.makepath(cwd, self._raw_path)

def resolve(self, strict=False):
"""
Expand Down Expand Up @@ -1180,7 +1176,8 @@ def expanduser(self):
homedir = self._flavour.expanduser(self._parts[0])
if homedir[:1] == "~":
raise RuntimeError("Could not determine home directory.")
return self.makepath(homedir, *self._parts[1:])
drv, root, parts = self._parse_path(homedir)
return self._from_parsed_parts(drv, root, parts + self._parts[1:])

return self

Expand Down Expand Up @@ -1222,9 +1219,10 @@ def walk(self, top_down=True, on_error=None, follow_symlinks=False):
else:
filenames.append(entry.name)

for dirname in dirnames:
dirpath = self.joinpath(dirname)
yield from dirpath._walk(top_down, on_error, follow_symlinks)
if top_down:
yield path, dirnames, filenames
else:
paths.append((path, dirnames, filenames))

paths += [path._make_child_relpath(d) for d in reversed(dirnames)]

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