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

Side by Side 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
Left:
Right:
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 unified diff | Download patch
« no previous file with comments | « Doc/library/os.path.rst ('k') | Lib/posixpath.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Module 'ntpath' -- common operations on WinNT/Win95 pathnames 1 # Module 'ntpath' -- common operations on WinNT/Win95 pathnames
2 """Common pathname manipulations, WindowsNT/95 version. 2 """Common pathname manipulations, WindowsNT/95 version.
3 3
4 Instead of importing this module directly, import os and refer to this 4 Instead of importing this module directly, import os and refer to this
5 module as os.path. 5 module as os.path.
6 """ 6 """
7 7
8 import os 8 import os
9 import sys 9 import sys
10 import stat 10 import stat
11 import genericpath 11 import genericpath
12 from genericpath import * 12 from genericpath import *
13 13
14 __all__ = ["normcase","isabs","join","splitdrive","split","splitext", 14 __all__ = ["normcase","isabs","join","splitdrive","split","splitext",
15 "basename","dirname","commonprefix","getsize","getmtime", 15 "basename","dirname","commonprefix","getsize","getmtime",
16 "getatime","getctime", "islink","exists","lexists","isdir","isfile", 16 "getatime","getctime", "islink","exists","lexists","isdir","isfile",
17 "ismount", "expanduser","expandvars","normpath","abspath", 17 "ismount", "expanduser","expandvars","normpath","abspath",
18 "splitunc","curdir","pardir","sep","pathsep","defpath","altsep", 18 "splitunc","curdir","pardir","sep","pathsep","defpath","altsep",
19 "extsep","devnull","realpath","supports_unicode_filenames","relpath", 19 "extsep","devnull","realpath","supports_unicode_filenames","relpath",
20 "samefile", "sameopenfile", "samestat",] 20 "samefile", "sameopenfile", "samestat", "commonpath"]
21 21
22 # strings representing various path-related bits and pieces 22 # strings representing various path-related bits and pieces
23 # These are primarily for export; internally, they are hardcoded. 23 # These are primarily for export; internally, they are hardcoded.
24 curdir = '.' 24 curdir = '.'
25 pardir = '..' 25 pardir = '..'
26 extsep = '.' 26 extsep = '.'
27 sep = '\\' 27 sep = '\\'
28 pathsep = ';' 28 pathsep = ';'
29 altsep = '/' 29 altsep = '/'
30 defpath = '.;C:\\bin' 30 defpath = '.;C:\\bin'
(...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after
588 i += 1 588 i += 1
589 589
590 if isinstance(path, bytes): 590 if isinstance(path, bytes):
591 pardir = b'..' 591 pardir = b'..'
592 else: 592 else:
593 pardir = '..' 593 pardir = '..'
594 rel_list = [pardir] * (len(start_list)-i) + path_list[i:] 594 rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
595 if not rel_list: 595 if not rel_list:
596 return _get_dot(path) 596 return _get_dot(path)
597 return join(*rel_list) 597 return join(*rel_list)
598
599
600 # Return the longest common sub-path of the sequence of paths given as input.
601 # The function is case-insensitive and 'separator-insensitive', i.e. if the
602 # only difference between two paths is the use of '\' versus '/' as separator,
603 # they are deemed to be equal.
604 #
605 # However, the returned path will have the standard '\' separator (even if the
606 # given paths had the alternative '/' separator) and will have the case of the
607 # first path given in the sequence. Additionally, any trailing separator is
608 # stripped from the returned path.
609
610 def commonpath(paths):
611 """Given a sequence of path names, returns the longest common sub-path."""
612
613 if not paths:
614 raise ValueError('commonpath() arg is an empty sequence')
615
616 if isinstance(paths[0], bytes):
617 sep = b'\\'
618 altsep = b'/'
619 curdir = b'.'
620 else:
621 sep = '\\'
622 altsep = '/'
623 curdir = '.'
624
625 drivesplits = [splitdrive(p.replace(altsep, sep).lower()) for p in paths]
626
627 try:
628 split_paths = [p.split(sep) for d, p in drivesplits]
629 except TypeError:
630 valid_types = all(isinstance(p, (str, bytes)) for p in paths)
631 if valid_types:
632 # Must have a mixture of text and binary data.
633 raise TypeError("Can't mix strings and bytes in paths") from None
634 raise
635
636 if len(set(p[:1] == sep for d, p in drivesplits)) != 1:
637 raise ValueError("Can't mix absolute and relative paths")
638
639 # Check that all drive letters or UNC paths match. The check is made only
640 # now otherwise type errors for mixing strings and bytes would not be
641 # caught.
642 if len(set(d for d, p in drivesplits)) != 1:
643 raise ValueError("Paths don't have the same drive")
644
645 drive, path = splitdrive(paths[0].replace(altsep, sep))
646 common = path.split(sep)
647 common = [c for c in common if c and c != curdir]
648
649 split_paths = [[c for c in s if c and c != curdir] for s in split_paths]
650 s1 = min(split_paths)
651 s2 = max(split_paths)
652 for i, c in enumerate(s1):
653 if c != s2[i]:
654 common = common[:i]
655 break
656 else:
657 common = common[:len(s1)]
658
659 prefix = drive + sep if isabs(paths[0]) else drive
660 if not common:
661 return prefix
662 else:
663 return prefix + sep.join(common)
598 664
599 665
600 # determine if two files are in fact the same file 666 # determine if two files are in fact the same file
601 try: 667 try:
602 # GetFinalPathNameByHandle is available starting with Windows 6.0. 668 # GetFinalPathNameByHandle is available starting with Windows 6.0.
603 # Windows XP and non-Windows OS'es will mock _getfinalpathname. 669 # Windows XP and non-Windows OS'es will mock _getfinalpathname.
604 if sys.getwindowsversion()[:2] >= (6, 0): 670 if sys.getwindowsversion()[:2] >= (6, 0):
605 from nt import _getfinalpathname 671 from nt import _getfinalpathname
606 else: 672 else:
607 raise ImportError 673 raise ImportError
608 except (AttributeError, ImportError): 674 except (AttributeError, ImportError):
609 # On Windows XP and earlier, two files are the same if their absolute 675 # On Windows XP and earlier, two files are the same if their absolute
610 # pathnames are the same. 676 # pathnames are the same.
611 # Non-Windows operating systems fake this method with an XP 677 # Non-Windows operating systems fake this method with an XP
612 # approximation. 678 # approximation.
613 def _getfinalpathname(f): 679 def _getfinalpathname(f):
614 return normcase(abspath(f)) 680 return normcase(abspath(f))
615 681
616 682
617 try: 683 try:
618 # The genericpath.isdir implementation uses os.stat and checks the mode 684 # The genericpath.isdir implementation uses os.stat and checks the mode
619 # attribute to tell whether or not the path is a directory. 685 # attribute to tell whether or not the path is a directory.
620 # This is overkill on Windows - just pass the path to GetFileAttributes 686 # This is overkill on Windows - just pass the path to GetFileAttributes
621 # and check the attribute from there. 687 # and check the attribute from there.
622 from nt import _isdir as isdir 688 from nt import _isdir as isdir
623 except ImportError: 689 except ImportError:
624 # Use genericpath.isdir as imported above. 690 # Use genericpath.isdir as imported above.
625 pass 691 pass
OLDNEW
« 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+