Skip to content

Commit 2ec6bb4

Browse files
authored
gh-117381: Improve error messages for ntpath.commonpath() (GH-117382)
1 parent a214f55 commit 2ec6bb4

File tree

3 files changed

+54
-53
lines changed

3 files changed

+54
-53
lines changed

Lib/ntpath.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -857,16 +857,19 @@ def commonpath(paths):
857857
drivesplits = [splitroot(p.replace(altsep, sep).lower()) for p in paths]
858858
split_paths = [p.split(sep) for d, r, p in drivesplits]
859859

860-
if len({r for d, r, p in drivesplits}) != 1:
861-
raise ValueError("Can't mix absolute and relative paths")
862-
863860
# Check that all drive letters or UNC paths match. The check is made only
864861
# now otherwise type errors for mixing strings and bytes would not be
865862
# caught.
866863
if len({d for d, r, p in drivesplits}) != 1:
867864
raise ValueError("Paths don't have the same drive")
868865

869866
drive, root, path = splitroot(paths[0].replace(altsep, sep))
867+
if len({r for d, r, p in drivesplits}) != 1:
868+
if drive:
869+
raise ValueError("Can't mix absolute and relative paths")
870+
else:
871+
raise ValueError("Can't mix rooted and not-rooted paths")
872+
870873
common = path.split(sep)
871874
common = [c for c in common if c and c != curdir]
872875

Lib/test/test_ntpath.py

Lines changed: 47 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -866,46 +866,47 @@ def test_commonpath(self):
866866
def check(paths, expected):
867867
tester(('ntpath.commonpath(%r)' % paths).replace('\\\\', '\\'),
868868
expected)
869-
def check_error(exc, paths):
870-
self.assertRaises(exc, ntpath.commonpath, paths)
871-
self.assertRaises(exc, ntpath.commonpath,
872-
[os.fsencode(p) for p in paths])
869+
def check_error(paths, expected):
870+
self.assertRaisesRegex(ValueError, expected, ntpath.commonpath, paths)
871+
self.assertRaisesRegex(ValueError, expected, ntpath.commonpath, paths[::-1])
872+
self.assertRaisesRegex(ValueError, expected, ntpath.commonpath,
873+
[os.fsencode(p) for p in paths])
874+
self.assertRaisesRegex(ValueError, expected, ntpath.commonpath,
875+
[os.fsencode(p) for p in paths[::-1]])
873876

