gh-117381: Improve error messages for ntpath.commonpath() (GH-117382)

This commit is contained in:
Nice Zombies 2024-04-03 15:10:09 +02:00 committed by GitHub
parent a214f55b27
commit 2ec6bb4111
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 50 additions and 49 deletions

View file

@ -857,9 +857,6 @@ def commonpath(paths):
drivesplits = [splitroot(p.replace(altsep, sep).lower()) for p in paths] drivesplits = [splitroot(p.replace(altsep, sep).lower()) for p in paths]
split_paths = [p.split(sep) for d, r, p in drivesplits] split_paths = [p.split(sep) for d, r, p in drivesplits]
if len({r for d, r, p in drivesplits}) != 1:
raise ValueError("Can't mix absolute and relative paths")
# Check that all drive letters or UNC paths match. The check is made only # Check that all drive letters or UNC paths match. The check is made only
# now otherwise type errors for mixing strings and bytes would not be # now otherwise type errors for mixing strings and bytes would not be
# caught. # caught.
@ -867,6 +864,12 @@ def commonpath(paths):
raise ValueError("Paths don't have the same drive") raise ValueError("Paths don't have the same drive")
drive, root, path = splitroot(paths[0].replace(altsep, sep)) drive, root, path = splitroot(paths[0].replace(altsep, sep))
if len({r for d, r, p in drivesplits}) != 1:
if drive:
raise ValueError("Can't mix absolute and relative paths")
else:
raise ValueError("Can't mix rooted and not-rooted paths")
common = path.split(sep) common = path.split(sep)
common = [c for c in common if c and c != curdir] common = [c for c in common if c and c != curdir]

View file

