-
-
Notifications
You must be signed in to change notification settings - Fork 30.7k
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
Conversation
…into fix-commonpath
Could you please add test cases covering: commonpath(['//foo', '/foo', 'foo'])
commonpath(['//foo', '/foo'])
commonpath(['//foo', 'foo']) I think I'd expect all three to raise |
Do I have permission to change this test then to 3 slashes? In the current implementation I made sure it wouldn't break. cpython/Lib/test/test_posixpath.py Line 716 in 54f7e14
Achieving the desired behaviour would be easy: if min(roots) != max(roots): # -> not all roots are the same
raise ValueError But I'm not sure what the error message would have to be. |
Ah interesting, OK! Preserving existing behaviour for |
The patch seems larger than necessary to fix the bug. Could something like this work instead? diff --git a/Lib/posixpath.py b/Lib/posixpath.py
index 4fc02be69b..4cbe1b1367 100644
--- a/Lib/posixpath.py
+++ b/Lib/posixpath.py
@@ -541,10 +541,9 @@ def commonpath(paths):
try:
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
+ prefixes = [splitroot(path)[1] for path in paths]
+ if any(prefixes) != all(prefixes):
+ 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)
@@ -555,7 +554,7 @@ def commonpath(paths):
common = s1[:i]
break
- prefix = sep if isabs else sep[:0]
+ prefix = min(prefixes)
return prefix + sep.join(common)
except (TypeError, AttributeError):
genericpath._check_arg_types('commonpath', *paths) |
I've tried to keep as much of the old structure as possible. Your code appears to do more work. |
|
I've made some changes to further reduce the diff. Now the fix is way more readable. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be faster to sort the roots up front and then check the first and last elements? (Untested).
@barneygale, do you think this can be merged now? There don't seem to be any optimisations remaining. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change can break user code which expects the result always has a single slash prefix. It is unsafe to backport it. So it should be documented as a new feature.
How does this change affect performance? Please test for short (2 items) and long (e.g. /usr/lib/**
) sequences.
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
The speed difference is smaller for long paths, but bigger for many paths (20). See, the updated benchmark. |
We should be careful about subtle breaking changes like this. @nineteendo: Ideally, a discussion would happen on the issue first, and then if a consensus on how to proceed has been reached, a PR can be created. Creating a lot of PRs before a decision has been reached tie up a reviewer resources, creating unneeded review churn and CI churn. |
NOTE: this is NOT a duplicate of #117202, the branch has been renamed, causing the old pull request to be closed.
Benchmark:
//
forposixpath.commonpath
#117201