GH-110109: Fix misleading `pathlib._abc.PurePathBase` repr (#113376)

`PurePathBase.__repr__()` produces a string like `MyPath('/foo')`. This
repr is incorrect/misleading when a subclass's `__init__()` method is
customized, which I expect to be the very common.

This commit moves the `__repr__()` method to `PurePath`, leaving
`PurePathBase` with the default `object` repr.

No user-facing changes because the `pathlib._abc` module remains private.
This commit is contained in:
Barney Gale 2023-12-22 15:11:16 +00:00 committed by GitHub
parent 45e09f921b
commit 237e2cff00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 16 additions and 15 deletions

View File

@ -99,6 +99,9 @@ class PurePath(_abc.PurePathBase):
# when pickling related paths. # when pickling related paths.
return (self.__class__, self.parts) return (self.__class__, self.parts)
def __repr__(self):
return "{}({!r})".format(self.__class__.__name__, self.as_posix())
def __fspath__(self): def __fspath__(self):
return str(self) return str(self)

View File

@ -282,9 +282,6 @@ class PurePathBase:
slashes.""" slashes."""
return str(self).replace(self.pathmod.sep, '/') return str(self).replace(self.pathmod.sep, '/')
def __repr__(self):
return "{}({!r})".format(self.__class__.__name__, self.as_posix())
@property @property
def drive(self): def drive(self):
"""The drive prefix (letter or UNC path), if any.""" """The drive prefix (letter or UNC path), if any."""

View File

@ -69,6 +69,18 @@ class PurePathTest(test_pathlib_abc.DummyPurePathTest):
self.assertEqual(hash(pp), hash(p)) self.assertEqual(hash(pp), hash(p))
self.assertEqual(str(pp), str(p)) self.assertEqual(str(pp), str(p))
def test_repr_common(self):
for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'):
with self.subTest(pathstr=pathstr):
p = self.cls(pathstr)
clsname = p.__class__.__name__
r = repr(p)
# The repr() is in the form ClassName("forward-slashes path").
self.assertTrue(r.startswith(clsname + '('), r)
self.assertTrue(r.endswith(')'), r)
inner = r[len(clsname) + 1 : -1]
self.assertEqual(eval(inner), p.as_posix())
def test_fspath_common(self): def test_fspath_common(self):
P = self.cls P = self.cls
p = P('a/b') p = P('a/b')

View File

@ -31,6 +31,7 @@ class PurePathBaseTest(unittest.TestCase):
self.assertFalse(hasattr(P, '__fspath__')) self.assertFalse(hasattr(P, '__fspath__'))
self.assertFalse(hasattr(P, '__bytes__')) self.assertFalse(hasattr(P, '__bytes__'))
self.assertIs(P.__reduce__, object.__reduce__) self.assertIs(P.__reduce__, object.__reduce__)
self.assertIs(P.__repr__, object.__repr__)
self.assertIs(P.__hash__, object.__hash__) self.assertIs(P.__hash__, object.__hash__)
self.assertIs(P.__eq__, object.__eq__) self.assertIs(P.__eq__, object.__eq__)
self.assertIs(P.__lt__, object.__lt__) self.assertIs(P.__lt__, object.__lt__)
@ -227,18 +228,6 @@ class DummyPurePathTest(unittest.TestCase):
self.assertEqual(P(pathstr).as_posix(), pathstr) self.assertEqual(P(pathstr).as_posix(), pathstr)
# Other tests for as_posix() are in test_equivalences(). # Other tests for as_posix() are in test_equivalences().
def test_repr_common(self):
for pathstr in ('a', 'a/b', 'a/b/c', '/', '/a/b', '/a/b/c'):
with self.subTest(pathstr=pathstr):
p = self.cls(pathstr)
clsname = p.__class__.__name__
r = repr(p)
# The repr() is in the form ClassName("forward-slashes path").
self.assertTrue(r.startswith(clsname + '('), r)
self.assertTrue(r.endswith(')'), r)
inner = r[len(clsname) + 1 : -1]
self.assertEqual(eval(inner), p.as_posix())
def test_eq_common(self): def test_eq_common(self):
P = self.cls P = self.cls
self.assertEqual(P('a/b'), P('a/b')) self.assertEqual(P('a/b'), P('a/b'))