Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-117201: Handle leading // for posixpath.commonpath #117334

Closed
wants to merge 33 commits into from
Closed
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
247c9af
Handle leading `//` for `posixpath.commonpath`
nineteendo Mar 24, 2024
0c38276
raise TypeError for non-sequences
nineteendo Mar 24, 2024
a9b0832
📜🤖 Added by blurb_it.
blurb-it[bot] Mar 26, 2024
a521282
Remove `break` & `else`
nineteendo Mar 26, 2024
b467e7e
Merge branch 'fix-commonpath' of https://github.com/nineteendo/cpytho…
nineteendo Mar 26, 2024
26eac21
Handle errors for iterable
nineteendo Mar 26, 2024
d83743d
Remove redundant check
nineteendo Mar 27, 2024
1ae0c43
raise TypeError for non-sequences
nineteendo Mar 28, 2024
e6de234
Update NEWS.d
nineteendo Mar 28, 2024
012c12e
Add newline
nineteendo Mar 28, 2024
fb1c91a
Speed up `posixpath.ismount`
nineteendo Mar 28, 2024
ca90fde
unnest `posixpath.expanduser`
nineteendo Mar 28, 2024
758e0d6
Speed up `posixpath.expanduser` & `posixpath.normpath`
nineteendo Mar 28, 2024
218e43e
Move refactoring to new branch
nineteendo Mar 28, 2024
6df0703
Move bug fix to new branch
nineteendo Mar 28, 2024
df5225b
Remove leftovers
nineteendo Mar 28, 2024
5cf500b
Add additional test cases
nineteendo Mar 29, 2024
c1cffda
Move in try except block
nineteendo Mar 29, 2024
53f414f
Move out try except block
nineteendo Mar 29, 2024
fef266e
Revert renaming
nineteendo Mar 29, 2024
34c9275
Revert unnecessary changes
nineteendo Mar 30, 2024
ad9c461
Speedup mix check
nineteendo Mar 31, 2024
7565559
Revert list comprehensions
nineteendo Apr 1, 2024
0a1aea2
Merge branch 'fix-posixpath.commonpath' of https://github.com/ninetee…
nineteendo Apr 1, 2024
a0ecc76
Rename `tails`
nineteendo Apr 1, 2024
89347ec
Merge branch 'main' into fix-posixpath.commonpath
serhiy-storchaka Apr 3, 2024
49bac97
Merge branch 'main' into fix-posixpath.commonpath
nineteendo Apr 3, 2024
1d5b419
pass *paths
nineteendo Apr 3, 2024
54fff2e
Add additional tests
nineteendo Apr 3, 2024
598f8a1
Fix tests
nineteendo Apr 3, 2024
bb35431
Add test & fix failing tests
nineteendo Apr 3, 2024
93a19e8
Remove `tuple()` call
nineteendo Apr 3, 2024
88e0e6d
remove try-except
nineteendo Apr 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions Lib/posixpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,19 +515,20 @@ def relpath(path, start=None):
raise


# Return the longest common sub-path of the sequence of paths given as input.
# Return the longest common sub-path of the iterable of paths given as input.
barneygale marked this conversation as resolved.
Show resolved Hide resolved
# The paths are not normalized before comparing them (this is the
# responsibility of the caller). Any trailing separator is stripped from the
# returned path.

def commonpath(paths):
"""Given a sequence of path names, returns the longest common sub-path."""
"""Given an iterable of path names, returns the longest common sub-path."""

paths = tuple(map(os.fspath, paths))
paths = tuple(paths)
nineteendo marked this conversation as resolved.
Show resolved Hide resolved

if not paths:
raise ValueError('commonpath() arg is an empty sequence')
raise ValueError('commonpath() arg is an empty iterable')

_, roots, paths = zip(*map(splitroot, paths))
barneygale marked this conversation as resolved.
Show resolved Hide resolved
if isinstance(paths[0], bytes):
sep = b'/'
curdir = b'.'
Expand All @@ -536,12 +537,11 @@ def commonpath(paths):
curdir = '.'

