summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Lib/ntpath.py
diff options
context:
space:
mode:
authororivej <[email protected]>2022-02-10 16:44:49 +0300
committerDaniil Cherednik <[email protected]>2022-02-10 16:44:49 +0300
commit718c552901d703c502ccbefdfc3c9028d608b947 (patch)
tree46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/tools/python3/src/Lib/ntpath.py
parente9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff)
Restoring authorship annotation for <[email protected]>. Commit 1 of 2.
Diffstat (limited to 'contrib/tools/python3/src/Lib/ntpath.py')
-rw-r--r--contrib/tools/python3/src/Lib/ntpath.py1268
1 files changed, 634 insertions, 634 deletions
diff --git a/contrib/tools/python3/src/Lib/ntpath.py b/contrib/tools/python3/src/Lib/ntpath.py
index 6f771773a7d..7e58bdffe97 100644
--- a/contrib/tools/python3/src/Lib/ntpath.py
+++ b/contrib/tools/python3/src/Lib/ntpath.py
@@ -1,66 +1,66 @@
-# 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",
- "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)
+# 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",
+ "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)
if isinstance(s, bytes):
return s.replace(b'/', b'\\').lower()
else:
return s.replace('/', '\\').lower()
-
-
-# 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)
+
+
+# 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)
# Paths beginning with \\?\ are always absolute, but do not
# necessarily contain a drive.
if isinstance(s, bytes):
@@ -69,465 +69,465 @@ def isabs(s):
else:
if s.replace('/', '\\').startswith('\\\\?\\'):
return True
- 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
-
-
-# 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)
+ 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
+
+
+# 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, ValueError, 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)
+ 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, ValueError):
- 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
-
+ 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 '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
+ 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 apart from the call to os.fspath()
- 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)
-
+ 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)
+
try:
from nt import _getfinalpathname, readlink as _nt_readlink
except ImportError:
@@ -671,124 +671,124 @@ else:
return path
-# 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
-
-
-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
+# 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
+
+
+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