From 78a368ac65081316376258cbe64db6d9795ef14a Mon Sep 17 00:00:00 2001 From: barneygale Date: Fri, 16 May 2025 19:05:46 +0100 Subject: [PATCH 1/2] GH-128520: pathlib ABCs: tweak protocol for virtual path strings Adjust `pathlib._os.vfspath()` so that it doesn't try `os.fsdecode()`. I don't know whether supporting `os.PathLike` arguments is a good idea, so it's best to leave it out for now. --- Lib/pathlib/__init__.py | 6 +++--- Lib/pathlib/_os.py | 16 +++++----------- Lib/test/test_pathlib/support/zip_path.py | 2 +- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/Lib/pathlib/__init__.py b/Lib/pathlib/__init__.py index 2dc1f7f7126063..2b09f31661c1ef 100644 --- a/Lib/pathlib/__init__.py +++ b/Lib/pathlib/__init__.py @@ -188,9 +188,6 @@ def __reduce__(self): def __repr__(self): return "{}({!r})".format(self.__class__.__name__, self.as_posix()) - def __fspath__(self): - return str(self) - def __bytes__(self): """Return the bytes representation of the path. This is only recommended to use under Unix.""" @@ -259,6 +256,9 @@ def __str__(self): self._tail) or '.' return self._str + __fspath__ = __str__ + __vfspath__ = __str__ + @classmethod def _format_parsed_parts(cls, drv, root, tail): if drv or root: diff --git a/Lib/pathlib/_os.py b/Lib/pathlib/_os.py index 62a4adb555ea89..e61f29543b868a 100644 --- a/Lib/pathlib/_os.py +++ b/Lib/pathlib/_os.py @@ -210,24 +210,18 @@ def magic_open(path, mode='r', buffering=-1, encoding=None, errors=None, raise TypeError(f"{cls.__name__} can't be opened with mode {mode!r}") -def vfspath(path): +def vfspath(obj): """ Return the string representation of a virtual path object. """ + cls = type(obj) try: - return os.fsdecode(path) - except TypeError: - pass - - path_type = type(path) - try: - return path_type.__vfspath__(path) + return cls.__vfspath__(obj) except AttributeError: - if hasattr(path_type, '__vfspath__'): + if hasattr(cls, '__vfspath__'): raise - raise TypeError("expected str, bytes, os.PathLike or JoinablePath " - "object, not " + path_type.__name__) + raise TypeError("expected JoinablePath object, not " + cls.__name__) def ensure_distinct_paths(source, target): diff --git a/Lib/test/test_pathlib/support/zip_path.py b/Lib/test/test_pathlib/support/zip_path.py index 21e1d07423aff5..2bfe89b36595b0 100644 --- a/Lib/test/test_pathlib/support/zip_path.py +++ b/Lib/test/test_pathlib/support/zip_path.py @@ -334,4 +334,4 @@ def symlink_to(self, target, target_is_directory=False): zinfo.external_attr = stat.S_IFLNK << 16 if target_is_directory: zinfo.external_attr |= 0x10 - self.zip_file.writestr(zinfo, vfspath(target)) + self.zip_file.writestr(zinfo, target) From 5bb6bb25f42ba71d8edc04d2eb49ca34b8816d93 Mon Sep 17 00:00:00 2001 From: barneygale Date: Sun, 20 Jul 2025 18:12:03 +0100 Subject: [PATCH 2/2] Match implementation in #134101 --- Lib/pathlib/_os.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/pathlib/_os.py b/Lib/pathlib/_os.py index e61f29543b868a..fbcbfb979d1278 100644 --- a/Lib/pathlib/_os.py +++ b/Lib/pathlib/_os.py @@ -216,12 +216,12 @@ def vfspath(obj): """ cls = type(obj) try: - return cls.__vfspath__(obj) + vfspath_method = cls.__vfspath__ except AttributeError: - if hasattr(cls, '__vfspath__'): - raise - - raise TypeError("expected JoinablePath object, not " + cls.__name__) + cls_name = cls.__name__ + raise TypeError(f"expected JoinablePath object, not {cls_name}") from None + else: + return vfspath_method(obj) def ensure_distinct_paths(source, target):