try:
prefix = min(roots)
nineteendo marked this conversation as resolved.
Show resolved Hide resolved
split_paths = [path.split(sep) for path in paths]

try:
isabs, = set(p[:1] == sep for p in paths)
except ValueError:
raise ValueError("Can't mix absolute and relative paths") from None
if not prefix and any(roots):
nineteendo marked this conversation as resolved.
Show resolved Hide resolved
raise ValueError("Can't mix absolute and relative paths")

split_paths = [[c for c in s if c and c != curdir] for s in split_paths]
s1 = min(split_paths)
Expand All @@ -552,7 +552,6 @@ def commonpath(paths):
common = s1[:i]
break

prefix = sep if isabs else sep[:0]
return prefix + sep.join(common)
except (TypeError, AttributeError):
genericpath._check_arg_types('commonpath', *paths)
Expand Down
31 changes: 17 additions & 14 deletions Lib/test/test_posixpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -700,20 +700,32 @@ def check(paths, expected):
os.fsencode(expected))
def check_error(exc, paths):
self.assertRaises(exc, posixpath.commonpath, paths)
self.assertRaises(exc, posixpath.commonpath, paths[::-1])
self.assertRaises(exc, posixpath.commonpath,
[os.fsencode(p) for p in paths])
self.assertRaises(exc, posixpath.commonpath,
[os.fsencode(p) for p in paths[::-1]])

self.assertRaises(TypeError, posixpath.commonpath, None)
self.assertRaises(ValueError, posixpath.commonpath, [])
self.assertRaises(ValueError, posixpath.commonpath, iter([]))
check_error(ValueError, ['/usr', 'usr'])
check_error(ValueError, ['usr', '/usr'])
check_error(ValueError, ['//usr', 'usr'])
check_error(ValueError, ['///usr', 'usr'])
check_error(ValueError, ['//usr', '/usr', 'usr'])

# gh-117201: Handle leading slashes
check(['/usr/local'], '/usr/local')
check(['//usr/local'], '//usr/local')
check(['///usr/local'], '/usr/local')
check(['/usr/local', '//usr/local'], '/usr/local')
check(['//usr/local', '//usr/local'], '//usr/local')
check(['///usr/local', '//usr/local'], '/usr/local')
nineteendo marked this conversation as resolved.
Show resolved Hide resolved

check(['/usr/local', '/usr/local'], '/usr/local')
check(['/usr/local/', '/usr/local'], '/usr/local')
check(['/usr/local/', '/usr/local/'], '/usr/local')
check(['/usr//local', '//usr/local'], '/usr/local')
check(['/usr//local', '/usr/local'], '/usr/local')
check(['/usr/./local', '/./usr/local'], '/usr/local')
check(['/', '/dev'], '/')
check(['/usr', '/dev'], '/')
Expand All @@ -736,18 +748,9 @@ def check_error(exc, paths):
check(['', 'spam/alot'], '')
check_error(ValueError, ['', '/spam/alot'])

self.assertRaises(TypeError, posixpath.commonpath,
[b'/usr/lib/', '/usr/lib/python3'])
self.assertRaises(TypeError, posixpath.commonpath,
[b'/usr/lib/', 'usr/lib/python3'])
self.assertRaises(TypeError, posixpath.commonpath,
[b'usr/lib/', '/usr/lib/python3'])
self.assertRaises(TypeError, posixpath.commonpath,
['/usr/lib/', b'/usr/lib/python3'])
self.assertRaises(TypeError, posixpath.commonpath,
['/usr/lib/', b'usr/lib/python3'])
self.assertRaises(TypeError, posixpath.commonpath,
['usr/lib/', b'/usr/lib/python3'])
check_error(TypeError, [b'/usr/lib/', '/usr/lib/python3'])
check_error(TypeError, [b'/usr/lib/', 'usr/lib/python3'])
check_error(TypeError, [b'usr/lib/', '/usr/lib/python3'])


class PosixCommonTest(test_genericpath.CommonTest, unittest.TestCase):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Handle leading ``//`` for :func:`posixpath.commonpath` using :func:`posixpath.splitroot`.
Loading