Skip to content

Commit d372472

Browse files
authored
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`.
1 parent d2d8862 commit d372472

File tree

2 files changed

+9
-29
lines changed

2 files changed

+9
-29
lines changed

Lib/pathlib/__init__.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -1105,11 +1105,7 @@ def copy(self, target, **kwargs):
11051105
if not hasattr(target, 'with_segments'):
11061106
target = self.with_segments(target)
11071107
ensure_distinct_paths(self, target)
1108-
try:
1109-
copy_to_target = target._copy_from
1110-
except AttributeError:
1111-
raise TypeError(f"Target path is not writable: {target!r}") from None
1112-
copy_to_target(self, **kwargs)
1108+
target._copy_from(self, **kwargs)
11131109
return target.joinpath() # Empty join to ensure fresh metadata.
11141110

11151111
def copy_into(self, target_dir, **kwargs):

Lib/pathlib/types.py

+8-24
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,12 @@
1717
from typing import Optional, Protocol, runtime_checkable
1818

1919

20-
def _explode_path(path):
20+
def _explode_path(path, split):
2121
"""
2222
Split the path into a 2-tuple (anchor, parts), where *anchor* is the
2323
uppermost parent of the path (equivalent to path.parents[-1]), and
2424
*parts* is a reversed list of parts following the anchor.
2525
"""
26-
split = path.parser.split
27-
path = str(path)
2826
parent, name = split(path)
2927
names = []
3028
while path != parent:
@@ -95,7 +93,7 @@ def __str__(self):
9593
@property
9694
def anchor(self):
9795
"""The concatenation of the drive and root, or ''."""
98-
return _explode_path(self)[0]
96+
return _explode_path(str(self), self.parser.split)[0]
9997

10098
@property
10199
def name(self):
@@ -169,7 +167,7 @@ def with_suffix(self, suffix):
169167
def parts(self):
170168
"""An object providing sequence-like access to the
171169
components in the filesystem path."""
172-
anchor, parts = _explode_path(self)
170+
anchor, parts = _explode_path(str(self), self.parser.split)
173171
if anchor:
174172
parts.append(anchor)
175173
return tuple(reversed(parts))
@@ -221,11 +219,9 @@ def full_match(self, pattern):
221219
Return True if this path matches the given glob-style pattern. The
222220
pattern is matched against the entire path.
223221
"""
224-
if not hasattr(pattern, 'with_segments'):
225-
pattern = self.with_segments(pattern)
226222
case_sensitive = self.parser.normcase('Aa') == 'Aa'
227-
globber = _PathGlobber(pattern.parser.sep, case_sensitive, recursive=True)
228-
match = globber.compile(str(pattern), altsep=pattern.parser.altsep)
223+
globber = _PathGlobber(self.parser.sep, case_sensitive, recursive=True)
224+
match = globber.compile(pattern, altsep=self.parser.altsep)
229225
return match(str(self)) is not None
230226

231227

@@ -282,9 +278,7 @@ def glob(self, pattern, *, recurse_symlinks=True):
282278
"""Iterate over this subtree and yield all existing files (of any
283279
kind, including directories) matching the given relative pattern.
284280
"""
285-
if not hasattr(pattern, 'with_segments'):
286-
pattern = self.with_segments(pattern)
287-
anchor, parts = _explode_path(pattern)
281+
anchor, parts = _explode_path(pattern, self.parser.split)
288282
if anchor:
289283
raise NotImplementedError("Non-relative patterns are unsupported")
290284
elif not parts:
@@ -338,14 +332,8 @@ def copy(self, target, **kwargs):
338332
"""
339333
Recursively copy this file or directory tree to the given destination.
340334
"""
341-
if not hasattr(target, 'with_segments'):
342-
target = self.with_segments(target)
343335
ensure_distinct_paths(self, target)
344-
try:
345-
copy_to_target = target._copy_from
346-
except AttributeError:
347-
raise TypeError(f"Target path is not writable: {target!r}") from None
348-
copy_to_target(self, **kwargs)
336+
target._copy_from(self, **kwargs)
349337
return target.joinpath() # Empty join to ensure fresh metadata.
350338

351339
def copy_into(self, target_dir, **kwargs):
@@ -355,11 +343,7 @@ def copy_into(self, target_dir, **kwargs):
355343
name = self.name
356344
if not name:
357345
raise ValueError(f"{self!r} has an empty name")
358-
elif hasattr(target_dir, 'with_segments'):
359-
target = target_dir / name
360-
else:
361-
target = self.with_segments(target_dir, name)
362-
return self.copy(target, **kwargs)
346+
return self.copy(target_dir / name, **kwargs)
363347

364348

365349
class _WritablePath(_JoinablePath):

0 commit comments

Comments
 (0)