mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-22 21:32:31 +00:00
python-3.6.zip added from Github
README.cosmo contains the necessary links.
This commit is contained in:
parent
75fc601ff5
commit
0c4c56ff39
4219 changed files with 1968626 additions and 0 deletions
691
third_party/python/Lib/ntpath.py
vendored
Normal file
691
third_party/python/Lib/ntpath.py
vendored
Normal file
|
@ -0,0 +1,691 @@
|
|||
# Module 'ntpath' -- common operations on WinNT/Win95 pathnames
|
||||
"""Common pathname manipulations, WindowsNT/95 version.
|
||||
|
||||
Instead of importing this module directly, import os and refer to this
|
||||
module as os.path.
|
||||
"""
|
||||
|
||||
# strings representing various path-related bits and pieces
|
||||
# These are primarily for export; internally, they are hardcoded.
|
||||
# Should be set before imports for resolving cyclic dependency.
|
||||
curdir = '.'
|
||||
pardir = '..'
|
||||
extsep = '.'
|
||||
sep = '\\'
|
||||
pathsep = ';'
|
||||
altsep = '/'
|
||||
defpath = '.;C:\\bin'
|
||||
devnull = 'nul'
|
||||
|
||||
import os
|
||||
import sys
|
||||
import stat
|
||||
import genericpath
|
||||
from genericpath import *
|
||||
|
||||
__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
|
||||
"basename","dirname","commonprefix","getsize","getmtime",
|
||||
"getatime","getctime", "islink","exists","lexists","isdir","isfile",
|
||||
"ismount", "expanduser","expandvars","normpath","abspath",
|
||||
"splitunc","curdir","pardir","sep","pathsep","defpath","altsep",
|
||||
"extsep","devnull","realpath","supports_unicode_filenames","relpath",
|
||||
"samefile", "sameopenfile", "samestat", "commonpath"]
|
||||
|
||||
def _get_bothseps(path):
|
||||
if isinstance(path, bytes):
|
||||
return b'\\/'
|
||||
else:
|
||||
return '\\/'
|
||||
|
||||
# Normalize the case of a pathname and map slashes to backslashes.
|
||||
# Other normalizations (such as optimizing '../' away) are not done
|
||||
# (this is done by normpath).
|
||||
|
||||
def normcase(s):
|
||||
"""Normalize case of pathname.
|
||||
|
||||
Makes all characters lowercase and all slashes into backslashes."""
|
||||
s = os.fspath(s)
|
||||
try:
|
||||
if isinstance(s, bytes):
|
||||
return s.replace(b'/', b'\\').lower()
|
||||
else:
|
||||
return s.replace('/', '\\').lower()
|
||||
except (TypeError, AttributeError):
|
||||
if not isinstance(s, (bytes, str)):
|
||||
raise TypeError("normcase() argument must be str or bytes, "
|
||||
"not %r" % s.__class__.__name__) from None
|
||||
raise
|
||||
|
||||
|
||||
# Return whether a path is absolute.
|
||||
# Trivial in Posix, harder on Windows.
|
||||
# For Windows it is absolute if it starts with a slash or backslash (current
|
||||
# volume), or if a pathname after the volume-letter-and-colon or UNC-resource
|
||||
# starts with a slash or backslash.
|
||||
|
||||
def isabs(s):
|
||||
"""Test whether a path is absolute"""
|
||||
s = os.fspath(s)
|
||||
s = splitdrive(s)[1]
|
||||
return len(s) > 0 and s[0] in _get_bothseps(s)
|
||||
|
||||
|
||||
# Join two (or more) paths.
|
||||
def join(path, *paths):
|
||||
path = os.fspath(path)
|
||||
if isinstance(path, bytes):
|
||||
sep = b'\\'
|
||||
seps = b'\\/'
|
||||
colon = b':'
|
||||
else:
|
||||
sep = '\\'
|
||||
seps = '\\/'
|
||||
colon = ':'
|
||||
try:
|
||||
if not paths:
|
||||
path[:0] + sep #23780: Ensure compatible data type even if p is null.
|
||||
result_drive, result_path = splitdrive(path)
|
||||
for p in map(os.fspath, paths):
|
||||
p_drive, p_path = splitdrive(p)
|
||||
if p_path and p_path[0] in seps:
|
||||
# Second path is absolute
|
||||
if p_drive or not result_drive:
|
||||
result_drive = p_drive
|
||||
result_path = p_path
|
||||
continue
|
||||
elif p_drive and p_drive != result_drive:
|
||||
if p_drive.lower() != result_drive.lower():
|
||||
# Different drives => ignore the first path entirely
|
||||
result_drive = p_drive
|
||||
result_path = p_path
|
||||
continue
|
||||
# Same drive in different case
|
||||
result_drive = p_drive
|
||||
# Second path is relative to the first
|
||||
if result_path and result_path[-1] not in seps:
|
||||
result_path = result_path + sep
|
||||
result_path = result_path + p_path
|
||||
## add separator between UNC and non-absolute path
|
||||
if (result_path and result_path[0] not in seps and
|
||||
result_drive and result_drive[-1:] != colon):
|
||||
return result_drive + sep + result_path
|
||||
return result_drive + result_path
|
||||
except (TypeError, AttributeError, BytesWarning):
|
||||
genericpath._check_arg_types('join', path, *paths)
|
||||
raise
|
||||
|
||||
|
||||
# Split a path in a drive specification (a drive letter followed by a
|
||||
# colon) and the path specification.
|
||||
# It is always true that drivespec + pathspec == p
|
||||
def splitdrive(p):
|
||||
"""Split a pathname into drive/UNC sharepoint and relative path specifiers.
|
||||
Returns a 2-tuple (drive_or_unc, path); either part may be empty.
|
||||
|
||||
If you assign
|
||||
result = splitdrive(p)
|
||||
It is always true that:
|
||||
result[0] + result[1] == p
|
||||
|
||||
If the path contained a drive letter, drive_or_unc will contain everything
|
||||
up to and including the colon. e.g. splitdrive("c:/dir") returns ("c:", "/dir")
|
||||
|
||||
If the path contained a UNC path, the drive_or_unc will contain the host name
|
||||
and share up to but not including the fourth directory separator character.
|
||||
e.g. splitdrive("//host/computer/dir") returns ("//host/computer", "/dir")
|
||||
|
||||
Paths cannot contain both a drive letter and a UNC path.
|
||||
|
||||
"""
|
||||
p = os.fspath(p)
|
||||
if len(p) >= 2:
|
||||
if isinstance(p, bytes):
|
||||
sep = b'\\'
|
||||
altsep = b'/'
|
||||
colon = b':'
|
||||
else:
|
||||
sep = '\\'
|
||||
altsep = '/'
|
||||
colon = ':'
|
||||
normp = p.replace(altsep, sep)
|
||||
if (normp[0:2] == sep*2) and (normp[2:3] != sep):
|
||||
# is a UNC path:
|
||||
# vvvvvvvvvvvvvvvvvvvv drive letter or UNC path
|
||||
# \\machine\mountpoint\directory\etc\...
|
||||
# directory ^^^^^^^^^^^^^^^
|
||||
index = normp.find(sep, 2)
|
||||
if index == -1:
|
||||
return p[:0], p
|
||||
index2 = normp.find(sep, index + 1)
|
||||
# a UNC path can't have two slashes in a row
|
||||
# (after the initial two)
|
||||
if index2 == index + 1:
|
||||
return p[:0], p
|
||||
if index2 == -1:
|
||||
index2 = len(p)
|
||||
return p[:index2], p[index2:]
|
||||
if normp[1:2] == colon:
|
||||
return p[:2], p[2:]
|
||||
return p[:0], p
|
||||
|
||||
|
||||
# Parse UNC paths
|
||||
def splitunc(p):
|
||||
"""Deprecated since Python 3.1. Please use splitdrive() instead;
|
||||
it now handles UNC paths.
|
||||
|
||||
Split a pathname into UNC mount point and relative path specifiers.
|
||||
|
||||
Return a 2-tuple (unc, rest); either part may be empty.
|
||||
If unc is not empty, it has the form '//host/mount' (or similar
|
||||
using backslashes). unc+rest is always the input path.
|
||||
Paths containing drive letters never have a UNC part.
|
||||
"""
|
||||
import warnings
|
||||
warnings.warn("ntpath.splitunc is deprecated, use ntpath.splitdrive instead",
|
||||
DeprecationWarning, 2)
|
||||
drive, path = splitdrive(p)
|
||||
if len(drive) == 2:
|
||||
# Drive letter present
|
||||
return p[:0], p
|
||||
return drive, path
|
||||
|
||||
|
||||
# Split a path in head (everything up to the last '/') and tail (the
|
||||
# rest). After the trailing '/' is stripped, the invariant
|
||||
# join(head, tail) == p holds.
|
||||
# The resulting head won't end in '/' unless it is the root.
|
||||
|
||||
def split(p):
|
||||
"""Split a pathname.
|
||||
|
||||
Return tuple (head, tail) where tail is everything after the final slash.
|
||||
Either part may be empty."""
|
||||
p = os.fspath(p)
|
||||
seps = _get_bothseps(p)
|
||||
d, p = splitdrive(p)
|
||||
# set i to index beyond p's last slash
|
||||
i = len(p)
|
||||
while i and p[i-1] not in seps:
|
||||
i -= 1
|
||||
head, tail = p[:i], p[i:] # now tail has no slashes
|
||||
# remove trailing slashes from head, unless it's all slashes
|
||||
head = head.rstrip(seps) or head
|
||||
return d + head, tail
|
||||
|
||||
|
||||
# Split a path in root and extension.
|
||||
# The extension is everything starting at the last dot in the last
|
||||
# pathname component; the root is everything before that.
|
||||
# It is always true that root + ext == p.
|
||||
|
||||
def splitext(p):
|
||||
p = os.fspath(p)
|
||||
if isinstance(p, bytes):
|
||||
return genericpath._splitext(p, b'\\', b'/', b'.')
|
||||
else:
|
||||
return genericpath._splitext(p, '\\', '/', '.')
|
||||
splitext.__doc__ = genericpath._splitext.__doc__
|
||||
|
||||
|
||||
# Return the tail (basename) part of a path.
|
||||
|
||||
def basename(p):
|
||||
"""Returns the final component of a pathname"""
|
||||
return split(p)[1]
|
||||
|
||||
|
||||
# Return the head (dirname) part of a path.
|
||||
|
||||
def dirname(p):
|
||||
"""Returns the directory component of a pathname"""
|
||||
return split(p)[0]
|
||||
|
||||
# Is a path a symbolic link?
|
||||
# This will always return false on systems where os.lstat doesn't exist.
|
||||
|
||||
def islink(path):
|
||||
"""Test whether a path is a symbolic link.
|
||||
This will always return false for Windows prior to 6.0.
|
||||
"""
|
||||
try:
|
||||
st = os.lstat(path)
|
||||
except (OSError, AttributeError):
|
||||
return False
|
||||
return stat.S_ISLNK(st.st_mode)
|
||||
|
||||
# Being true for dangling symbolic links is also useful.
|
||||
|
||||
def lexists(path):
|
||||
"""Test whether a path exists. Returns True for broken symbolic links"""
|
||||
try:
|
||||
st = os.lstat(path)
|
||||
except OSError:
|
||||
return False
|
||||
return True
|
||||
|
||||
# Is a path a mount point?
|
||||
# Any drive letter root (eg c:\)
|
||||
# Any share UNC (eg \\server\share)
|
||||
# Any volume mounted on a filesystem folder
|
||||
#
|
||||
# No one method detects all three situations. Historically we've lexically
|
||||
# detected drive letter roots and share UNCs. The canonical approach to
|
||||
# detecting mounted volumes (querying the reparse tag) fails for the most
|
||||
# common case: drive letter roots. The alternative which uses GetVolumePathName
|
||||
# fails if the drive letter is the result of a SUBST.
|
||||
try:
|
||||
from nt import _getvolumepathname
|
||||
except ImportError:
|
||||
_getvolumepathname = None
|
||||
def ismount(path):
|
||||
"""Test whether a path is a mount point (a drive root, the root of a
|
||||
share, or a mounted volume)"""
|
||||
path = os.fspath(path)
|
||||
seps = _get_bothseps(path)
|
||||
path = abspath(path)
|
||||
root, rest = splitdrive(path)
|
||||
if root and root[0] in seps:
|
||||
return (not rest) or (rest in seps)
|
||||
if rest in seps:
|
||||
return True
|
||||
|
||||
if _getvolumepathname:
|
||||
return path.rstrip(seps) == _getvolumepathname(path).rstrip(seps)
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
# Expand paths beginning with '~' or '~user'.
|
||||
# '~' means $HOME; '~user' means that user's home directory.
|
||||
# If the path doesn't begin with '~', or if the user or $HOME is unknown,
|
||||
# the path is returned unchanged (leaving error reporting to whatever
|
||||
# function is called with the expanded path as argument).
|
||||
# See also module 'glob' for expansion of *, ? and [...] in pathnames.
|
||||
# (A function should also be defined to do full *sh-style environment
|
||||
# variable expansion.)
|
||||
|
||||
def expanduser(path):
|
||||
"""Expand ~ and ~user constructs.
|
||||
|
||||
If user or $HOME is unknown, do nothing."""
|
||||
path = os.fspath(path)
|
||||
if isinstance(path, bytes):
|
||||
tilde = b'~'
|
||||
else:
|
||||
tilde = '~'
|
||||
if not path.startswith(tilde):
|
||||
return path
|
||||
i, n = 1, len(path)
|
||||
while i < n and path[i] not in _get_bothseps(path):
|
||||
i += 1
|
||||
|
||||
if 'HOME' in os.environ:
|
||||
userhome = os.environ['HOME']
|
||||
elif 'USERPROFILE' in os.environ:
|
||||
userhome = os.environ['USERPROFILE']
|
||||
elif not 'HOMEPATH' in os.environ:
|
||||
return path
|
||||
else:
|
||||
try:
|
||||
drive = os.environ['HOMEDRIVE']
|
||||
except KeyError:
|
||||
drive = ''
|
||||
userhome = join(drive, os.environ['HOMEPATH'])
|
||||
|
||||
if isinstance(path, bytes):
|
||||
userhome = os.fsencode(userhome)
|
||||
|
||||
if i != 1: #~user
|
||||
userhome = join(dirname(userhome), path[1:i])
|
||||
|
||||
return userhome + path[i:]
|
||||
|
||||
|
||||
# Expand paths containing shell variable substitutions.
|
||||
# The following rules apply:
|
||||
# - no expansion within single quotes
|
||||
# - '$$' is translated into '$'
|
||||
# - '%%' is translated into '%' if '%%' are not seen in %var1%%var2%
|
||||
# - ${varname} is accepted.
|
||||
# - $varname is accepted.
|
||||
# - %varname% is accepted.
|
||||
# - varnames can be made out of letters, digits and the characters '_-'
|
||||
# (though is not verified in the ${varname} and %varname% cases)
|
||||
# XXX With COMMAND.COM you can use any characters in a variable name,
|
||||
# XXX except '^|<>='.
|
||||
|
||||
def expandvars(path):
|
||||
"""Expand shell variables of the forms $var, ${var} and %var%.
|
||||
|
||||
Unknown variables are left unchanged."""
|
||||
path = os.fspath(path)
|
||||
if isinstance(path, bytes):
|
||||
if b'$' not in path and b'%' not in path:
|
||||
return path
|
||||
import string
|
||||
varchars = bytes(string.ascii_letters + string.digits + '_-', 'ascii')
|
||||
quote = b'\''
|
||||
percent = b'%'
|
||||
brace = b'{'
|
||||
rbrace = b'}'
|
||||
dollar = b'$'
|
||||
environ = getattr(os, 'environb', None)
|
||||
else:
|
||||
if '$' not in path and '%' not in path:
|
||||
return path
|
||||
import string
|
||||
varchars = string.ascii_letters + string.digits + '_-'
|
||||
quote = '\''
|
||||
percent = '%'
|
||||
brace = '{'
|
||||
rbrace = '}'
|
||||
dollar = '$'
|
||||
environ = os.environ
|
||||
res = path[:0]
|
||||
index = 0
|
||||
pathlen = len(path)
|
||||
while index < pathlen:
|
||||
c = path[index:index+1]
|
||||
if c == quote: # no expansion within single quotes
|
||||
path = path[index + 1:]
|
||||
pathlen = len(path)
|
||||
try:
|
||||
index = path.index(c)
|
||||
res += c + path[:index + 1]
|
||||
except ValueError:
|
||||
res += c + path
|
||||
index = pathlen - 1
|
||||
elif c == percent: # variable or '%'
|
||||
if path[index + 1:index + 2] == percent:
|
||||
res += c
|
||||
index += 1
|
||||
else:
|
||||
path = path[index+1:]
|
||||
pathlen = len(path)
|
||||
try:
|
||||
index = path.index(percent)
|
||||
except ValueError:
|
||||
res += percent + path
|
||||
index = pathlen - 1
|
||||
else:
|
||||
var = path[:index]
|
||||
try:
|
||||
if environ is None:
|
||||
value = os.fsencode(os.environ[os.fsdecode(var)])
|
||||
else:
|
||||
value = environ[var]
|
||||
except KeyError:
|
||||
value = percent + var + percent
|
||||
res += value
|
||||
elif c == dollar: # variable or '$$'
|
||||
if path[index + 1:index + 2] == dollar:
|
||||
res += c
|
||||
index += 1
|
||||
elif path[index + 1:index + 2] == brace:
|
||||
path = path[index+2:]
|
||||
pathlen = len(path)
|
||||
try:
|
||||
index = path.index(rbrace)
|
||||
except ValueError:
|
||||
res += dollar + brace + path
|
||||
index = pathlen - 1
|
||||
else:
|
||||
var = path[:index]
|
||||
try:
|
||||
if environ is None:
|
||||
value = os.fsencode(os.environ[os.fsdecode(var)])
|
||||
else:
|
||||
value = environ[var]
|
||||
except KeyError:
|
||||
value = dollar + brace + var + rbrace
|
||||
res += value
|
||||
else:
|
||||
var = path[:0]
|
||||
index += 1
|
||||
c = path[index:index + 1]
|
||||
while c and c in varchars:
|
||||
var += c
|
||||
index += 1
|
||||
c = path[index:index + 1]
|
||||
try:
|
||||
if environ is None:
|
||||
value = os.fsencode(os.environ[os.fsdecode(var)])
|
||||
else:
|
||||
value = environ[var]
|
||||
except KeyError:
|
||||
value = dollar + var
|
||||
res += value
|
||||
if c:
|
||||
index -= 1
|
||||
else:
|
||||
res += c
|
||||
index += 1
|
||||
return res
|
||||
|
||||
|
||||
# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B.
|
||||
# Previously, this function also truncated pathnames to 8+3 format,
|
||||
# but as this module is called "ntpath", that's obviously wrong!
|
||||
|
||||
def normpath(path):
|
||||
"""Normalize path, eliminating double slashes, etc."""
|
||||
path = os.fspath(path)
|
||||
if isinstance(path, bytes):
|
||||
sep = b'\\'
|
||||
altsep = b'/'
|
||||
curdir = b'.'
|
||||
pardir = b'..'
|
||||
special_prefixes = (b'\\\\.\\', b'\\\\?\\')
|
||||
else:
|
||||
sep = '\\'
|
||||
altsep = '/'
|
||||
curdir = '.'
|
||||
pardir = '..'
|
||||
special_prefixes = ('\\\\.\\', '\\\\?\\')
|
||||
if path.startswith(special_prefixes):
|
||||
# in the case of paths with these prefixes:
|
||||
# \\.\ -> device names
|
||||
# \\?\ -> literal paths
|
||||
# do not do any normalization, but return the path unchanged
|
||||
return path
|
||||
path = path.replace(altsep, sep)
|
||||
prefix, path = splitdrive(path)
|
||||
|
||||
# collapse initial backslashes
|
||||
if path.startswith(sep):
|
||||
prefix += sep
|
||||
path = path.lstrip(sep)
|
||||
|
||||
comps = path.split(sep)
|
||||
i = 0
|
||||
while i < len(comps):
|
||||
if not comps[i] or comps[i] == curdir:
|
||||
del comps[i]
|
||||
elif comps[i] == pardir:
|
||||
if i > 0 and comps[i-1] != pardir:
|
||||
del comps[i-1:i+1]
|
||||
i -= 1
|
||||
elif i == 0 and prefix.endswith(sep):
|
||||
del comps[i]
|
||||
else:
|
||||
i += 1
|
||||
else:
|
||||
i += 1
|
||||
# If the path is now empty, substitute '.'
|
||||
if not prefix and not comps:
|
||||
comps.append(curdir)
|
||||
return prefix + sep.join(comps)
|
||||
|
||||
def _abspath_fallback(path):
|
||||
"""Return the absolute version of a path as a fallback function in case
|
||||
`nt._getfullpathname` is not available or raises OSError. See bpo-31047 for
|
||||
more.
|
||||
|
||||
"""
|
||||
|
||||
path = os.fspath(path)
|
||||
if not isabs(path):
|
||||
if isinstance(path, bytes):
|
||||
cwd = os.getcwdb()
|
||||
else:
|
||||
cwd = os.getcwd()
|
||||
path = join(cwd, path)
|
||||
return normpath(path)
|
||||
|
||||
# Return an absolute path.
|
||||
try:
|
||||
from nt import _getfullpathname
|
||||
|
||||
except ImportError: # not running on Windows - mock up something sensible
|
||||
abspath = _abspath_fallback
|
||||
|
||||
else: # use native Windows method on Windows
|
||||
def abspath(path):
|
||||
"""Return the absolute version of a path."""
|
||||
try:
|
||||
return normpath(_getfullpathname(path))
|
||||
except (OSError, ValueError):
|
||||
return _abspath_fallback(path)
|
||||
|
||||
# realpath is a no-op on systems without islink support
|
||||
realpath = abspath
|
||||
# Win9x family and earlier have no Unicode filename support.
|
||||
supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
|
||||
sys.getwindowsversion()[3] >= 2)
|
||||
|
||||
def relpath(path, start=None):
|
||||
"""Return a relative version of a path"""
|
||||
path = os.fspath(path)
|
||||
if isinstance(path, bytes):
|
||||
sep = b'\\'
|
||||
curdir = b'.'
|
||||
pardir = b'..'
|
||||
else:
|
||||
sep = '\\'
|
||||
curdir = '.'
|
||||
pardir = '..'
|
||||
|
||||
if start is None:
|
||||
start = curdir
|
||||
|
||||
if not path:
|
||||
raise ValueError("no path specified")
|
||||
|
||||
start = os.fspath(start)
|
||||
try:
|
||||
start_abs = abspath(normpath(start))
|
||||
path_abs = abspath(normpath(path))
|
||||
start_drive, start_rest = splitdrive(start_abs)
|
||||
path_drive, path_rest = splitdrive(path_abs)
|
||||
if normcase(start_drive) != normcase(path_drive):
|
||||
raise ValueError("path is on mount %r, start on mount %r" % (
|
||||
path_drive, start_drive))
|
||||
|
||||
start_list = [x for x in start_rest.split(sep) if x]
|
||||
path_list = [x for x in path_rest.split(sep) if x]
|
||||
# Work out how much of the filepath is shared by start and path.
|
||||
i = 0
|
||||
for e1, e2 in zip(start_list, path_list):
|
||||
if normcase(e1) != normcase(e2):
|
||||
break
|
||||
i += 1
|
||||
|
||||
rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
|
||||
if not rel_list:
|
||||
return curdir
|
||||
return join(*rel_list)
|
||||
except (TypeError, ValueError, AttributeError, BytesWarning, DeprecationWarning):
|
||||
genericpath._check_arg_types('relpath', path, start)
|
||||
raise
|
||||
|
||||
|
||||
# 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')
|
||||
|
||||
paths = tuple(map(os.fspath, paths))
|
||||
if isinstance(paths[0], bytes):
|
||||
sep = b'\\'
|
||||
altsep = b'/'
|
||||
curdir = b'.'
|
||||
else:
|
||||
sep = '\\'
|
||||
altsep = '/'
|
||||
curdir = '.'
|
||||
|
||||
try:
|
||||
drivesplits = [splitdrive(p.replace(altsep, sep).lower()) for p in paths]
|
||||
split_paths = [p.split(sep) for d, p in drivesplits]
|
||||
|
||||
try:
|
||||
isabs, = set(p[:1] == sep for d, p in drivesplits)
|
||||
except ValueError:
|
||||
raise ValueError("Can't mix absolute and relative paths") from None
|
||||
|
||||
# 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 else drive
|
||||
return prefix + sep.join(common)
|
||||
except (TypeError, AttributeError):
|
||||
genericpath._check_arg_types('commonpath', *paths)
|
||||
raise
|
||||
|
||||
|
||||
# determine if two files are in fact the same file
|
||||
try:
|
||||
# GetFinalPathNameByHandle is available starting with Windows 6.0.
|
||||
# Windows XP and non-Windows OS'es will mock _getfinalpathname.
|
||||
if sys.getwindowsversion()[:2] >= (6, 0):
|
||||
from nt import _getfinalpathname
|
||||
else:
|
||||
raise ImportError
|
||||
except (AttributeError, ImportError):
|
||||
# On Windows XP and earlier, two files are the same if their absolute
|
||||
# pathnames are the same.
|
||||
# Non-Windows operating systems fake this method with an XP
|
||||
# approximation.
|
||||
def _getfinalpathname(f):
|
||||
return normcase(abspath(f))
|
||||
|
||||
|
||||
try:
|
||||
# The genericpath.isdir implementation uses os.stat and checks the mode
|
||||
# attribute to tell whether or not the path is a directory.
|
||||
# This is overkill on Windows - just pass the path to GetFileAttributes
|
||||
# and check the attribute from there.
|
||||
from nt import _isdir as isdir
|
||||
except ImportError:
|
||||
# Use genericpath.isdir as imported above.
|
||||
pass
|
Loading…
Add table
Add a link
Reference in a new issue