874877
self.assertRaises(TypeError, ntpath.commonpath, None)
875878
self.assertRaises(ValueError, ntpath.commonpath, [])
876879
self.assertRaises(ValueError, ntpath.commonpath, iter([]))
877-
check_error(ValueError, ['C:\\Program Files', 'Program Files'])
878-
check_error(ValueError, ['C:\\Program Files', 'C:Program Files'])
879-
check_error(ValueError, ['\\Program Files', 'Program Files'])
880-
check_error(ValueError, ['Program Files', 'C:\\Program Files'])
881-
882-
check(['C:\\Program Files'], 'C:\\Program Files')
883-
check(['C:\\Program Files', 'C:\\Program Files'], 'C:\\Program Files')
884-
check(['C:\\Program Files\\', 'C:\\Program Files'],
885-
'C:\\Program Files')
886-
check(['C:\\Program Files\\', 'C:\\Program Files\\'],
887-
'C:\\Program Files')
888-
check(['C:\\\\Program Files', 'C:\\Program Files\\\\'],
889-
'C:\\Program Files')
890-
check(['C:\\.\\Program Files', 'C:\\Program Files\\.'],
891-
'C:\\Program Files')
892-
check(['C:\\', 'C:\\bin'], 'C:\\')
893-
check(['C:\\Program Files', 'C:\\bin'], 'C:\\')
894-
check(['C:\\Program Files', 'C:\\Program Files\\Bar'],
895-
'C:\\Program Files')
896-
check(['C:\\Program Files\\Foo', 'C:\\Program Files\\Bar'],
897-
'C:\\Program Files')
898-
check(['C:\\Program Files', 'C:\\Projects'], 'C:\\')
899-
check(['C:\\Program Files\\', 'C:\\Projects'], 'C:\\')
900-
901-
check(['C:\\Program Files\\Foo', 'C:/Program Files/Bar'],
902-
'C:\\Program Files')
903-
check(['C:\\Program Files\\Foo', 'c:/program files/bar'],
904-
'C:\\Program Files')
905-
check(['c:/program files/bar', 'C:\\Program Files\\Foo'],
906-
'c:\\program files')
907-
908-
check_error(ValueError, ['C:\\Program Files', 'D:\\Program Files'])
880+
881+
# gh-117381: Logical error messages
882+
check_error(['C:\\Foo', 'C:Foo'], "Can't mix absolute and relative paths")
883+
check_error(['C:\\Foo', '\\Foo'], "Paths don't have the same drive")
884+
check_error(['C:\\Foo', 'Foo'], "Paths don't have the same drive")
885+
check_error(['C:Foo', '\\Foo'], "Paths don't have the same drive")
886+
check_error(['C:Foo', 'Foo'], "Paths don't have the same drive")
887+
check_error(['\\Foo', 'Foo'], "Can't mix rooted and not-rooted paths")
888+
889+
check(['C:\\Foo'], 'C:\\Foo')
890+
check(['C:\\Foo', 'C:\\Foo'], 'C:\\Foo')
891+
check(['C:\\Foo\\', 'C:\\Foo'], 'C:\\Foo')
892+
check(['C:\\Foo\\', 'C:\\Foo\\'], 'C:\\Foo')
893+
check(['C:\\\\Foo', 'C:\\Foo\\\\'], 'C:\\Foo')
894+
check(['C:\\.\\Foo', 'C:\\Foo\\.'], 'C:\\Foo')
895+
check(['C:\\', 'C:\\baz'], 'C:\\')
896+
check(['C:\\Bar', 'C:\\baz'], 'C:\\')
897+
check(['C:\\Foo', 'C:\\Foo\\Baz'], 'C:\\Foo')
898+
check(['C:\\Foo\\Bar', 'C:\\Foo\\Baz'], 'C:\\Foo')
899+
check(['C:\\Bar', 'C:\\Baz'], 'C:\\')
900+
check(['C:\\Bar\\', 'C:\\Baz'], 'C:\\')
901+
902+
check(['C:\\Foo\\Bar', 'C:/Foo/Baz'], 'C:\\Foo')
903+
check(['C:\\Foo\\Bar', 'c:/foo/baz'], 'C:\\Foo')
904+
check(['c:/foo/bar', 'C:\\Foo\\Baz'], 'c:\\foo')
905+
906+
# gh-117381: Logical error messages
907+
check_error(['C:\\Foo', 'D:\\Foo'], "Paths don't have the same drive")
908+
check_error(['C:\\Foo', 'D:Foo'], "Paths don't have the same drive")
909+
check_error(['C:Foo', 'D:Foo'], "Paths don't have the same drive")
909910

910911
check(['spam'], 'spam')
911912
check(['spam', 'spam'], 'spam')
@@ -919,20 +920,16 @@ def check_error(exc, paths):
919920

920921
check([''], '')
921922
check(['', 'spam\\alot'], '')
922-
check_error(ValueError, ['', '\\spam\\alot'])
923-
924-
self.assertRaises(TypeError, ntpath.commonpath,
925-
[b'C:\\Program Files', 'C:\\Program Files\\Foo'])
926-
self.assertRaises(TypeError, ntpath.commonpath,
927-
[b'C:\\Program Files', 'Program Files\\Foo'])
928-
self.assertRaises(TypeError, ntpath.commonpath,
929-
[b'Program Files', 'C:\\Program Files\\Foo'])
930-
self.assertRaises(TypeError, ntpath.commonpath,
931-
['C:\\Program Files', b'C:\\Program Files\\Foo'])
932-
self.assertRaises(TypeError, ntpath.commonpath,
933-
['C:\\Program Files', b'Program Files\\Foo'])
934-
self.assertRaises(TypeError, ntpath.commonpath,
935-
['Program Files', b'C:\\Program Files\\Foo'])
923+
924+
# gh-117381: Logical error messages
925+
check_error(['', '\\spam\\alot'], "Can't mix rooted and not-rooted paths")
926+
927+
self.assertRaises(TypeError, ntpath.commonpath, [b'C:\\Foo', 'C:\\Foo\\Baz'])
928+
self.assertRaises(TypeError, ntpath.commonpath, [b'C:\\Foo', 'Foo\\Baz'])
929+
self.assertRaises(TypeError, ntpath.commonpath, [b'Foo', 'C:\\Foo\\Baz'])
930+
self.assertRaises(TypeError, ntpath.commonpath, ['C:\\Foo', b'C:\\Foo\\Baz'])
931+
self.assertRaises(TypeError, ntpath.commonpath, ['C:\\Foo', b'Foo\\Baz'])
932+
self.assertRaises(TypeError, ntpath.commonpath, ['Foo', b'C:\\Foo\\Baz'])
936933

937934
@unittest.skipIf(is_emscripten, "Emscripten cannot fstat unnamed files.")
938935
def test_sameopenfile(self):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix error message for :func:`ntpath.commonpath`.

0 commit comments

Comments
 (0)