@ -866,46 +866,47 @@ class TestNtpath(NtpathTestCase):
def check(paths, expected): def check(paths, expected):
tester(('ntpath.commonpath(%r)' % paths).replace('\\\\', '\\'), tester(('ntpath.commonpath(%r)' % paths).replace('\\\\', '\\'),
expected) expected)
def check_error(exc, paths): def check_error(paths, expected):
self.assertRaises(exc, ntpath.commonpath, paths) self.assertRaisesRegex(ValueError, expected, ntpath.commonpath, paths)
self.assertRaises(exc, ntpath.commonpath, self.assertRaisesRegex(ValueError, expected, ntpath.commonpath, paths[::-1])
[os.fsencode(p) for p in paths]) self.assertRaisesRegex(ValueError, expected, ntpath.commonpath,
[os.fsencode(p) for p in paths])
self.assertRaisesRegex(ValueError, expected, ntpath.commonpath,
[os.fsencode(p) for p in paths[::-1]])
self.assertRaises(TypeError, ntpath.commonpath, None) self.assertRaises(TypeError, ntpath.commonpath, None)
self.assertRaises(ValueError, ntpath.commonpath, []) self.assertRaises(ValueError, ntpath.commonpath, [])
self.assertRaises(ValueError, ntpath.commonpath, iter([])) self.assertRaises(ValueError, ntpath.commonpath, iter([]))
check_error(ValueError, ['C:\\Program Files', 'Program Files'])
check_error(ValueError, ['C:\\Program Files', 'C:Program Files'])
check_error(ValueError, ['\\Program Files', 'Program Files'])
check_error(ValueError, ['Program Files', 'C:\\Program Files'])
check(['C:\\Program Files'], 'C:\\Program Files') # gh-117381: Logical error messages
check(['C:\\Program Files', 'C:\\Program Files'], 'C:\\Program Files') check_error(['C:\\Foo', 'C:Foo'], "Can't mix absolute and relative paths")
check(['C:\\Program Files\\', 'C:\\Program Files'], check_error(['C:\\Foo', '\\Foo'], "Paths don't have the same drive")
'C:\\Program Files') check_error(['C:\\Foo', 'Foo'], "Paths don't have the same drive")
check(['C:\\Program Files\\', 'C:\\Program Files\\'], check_error(['C:Foo', '\\Foo'], "Paths don't have the same drive")
'C:\\Program Files') check_error(['C:Foo', 'Foo'], "Paths don't have the same drive")
check(['C:\\\\Program Files', 'C:\\Program Files\\\\'], check_error(['\\Foo', 'Foo'], "Can't mix rooted and not-rooted paths")
'C:\\Program Files')
check(['C:\\.\\Program Files', 'C:\\Program Files\\.'],
'C:\\Program Files')
check(['C:\\', 'C:\\bin'], 'C:\\')
check(['C:\\Program Files', 'C:\\bin'], 'C:\\')
check(['C:\\Program Files', 'C:\\Program Files\\Bar'],
'C:\\Program Files')
check(['C:\\Program Files\\Foo', 'C:\\Program Files\\Bar'],
'C:\\Program Files')
check(['C:\\Program Files', 'C:\\Projects'], 'C:\\')
check(['C:\\Program Files\\', 'C:\\Projects'], 'C:\\')
check(['C:\\Program Files\\Foo', 'C:/Program Files/Bar'], check(['C:\\Foo'], 'C:\\Foo')
'C:\\Program Files') check(['C:\\Foo', 'C:\\Foo'], 'C:\\Foo')
check(['C:\\Program Files\\Foo', 'c:/program files/bar'], check(['C:\\Foo\\', 'C:\\Foo'], 'C:\\Foo')
'C:\\Program Files') check(['C:\\Foo\\', 'C:\\Foo\\'], 'C:\\Foo')
check(['c:/program files/bar', 'C:\\Program Files\\Foo'], check(['C:\\\\Foo', 'C:\\Foo\\\\'], 'C:\\Foo')
'c:\\program files') check(['C:\\.\\Foo', 'C:\\Foo\\.'], 'C:\\Foo')
check(['C:\\', 'C:\\baz'], 'C:\\')
check(['C:\\Bar', 'C:\\baz'], 'C:\\')
check(['C:\\Foo', 'C:\\Foo\\Baz'], 'C:\\Foo')
check(['C:\\Foo\\Bar', 'C:\\Foo\\Baz'], 'C:\\Foo')
check(['C:\\Bar', 'C:\\Baz'], 'C:\\')
check(['C:\\Bar\\', 'C:\\Baz'], 'C:\\')
check_error(ValueError, ['C:\\Program Files', 'D:\\Program Files']) check(['C:\\Foo\\Bar', 'C:/Foo/Baz'], 'C:\\Foo')
check(['C:\\Foo\\Bar', 'c:/foo/baz'], 'C:\\Foo')
check(['c:/foo/bar', 'C:\\Foo\\Baz'], 'c:\\foo')
# gh-117381: Logical error messages
check_error(['C:\\Foo', 'D:\\Foo'], "Paths don't have the same drive")
check_error(['C:\\Foo', 'D:Foo'], "Paths don't have the same drive")
check_error(['C:Foo', 'D:Foo'], "Paths don't have the same drive")
check(['spam'], 'spam') check(['spam'], 'spam')
check(['spam', 'spam'], 'spam') check(['spam', 'spam'], 'spam')
@ -919,20 +920,16 @@ class TestNtpath(NtpathTestCase):
check([''], '') check([''], '')
check(['', 'spam\\alot'], '') check(['', 'spam\\alot'], '')
check_error(ValueError, ['', '\\spam\\alot'])
self.assertRaises(TypeError, ntpath.commonpath, # gh-117381: Logical error messages
[b'C:\\Program Files', 'C:\\Program Files\\Foo']) check_error(['', '\\spam\\alot'], "Can't mix rooted and not-rooted paths")
self.assertRaises(TypeError, ntpath.commonpath,
[b'C:\\Program Files', 'Program Files\\Foo']) self.assertRaises(TypeError, ntpath.commonpath, [b'C:\\Foo', 'C:\\Foo\\Baz'])
self.assertRaises(TypeError, ntpath.commonpath, self.assertRaises(TypeError, ntpath.commonpath, [b'C:\\Foo', 'Foo\\Baz'])
[b'Program Files', 'C:\\Program Files\\Foo']) self.assertRaises(TypeError, ntpath.commonpath, [b'Foo', 'C:\\Foo\\Baz'])
self.assertRaises(TypeError, ntpath.commonpath, self.assertRaises(TypeError, ntpath.commonpath, ['C:\\Foo', b'C:\\Foo\\Baz'])
['C:\\Program Files', b'C:\\Program Files\\Foo']) self.assertRaises(TypeError, ntpath.commonpath, ['C:\\Foo', b'Foo\\Baz'])
self.assertRaises(TypeError, ntpath.commonpath, self.assertRaises(TypeError, ntpath.commonpath, ['Foo', b'C:\\Foo\\Baz'])
['C:\\Program Files', b'Program Files\\Foo'])
self.assertRaises(TypeError, ntpath.commonpath,
['Program Files', b'C:\\Program Files\\Foo'])
@unittest.skipIf(is_emscripten, "Emscripten cannot fstat unnamed files.") @unittest.skipIf(is_emscripten, "Emscripten cannot fstat unnamed files.")
def test_sameopenfile(self): def test_sameopenfile(self):

View file

@ -0,0 +1 @@
Fix error message for :func:`ntpath.commonpath`.