From d372472896ca9d5666b40072a9ed7040300e11a0 Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Mon, 24 Mar 2025 15:39:08 +0000 Subject: GH-128520: pathlib ABCs: tighten up argument types (#131621) In `JoinablePath.full_match()` and `ReadablePath.glob()`, accept a `str` pattern argument rather than `JoinablePath | str`. In `ReadablePath.copy()` and `copy_into()`, accept a `WritablePath` target argument rather than `WritablePath | str`. --- Lib/pathlib/__init__.py | 6 +----- Lib/pathlib/types.py | 32 ++++++++------------------------ 2 files changed, 9 insertions(+), 29 deletions(-) diff --git a/Lib/pathlib/__init__.py b/Lib/pathlib/__init__.py index a8111cc..cd28f62 100644 --- a/Lib/pathlib/__init__.py +++ b/Lib/pathlib/__init__.py @@ -1105,11 +1105,7 @@ class Path(PurePath): if not hasattr(target, 'with_segments'): target = self.with_segments(target) ensure_distinct_paths(self, target) - try: - copy_to_target = target._copy_from - except AttributeError: - raise TypeError(f"Target path is not writable: {target!r}") from None - copy_to_target(self, **kwargs) + target._copy_from(self, **kwargs) return target.joinpath() # Empty join to ensure fresh metadata. def copy_into(self, target_dir, **kwargs): diff --git a/Lib/pathlib/types.py b/Lib/pathlib/types.py index cd8b2a9..d1bb870 100644 --- a/Lib/pathlib/types.py +++ b/Lib/pathlib/types.py @@ -17,14 +17,12 @@ from pathlib import PurePath, Path from typing import Optional, Protocol, runtime_checkable -def _explode_path(path): +def _explode_path(path, split): """ Split the path into a 2-tuple (anchor, parts), where *anchor* is the uppermost parent of the path (equivalent to path.parents[-1]), and *parts* is a reversed list of parts following the anchor. """ - split = path.parser.split - path = str(path) parent, name = split(path) names = [] while path != parent: @@ -95,7 +93,7 @@ class _JoinablePath(ABC): @property def anchor(self): """The concatenation of the drive and root, or ''.""" - return _explode_path(self)[0] + return _explode_path(str(self), self.parser.split)[0] @property def name(self): @@ -169,7 +167,7 @@ class _JoinablePath(ABC): def parts(self): """An object providing sequence-like access to the components in the filesystem path.""" - anchor, parts = _explode_path(self) + anchor, parts = _explode_path(str(self), self.parser.split) if anchor: parts.append(anchor) return tuple(reversed(parts)) @@ -221,11 +219,9 @@ class _JoinablePath(ABC): Return True if this path matches the given glob-style pattern. The pattern is matched against the entire path. """ - if not hasattr(pattern, 'with_segments'): - pattern = self.with_segments(pattern) case_sensitive = self.parser.normcase('Aa') == 'Aa' - globber = _PathGlobber(pattern.parser.sep, case_sensitive, recursive=True) - match = globber.compile(str(pattern), altsep=pattern.parser.altsep) + globber = _PathGlobber(self.parser.sep, case_sensitive, recursive=True) + match = globber.compile(pattern, altsep=self.parser.altsep) return match(str(self)) is not None @@ -282,9 +278,7 @@ class _ReadablePath(_JoinablePath): """Iterate over this subtree and yield all existing files (of any kind, including directories) matching the given relative pattern. """ - if not hasattr(pattern, 'with_segments'): - pattern = self.with_segments(pattern) - anchor, parts = _explode_path(pattern) + anchor, parts = _explode_path(pattern, self.parser.split) if anchor: raise NotImplementedError("Non-relative patterns are unsupported") elif not parts: @@ -338,14 +332,8 @@ class _ReadablePath(_JoinablePath): """ Recursively copy this file or directory tree to the given destination. """ - if not hasattr(target, 'with_segments'): - target = self.with_segments(target) ensure_distinct_paths(self, target) - try: - copy_to_target = target._copy_from - except AttributeError: - raise TypeError(f"Target path is not writable: {target!r}") from None - copy_to_target(self, **kwargs) + target._copy_from(self, **kwargs) return target.joinpath() # Empty join to ensure fresh metadata. def copy_into(self, target_dir, **kwargs): @@ -355,11 +343,7 @@ class _ReadablePath(_JoinablePath): name = self.name if not name: raise ValueError(f"{self!r} has an empty name") - elif hasattr(target_dir, 'with_segments'): - target = target_dir / name - else: - target = self.with_segments(target_dir, name) - return self.copy(target, **kwargs) + return self.copy(target_dir / name, **kwargs) class _WritablePath(_JoinablePath): -- cgit v0.12