Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(37332)

Unified Diff: Lib/ntpath.py

Issue 10395: new os.path function to extract common prefix based on path components
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Doc/library/os.path.rst ('k') | Lib/posixpath.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
--- a/Lib/ntpath.py Sat Jul 12 18:26:03 2014 +0300
+++ b/Lib/ntpath.py Sun Jul 13 21:30:38 2014 +0300
@@ -17,7 +17,7 @@
"ismount", "expanduser","expandvars","normpath","abspath",
"splitunc","curdir","pardir","sep","pathsep","defpath","altsep",
"extsep","devnull","realpath","supports_unicode_filenames","relpath",
- "samefile", "sameopenfile", "samestat",]
+ "samefile", "sameopenfile", "samestat", "commonpath"]
# strings representing various path-related bits and pieces
# These are primarily for export; internally, they are hardcoded.
@@ -597,6 +597,72 @@
return join(*rel_list)
+# Return the longest common sub-path of the sequence of paths given as input.
+# The function is case-insensitive and 'separator-insensitive', i.e. if the
+# only difference between two paths is the use of '\' versus '/' as separator,
+# they are deemed to be equal.
+#
+# However, the returned path will have the standard '\' separator (even if the
+# given paths had the alternative '/' separator) and will have the case of the
+# first path given in the sequence. Additionally, any trailing separator is
+# stripped from the returned path.
+
+def commonpath(paths):
+ """Given a sequence of path names, returns the longest common sub-path."""
+
+ if not paths:
+ raise ValueError('commonpath() arg is an empty sequence')
+
+ if isinstance(paths[0], bytes):
+ sep = b'\\'
+ altsep = b'/'
+ curdir = b'.'
+ else:
+ sep = '\\'
+ altsep = '/'
+ curdir = '.'
+
+ drivesplits = [splitdrive(p.replace(altsep, sep).lower()) for p in paths]
+
+ try:
+ split_paths = [p.split(sep) for d, p in drivesplits]
+ except TypeError:
+ valid_types = all(isinstance(p, (str, bytes)) for p in paths)
+ if valid_types:
+ # Must have a mixture of text and binary data.
+ raise TypeError("Can't mix strings and bytes in paths") from None
+ raise
+
+ if len(set(p[:1] == sep for d, 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
+ # now otherwise type errors for mixing strings and bytes would not be
+ # caught.
+ if len(set(d for d, p in drivesplits)) != 1:
+ raise ValueError("Paths don't have the same drive")
+
+ drive, path = splitdrive(paths[0].replace(altsep, sep))
+ common = path.split(sep)
+ common = [c for c in common if c and c != curdir]
+
+ split_paths = [[c for c in s if c and c != curdir] for s in split_paths]
+ s1 = min(split_paths)
+ s2 = max(split_paths)
+ for i, c in enumerate(s1):
+ if c != s2[i]:
+ common = common[:i]
+ break
+ else:
+ common = common[:len(s1)]
+
+ prefix = drive + sep if isabs(paths[0]) else drive
+ if not common:
+ return prefix
+ else:
+ return prefix + sep.join(common)
+
+
# determine if two files are in fact the same file
try:
# GetFinalPathNameByHandle is available starting with Windows 6.0.
« no previous file with comments | « Doc/library/os.path.rst ('k') | Lib/posixpath.py » ('j') | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+