diff --git a/Lib/pathlib.py b/Lib/pathlib.py index a36ffdd73d8af1..b4a872e2e05feb 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -399,9 +399,6 @@ def __str__(self): self._tail) or '.' return self._str - def __fspath__(self): - return str(self) - def as_posix(self): """Return the string representation of the path with forward (/) slashes.""" @@ -411,7 +408,7 @@ def as_posix(self): def __bytes__(self): """Return the bytes representation of the path. This is only recommended to use under Unix.""" - return os.fsencode(self) + return os.fsencode(str(self)) def __repr__(self): return "{}({!r})".format(self.__class__.__name__, self.as_posix()) @@ -743,11 +740,6 @@ def match(self, path_pattern, *, case_sensitive=None): raise ValueError("empty pattern") -# Subclassing os.PathLike makes isinstance() checks slower, -# which in turn makes Path construction slower. Register instead! -os.PathLike.register(PurePath) - - class PurePosixPath(PurePath): """PurePath subclass for non-Windows systems. @@ -757,6 +749,8 @@ class PurePosixPath(PurePath): _flavour = posixpath __slots__ = () + def __fspath__(self): + return str(self) class PureWindowsPath(PurePath): """PurePath subclass for Windows systems. @@ -767,6 +761,13 @@ class PureWindowsPath(PurePath): _flavour = ntpath __slots__ = () + def __fspath__(self): + return str(self) + + +# These classes implement os.PathLike for backwards compatibility. +os.PathLike.register(PurePosixPath) +os.PathLike.register(PureWindowsPath) # Filesystem-accessing classes @@ -1174,6 +1175,9 @@ def __new__(cls, *args, **kwargs): cls = WindowsPath if os.name == 'nt' else PosixPath return object.__new__(cls) + def __fspath__(self): + return str(self) + @classmethod def cwd(cls): """Return a new path pointing to the current working directory.""" @@ -1398,6 +1402,10 @@ def expanduser(self): return self +# Subclassing os.PathLike makes isinstance() checks slower, +# which in turn makes Path construction slower. Register instead! +os.PathLike.register(Path) + class PosixPath(Path, PurePosixPath): """Path subclass for non-Windows systems. diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index f9356909cb0982..a3db944364994d 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1545,6 +1545,15 @@ class cls(pathlib.PurePath): # repr() roundtripping is not supported in custom subclass. test_repr_roundtrips = None + # PurePath subclass is not automatically path-like + def test_fspath_common(self): + P = self.cls + p = P() + self.assertFalse(issubclass(P, os.PathLike)) + self.assertFalse(isinstance(p, os.PathLike)) + with self.assertRaises(TypeError): + os.fspath(p) + @only_posix class PosixPathAsPureTest(PurePosixPathTest): diff --git a/Misc/NEWS.d/next/Library/2023-06-23-18-23-18.gh-issue-106037.hLb-E3.rst b/Misc/NEWS.d/next/Library/2023-06-23-18-23-18.gh-issue-106037.hLb-E3.rst new file mode 100644 index 00000000000000..69b1a0335eaa95 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-23-18-23-18.gh-issue-106037.hLb-E3.rst @@ -0,0 +1,3 @@ +Fix misidentification of :class:`pathlib.PurePath` user subclasses as +:class:`os.PathLike`. Subclasses are free to define an +:meth:`~os.PathLike.__fspath__` method, but do not inherit one.