pathlib ABCs: Require one or more initialiser arguments (#113885)

Refuse to guess what a user means when they initialise a pathlib ABC
without any positional arguments. In mainline pathlib it's normalised to
`.`, but in the ABCs this guess isn't appropriate; for example, the path
type may not represent the current directory as `.`, or may have no concept
of a "current directory" at all.
This commit is contained in:
Barney Gale 2024-01-10 01:12:58 +00:00 committed by GitHub
parent beb80d11ec
commit 5d8a3e74b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 26 additions and 32 deletions

View File

@ -167,13 +167,7 @@ class PurePathBase:
def __str__(self): def __str__(self):
"""Return the string representation of the path, suitable for """Return the string representation of the path, suitable for
passing to system calls.""" passing to system calls."""
paths = self._raw_paths return self.pathmod.join(*self._raw_paths)
if len(paths) == 1:
return paths[0]
elif paths:
return self.pathmod.join(*paths)
else:
return ''
def as_posix(self): def as_posix(self):
"""Return the string representation of the path with forward (/) """Return the string representation of the path with forward (/)
@ -838,7 +832,7 @@ class PathBase(PurePathBase):
# enable users to replace the implementation of 'absolute()' in a # enable users to replace the implementation of 'absolute()' in a
# subclass and benefit from the new behaviour here. This works because # subclass and benefit from the new behaviour here. This works because
# os.path.abspath('.') == os.getcwd(). # os.path.abspath('.') == os.getcwd().
return cls().absolute() return cls('').absolute()
def expanduser(self): def expanduser(self):
""" Return a new path with expanded ~ and ~user constructs """ Return a new path with expanded ~ and ~user constructs

View File

@ -227,9 +227,9 @@ class DummyPurePathTest(unittest.TestCase):
self.assertFalse(P('c:/a/B.Py').match('C:/A/*.pY', case_sensitive=True)) self.assertFalse(P('c:/a/B.Py').match('C:/A/*.pY', case_sensitive=True))
self.assertTrue(P('/a/b/c.py').match('/A/*/*.Py', case_sensitive=False)) self.assertTrue(P('/a/b/c.py').match('/A/*/*.Py', case_sensitive=False))
# Matching against empty path # Matching against empty path
self.assertFalse(P().match('*')) self.assertFalse(P('').match('*'))
self.assertTrue(P().match('**')) self.assertTrue(P('').match('**'))
self.assertFalse(P().match('**/*')) self.assertFalse(P('').match('**/*'))
def test_parts_common(self): def test_parts_common(self):
# `parts` returns a tuple. # `parts` returns a tuple.
@ -249,8 +249,8 @@ class DummyPurePathTest(unittest.TestCase):
p = P('a/b/c') p = P('a/b/c')
self.assertEqual(p.parent, P('a/b')) self.assertEqual(p.parent, P('a/b'))
self.assertEqual(p.parent.parent, P('a')) self.assertEqual(p.parent.parent, P('a'))
self.assertEqual(p.parent.parent.parent, P()) self.assertEqual(p.parent.parent.parent, P(''))
self.assertEqual(p.parent.parent.parent.parent, P()) self.assertEqual(p.parent.parent.parent.parent, P(''))
# Anchored # Anchored
p = P('/a/b/c') p = P('/a/b/c')
self.assertEqual(p.parent, P('/a/b')) self.assertEqual(p.parent, P('/a/b'))
@ -478,20 +478,20 @@ class DummyPurePathTest(unittest.TestCase):
p = P('a/b') p = P('a/b')
self.assertRaises(TypeError, p.relative_to) self.assertRaises(TypeError, p.relative_to)
self.assertRaises(TypeError, p.relative_to, b'a') self.assertRaises(TypeError, p.relative_to, b'a')
self.assertEqual(p.relative_to(P()), P('a/b')) self.assertEqual(p.relative_to(P('')), P('a/b'))
self.assertEqual(p.relative_to(''), P('a/b')) self.assertEqual(p.relative_to(''), P('a/b'))
self.assertEqual(p.relative_to(P('a')), P('b')) self.assertEqual(p.relative_to(P('a')), P('b'))
self.assertEqual(p.relative_to('a'), P('b')) self.assertEqual(p.relative_to('a'), P('b'))
self.assertEqual(p.relative_to('a/'), P('b')) self.assertEqual(p.relative_to('a/'), P('b'))
self.assertEqual(p.relative_to(P('a/b')), P()) self.assertEqual(p.relative_to(P('a/b')), P(''))
self.assertEqual(p.relative_to('a/b'), P()) self.assertEqual(p.relative_to('a/b'), P(''))
self.assertEqual(p.relative_to(P(), walk_up=True), P('a/b')) self.assertEqual(p.relative_to(P(''), walk_up=True), P('a/b'))
self.assertEqual(p.relative_to('', walk_up=True), P('a/b')) self.assertEqual(p.relative_to('', walk_up=True), P('a/b'))
self.assertEqual(p.relative_to(P('a'), walk_up=True), P('b')) self.assertEqual(p.relative_to(P('a'), walk_up=True), P('b'))
self.assertEqual(p.relative_to('a', walk_up=True), P('b')) self.assertEqual(p.relative_to('a', walk_up=True), P('b'))
self.assertEqual(p.relative_to('a/', walk_up=True), P('b')) self.assertEqual(p.relative_to('a/', walk_up=True), P('b'))
self.assertEqual(p.relative_to(P('a/b'), walk_up=True), P()) self.assertEqual(p.relative_to(P('a/b'), walk_up=True), P(''))
self.assertEqual(p.relative_to('a/b', walk_up=True), P()) self.assertEqual(p.relative_to('a/b', walk_up=True), P(''))
self.assertEqual(p.relative_to(P('a/c'), walk_up=True), P('../b')) self.assertEqual(p.relative_to(P('a/c'), walk_up=True), P('../b'))
self.assertEqual(p.relative_to('a/c', walk_up=True), P('../b')) self.assertEqual(p.relative_to('a/c', walk_up=True), P('../b'))
self.assertEqual(p.relative_to(P('a/b/c'), walk_up=True), P('..')) self.assertEqual(p.relative_to(P('a/b/c'), walk_up=True), P('..'))
@ -517,15 +517,15 @@ class DummyPurePathTest(unittest.TestCase):
self.assertEqual(p.relative_to(P('/a')), P('b')) self.assertEqual(p.relative_to(P('/a')), P('b'))
self.assertEqual(p.relative_to('/a'), P('b')) self.assertEqual(p.relative_to('/a'), P('b'))
self.assertEqual(p.relative_to('/a/'), P('b')) self.assertEqual(p.relative_to('/a/'), P('b'))
self.assertEqual(p.relative_to(P('/a/b')), P()) self.assertEqual(p.relative_to(P('/a/b')), P(''))
self.assertEqual(p.relative_to('/a/b'), P()) self.assertEqual(p.relative_to('/a/b'), P(''))
self.assertEqual(p.relative_to(P('/'), walk_up=True), P('a/b')) self.assertEqual(p.relative_to(P('/'), walk_up=True), P('a/b'))
self.assertEqual(p.relative_to('/', walk_up=True), P('a/b')) self.assertEqual(p.relative_to('/', walk_up=True), P('a/b'))
self.assertEqual(p.relative_to(P('/a'), walk_up=True), P('b')) self.assertEqual(p.relative_to(P('/a'), walk_up=True), P('b'))
self.assertEqual(p.relative_to('/a', walk_up=True), P('b')) self.assertEqual(p.relative_to('/a', walk_up=True), P('b'))
self.assertEqual(p.relative_to('/a/', walk_up=True), P('b')) self.assertEqual(p.relative_to('/a/', walk_up=True), P('b'))
self.assertEqual(p.relative_to(P('/a/b'), walk_up=True), P()) self.assertEqual(p.relative_to(P('/a/b'), walk_up=True), P(''))
self.assertEqual(p.relative_to('/a/b', walk_up=True), P()) self.assertEqual(p.relative_to('/a/b', walk_up=True), P(''))
self.assertEqual(p.relative_to(P('/a/c'), walk_up=True), P('../b')) self.assertEqual(p.relative_to(P('/a/c'), walk_up=True), P('../b'))
self.assertEqual(p.relative_to('/a/c', walk_up=True), P('../b')) self.assertEqual(p.relative_to('/a/c', walk_up=True), P('../b'))
self.assertEqual(p.relative_to(P('/a/b/c'), walk_up=True), P('..')) self.assertEqual(p.relative_to(P('/a/b/c'), walk_up=True), P('..'))
@ -536,7 +536,7 @@ class DummyPurePathTest(unittest.TestCase):
self.assertRaises(ValueError, p.relative_to, P('/c')) self.assertRaises(ValueError, p.relative_to, P('/c'))
self.assertRaises(ValueError, p.relative_to, P('/a/b/c')) self.assertRaises(ValueError, p.relative_to, P('/a/b/c'))
self.assertRaises(ValueError, p.relative_to, P('/a/c')) self.assertRaises(ValueError, p.relative_to, P('/a/c'))
self.assertRaises(ValueError, p.relative_to, P()) self.assertRaises(ValueError, p.relative_to, P(''))
self.assertRaises(ValueError, p.relative_to, '') self.assertRaises(ValueError, p.relative_to, '')
self.assertRaises(ValueError, p.relative_to, P('a')) self.assertRaises(ValueError, p.relative_to, P('a'))
self.assertRaises(ValueError, p.relative_to, P("../a")) self.assertRaises(ValueError, p.relative_to, P("../a"))
@ -553,7 +553,7 @@ class DummyPurePathTest(unittest.TestCase):
p = P('a/b') p = P('a/b')
self.assertRaises(TypeError, p.is_relative_to) self.assertRaises(TypeError, p.is_relative_to)
self.assertRaises(TypeError, p.is_relative_to, b'a') self.assertRaises(TypeError, p.is_relative_to, b'a')
self.assertTrue(p.is_relative_to(P())) self.assertTrue(p.is_relative_to(P('')))
self.assertTrue(p.is_relative_to('')) self.assertTrue(p.is_relative_to(''))
self.assertTrue(p.is_relative_to(P('a'))) self.assertTrue(p.is_relative_to(P('a')))
self.assertTrue(p.is_relative_to('a/')) self.assertTrue(p.is_relative_to('a/'))
@ -576,7 +576,7 @@ class DummyPurePathTest(unittest.TestCase):
self.assertFalse(p.is_relative_to(P('/c'))) self.assertFalse(p.is_relative_to(P('/c')))
self.assertFalse(p.is_relative_to(P('/a/b/c'))) self.assertFalse(p.is_relative_to(P('/a/b/c')))
self.assertFalse(p.is_relative_to(P('/a/c'))) self.assertFalse(p.is_relative_to(P('/a/c')))
self.assertFalse(p.is_relative_to(P())) self.assertFalse(p.is_relative_to(P('')))
self.assertFalse(p.is_relative_to('')) self.assertFalse(p.is_relative_to(''))
self.assertFalse(p.is_relative_to(P('a'))) self.assertFalse(p.is_relative_to(P('a')))
@ -590,7 +590,7 @@ class PathBaseTest(PurePathBaseTest):
def test_unsupported_operation(self): def test_unsupported_operation(self):
P = self.cls P = self.cls
p = self.cls() p = self.cls('')
e = UnsupportedOperation e = UnsupportedOperation
self.assertRaises(e, p.stat) self.assertRaises(e, p.stat)
self.assertRaises(e, p.lstat) self.assertRaises(e, p.lstat)
@ -634,13 +634,13 @@ class PathBaseTest(PurePathBaseTest):
def test_as_uri_common(self): def test_as_uri_common(self):
e = UnsupportedOperation e = UnsupportedOperation
self.assertRaises(e, self.cls().as_uri) self.assertRaises(e, self.cls('').as_uri)
def test_fspath_common(self): def test_fspath_common(self):
self.assertRaises(TypeError, os.fspath, self.cls()) self.assertRaises(TypeError, os.fspath, self.cls(''))
def test_as_bytes_common(self): def test_as_bytes_common(self):
self.assertRaises(TypeError, bytes, self.cls()) self.assertRaises(TypeError, bytes, self.cls(''))
class DummyPathIO(io.BytesIO): class DummyPathIO(io.BytesIO):
@ -993,7 +993,7 @@ class DummyPathTest(DummyPurePathTest):
_check(p.glob("*/"), ["dirA/", "dirB/", "dirC/", "dirE/", "linkB/"]) _check(p.glob("*/"), ["dirA/", "dirB/", "dirC/", "dirE/", "linkB/"])
def test_glob_empty_pattern(self): def test_glob_empty_pattern(self):
p = self.cls() p = self.cls('')
with self.assertRaisesRegex(ValueError, 'Unacceptable pattern'): with self.assertRaisesRegex(ValueError, 'Unacceptable pattern'):
list(p.glob('')) list(p.glob(''))
@ -1554,7 +1554,7 @@ class DummyPathTest(DummyPurePathTest):
# Resolve relative paths. # Resolve relative paths.
try: try:
self.cls().absolute() self.cls('').absolute()
except UnsupportedOperation: except UnsupportedOperation:
return return
old_path = os.getcwd() old_path = os.getcwd()