mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Update {nt,posix}path.py from 3.13.5 (#6070)
* Update `{nt,posix}path.py` from 3.13.5
* Mark failing tests
This commit is contained in:
367
Lib/ntpath.py
vendored
367
Lib/ntpath.py
vendored
@@ -19,18 +19,17 @@ devnull = 'nul'
|
||||
|
||||
import os
|
||||
import sys
|
||||
import stat
|
||||
import genericpath
|
||||
from genericpath import *
|
||||
|
||||
|
||||
__all__ = ["normcase","isabs","join","splitdrive","splitroot","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",
|
||||
"ismount","isreserved","expanduser","expandvars","normpath",
|
||||
"abspath","curdir","pardir","sep","pathsep","defpath","altsep",
|
||||
"extsep","devnull","realpath","supports_unicode_filenames","relpath",
|
||||
"samefile", "sameopenfile", "samestat", "commonpath", "isjunction"]
|
||||
"samefile", "sameopenfile", "samestat", "commonpath", "isjunction",
|
||||
"isdevdrive", "ALLOW_MISSING"]
|
||||
|
||||
def _get_bothseps(path):
|
||||
if isinstance(path, bytes):
|
||||
@@ -78,12 +77,6 @@ except ImportError:
|
||||
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)
|
||||
@@ -91,16 +84,15 @@ def isabs(s):
|
||||
sep = b'\\'
|
||||
altsep = b'/'
|
||||
colon_sep = b':\\'
|
||||
double_sep = b'\\\\'
|
||||
else:
|
||||
sep = '\\'
|
||||
altsep = '/'
|
||||
colon_sep = ':\\'
|
||||
double_sep = '\\\\'
|
||||
s = s[:3].replace(altsep, sep)
|
||||
# Absolute: UNC, device, and paths with a drive and root.
|
||||
# LEGACY BUG: isabs("/x") should be false since the path has no drive.
|
||||
if s.startswith(sep) or s.startswith(colon_sep, 1):
|
||||
return True
|
||||
return False
|
||||
return s.startswith(colon_sep, 1) or s.startswith(double_sep)
|
||||
|
||||
|
||||
# Join two (or more) paths.
|
||||
@@ -109,16 +101,14 @@ def join(path, *paths):
|
||||
if isinstance(path, bytes):
|
||||
sep = b'\\'
|
||||
seps = b'\\/'
|
||||
colon = b':'
|
||||
colon_seps = b':\\/'
|
||||
else:
|
||||
sep = '\\'
|
||||
seps = '\\/'
|
||||
colon = ':'
|
||||
colon_seps = ':\\/'
|
||||
try:
|
||||
if not paths:
|
||||
path[:0] + sep #23780: Ensure compatible data type even if p is null.
|
||||
result_drive, result_root, result_path = splitroot(path)
|
||||
for p in map(os.fspath, paths):
|
||||
for p in paths:
|
||||
p_drive, p_root, p_path = splitroot(p)
|
||||
if p_root:
|
||||
# Second path is absolute
|
||||
@@ -142,7 +132,7 @@ def join(path, *paths):
|
||||
result_path = result_path + p_path
|
||||
## add separator between UNC and non-absolute path
|
||||
if (result_path and not result_root and
|
||||
result_drive and result_drive[-1:] not in colon + seps):
|
||||
result_drive and result_drive[-1] not in colon_seps):
|
||||
return result_drive + sep + result_path
|
||||
return result_drive + result_root + result_path
|
||||
except (TypeError, AttributeError, BytesWarning):
|
||||
@@ -176,56 +166,52 @@ def splitdrive(p):
|
||||
return drive, root + tail
|
||||
|
||||
|
||||
def splitroot(p):
|
||||
"""Split a pathname into drive, root and tail. The drive is defined
|
||||
exactly as in splitdrive(). On Windows, the root may be a single path
|
||||
separator or an empty string. The tail contains anything after the root.
|
||||
For example:
|
||||
try:
|
||||
from nt import _path_splitroot_ex as splitroot
|
||||
except ImportError:
|
||||
def splitroot(p):
|
||||
"""Split a pathname into drive, root and tail.
|
||||
|
||||
splitroot('//server/share/') == ('//server/share', '/', '')
|
||||
splitroot('C:/Users/Barney') == ('C:', '/', 'Users/Barney')
|
||||
splitroot('C:///spam///ham') == ('C:', '/', '//spam///ham')
|
||||
splitroot('Windows/notepad') == ('', '', 'Windows/notepad')
|
||||
"""
|
||||
p = os.fspath(p)
|
||||
if isinstance(p, bytes):
|
||||
sep = b'\\'
|
||||
altsep = b'/'
|
||||
colon = b':'
|
||||
unc_prefix = b'\\\\?\\UNC\\'
|
||||
empty = b''
|
||||
else:
|
||||
sep = '\\'
|
||||
altsep = '/'
|
||||
colon = ':'
|
||||
unc_prefix = '\\\\?\\UNC\\'
|
||||
empty = ''
|
||||
normp = p.replace(altsep, sep)
|
||||
if normp[:1] == sep:
|
||||
if normp[1:2] == sep:
|
||||
# UNC drives, e.g. \\server\share or \\?\UNC\server\share
|
||||
# Device drives, e.g. \\.\device or \\?\device
|
||||
start = 8 if normp[:8].upper() == unc_prefix else 2
|
||||
index = normp.find(sep, start)
|
||||
if index == -1:
|
||||
return p, empty, empty
|
||||
index2 = normp.find(sep, index + 1)
|
||||
if index2 == -1:
|
||||
return p, empty, empty
|
||||
return p[:index2], p[index2:index2 + 1], p[index2 + 1:]
|
||||
The tail contains anything after the root."""
|
||||
p = os.fspath(p)
|
||||
if isinstance(p, bytes):
|
||||
sep = b'\\'
|
||||
altsep = b'/'
|
||||
colon = b':'
|
||||
unc_prefix = b'\\\\?\\UNC\\'
|
||||
empty = b''
|
||||
else:
|
||||
# Relative path with root, e.g. \Windows
|
||||
return empty, p[:1], p[1:]
|
||||
elif normp[1:2] == colon:
|
||||
if normp[2:3] == sep:
|
||||
# Absolute drive-letter path, e.g. X:\Windows
|
||||
return p[:2], p[2:3], p[3:]
|
||||
sep = '\\'
|
||||
altsep = '/'
|
||||
colon = ':'
|
||||
unc_prefix = '\\\\?\\UNC\\'
|
||||
empty = ''
|
||||
normp = p.replace(altsep, sep)
|
||||
if normp[:1] == sep:
|
||||
if normp[1:2] == sep:
|
||||
# UNC drives, e.g. \\server\share or \\?\UNC\server\share
|
||||
# Device drives, e.g. \\.\device or \\?\device
|
||||
start = 8 if normp[:8].upper() == unc_prefix else 2
|
||||
index = normp.find(sep, start)
|
||||
if index == -1:
|
||||
return p, empty, empty
|
||||
index2 = normp.find(sep, index + 1)
|
||||
if index2 == -1:
|
||||
return p, empty, empty
|
||||
return p[:index2], p[index2:index2 + 1], p[index2 + 1:]
|
||||
else:
|
||||
# Relative path with root, e.g. \Windows
|
||||
return empty, p[:1], p[1:]
|
||||
elif normp[1:2] == colon:
|
||||
if normp[2:3] == sep:
|
||||
# Absolute drive-letter path, e.g. X:\Windows
|
||||
return p[:2], p[2:3], p[3:]
|
||||
else:
|
||||
# Relative path with drive, e.g. X:Windows
|
||||
return p[:2], empty, p[2:]
|
||||
else:
|
||||
# Relative path with drive, e.g. X:Windows
|
||||
return p[:2], empty, p[2:]
|
||||
else:
|
||||
# Relative path, e.g. Windows
|
||||
return empty, empty, p
|
||||
# Relative path, e.g. Windows
|
||||
return empty, empty, p
|
||||
|
||||
|
||||
# Split a path in head (everything up to the last '/') and tail (the
|
||||
@@ -277,33 +263,6 @@ def dirname(p):
|
||||
return split(p)[0]
|
||||
|
||||
|
||||
# Is a path a junction?
|
||||
|
||||
if hasattr(os.stat_result, 'st_reparse_tag'):
|
||||
def isjunction(path):
|
||||
"""Test whether a path is a junction"""
|
||||
try:
|
||||
st = os.lstat(path)
|
||||
except (OSError, ValueError, AttributeError):
|
||||
return False
|
||||
return bool(st.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT)
|
||||
else:
|
||||
def isjunction(path):
|
||||
"""Test whether a path is a junction"""
|
||||
os.fspath(path)
|
||||
return False
|
||||
|
||||
|
||||
# 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)
|
||||
@@ -338,6 +297,40 @@ def ismount(path):
|
||||
return False
|
||||
|
||||
|
||||
_reserved_chars = frozenset(
|
||||
{chr(i) for i in range(32)} |
|
||||
{'"', '*', ':', '<', '>', '?', '|', '/', '\\'}
|
||||
)
|
||||
|
||||
_reserved_names = frozenset(
|
||||
{'CON', 'PRN', 'AUX', 'NUL', 'CONIN$', 'CONOUT$'} |
|
||||
{f'COM{c}' for c in '123456789\xb9\xb2\xb3'} |
|
||||
{f'LPT{c}' for c in '123456789\xb9\xb2\xb3'}
|
||||
)
|
||||
|
||||
def isreserved(path):
|
||||
"""Return true if the pathname is reserved by the system."""
|
||||
# Refer to "Naming Files, Paths, and Namespaces":
|
||||
# https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
|
||||
path = os.fsdecode(splitroot(path)[2]).replace(altsep, sep)
|
||||
return any(_isreservedname(name) for name in reversed(path.split(sep)))
|
||||
|
||||
def _isreservedname(name):
|
||||
"""Return true if the filename is reserved by the system."""
|
||||
# Trailing dots and spaces are reserved.
|
||||
if name[-1:] in ('.', ' '):
|
||||
return name not in ('.', '..')
|
||||
# Wildcards, separators, colon, and pipe (*?"<>/\:|) are reserved.
|
||||
# ASCII control characters (0-31) are reserved.
|
||||
# Colon is reserved for file streams (e.g. "name:stream[:type]").
|
||||
if _reserved_chars.intersection(name):
|
||||
return True
|
||||
# DOS device names are reserved (e.g. "nul" or "nul .txt"). The rules
|
||||
# are complex and vary across Windows versions. On the side of
|
||||
# caution, return True for names that may not be reserved.
|
||||
return name.partition('.')[0].rstrip(' ').upper() in _reserved_names
|
||||
|
||||
|
||||
# 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,
|
||||
@@ -353,24 +346,23 @@ def expanduser(path):
|
||||
If user or $HOME is unknown, do nothing."""
|
||||
path = os.fspath(path)
|
||||
if isinstance(path, bytes):
|
||||
seps = b'\\/'
|
||||
tilde = b'~'
|
||||
else:
|
||||
seps = '\\/'
|
||||
tilde = '~'
|
||||
if not path.startswith(tilde):
|
||||
return path
|
||||
i, n = 1, len(path)
|
||||
while i < n and path[i] not in _get_bothseps(path):
|
||||
while i < n and path[i] not in seps:
|
||||
i += 1
|
||||
|
||||
if 'USERPROFILE' in os.environ:
|
||||
userhome = os.environ['USERPROFILE']
|
||||
elif not 'HOMEPATH' in os.environ:
|
||||
elif 'HOMEPATH' not in os.environ:
|
||||
return path
|
||||
else:
|
||||
try:
|
||||
drive = os.environ['HOMEDRIVE']
|
||||
except KeyError:
|
||||
drive = ''
|
||||
drive = os.environ.get('HOMEDRIVE', '')
|
||||
userhome = join(drive, os.environ['HOMEPATH'])
|
||||
|
||||
if i != 1: #~user
|
||||
@@ -521,7 +513,7 @@ def expandvars(path):
|
||||
# Previously, this function also truncated pathnames to 8+3 format,
|
||||
# but as this module is called "ntpath", that's obviously wrong!
|
||||
try:
|
||||
from nt import _path_normpath
|
||||
from nt import _path_normpath as normpath
|
||||
|
||||
except ImportError:
|
||||
def normpath(path):
|
||||
@@ -560,37 +552,22 @@ except ImportError:
|
||||
comps.append(curdir)
|
||||
return prefix + sep.join(comps)
|
||||
|
||||
else:
|
||||
def normpath(path):
|
||||
"""Normalize path, eliminating double slashes, etc."""
|
||||
path = os.fspath(path)
|
||||
if isinstance(path, bytes):
|
||||
return os.fsencode(_path_normpath(os.fsdecode(path))) or b"."
|
||||
return _path_normpath(path) or "."
|
||||
|
||||
|
||||
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
|
||||
def abspath(path):
|
||||
"""Return the absolute version of a path."""
|
||||
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)
|
||||
|
||||
else: # use native Windows method on Windows
|
||||
def abspath(path):
|
||||
@@ -598,15 +575,36 @@ else: # use native Windows method on Windows
|
||||
try:
|
||||
return _getfullpathname(normpath(path))
|
||||
except (OSError, ValueError):
|
||||
return _abspath_fallback(path)
|
||||
# See gh-75230, handle outside for cleaner traceback
|
||||
pass
|
||||
path = os.fspath(path)
|
||||
if not isabs(path):
|
||||
if isinstance(path, bytes):
|
||||
sep = b'\\'
|
||||
getcwd = os.getcwdb
|
||||
else:
|
||||
sep = '\\'
|
||||
getcwd = os.getcwd
|
||||
drive, root, path = splitroot(path)
|
||||
# Either drive or root can be nonempty, but not both.
|
||||
if drive or root:
|
||||
try:
|
||||
path = join(_getfullpathname(drive + root), path)
|
||||
except (OSError, ValueError):
|
||||
# Drive "\0:" cannot exist; use the root directory.
|
||||
path = drive + sep + path
|
||||
else:
|
||||
path = join(getcwd(), path)
|
||||
return normpath(path)
|
||||
|
||||
try:
|
||||
from nt import _getfinalpathname, readlink as _nt_readlink
|
||||
from nt import _findfirstfile, _getfinalpathname, readlink as _nt_readlink
|
||||
except ImportError:
|
||||
# realpath is a no-op on systems without _getfinalpathname support.
|
||||
realpath = abspath
|
||||
def realpath(path, *, strict=False):
|
||||
return abspath(path)
|
||||
else:
|
||||
def _readlink_deep(path):
|
||||
def _readlink_deep(path, ignored_error=OSError):
|
||||
# These error codes indicate that we should stop reading links and
|
||||
# return the path we currently have.
|
||||
# 1: ERROR_INVALID_FUNCTION
|
||||
@@ -639,7 +637,7 @@ else:
|
||||
path = old_path
|
||||
break
|
||||
path = normpath(join(dirname(old_path), path))
|
||||
except OSError as ex:
|
||||
except ignored_error as ex:
|
||||
if ex.winerror in allowed_winerror:
|
||||
break
|
||||
raise
|
||||
@@ -648,7 +646,7 @@ else:
|
||||
break
|
||||
return path
|
||||
|
||||
def _getfinalpathname_nonstrict(path):
|
||||
def _getfinalpathname_nonstrict(path, ignored_error=OSError):
|
||||
# These error codes indicate that we should stop resolving the path
|
||||
# and return the value we currently have.
|
||||
# 1: ERROR_INVALID_FUNCTION
|
||||
@@ -664,9 +662,10 @@ else:
|
||||
# 87: ERROR_INVALID_PARAMETER
|
||||
# 123: ERROR_INVALID_NAME
|
||||
# 161: ERROR_BAD_PATHNAME
|
||||
# 1005: ERROR_UNRECOGNIZED_VOLUME
|
||||
# 1920: ERROR_CANT_ACCESS_FILE
|
||||
# 1921: ERROR_CANT_RESOLVE_FILENAME (implies unfollowable symlink)
|
||||
allowed_winerror = 1, 2, 3, 5, 21, 32, 50, 53, 65, 67, 87, 123, 161, 1920, 1921
|
||||
allowed_winerror = 1, 2, 3, 5, 21, 32, 50, 53, 65, 67, 87, 123, 161, 1005, 1920, 1921
|
||||
|
||||
# Non-strict algorithm is to find as much of the target directory
|
||||
# as we can and join the rest.
|
||||
@@ -675,23 +674,29 @@ else:
|
||||
try:
|
||||
path = _getfinalpathname(path)
|
||||
return join(path, tail) if tail else path
|
||||
except OSError as ex:
|
||||
except ignored_error as ex:
|
||||
if ex.winerror not in allowed_winerror:
|
||||
raise
|
||||
try:
|
||||
# The OS could not resolve this path fully, so we attempt
|
||||
# to follow the link ourselves. If we succeed, join the tail
|
||||
# and return.
|
||||
new_path = _readlink_deep(path)
|
||||
new_path = _readlink_deep(path,
|
||||
ignored_error=ignored_error)
|
||||
if new_path != path:
|
||||
return join(new_path, tail) if tail else new_path
|
||||
except OSError:
|
||||
except ignored_error:
|
||||
# If we fail to readlink(), let's keep traversing
|
||||
pass
|
||||
path, name = split(path)
|
||||
# TODO (bpo-38186): Request the real file name from the directory
|
||||
# entry using FindFirstFileW. For now, we will return the path
|
||||
# as best we have it
|
||||
# If we get these errors, try to get the real name of the file without accessing it.
|
||||
if ex.winerror in (1, 5, 32, 50, 87, 1920, 1921):
|
||||
try:
|
||||
name = _findfirstfile(path)
|
||||
path, _ = split(path)
|
||||
except ignored_error:
|
||||
path, name = split(path)
|
||||
else:
|
||||
path, name = split(path)
|
||||
if path and not name:
|
||||
return path + tail
|
||||
tail = join(name, tail) if tail else name
|
||||
@@ -705,7 +710,8 @@ else:
|
||||
new_unc_prefix = b'\\\\'
|
||||
cwd = os.getcwdb()
|
||||
# bpo-38081: Special case for realpath(b'nul')
|
||||
if normcase(path) == normcase(os.fsencode(devnull)):
|
||||
devnull = b'nul'
|
||||
if normcase(path) == devnull:
|
||||
return b'\\\\.\\NUL'
|
||||
else:
|
||||
prefix = '\\\\?\\'
|
||||
@@ -713,9 +719,19 @@ else:
|
||||
new_unc_prefix = '\\\\'
|
||||
cwd = os.getcwd()
|
||||
# bpo-38081: Special case for realpath('nul')
|
||||
if normcase(path) == normcase(devnull):
|
||||
devnull = 'nul'
|
||||
if normcase(path) == devnull:
|
||||
return '\\\\.\\NUL'
|
||||
had_prefix = path.startswith(prefix)
|
||||
|
||||
if strict is ALLOW_MISSING:
|
||||
ignored_error = FileNotFoundError
|
||||
strict = True
|
||||
elif strict:
|
||||
ignored_error = ()
|
||||
else:
|
||||
ignored_error = OSError
|
||||
|
||||
if not had_prefix and not isabs(path):
|
||||
path = join(cwd, path)
|
||||
try:
|
||||
@@ -723,17 +739,16 @@ else:
|
||||
initial_winerror = 0
|
||||
except ValueError as ex:
|
||||
# gh-106242: Raised for embedded null characters
|
||||
# In strict mode, we convert into an OSError.
|
||||
# In strict modes, we convert into an OSError.
|
||||
# Non-strict mode returns the path as-is, since we've already
|
||||
# made it absolute.
|
||||
if strict:
|
||||
raise OSError(str(ex)) from None
|
||||
path = normpath(path)
|
||||
except OSError as ex:
|
||||
if strict:
|
||||
raise
|
||||
except ignored_error as ex:
|
||||
initial_winerror = ex.winerror
|
||||
path = _getfinalpathname_nonstrict(path)
|
||||
path = _getfinalpathname_nonstrict(path,
|
||||
ignored_error=ignored_error)
|
||||
# The path returned by _getfinalpathname will always start with \\?\ -
|
||||
# strip off that prefix unless it was already provided on the original
|
||||
# path.
|
||||
@@ -766,6 +781,9 @@ supports_unicode_filenames = True
|
||||
def relpath(path, start=None):
|
||||
"""Return a relative version of a path"""
|
||||
path = os.fspath(path)
|
||||
if not path:
|
||||
raise ValueError("no path specified")
|
||||
|
||||
if isinstance(path, bytes):
|
||||
sep = b'\\'
|
||||
curdir = b'.'
|
||||
@@ -777,22 +795,20 @@ def relpath(path, start=None):
|
||||
|
||||
if start is None:
|
||||
start = curdir
|
||||
else:
|
||||
start = os.fspath(start)
|
||||
|
||||
if not path:
|
||||
raise ValueError("no path specified")
|
||||
|
||||
start = os.fspath(start)
|
||||
try:
|
||||
start_abs = abspath(normpath(start))
|
||||
path_abs = abspath(normpath(path))
|
||||
start_abs = abspath(start)
|
||||
path_abs = abspath(path)
|
||||
start_drive, _, start_rest = splitroot(start_abs)
|
||||
path_drive, _, path_rest = splitroot(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]
|
||||
start_list = start_rest.split(sep) if start_rest else []
|
||||
path_list = path_rest.split(sep) if path_rest else []
|
||||
# Work out how much of the filepath is shared by start and path.
|
||||
i = 0
|
||||
for e1, e2 in zip(start_list, path_list):
|
||||
@@ -803,29 +819,28 @@ def relpath(path, start=None):
|
||||
rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
|
||||
if not rel_list:
|
||||
return curdir
|
||||
return join(*rel_list)
|
||||
return sep.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.
|
||||
# Return the longest common sub-path of the iterable 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
|
||||
# first path given in the iterable. 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')
|
||||
|
||||
"""Given an iterable of path names, returns the longest common sub-path."""
|
||||
paths = tuple(map(os.fspath, paths))
|
||||
if not paths:
|
||||
raise ValueError('commonpath() arg is an empty iterable')
|
||||
|
||||
if isinstance(paths[0], bytes):
|
||||
sep = b'\\'
|
||||
altsep = b'/'
|
||||
@@ -839,9 +854,6 @@ def commonpath(paths):
|
||||
drivesplits = [splitroot(p.replace(altsep, sep).lower()) for p in paths]
|
||||
split_paths = [p.split(sep) for d, r, p in drivesplits]
|
||||
|
||||
if len({r for d, r, 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.
|
||||
@@ -849,6 +861,12 @@ def commonpath(paths):
|
||||
raise ValueError("Paths don't have the same drive")
|
||||
|
||||
drive, root, path = splitroot(paths[0].replace(altsep, sep))
|
||||
if len({r for d, r, p in drivesplits}) != 1:
|
||||
if drive:
|
||||
raise ValueError("Can't mix absolute and relative paths")
|
||||
else:
|
||||
raise ValueError("Can't mix rooted and not-rooted paths")
|
||||
|
||||
common = path.split(sep)
|
||||
common = [c for c in common if c and c != curdir]
|
||||
|
||||
@@ -869,13 +887,15 @@ def commonpath(paths):
|
||||
|
||||
|
||||
try:
|
||||
# The isdir(), isfile(), islink() and exists() implementations in
|
||||
# genericpath use os.stat(). This is overkill on Windows. Use simpler
|
||||
# The isdir(), isfile(), islink(), exists() and lexists() implementations
|
||||
# in genericpath use os.stat(). This is overkill on Windows. Use simpler
|
||||
# builtin functions if they are available.
|
||||
from nt import _path_isdir as isdir
|
||||
from nt import _path_isfile as isfile
|
||||
from nt import _path_islink as islink
|
||||
from nt import _path_isjunction as isjunction
|
||||
from nt import _path_exists as exists
|
||||
from nt import _path_lexists as lexists
|
||||
except ImportError:
|
||||
# Use genericpath.* as imported above
|
||||
pass
|
||||
@@ -883,15 +903,12 @@ except ImportError:
|
||||
|
||||
try:
|
||||
from nt import _path_isdevdrive
|
||||
except ImportError:
|
||||
def isdevdrive(path):
|
||||
"""Determines whether the specified path is on a Windows Dev Drive."""
|
||||
# Never a Dev Drive
|
||||
return False
|
||||
else:
|
||||
def isdevdrive(path):
|
||||
"""Determines whether the specified path is on a Windows Dev Drive."""
|
||||
try:
|
||||
return _path_isdevdrive(abspath(path))
|
||||
except OSError:
|
||||
return False
|
||||
except ImportError:
|
||||
# Use genericpath.isdevdrive as imported above
|
||||
pass
|
||||
|
||||
286
Lib/posixpath.py
vendored
286
Lib/posixpath.py
vendored
@@ -22,6 +22,7 @@ defpath = '/bin:/usr/bin'
|
||||
altsep = None
|
||||
devnull = '/dev/null'
|
||||
|
||||
import errno
|
||||
import os
|
||||
import sys
|
||||
import stat
|
||||
@@ -35,7 +36,7 @@ __all__ = ["normcase","isabs","join","splitdrive","splitroot","split","splitext"
|
||||
"samefile","sameopenfile","samestat",
|
||||
"curdir","pardir","sep","pathsep","defpath","altsep","extsep",
|
||||
"devnull","realpath","supports_unicode_filenames","relpath",
|
||||
"commonpath", "isjunction"]
|
||||
"commonpath", "isjunction","isdevdrive","ALLOW_MISSING"]
|
||||
|
||||
|
||||
def _get_sep(path):
|
||||
@@ -77,12 +78,11 @@ def join(a, *p):
|
||||
sep = _get_sep(a)
|
||||
path = a
|
||||
try:
|
||||
if not p:
|
||||
path[:0] + sep #23780: Ensure compatible data type even if p is null.
|
||||
for b in map(os.fspath, p):
|
||||
if b.startswith(sep):
|
||||
for b in p:
|
||||
b = os.fspath(b)
|
||||
if b.startswith(sep) or not path:
|
||||
path = b
|
||||
elif not path or path.endswith(sep):
|
||||
elif path.endswith(sep):
|
||||
path += b
|
||||
else:
|
||||
path += sep + b
|
||||
@@ -135,33 +135,30 @@ def splitdrive(p):
|
||||
return p[:0], p
|
||||
|
||||
|
||||
def splitroot(p):
|
||||
"""Split a pathname into drive, root and tail. On Posix, drive is always
|
||||
empty; the root may be empty, a single slash, or two slashes. The tail
|
||||
contains anything after the root. For example:
|
||||
try:
|
||||
from posix import _path_splitroot_ex as splitroot
|
||||
except ImportError:
|
||||
def splitroot(p):
|
||||
"""Split a pathname into drive, root and tail.
|
||||
|
||||
splitroot('foo/bar') == ('', '', 'foo/bar')
|
||||
splitroot('/foo/bar') == ('', '/', 'foo/bar')
|
||||
splitroot('//foo/bar') == ('', '//', 'foo/bar')
|
||||
splitroot('///foo/bar') == ('', '/', '//foo/bar')
|
||||
"""
|
||||
p = os.fspath(p)
|
||||
if isinstance(p, bytes):
|
||||
sep = b'/'
|
||||
empty = b''
|
||||
else:
|
||||
sep = '/'
|
||||
empty = ''
|
||||
if p[:1] != sep:
|
||||
# Relative path, e.g.: 'foo'
|
||||
return empty, empty, p
|
||||
elif p[1:2] != sep or p[2:3] == sep:
|
||||
# Absolute path, e.g.: '/foo', '///foo', '////foo', etc.
|
||||
return empty, sep, p[1:]
|
||||
else:
|
||||
# Precisely two leading slashes, e.g.: '//foo'. Implementation defined per POSIX, see
|
||||
# https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
|
||||
return empty, p[:2], p[2:]
|
||||
The tail contains anything after the root."""
|
||||
p = os.fspath(p)
|
||||
if isinstance(p, bytes):
|
||||
sep = b'/'
|
||||
empty = b''
|
||||
else:
|
||||
sep = '/'
|
||||
empty = ''
|
||||
if p[:1] != sep:
|
||||
# Relative path, e.g.: 'foo'
|
||||
return empty, empty, p
|
||||
elif p[1:2] != sep or p[2:3] == sep:
|
||||
# Absolute path, e.g.: '/foo', '///foo', '////foo', etc.
|
||||
return empty, sep, p[1:]
|
||||
else:
|
||||
# Precisely two leading slashes, e.g.: '//foo'. Implementation defined per POSIX, see
|
||||
# https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
|
||||
return empty, p[:2], p[2:]
|
||||
|
||||
|
||||
# Return the tail (basename) part of a path, same as split(path)[1].
|
||||
@@ -187,26 +184,6 @@ def dirname(p):
|
||||
return head
|
||||
|
||||
|
||||
# Is a path a junction?
|
||||
|
||||
def isjunction(path):
|
||||
"""Test whether a path is a junction
|
||||
Junctions are not a part of posix semantics"""
|
||||
os.fspath(path)
|
||||
return False
|
||||
|
||||
|
||||
# Being true for dangling symbolic links is also useful.
|
||||
|
||||
def lexists(path):
|
||||
"""Test whether a path exists. Returns True for broken symbolic links"""
|
||||
try:
|
||||
os.lstat(path)
|
||||
except (OSError, ValueError):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
# Is a path a mount point?
|
||||
# (Does this work for all UNIXes? Is it even guaranteed to work by Posix?)
|
||||
|
||||
@@ -227,21 +204,17 @@ def ismount(path):
|
||||
parent = join(path, b'..')
|
||||
else:
|
||||
parent = join(path, '..')
|
||||
parent = realpath(parent)
|
||||
try:
|
||||
s2 = os.lstat(parent)
|
||||
except (OSError, ValueError):
|
||||
return False
|
||||
except OSError:
|
||||
parent = realpath(parent)
|
||||
try:
|
||||
s2 = os.lstat(parent)
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
dev1 = s1.st_dev
|
||||
dev2 = s2.st_dev
|
||||
if dev1 != dev2:
|
||||
return True # path/.. on a different device as path
|
||||
ino1 = s1.st_ino
|
||||
ino2 = s2.st_ino
|
||||
if ino1 == ino2:
|
||||
return True # path/.. is the same i-node as path
|
||||
return False
|
||||
# path/.. on a different device as path or the same i-node as path
|
||||
return s1.st_dev != s2.st_dev or s1.st_ino == s2.st_ino
|
||||
|
||||
|
||||
# Expand paths beginning with '~' or '~user'.
|
||||
@@ -290,7 +263,7 @@ def expanduser(path):
|
||||
return path
|
||||
name = path[1:i]
|
||||
if isinstance(name, bytes):
|
||||
name = str(name, 'ASCII')
|
||||
name = os.fsdecode(name)
|
||||
try:
|
||||
pwent = pwd.getpwnam(name)
|
||||
except KeyError:
|
||||
@@ -303,11 +276,8 @@ def expanduser(path):
|
||||
return path
|
||||
if isinstance(path, bytes):
|
||||
userhome = os.fsencode(userhome)
|
||||
root = b'/'
|
||||
else:
|
||||
root = '/'
|
||||
userhome = userhome.rstrip(root)
|
||||
return (userhome + path[i:]) or root
|
||||
userhome = userhome.rstrip(sep)
|
||||
return (userhome + path[i:]) or sep
|
||||
|
||||
|
||||
# Expand paths containing shell variable substitutions.
|
||||
@@ -371,7 +341,7 @@ def expandvars(path):
|
||||
# if it contains symbolic links!
|
||||
|
||||
try:
|
||||
from posix import _path_normpath
|
||||
from posix import _path_normpath as normpath
|
||||
|
||||
except ImportError:
|
||||
def normpath(path):
|
||||
@@ -379,21 +349,19 @@ except ImportError:
|
||||
path = os.fspath(path)
|
||||
if isinstance(path, bytes):
|
||||
sep = b'/'
|
||||
empty = b''
|
||||
dot = b'.'
|
||||
dotdot = b'..'
|
||||
else:
|
||||
sep = '/'
|
||||
empty = ''
|
||||
dot = '.'
|
||||
dotdot = '..'
|
||||
if path == empty:
|
||||
if not path:
|
||||
return dot
|
||||
_, initial_slashes, path = splitroot(path)
|
||||
comps = path.split(sep)
|
||||
new_comps = []
|
||||
for comp in comps:
|
||||
if comp in (empty, dot):
|
||||
if not comp or comp == dot:
|
||||
continue
|
||||
if (comp != dotdot or (not initial_slashes and not new_comps) or
|
||||
(new_comps and new_comps[-1] == dotdot)):
|
||||
@@ -404,24 +372,16 @@ except ImportError:
|
||||
path = initial_slashes + sep.join(comps)
|
||||
return path or dot
|
||||
|
||||
else:
|
||||
def normpath(path):
|
||||
"""Normalize path, eliminating double slashes, etc."""
|
||||
path = os.fspath(path)
|
||||
if isinstance(path, bytes):
|
||||
return os.fsencode(_path_normpath(os.fsdecode(path))) or b"."
|
||||
return _path_normpath(path) or "."
|
||||
|
||||
|
||||
def abspath(path):
|
||||
"""Return an absolute path."""
|
||||
path = os.fspath(path)
|
||||
if not isabs(path):
|
||||
if isinstance(path, bytes):
|
||||
cwd = os.getcwdb()
|
||||
else:
|
||||
cwd = os.getcwd()
|
||||
path = join(cwd, path)
|
||||
if isinstance(path, bytes):
|
||||
if not path.startswith(b'/'):
|
||||
path = join(os.getcwdb(), path)
|
||||
else:
|
||||
if not path.startswith('/'):
|
||||
path = join(os.getcwd(), path)
|
||||
return normpath(path)
|
||||
|
||||
|
||||
@@ -432,72 +392,109 @@ def realpath(filename, *, strict=False):
|
||||
"""Return the canonical path of the specified filename, eliminating any
|
||||
symbolic links encountered in the path."""
|
||||
filename = os.fspath(filename)
|
||||
path, ok = _joinrealpath(filename[:0], filename, strict, {})
|
||||
return abspath(path)
|
||||
|
||||
# Join two paths, normalizing and eliminating any symbolic links
|
||||
# encountered in the second path.
|
||||
def _joinrealpath(path, rest, strict, seen):
|
||||
if isinstance(path, bytes):
|
||||
if isinstance(filename, bytes):
|
||||
sep = b'/'
|
||||
curdir = b'.'
|
||||
pardir = b'..'
|
||||
getcwd = os.getcwdb
|
||||
else:
|
||||
sep = '/'
|
||||
curdir = '.'
|
||||
pardir = '..'
|
||||
getcwd = os.getcwd
|
||||
if strict is ALLOW_MISSING:
|
||||
ignored_error = FileNotFoundError
|
||||
strict = True
|
||||
elif strict:
|
||||
ignored_error = ()
|
||||
else:
|
||||
ignored_error = OSError
|
||||
|
||||
if isabs(rest):
|
||||
rest = rest[1:]
|
||||
path = sep
|
||||
maxlinks = None
|
||||
|
||||
while rest:
|
||||
name, _, rest = rest.partition(sep)
|
||||
# The stack of unresolved path parts. When popped, a special value of None
|
||||
# indicates that a symlink target has been resolved, and that the original
|
||||
# symlink path can be retrieved by popping again. The [::-1] slice is a
|
||||
# very fast way of spelling list(reversed(...)).
|
||||
rest = filename.split(sep)[::-1]
|
||||
|
||||
# Number of unprocessed parts in 'rest'. This can differ from len(rest)
|
||||
# later, because 'rest' might contain markers for unresolved symlinks.
|
||||
part_count = len(rest)
|
||||
|
||||
# The resolved path, which is absolute throughout this function.
|
||||
# Note: getcwd() returns a normalized and symlink-free path.
|
||||
path = sep if filename.startswith(sep) else getcwd()
|
||||
|
||||
# Mapping from symlink paths to *fully resolved* symlink targets. If a
|
||||
# symlink is encountered but not yet resolved, the value is None. This is
|
||||
# used both to detect symlink loops and to speed up repeated traversals of
|
||||
# the same links.
|
||||
seen = {}
|
||||
|
||||
while part_count:
|
||||
name = rest.pop()
|
||||
if name is None:
|
||||
# resolved symlink target
|
||||
seen[rest.pop()] = path
|
||||
continue
|
||||
part_count -= 1
|
||||
if not name or name == curdir:
|
||||
# current dir
|
||||
continue
|
||||
if name == pardir:
|
||||
# parent dir
|
||||
if path:
|
||||
path, name = split(path)
|
||||
if name == pardir:
|
||||
path = join(path, pardir, pardir)
|
||||
else:
|
||||
path = pardir
|
||||
path = path[:path.rindex(sep)] or sep
|
||||
continue
|
||||
newpath = join(path, name)
|
||||
try:
|
||||
st = os.lstat(newpath)
|
||||
except OSError:
|
||||
if strict:
|
||||
raise
|
||||
is_link = False
|
||||
if path == sep:
|
||||
newpath = path + name
|
||||
else:
|
||||
is_link = stat.S_ISLNK(st.st_mode)
|
||||
if not is_link:
|
||||
path = newpath
|
||||
continue
|
||||
# Resolve the symbolic link
|
||||
if newpath in seen:
|
||||
# Already seen this path
|
||||
path = seen[newpath]
|
||||
if path is not None:
|
||||
# use cached value
|
||||
newpath = path + sep + name
|
||||
try:
|
||||
st_mode = os.lstat(newpath).st_mode
|
||||
if not stat.S_ISLNK(st_mode):
|
||||
if strict and part_count and not stat.S_ISDIR(st_mode):
|
||||
raise OSError(errno.ENOTDIR, os.strerror(errno.ENOTDIR),
|
||||
newpath)
|
||||
path = newpath
|
||||
continue
|
||||
# The symlink is not resolved, so we must have a symlink loop.
|
||||
if strict:
|
||||
# Raise OSError(errno.ELOOP)
|
||||
os.stat(newpath)
|
||||
else:
|
||||
# Return already resolved part + rest of the path unchanged.
|
||||
return join(newpath, rest), False
|
||||
seen[newpath] = None # not resolved symlink
|
||||
path, ok = _joinrealpath(path, os.readlink(newpath), strict, seen)
|
||||
if not ok:
|
||||
return join(path, rest), False
|
||||
seen[newpath] = path # resolved symlink
|
||||
if newpath in seen:
|
||||
# Already seen this path
|
||||
path = seen[newpath]
|
||||
if path is not None:
|
||||
# use cached value
|
||||
continue
|
||||
# The symlink is not resolved, so we must have a symlink loop.
|
||||
if strict:
|
||||
# Raise OSError(errno.ELOOP)
|
||||
os.stat(newpath)
|
||||
path = newpath
|
||||
continue
|
||||
target = os.readlink(newpath)
|
||||
except ignored_error:
|
||||
pass
|
||||
else:
|
||||
# Resolve the symbolic link
|
||||
if target.startswith(sep):
|
||||
# Symlink target is absolute; reset resolved path.
|
||||
path = sep
|
||||
if maxlinks is None:
|
||||
# Mark this symlink as seen but not fully resolved.
|
||||
seen[newpath] = None
|
||||
# Push the symlink path onto the stack, and signal its specialness
|
||||
# by also pushing None. When these entries are popped, we'll
|
||||
# record the fully-resolved symlink target in the 'seen' mapping.
|
||||
rest.append(newpath)
|
||||
rest.append(None)
|
||||
# Push the unresolved symlink target parts onto the stack.
|
||||
target_parts = target.split(sep)[::-1]
|
||||
rest.extend(target_parts)
|
||||
part_count += len(target_parts)
|
||||
continue
|
||||
# An error occurred and was ignored.
|
||||
path = newpath
|
||||
|
||||
return path, True
|
||||
return path
|
||||
|
||||
|
||||
supports_unicode_filenames = (sys.platform == 'darwin')
|
||||
@@ -505,10 +502,10 @@ supports_unicode_filenames = (sys.platform == 'darwin')
|
||||
def relpath(path, start=None):
|
||||
"""Return a relative version of a path"""
|
||||
|
||||
path = os.fspath(path)
|
||||
if not path:
|
||||
raise ValueError("no path specified")
|
||||
|
||||
path = os.fspath(path)
|
||||
if isinstance(path, bytes):
|
||||
curdir = b'.'
|
||||
sep = b'/'
|
||||
@@ -524,15 +521,17 @@ def relpath(path, start=None):
|
||||
start = os.fspath(start)
|
||||
|
||||
try:
|
||||
start_list = [x for x in abspath(start).split(sep) if x]
|
||||
path_list = [x for x in abspath(path).split(sep) if x]
|
||||
start_tail = abspath(start).lstrip(sep)
|
||||
path_tail = abspath(path).lstrip(sep)
|
||||
start_list = start_tail.split(sep) if start_tail else []
|
||||
path_list = path_tail.split(sep) if path_tail else []
|
||||
# Work out how much of the filepath is shared by start and path.
|
||||
i = len(commonprefix([start_list, path_list]))
|
||||
|
||||
rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
|
||||
if not rel_list:
|
||||
return curdir
|
||||
return join(*rel_list)
|
||||
return sep.join(rel_list)
|
||||
except (TypeError, AttributeError, BytesWarning, DeprecationWarning):
|
||||
genericpath._check_arg_types('relpath', path, start)
|
||||
raise
|
||||
@@ -546,10 +545,11 @@ def relpath(path, start=None):
|
||||
def commonpath(paths):
|
||||
"""Given a sequence of path names, returns the longest common sub-path."""
|
||||
|
||||
paths = tuple(map(os.fspath, paths))
|
||||
|
||||
if not paths:
|
||||
raise ValueError('commonpath() arg is an empty sequence')
|
||||
|
||||
paths = tuple(map(os.fspath, paths))
|
||||
if isinstance(paths[0], bytes):
|
||||
sep = b'/'
|
||||
curdir = b'.'
|
||||
@@ -561,7 +561,7 @@ def commonpath(paths):
|
||||
split_paths = [path.split(sep) for path in paths]
|
||||
|
||||
try:
|
||||
isabs, = set(p[:1] == sep for p in paths)
|
||||
isabs, = {p.startswith(sep) for p in paths}
|
||||
except ValueError:
|
||||
raise ValueError("Can't mix absolute and relative paths") from None
|
||||
|
||||
|
||||
641
Lib/test/test_ntpath.py
vendored
641
Lib/test/test_ntpath.py
vendored
@@ -2,9 +2,12 @@ import inspect
|
||||
import ntpath
|
||||
import os
|
||||
import string
|
||||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
import warnings
|
||||
from ntpath import ALLOW_MISSING
|
||||
from test import support
|
||||
from test.support import cpython_only, os_helper
|
||||
from test.support import TestFailed, is_emscripten
|
||||
from test.support.os_helper import FakePath
|
||||
@@ -76,6 +79,10 @@ def tester(fn, wantResult):
|
||||
%(str(fn), str(wantResult), repr(gotResult)))
|
||||
|
||||
|
||||
def _parameterize(*parameters):
|
||||
return support.subTests('kwargs', parameters, _do_cleanups=True)
|
||||
|
||||
|
||||
class NtpathTestCase(unittest.TestCase):
|
||||
def assertPathEqual(self, path1, path2):
|
||||
if path1 == path2 or _norm(path1) == _norm(path2):
|
||||
@@ -123,6 +130,24 @@ class TestNtpath(NtpathTestCase):
|
||||
tester('ntpath.splitdrive("//?/UNC/server/share/dir")',
|
||||
("//?/UNC/server/share", "/dir"))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
|
||||
def test_splitdrive_invalid_paths(self):
|
||||
splitdrive = ntpath.splitdrive
|
||||
self.assertEqual(splitdrive('\\\\ser\x00ver\\sha\x00re\\di\x00r'),
|
||||
('\\\\ser\x00ver\\sha\x00re', '\\di\x00r'))
|
||||
self.assertEqual(splitdrive(b'\\\\ser\x00ver\\sha\x00re\\di\x00r'),
|
||||
(b'\\\\ser\x00ver\\sha\x00re', b'\\di\x00r'))
|
||||
self.assertEqual(splitdrive("\\\\\udfff\\\udffe\\\udffd"),
|
||||
('\\\\\udfff\\\udffe', '\\\udffd'))
|
||||
if sys.platform == 'win32':
|
||||
self.assertRaises(UnicodeDecodeError, splitdrive, b'\\\\\xff\\share\\dir')
|
||||
self.assertRaises(UnicodeDecodeError, splitdrive, b'\\\\server\\\xff\\dir')
|
||||
self.assertRaises(UnicodeDecodeError, splitdrive, b'\\\\server\\share\\\xff')
|
||||
else:
|
||||
self.assertEqual(splitdrive(b'\\\\\xff\\\xfe\\\xfd'),
|
||||
(b'\\\\\xff\\\xfe', b'\\\xfd'))
|
||||
|
||||
def test_splitroot(self):
|
||||
tester("ntpath.splitroot('')", ('', '', ''))
|
||||
tester("ntpath.splitroot('foo')", ('', '', 'foo'))
|
||||
@@ -213,6 +238,24 @@ class TestNtpath(NtpathTestCase):
|
||||
tester('ntpath.splitroot(" :/foo")', (" :", "/", "foo"))
|
||||
tester('ntpath.splitroot("/:/foo")', ("", "/", ":/foo"))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
|
||||
def test_splitroot_invalid_paths(self):
|
||||
splitroot = ntpath.splitroot
|
||||
self.assertEqual(splitroot('\\\\ser\x00ver\\sha\x00re\\di\x00r'),
|
||||
('\\\\ser\x00ver\\sha\x00re', '\\', 'di\x00r'))
|
||||
self.assertEqual(splitroot(b'\\\\ser\x00ver\\sha\x00re\\di\x00r'),
|
||||
(b'\\\\ser\x00ver\\sha\x00re', b'\\', b'di\x00r'))
|
||||
self.assertEqual(splitroot("\\\\\udfff\\\udffe\\\udffd"),
|
||||
('\\\\\udfff\\\udffe', '\\', '\udffd'))
|
||||
if sys.platform == 'win32':
|
||||
self.assertRaises(UnicodeDecodeError, splitroot, b'\\\\\xff\\share\\dir')
|
||||
self.assertRaises(UnicodeDecodeError, splitroot, b'\\\\server\\\xff\\dir')
|
||||
self.assertRaises(UnicodeDecodeError, splitroot, b'\\\\server\\share\\\xff')
|
||||
else:
|
||||
self.assertEqual(splitroot(b'\\\\\xff\\\xfe\\\xfd'),
|
||||
(b'\\\\\xff\\\xfe', b'\\', b'\xfd'))
|
||||
|
||||
def test_split(self):
|
||||
tester('ntpath.split("c:\\foo\\bar")', ('c:\\foo', 'bar'))
|
||||
tester('ntpath.split("\\\\conky\\mountpoint\\foo\\bar")',
|
||||
@@ -225,11 +268,36 @@ class TestNtpath(NtpathTestCase):
|
||||
tester('ntpath.split("c:/")', ('c:/', ''))
|
||||
tester('ntpath.split("//conky/mountpoint/")', ('//conky/mountpoint/', ''))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
|
||||
def test_split_invalid_paths(self):
|
||||
split = ntpath.split
|
||||
self.assertEqual(split('c:\\fo\x00o\\ba\x00r'),
|
||||
('c:\\fo\x00o', 'ba\x00r'))
|
||||
self.assertEqual(split(b'c:\\fo\x00o\\ba\x00r'),
|
||||
(b'c:\\fo\x00o', b'ba\x00r'))
|
||||
self.assertEqual(split('c:\\\udfff\\\udffe'),
|
||||
('c:\\\udfff', '\udffe'))
|
||||
if sys.platform == 'win32':
|
||||
self.assertRaises(UnicodeDecodeError, split, b'c:\\\xff\\bar')
|
||||
self.assertRaises(UnicodeDecodeError, split, b'c:\\foo\\\xff')
|
||||
else:
|
||||
self.assertEqual(split(b'c:\\\xff\\\xfe'),
|
||||
(b'c:\\\xff', b'\xfe'))
|
||||
|
||||
def test_isabs(self):
|
||||
tester('ntpath.isabs("foo\\bar")', 0)
|
||||
tester('ntpath.isabs("foo/bar")', 0)
|
||||
tester('ntpath.isabs("c:\\")', 1)
|
||||
tester('ntpath.isabs("c:\\foo\\bar")', 1)
|
||||
tester('ntpath.isabs("c:/foo/bar")', 1)
|
||||
tester('ntpath.isabs("\\\\conky\\mountpoint\\")', 1)
|
||||
tester('ntpath.isabs("\\foo")', 1)
|
||||
tester('ntpath.isabs("\\foo\\bar")', 1)
|
||||
|
||||
# gh-44626: paths with only a drive or root are not absolute.
|
||||
tester('ntpath.isabs("\\foo\\bar")', 0)
|
||||
tester('ntpath.isabs("/foo/bar")', 0)
|
||||
tester('ntpath.isabs("c:foo\\bar")', 0)
|
||||
tester('ntpath.isabs("c:foo/bar")', 0)
|
||||
|
||||
# gh-96290: normal UNC paths and device paths without trailing backslashes
|
||||
tester('ntpath.isabs("\\\\conky\\mountpoint")', 1)
|
||||
@@ -255,6 +323,7 @@ class TestNtpath(NtpathTestCase):
|
||||
tester('ntpath.join("a", "b", "c")', 'a\\b\\c')
|
||||
tester('ntpath.join("a\\", "b", "c")', 'a\\b\\c')
|
||||
tester('ntpath.join("a", "b\\", "c")', 'a\\b\\c')
|
||||
tester('ntpath.join("a", "b", "c\\")', 'a\\b\\c\\')
|
||||
tester('ntpath.join("a", "b", "\\c")', '\\c')
|
||||
tester('ntpath.join("d:\\", "\\pleep")', 'd:\\pleep')
|
||||
tester('ntpath.join("d:\\", "a", "b")', 'd:\\a\\b')
|
||||
@@ -312,6 +381,44 @@ class TestNtpath(NtpathTestCase):
|
||||
tester("ntpath.join('\\\\computer\\', 'share')", '\\\\computer\\share')
|
||||
tester("ntpath.join('\\\\computer\\share\\', 'a')", '\\\\computer\\share\\a')
|
||||
tester("ntpath.join('\\\\computer\\share\\a\\', 'b')", '\\\\computer\\share\\a\\b')
|
||||
# Second part is anchored, so that the first part is ignored.
|
||||
tester("ntpath.join('a', 'Z:b', 'c')", 'Z:b\\c')
|
||||
tester("ntpath.join('a', 'Z:\\b', 'c')", 'Z:\\b\\c')
|
||||
tester("ntpath.join('a', '\\\\b\\c', 'd')", '\\\\b\\c\\d')
|
||||
# Second part has a root but not drive.
|
||||
tester("ntpath.join('a', '\\b', 'c')", '\\b\\c')
|
||||
tester("ntpath.join('Z:/a', '/b', 'c')", 'Z:\\b\\c')
|
||||
tester("ntpath.join('//?/Z:/a', '/b', 'c')", '\\\\?\\Z:\\b\\c')
|
||||
tester("ntpath.join('D:a', './c:b')", 'D:a\\.\\c:b')
|
||||
tester("ntpath.join('D:/a', './c:b')", 'D:\\a\\.\\c:b')
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
|
||||
def test_normcase(self):
|
||||
normcase = ntpath.normcase
|
||||
self.assertEqual(normcase(''), '')
|
||||
self.assertEqual(normcase(b''), b'')
|
||||
self.assertEqual(normcase('ABC'), 'abc')
|
||||
self.assertEqual(normcase(b'ABC'), b'abc')
|
||||
self.assertEqual(normcase('\xc4\u0141\u03a8'), '\xe4\u0142\u03c8')
|
||||
expected = '\u03c9\u2126' if sys.platform == 'win32' else '\u03c9\u03c9'
|
||||
self.assertEqual(normcase('\u03a9\u2126'), expected)
|
||||
if sys.platform == 'win32' or sys.getfilesystemencoding() == 'utf-8':
|
||||
self.assertEqual(normcase('\xc4\u0141\u03a8'.encode()),
|
||||
'\xe4\u0142\u03c8'.encode())
|
||||
self.assertEqual(normcase('\u03a9\u2126'.encode()),
|
||||
expected.encode())
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
|
||||
def test_normcase_invalid_paths(self):
|
||||
normcase = ntpath.normcase
|
||||
self.assertEqual(normcase('abc\x00def'), 'abc\x00def')
|
||||
self.assertEqual(normcase(b'abc\x00def'), b'abc\x00def')
|
||||
self.assertEqual(normcase('\udfff'), '\udfff')
|
||||
if sys.platform == 'win32':
|
||||
path = b'ABC' + bytes(range(128, 256))
|
||||
self.assertEqual(normcase(path), path.lower())
|
||||
|
||||
def test_normpath(self):
|
||||
tester("ntpath.normpath('A//////././//.//B')", r'A\B')
|
||||
@@ -327,13 +434,18 @@ class TestNtpath(NtpathTestCase):
|
||||
|
||||
tester("ntpath.normpath('..')", r'..')
|
||||
tester("ntpath.normpath('.')", r'.')
|
||||
tester("ntpath.normpath('c:.')", 'c:')
|
||||
tester("ntpath.normpath('')", r'.')
|
||||
tester("ntpath.normpath('/')", '\\')
|
||||
tester("ntpath.normpath('c:/')", 'c:\\')
|
||||
tester("ntpath.normpath('/../.././..')", '\\')
|
||||
tester("ntpath.normpath('c:/../../..')", 'c:\\')
|
||||
tester("ntpath.normpath('/./a/b')", r'\a\b')
|
||||
tester("ntpath.normpath('c:/./a/b')", r'c:\a\b')
|
||||
tester("ntpath.normpath('../.././..')", r'..\..\..')
|
||||
tester("ntpath.normpath('K:../.././..')", r'K:..\..\..')
|
||||
tester("ntpath.normpath('./a/b')", r'a\b')
|
||||
tester("ntpath.normpath('c:./a/b')", r'c:a\b')
|
||||
tester("ntpath.normpath('C:////a/b')", r'C:\a\b')
|
||||
tester("ntpath.normpath('//machine/share//a/b')", r'\\machine\share\a\b')
|
||||
|
||||
@@ -354,6 +466,24 @@ class TestNtpath(NtpathTestCase):
|
||||
tester("ntpath.normpath('\\\\foo\\')", '\\\\foo\\')
|
||||
tester("ntpath.normpath('\\\\foo')", '\\\\foo')
|
||||
tester("ntpath.normpath('\\\\')", '\\\\')
|
||||
tester("ntpath.normpath('//?/UNC/server/share/..')", '\\\\?\\UNC\\server\\share\\')
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
|
||||
def test_normpath_invalid_paths(self):
|
||||
normpath = ntpath.normpath
|
||||
self.assertEqual(normpath('fo\x00o'), 'fo\x00o')
|
||||
self.assertEqual(normpath(b'fo\x00o'), b'fo\x00o')
|
||||
self.assertEqual(normpath('fo\x00o\\..\\bar'), 'bar')
|
||||
self.assertEqual(normpath(b'fo\x00o\\..\\bar'), b'bar')
|
||||
self.assertEqual(normpath('\udfff'), '\udfff')
|
||||
self.assertEqual(normpath('\udfff\\..\\foo'), 'foo')
|
||||
if sys.platform == 'win32':
|
||||
self.assertRaises(UnicodeDecodeError, normpath, b'\xff')
|
||||
self.assertRaises(UnicodeDecodeError, normpath, b'\xff\\..\\foo')
|
||||
else:
|
||||
self.assertEqual(normpath(b'\xff'), b'\xff')
|
||||
self.assertEqual(normpath(b'\xff\\..\\foo'), b'foo')
|
||||
|
||||
def test_realpath_curdir(self):
|
||||
expected = ntpath.normpath(os.getcwd())
|
||||
@@ -363,6 +493,27 @@ class TestNtpath(NtpathTestCase):
|
||||
tester("ntpath.realpath('.\\.')", expected)
|
||||
tester("ntpath.realpath('\\'.join(['.'] * 100))", expected)
|
||||
|
||||
def test_realpath_curdir_strict(self):
|
||||
expected = ntpath.normpath(os.getcwd())
|
||||
tester("ntpath.realpath('.', strict=True)", expected)
|
||||
tester("ntpath.realpath('./.', strict=True)", expected)
|
||||
tester("ntpath.realpath('/'.join(['.'] * 100), strict=True)", expected)
|
||||
tester("ntpath.realpath('.\\.', strict=True)", expected)
|
||||
tester("ntpath.realpath('\\'.join(['.'] * 100), strict=True)", expected)
|
||||
|
||||
def test_realpath_curdir_missing_ok(self):
|
||||
expected = ntpath.normpath(os.getcwd())
|
||||
tester("ntpath.realpath('.', strict=ALLOW_MISSING)",
|
||||
expected)
|
||||
tester("ntpath.realpath('./.', strict=ALLOW_MISSING)",
|
||||
expected)
|
||||
tester("ntpath.realpath('/'.join(['.'] * 100), strict=ALLOW_MISSING)",
|
||||
expected)
|
||||
tester("ntpath.realpath('.\\.', strict=ALLOW_MISSING)",
|
||||
expected)
|
||||
tester("ntpath.realpath('\\'.join(['.'] * 100), strict=ALLOW_MISSING)",
|
||||
expected)
|
||||
|
||||
def test_realpath_pardir(self):
|
||||
expected = ntpath.normpath(os.getcwd())
|
||||
tester("ntpath.realpath('..')", ntpath.dirname(expected))
|
||||
@@ -375,28 +526,59 @@ class TestNtpath(NtpathTestCase):
|
||||
tester("ntpath.realpath('\\'.join(['..'] * 50))",
|
||||
ntpath.splitdrive(expected)[0] + '\\')
|
||||
|
||||
def test_realpath_pardir_strict(self):
|
||||
expected = ntpath.normpath(os.getcwd())
|
||||
tester("ntpath.realpath('..', strict=True)", ntpath.dirname(expected))
|
||||
tester("ntpath.realpath('../..', strict=True)",
|
||||
ntpath.dirname(ntpath.dirname(expected)))
|
||||
tester("ntpath.realpath('/'.join(['..'] * 50), strict=True)",
|
||||
ntpath.splitdrive(expected)[0] + '\\')
|
||||
tester("ntpath.realpath('..\\..', strict=True)",
|
||||
ntpath.dirname(ntpath.dirname(expected)))
|
||||
tester("ntpath.realpath('\\'.join(['..'] * 50), strict=True)",
|
||||
ntpath.splitdrive(expected)[0] + '\\')
|
||||
|
||||
def test_realpath_pardir_missing_ok(self):
|
||||
expected = ntpath.normpath(os.getcwd())
|
||||
tester("ntpath.realpath('..', strict=ALLOW_MISSING)",
|
||||
ntpath.dirname(expected))
|
||||
tester("ntpath.realpath('../..', strict=ALLOW_MISSING)",
|
||||
ntpath.dirname(ntpath.dirname(expected)))
|
||||
tester("ntpath.realpath('/'.join(['..'] * 50), strict=ALLOW_MISSING)",
|
||||
ntpath.splitdrive(expected)[0] + '\\')
|
||||
tester("ntpath.realpath('..\\..', strict=ALLOW_MISSING)",
|
||||
ntpath.dirname(ntpath.dirname(expected)))
|
||||
tester("ntpath.realpath('\\'.join(['..'] * 50), strict=ALLOW_MISSING)",
|
||||
ntpath.splitdrive(expected)[0] + '\\')
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
|
||||
def test_realpath_basic(self):
|
||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
||||
def test_realpath_basic(self, kwargs):
|
||||
ABSTFN = ntpath.abspath(os_helper.TESTFN)
|
||||
open(ABSTFN, "wb").close()
|
||||
self.addCleanup(os_helper.unlink, ABSTFN)
|
||||
self.addCleanup(os_helper.unlink, ABSTFN + "1")
|
||||
|
||||
os.symlink(ABSTFN, ABSTFN + "1")
|
||||
self.assertPathEqual(ntpath.realpath(ABSTFN + "1"), ABSTFN)
|
||||
self.assertPathEqual(ntpath.realpath(os.fsencode(ABSTFN + "1")),
|
||||
self.assertPathEqual(ntpath.realpath(ABSTFN + "1", **kwargs), ABSTFN)
|
||||
self.assertPathEqual(ntpath.realpath(os.fsencode(ABSTFN + "1"), **kwargs),
|
||||
os.fsencode(ABSTFN))
|
||||
|
||||
# gh-88013: call ntpath.realpath with binary drive name may raise a
|
||||
# TypeError. The drive should not exist to reproduce the bug.
|
||||
drives = {f"{c}:\\" for c in string.ascii_uppercase} - set(os.listdrives())
|
||||
d = drives.pop().encode()
|
||||
self.assertEqual(ntpath.realpath(d), d)
|
||||
self.assertEqual(ntpath.realpath(d, strict=False), d)
|
||||
|
||||
# gh-106242: Embedded nulls and non-strict fallback to abspath
|
||||
self.assertEqual(ABSTFN + "\0spam",
|
||||
ntpath.realpath(os_helper.TESTFN + "\0spam", strict=False))
|
||||
if kwargs:
|
||||
with self.assertRaises(OSError):
|
||||
ntpath.realpath(os_helper.TESTFN + "\0spam",
|
||||
**kwargs)
|
||||
else:
|
||||
self.assertEqual(ABSTFN + "\0spam",
|
||||
ntpath.realpath(os_helper.TESTFN + "\0spam", **kwargs))
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
|
||||
@@ -408,19 +590,77 @@ class TestNtpath(NtpathTestCase):
|
||||
self.addCleanup(os_helper.unlink, ABSTFN)
|
||||
self.assertRaises(FileNotFoundError, ntpath.realpath, ABSTFN, strict=True)
|
||||
self.assertRaises(FileNotFoundError, ntpath.realpath, ABSTFN + "2", strict=True)
|
||||
|
||||
@unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
|
||||
def test_realpath_invalid_paths(self):
|
||||
realpath = ntpath.realpath
|
||||
ABSTFN = ntpath.abspath(os_helper.TESTFN)
|
||||
ABSTFNb = os.fsencode(ABSTFN)
|
||||
path = ABSTFN + '\x00'
|
||||
# gh-106242: Embedded nulls and non-strict fallback to abspath
|
||||
self.assertEqual(realpath(path, strict=False), path)
|
||||
# gh-106242: Embedded nulls should raise OSError (not ValueError)
|
||||
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "\0spam", strict=True)
|
||||
self.assertRaises(OSError, realpath, path, strict=True)
|
||||
self.assertRaises(OSError, realpath, path, strict=ALLOW_MISSING)
|
||||
path = ABSTFNb + b'\x00'
|
||||
self.assertEqual(realpath(path, strict=False), path)
|
||||
self.assertRaises(OSError, realpath, path, strict=True)
|
||||
self.assertRaises(OSError, realpath, path, strict=ALLOW_MISSING)
|
||||
path = ABSTFN + '\\nonexistent\\x\x00'
|
||||
self.assertEqual(realpath(path, strict=False), path)
|
||||
self.assertRaises(OSError, realpath, path, strict=True)
|
||||
self.assertRaises(OSError, realpath, path, strict=ALLOW_MISSING)
|
||||
path = ABSTFNb + b'\\nonexistent\\x\x00'
|
||||
self.assertEqual(realpath(path, strict=False), path)
|
||||
self.assertRaises(OSError, realpath, path, strict=True)
|
||||
self.assertRaises(OSError, realpath, path, strict=ALLOW_MISSING)
|
||||
path = ABSTFN + '\x00\\..'
|
||||
self.assertEqual(realpath(path, strict=False), os.getcwd())
|
||||
self.assertEqual(realpath(path, strict=True), os.getcwd())
|
||||
self.assertEqual(realpath(path, strict=ALLOW_MISSING), os.getcwd())
|
||||
path = ABSTFNb + b'\x00\\..'
|
||||
self.assertEqual(realpath(path, strict=False), os.getcwdb())
|
||||
self.assertEqual(realpath(path, strict=True), os.getcwdb())
|
||||
self.assertEqual(realpath(path, strict=ALLOW_MISSING), os.getcwdb())
|
||||
path = ABSTFN + '\\nonexistent\\x\x00\\..'
|
||||
self.assertEqual(realpath(path, strict=False), ABSTFN + '\\nonexistent')
|
||||
self.assertRaises(OSError, realpath, path, strict=True)
|
||||
self.assertEqual(realpath(path, strict=ALLOW_MISSING), ABSTFN + '\\nonexistent')
|
||||
path = ABSTFNb + b'\\nonexistent\\x\x00\\..'
|
||||
self.assertEqual(realpath(path, strict=False), ABSTFNb + b'\\nonexistent')
|
||||
self.assertRaises(OSError, realpath, path, strict=True)
|
||||
self.assertEqual(realpath(path, strict=ALLOW_MISSING), ABSTFNb + b'\\nonexistent')
|
||||
|
||||
@unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
|
||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
||||
def test_realpath_invalid_unicode_paths(self, kwargs):
|
||||
realpath = ntpath.realpath
|
||||
ABSTFN = ntpath.abspath(os_helper.TESTFN)
|
||||
ABSTFNb = os.fsencode(ABSTFN)
|
||||
path = ABSTFNb + b'\xff'
|
||||
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
||||
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
||||
path = ABSTFNb + b'\\nonexistent\\\xff'
|
||||
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
||||
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
||||
path = ABSTFNb + b'\xff\\..'
|
||||
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
||||
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
||||
path = ABSTFNb + b'\\nonexistent\\\xff\\..'
|
||||
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
||||
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
|
||||
def test_realpath_relative(self):
|
||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
||||
def test_realpath_relative(self, kwargs):
|
||||
ABSTFN = ntpath.abspath(os_helper.TESTFN)
|
||||
open(ABSTFN, "wb").close()
|
||||
self.addCleanup(os_helper.unlink, ABSTFN)
|
||||
self.addCleanup(os_helper.unlink, ABSTFN + "1")
|
||||
|
||||
os.symlink(ABSTFN, ntpath.relpath(ABSTFN + "1"))
|
||||
self.assertPathEqual(ntpath.realpath(ABSTFN + "1"), ABSTFN)
|
||||
self.assertPathEqual(ntpath.realpath(ABSTFN + "1", **kwargs), ABSTFN)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@@ -574,7 +814,62 @@ class TestNtpath(NtpathTestCase):
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
|
||||
def test_realpath_symlink_prefix(self):
|
||||
def test_realpath_symlink_loops_raise(self):
|
||||
# Symlink loops raise OSError in ALLOW_MISSING mode
|
||||
ABSTFN = ntpath.abspath(os_helper.TESTFN)
|
||||
self.addCleanup(os_helper.unlink, ABSTFN)
|
||||
self.addCleanup(os_helper.unlink, ABSTFN + "1")
|
||||
self.addCleanup(os_helper.unlink, ABSTFN + "2")
|
||||
self.addCleanup(os_helper.unlink, ABSTFN + "y")
|
||||
self.addCleanup(os_helper.unlink, ABSTFN + "c")
|
||||
self.addCleanup(os_helper.unlink, ABSTFN + "a")
|
||||
self.addCleanup(os_helper.unlink, ABSTFN + "x")
|
||||
|
||||
os.symlink(ABSTFN, ABSTFN)
|
||||
self.assertRaises(OSError, ntpath.realpath, ABSTFN, strict=ALLOW_MISSING)
|
||||
|
||||
os.symlink(ABSTFN + "1", ABSTFN + "2")
|
||||
os.symlink(ABSTFN + "2", ABSTFN + "1")
|
||||
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1",
|
||||
strict=ALLOW_MISSING)
|
||||
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "2",
|
||||
strict=ALLOW_MISSING)
|
||||
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1\\x",
|
||||
strict=ALLOW_MISSING)
|
||||
|
||||
# Windows eliminates '..' components before resolving links;
|
||||
# realpath is not expected to raise if this removes the loop.
|
||||
self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\.."),
|
||||
ntpath.dirname(ABSTFN))
|
||||
self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\..\\x"),
|
||||
ntpath.dirname(ABSTFN) + "\\x")
|
||||
|
||||
os.symlink(ABSTFN + "x", ABSTFN + "y")
|
||||
self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\..\\"
|
||||
+ ntpath.basename(ABSTFN) + "y"),
|
||||
ABSTFN + "x")
|
||||
self.assertRaises(
|
||||
OSError, ntpath.realpath,
|
||||
ABSTFN + "1\\..\\" + ntpath.basename(ABSTFN) + "1",
|
||||
strict=ALLOW_MISSING)
|
||||
|
||||
os.symlink(ntpath.basename(ABSTFN) + "a\\b", ABSTFN + "a")
|
||||
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "a",
|
||||
strict=ALLOW_MISSING)
|
||||
|
||||
os.symlink("..\\" + ntpath.basename(ntpath.dirname(ABSTFN))
|
||||
+ "\\" + ntpath.basename(ABSTFN) + "c", ABSTFN + "c")
|
||||
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "c",
|
||||
strict=ALLOW_MISSING)
|
||||
|
||||
# Test using relative path as well.
|
||||
self.assertRaises(OSError, ntpath.realpath, ntpath.basename(ABSTFN),
|
||||
strict=ALLOW_MISSING)
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
|
||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
||||
def test_realpath_symlink_prefix(self, kwargs):
|
||||
ABSTFN = ntpath.abspath(os_helper.TESTFN)
|
||||
self.addCleanup(os_helper.unlink, ABSTFN + "3")
|
||||
self.addCleanup(os_helper.unlink, "\\\\?\\" + ABSTFN + "3.")
|
||||
@@ -589,9 +884,9 @@ class TestNtpath(NtpathTestCase):
|
||||
f.write(b'1')
|
||||
os.symlink("\\\\?\\" + ABSTFN + "3.", ABSTFN + "3.link")
|
||||
|
||||
self.assertPathEqual(ntpath.realpath(ABSTFN + "3link"),
|
||||
self.assertPathEqual(ntpath.realpath(ABSTFN + "3link", **kwargs),
|
||||
ABSTFN + "3")
|
||||
self.assertPathEqual(ntpath.realpath(ABSTFN + "3.link"),
|
||||
self.assertPathEqual(ntpath.realpath(ABSTFN + "3.link", **kwargs),
|
||||
"\\\\?\\" + ABSTFN + "3.")
|
||||
|
||||
# Resolved paths should be usable to open target files
|
||||
@@ -601,14 +896,17 @@ class TestNtpath(NtpathTestCase):
|
||||
self.assertEqual(f.read(), b'1')
|
||||
|
||||
# When the prefix is included, it is not stripped
|
||||
self.assertPathEqual(ntpath.realpath("\\\\?\\" + ABSTFN + "3link"),
|
||||
self.assertPathEqual(ntpath.realpath("\\\\?\\" + ABSTFN + "3link", **kwargs),
|
||||
"\\\\?\\" + ABSTFN + "3")
|
||||
self.assertPathEqual(ntpath.realpath("\\\\?\\" + ABSTFN + "3.link"),
|
||||
self.assertPathEqual(ntpath.realpath("\\\\?\\" + ABSTFN + "3.link", **kwargs),
|
||||
"\\\\?\\" + ABSTFN + "3.")
|
||||
|
||||
@unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
|
||||
def test_realpath_nul(self):
|
||||
tester("ntpath.realpath('NUL')", r'\\.\NUL')
|
||||
tester("ntpath.realpath('NUL', strict=False)", r'\\.\NUL')
|
||||
tester("ntpath.realpath('NUL', strict=True)", r'\\.\NUL')
|
||||
tester("ntpath.realpath('NUL', strict=ALLOW_MISSING)", r'\\.\NUL')
|
||||
|
||||
@unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
|
||||
@unittest.skipUnless(HAVE_GETSHORTPATHNAME, 'need _getshortpathname')
|
||||
@@ -632,13 +930,67 @@ class TestNtpath(NtpathTestCase):
|
||||
|
||||
self.assertPathEqual(test_file_long, ntpath.realpath(test_file_short))
|
||||
|
||||
with os_helper.change_cwd(test_dir_long):
|
||||
self.assertPathEqual(test_file_long, ntpath.realpath("file.txt"))
|
||||
with os_helper.change_cwd(test_dir_long.lower()):
|
||||
self.assertPathEqual(test_file_long, ntpath.realpath("file.txt"))
|
||||
with os_helper.change_cwd(test_dir_short):
|
||||
self.assertPathEqual(test_file_long, ntpath.realpath("file.txt"))
|
||||
for kwargs in {}, {'strict': True}, {'strict': ALLOW_MISSING}:
|
||||
with self.subTest(**kwargs):
|
||||
with os_helper.change_cwd(test_dir_long):
|
||||
self.assertPathEqual(
|
||||
test_file_long,
|
||||
ntpath.realpath("file.txt", **kwargs))
|
||||
with os_helper.change_cwd(test_dir_long.lower()):
|
||||
self.assertPathEqual(
|
||||
test_file_long,
|
||||
ntpath.realpath("file.txt", **kwargs))
|
||||
with os_helper.change_cwd(test_dir_short):
|
||||
self.assertPathEqual(
|
||||
test_file_long,
|
||||
ntpath.realpath("file.txt", **kwargs))
|
||||
|
||||
@unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
|
||||
def test_realpath_permission(self):
|
||||
# Test whether python can resolve the real filename of a
|
||||
# shortened file name even if it does not have permission to access it.
|
||||
ABSTFN = ntpath.realpath(os_helper.TESTFN)
|
||||
|
||||
os_helper.unlink(ABSTFN)
|
||||
os_helper.rmtree(ABSTFN)
|
||||
os.mkdir(ABSTFN)
|
||||
self.addCleanup(os_helper.rmtree, ABSTFN)
|
||||
|
||||
test_file = ntpath.join(ABSTFN, "LongFileName123.txt")
|
||||
test_file_short = ntpath.join(ABSTFN, "LONGFI~1.TXT")
|
||||
|
||||
with open(test_file, "wb") as f:
|
||||
f.write(b"content")
|
||||
# Automatic generation of short names may be disabled on
|
||||
# NTFS volumes for the sake of performance.
|
||||
# They're not supported at all on ReFS and exFAT.
|
||||
p = subprocess.run(
|
||||
# Try to set the short name manually.
|
||||
['fsutil.exe', 'file', 'setShortName', test_file, 'LONGFI~1.TXT'],
|
||||
creationflags=subprocess.DETACHED_PROCESS
|
||||
)
|
||||
|
||||
if p.returncode:
|
||||
raise unittest.SkipTest('failed to set short name')
|
||||
|
||||
try:
|
||||
self.assertPathEqual(test_file, ntpath.realpath(test_file_short))
|
||||
except AssertionError:
|
||||
raise unittest.SkipTest('the filesystem seems to lack support for short filenames')
|
||||
|
||||
# Deny the right to [S]YNCHRONIZE on the file to
|
||||
# force nt._getfinalpathname to fail with ERROR_ACCESS_DENIED.
|
||||
p = subprocess.run(
|
||||
['icacls.exe', test_file, '/deny', '*S-1-5-32-545:(S)'],
|
||||
creationflags=subprocess.DETACHED_PROCESS
|
||||
)
|
||||
|
||||
if p.returncode:
|
||||
raise unittest.SkipTest('failed to deny access to the test file')
|
||||
|
||||
self.assertPathEqual(test_file, ntpath.realpath(test_file_short))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; ValueError: illegal environment variable name")
|
||||
def test_expandvars(self):
|
||||
with os_helper.EnvironmentVarGuard() as env:
|
||||
@@ -666,6 +1018,7 @@ class TestNtpath(NtpathTestCase):
|
||||
tester('ntpath.expandvars("\'%foo%\'%bar")', "\'%foo%\'%bar")
|
||||
tester('ntpath.expandvars("bar\'%foo%")', "bar\'%foo%")
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; ValueError: illegal environment variable name")
|
||||
@unittest.skipUnless(os_helper.FS_NONASCII, 'need os_helper.FS_NONASCII')
|
||||
def test_expandvars_nonascii(self):
|
||||
@@ -687,6 +1040,7 @@ class TestNtpath(NtpathTestCase):
|
||||
check('%spam%bar', '%sbar' % nonascii)
|
||||
check('%{}%bar'.format(nonascii), 'ham%sbar' % nonascii)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
|
||||
def test_expanduser(self):
|
||||
tester('ntpath.expanduser("test")', 'test')
|
||||
@@ -748,6 +1102,7 @@ class TestNtpath(NtpathTestCase):
|
||||
tester('ntpath.abspath("C:\\spam. . .")', "C:\\spam")
|
||||
tester('ntpath.abspath("C:/nul")', "\\\\.\\nul")
|
||||
tester('ntpath.abspath("C:\\nul")', "\\\\.\\nul")
|
||||
self.assertTrue(ntpath.isabs(ntpath.abspath("C:spam")))
|
||||
tester('ntpath.abspath("//..")', "\\\\")
|
||||
tester('ntpath.abspath("//../")', "\\\\..\\")
|
||||
tester('ntpath.abspath("//../..")', "\\\\..\\")
|
||||
@@ -781,6 +1136,28 @@ class TestNtpath(NtpathTestCase):
|
||||
drive, _ = ntpath.splitdrive(cwd_dir)
|
||||
tester('ntpath.abspath("/abc/")', drive + "\\abc")
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
|
||||
def test_abspath_invalid_paths(self):
|
||||
abspath = ntpath.abspath
|
||||
if sys.platform == 'win32':
|
||||
self.assertEqual(abspath("C:\x00"), ntpath.join(abspath("C:"), "\x00"))
|
||||
self.assertEqual(abspath(b"C:\x00"), ntpath.join(abspath(b"C:"), b"\x00"))
|
||||
self.assertEqual(abspath("\x00:spam"), "\x00:\\spam")
|
||||
self.assertEqual(abspath(b"\x00:spam"), b"\x00:\\spam")
|
||||
self.assertEqual(abspath('c:\\fo\x00o'), 'c:\\fo\x00o')
|
||||
self.assertEqual(abspath(b'c:\\fo\x00o'), b'c:\\fo\x00o')
|
||||
self.assertEqual(abspath('c:\\fo\x00o\\..\\bar'), 'c:\\bar')
|
||||
self.assertEqual(abspath(b'c:\\fo\x00o\\..\\bar'), b'c:\\bar')
|
||||
self.assertEqual(abspath('c:\\\udfff'), 'c:\\\udfff')
|
||||
self.assertEqual(abspath('c:\\\udfff\\..\\foo'), 'c:\\foo')
|
||||
if sys.platform == 'win32':
|
||||
self.assertRaises(UnicodeDecodeError, abspath, b'c:\\\xff')
|
||||
self.assertRaises(UnicodeDecodeError, abspath, b'c:\\\xff\\..\\foo')
|
||||
else:
|
||||
self.assertEqual(abspath(b'c:\\\xff'), b'c:\\\xff')
|
||||
self.assertEqual(abspath(b'c:\\\xff\\..\\foo'), b'c:\\foo')
|
||||
|
||||
def test_relpath(self):
|
||||
tester('ntpath.relpath("a")', 'a')
|
||||
tester('ntpath.relpath(ntpath.abspath("a"))', 'a')
|
||||
@@ -809,43 +1186,47 @@ class TestNtpath(NtpathTestCase):
|
||||
def check(paths, expected):
|
||||
tester(('ntpath.commonpath(%r)' % paths).replace('\\\\', '\\'),
|
||||
expected)
|
||||
def check_error(exc, paths):
|
||||
self.assertRaises(exc, ntpath.commonpath, paths)
|
||||
self.assertRaises(exc, ntpath.commonpath,
|
||||
[os.fsencode(p) for p in paths])
|
||||
def check_error(paths, expected):
|
||||
self.assertRaisesRegex(ValueError, expected, ntpath.commonpath, paths)
|
||||
self.assertRaisesRegex(ValueError, expected, ntpath.commonpath, paths[::-1])
|
||||
self.assertRaisesRegex(ValueError, expected, ntpath.commonpath,
|
||||
[os.fsencode(p) for p in paths])
|
||||
self.assertRaisesRegex(ValueError, expected, ntpath.commonpath,
|
||||
[os.fsencode(p) for p in paths[::-1]])
|
||||
|
||||
self.assertRaises(TypeError, ntpath.commonpath, None)
|
||||
self.assertRaises(ValueError, ntpath.commonpath, [])
|
||||
check_error(ValueError, ['C:\\Program Files', 'Program Files'])
|
||||
check_error(ValueError, ['C:\\Program Files', 'C:Program Files'])
|
||||
check_error(ValueError, ['\\Program Files', 'Program Files'])
|
||||
check_error(ValueError, ['Program Files', 'C:\\Program Files'])
|
||||
check(['C:\\Program Files'], 'C:\\Program Files')
|
||||
check(['C:\\Program Files', 'C:\\Program Files'], 'C:\\Program Files')
|
||||
check(['C:\\Program Files\\', 'C:\\Program Files'],
|
||||
'C:\\Program Files')
|
||||
check(['C:\\Program Files\\', 'C:\\Program Files\\'],
|
||||
'C:\\Program Files')
|
||||
check(['C:\\\\Program Files', 'C:\\Program Files\\\\'],
|
||||
'C:\\Program Files')
|
||||
check(['C:\\.\\Program Files', 'C:\\Program Files\\.'],
|
||||
'C:\\Program Files')
|
||||
check(['C:\\', 'C:\\bin'], 'C:\\')
|
||||
check(['C:\\Program Files', 'C:\\bin'], 'C:\\')
|
||||
check(['C:\\Program Files', 'C:\\Program Files\\Bar'],
|
||||
'C:\\Program Files')
|
||||
check(['C:\\Program Files\\Foo', 'C:\\Program Files\\Bar'],
|
||||
'C:\\Program Files')
|
||||
check(['C:\\Program Files', 'C:\\Projects'], 'C:\\')
|
||||
check(['C:\\Program Files\\', 'C:\\Projects'], 'C:\\')
|
||||
self.assertRaises(ValueError, ntpath.commonpath, iter([]))
|
||||
|
||||
check(['C:\\Program Files\\Foo', 'C:/Program Files/Bar'],
|
||||
'C:\\Program Files')
|
||||
check(['C:\\Program Files\\Foo', 'c:/program files/bar'],
|
||||
'C:\\Program Files')
|
||||
check(['c:/program files/bar', 'C:\\Program Files\\Foo'],
|
||||
'c:\\program files')
|
||||
# gh-117381: Logical error messages
|
||||
check_error(['C:\\Foo', 'C:Foo'], "Can't mix absolute and relative paths")
|
||||
check_error(['C:\\Foo', '\\Foo'], "Paths don't have the same drive")
|
||||
check_error(['C:\\Foo', 'Foo'], "Paths don't have the same drive")
|
||||
check_error(['C:Foo', '\\Foo'], "Paths don't have the same drive")
|
||||
check_error(['C:Foo', 'Foo'], "Paths don't have the same drive")
|
||||
check_error(['\\Foo', 'Foo'], "Can't mix rooted and not-rooted paths")
|
||||
|
||||
check_error(ValueError, ['C:\\Program Files', 'D:\\Program Files'])
|
||||
check(['C:\\Foo'], 'C:\\Foo')
|
||||
check(['C:\\Foo', 'C:\\Foo'], 'C:\\Foo')
|
||||
check(['C:\\Foo\\', 'C:\\Foo'], 'C:\\Foo')
|
||||
check(['C:\\Foo\\', 'C:\\Foo\\'], 'C:\\Foo')
|
||||
check(['C:\\\\Foo', 'C:\\Foo\\\\'], 'C:\\Foo')
|
||||
check(['C:\\.\\Foo', 'C:\\Foo\\.'], 'C:\\Foo')
|
||||
check(['C:\\', 'C:\\baz'], 'C:\\')
|
||||
check(['C:\\Bar', 'C:\\baz'], 'C:\\')
|
||||
check(['C:\\Foo', 'C:\\Foo\\Baz'], 'C:\\Foo')
|
||||
check(['C:\\Foo\\Bar', 'C:\\Foo\\Baz'], 'C:\\Foo')
|
||||
check(['C:\\Bar', 'C:\\Baz'], 'C:\\')
|
||||
check(['C:\\Bar\\', 'C:\\Baz'], 'C:\\')
|
||||
|
||||
check(['C:\\Foo\\Bar', 'C:/Foo/Baz'], 'C:\\Foo')
|
||||
check(['C:\\Foo\\Bar', 'c:/foo/baz'], 'C:\\Foo')
|
||||
check(['c:/foo/bar', 'C:\\Foo\\Baz'], 'c:\\foo')
|
||||
|
||||
# gh-117381: Logical error messages
|
||||
check_error(['C:\\Foo', 'D:\\Foo'], "Paths don't have the same drive")
|
||||
check_error(['C:\\Foo', 'D:Foo'], "Paths don't have the same drive")
|
||||
check_error(['C:Foo', 'D:Foo'], "Paths don't have the same drive")
|
||||
|
||||
check(['spam'], 'spam')
|
||||
check(['spam', 'spam'], 'spam')
|
||||
@@ -859,20 +1240,16 @@ class TestNtpath(NtpathTestCase):
|
||||
|
||||
check([''], '')
|
||||
check(['', 'spam\\alot'], '')
|
||||
check_error(ValueError, ['', '\\spam\\alot'])
|
||||
|
||||
self.assertRaises(TypeError, ntpath.commonpath,
|
||||
[b'C:\\Program Files', 'C:\\Program Files\\Foo'])
|
||||
self.assertRaises(TypeError, ntpath.commonpath,
|
||||
[b'C:\\Program Files', 'Program Files\\Foo'])
|
||||
self.assertRaises(TypeError, ntpath.commonpath,
|
||||
[b'Program Files', 'C:\\Program Files\\Foo'])
|
||||
self.assertRaises(TypeError, ntpath.commonpath,
|
||||
['C:\\Program Files', b'C:\\Program Files\\Foo'])
|
||||
self.assertRaises(TypeError, ntpath.commonpath,
|
||||
['C:\\Program Files', b'Program Files\\Foo'])
|
||||
self.assertRaises(TypeError, ntpath.commonpath,
|
||||
['Program Files', b'C:\\Program Files\\Foo'])
|
||||
# gh-117381: Logical error messages
|
||||
check_error(['', '\\spam\\alot'], "Can't mix rooted and not-rooted paths")
|
||||
|
||||
self.assertRaises(TypeError, ntpath.commonpath, [b'C:\\Foo', 'C:\\Foo\\Baz'])
|
||||
self.assertRaises(TypeError, ntpath.commonpath, [b'C:\\Foo', 'Foo\\Baz'])
|
||||
self.assertRaises(TypeError, ntpath.commonpath, [b'Foo', 'C:\\Foo\\Baz'])
|
||||
self.assertRaises(TypeError, ntpath.commonpath, ['C:\\Foo', b'C:\\Foo\\Baz'])
|
||||
self.assertRaises(TypeError, ntpath.commonpath, ['C:\\Foo', b'Foo\\Baz'])
|
||||
self.assertRaises(TypeError, ntpath.commonpath, ['Foo', b'C:\\Foo\\Baz'])
|
||||
|
||||
@unittest.skipIf(is_emscripten, "Emscripten cannot fstat unnamed files.")
|
||||
def test_sameopenfile(self):
|
||||
@@ -924,6 +1301,76 @@ class TestNtpath(NtpathTestCase):
|
||||
self.assertTrue(ntpath.ismount(b"\\\\localhost\\c$"))
|
||||
self.assertTrue(ntpath.ismount(b"\\\\localhost\\c$\\"))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.skipIf(sys.platform == 'win32', "TODO: RUSTPYTHON; crash")
|
||||
def test_ismount_invalid_paths(self):
|
||||
ismount = ntpath.ismount
|
||||
self.assertFalse(ismount("c:\\\udfff"))
|
||||
if sys.platform == 'win32':
|
||||
self.assertRaises(ValueError, ismount, "c:\\\x00")
|
||||
self.assertRaises(ValueError, ismount, b"c:\\\x00")
|
||||
self.assertRaises(UnicodeDecodeError, ismount, b"c:\\\xff")
|
||||
else:
|
||||
self.assertFalse(ismount("c:\\\x00"))
|
||||
self.assertFalse(ismount(b"c:\\\x00"))
|
||||
self.assertFalse(ismount(b"c:\\\xff"))
|
||||
|
||||
def test_isreserved(self):
|
||||
self.assertFalse(ntpath.isreserved(''))
|
||||
self.assertFalse(ntpath.isreserved('.'))
|
||||
self.assertFalse(ntpath.isreserved('..'))
|
||||
self.assertFalse(ntpath.isreserved('/'))
|
||||
self.assertFalse(ntpath.isreserved('/foo/bar'))
|
||||
# A name that ends with a space or dot is reserved.
|
||||
self.assertTrue(ntpath.isreserved('foo.'))
|
||||
self.assertTrue(ntpath.isreserved('foo '))
|
||||
# ASCII control characters are reserved.
|
||||
self.assertTrue(ntpath.isreserved('\foo'))
|
||||
# Wildcard characters, colon, and pipe are reserved.
|
||||
self.assertTrue(ntpath.isreserved('foo*bar'))
|
||||
self.assertTrue(ntpath.isreserved('foo?bar'))
|
||||
self.assertTrue(ntpath.isreserved('foo"bar'))
|
||||
self.assertTrue(ntpath.isreserved('foo<bar'))
|
||||
self.assertTrue(ntpath.isreserved('foo>bar'))
|
||||
self.assertTrue(ntpath.isreserved('foo:bar'))
|
||||
self.assertTrue(ntpath.isreserved('foo|bar'))
|
||||
# Case-insensitive DOS-device names are reserved.
|
||||
self.assertTrue(ntpath.isreserved('nul'))
|
||||
self.assertTrue(ntpath.isreserved('aux'))
|
||||
self.assertTrue(ntpath.isreserved('prn'))
|
||||
self.assertTrue(ntpath.isreserved('con'))
|
||||
self.assertTrue(ntpath.isreserved('conin$'))
|
||||
self.assertTrue(ntpath.isreserved('conout$'))
|
||||
# COM/LPT + 1-9 or + superscript 1-3 are reserved.
|
||||
self.assertTrue(ntpath.isreserved('COM1'))
|
||||
self.assertTrue(ntpath.isreserved('LPT9'))
|
||||
self.assertTrue(ntpath.isreserved('com\xb9'))
|
||||
self.assertTrue(ntpath.isreserved('com\xb2'))
|
||||
self.assertTrue(ntpath.isreserved('lpt\xb3'))
|
||||
# DOS-device name matching ignores characters after a dot or
|
||||
# a colon and also ignores trailing spaces.
|
||||
self.assertTrue(ntpath.isreserved('NUL.txt'))
|
||||
self.assertTrue(ntpath.isreserved('PRN '))
|
||||
self.assertTrue(ntpath.isreserved('AUX .txt'))
|
||||
self.assertTrue(ntpath.isreserved('COM1:bar'))
|
||||
self.assertTrue(ntpath.isreserved('LPT9 :bar'))
|
||||
# DOS-device names are only matched at the beginning
|
||||
# of a path component.
|
||||
self.assertFalse(ntpath.isreserved('bar.com9'))
|
||||
self.assertFalse(ntpath.isreserved('bar.lpt9'))
|
||||
# The entire path is checked, except for the drive.
|
||||
self.assertTrue(ntpath.isreserved('c:/bar/baz/NUL'))
|
||||
self.assertTrue(ntpath.isreserved('c:/NUL/bar/baz'))
|
||||
self.assertFalse(ntpath.isreserved('//./NUL'))
|
||||
# Bytes are supported.
|
||||
self.assertFalse(ntpath.isreserved(b''))
|
||||
self.assertFalse(ntpath.isreserved(b'.'))
|
||||
self.assertFalse(ntpath.isreserved(b'..'))
|
||||
self.assertFalse(ntpath.isreserved(b'/'))
|
||||
self.assertFalse(ntpath.isreserved(b'/foo/bar'))
|
||||
self.assertTrue(ntpath.isreserved(b'foo.'))
|
||||
self.assertTrue(ntpath.isreserved(b'nul'))
|
||||
|
||||
def assertEqualCI(self, s1, s2):
|
||||
"""Assert that two strings are equal ignoring case differences."""
|
||||
self.assertEqual(s1.lower(), s2.lower())
|
||||
@@ -974,6 +1421,13 @@ class TestNtpath(NtpathTestCase):
|
||||
self.assertFalse(ntpath.isjunction('tmpdir'))
|
||||
self.assertPathEqual(ntpath.realpath('testjunc'), ntpath.realpath('tmpdir'))
|
||||
|
||||
def test_isfile_invalid_paths(self):
|
||||
isfile = ntpath.isfile
|
||||
self.assertIs(isfile('/tmp\udfffabcds'), False)
|
||||
self.assertIs(isfile(b'/tmp\xffabcds'), False)
|
||||
self.assertIs(isfile('/tmp\x00abcds'), False)
|
||||
self.assertIs(isfile(b'/tmp\x00abcds'), False)
|
||||
|
||||
@unittest.skipIf(sys.platform != 'win32', "drive letters are a windows concept")
|
||||
def test_isfile_driveletter(self):
|
||||
drive = os.environ.get('SystemDrive')
|
||||
@@ -981,6 +1435,29 @@ class TestNtpath(NtpathTestCase):
|
||||
raise unittest.SkipTest('SystemDrive is not defined or malformed')
|
||||
self.assertFalse(os.path.isfile('\\\\.\\' + drive))
|
||||
|
||||
@unittest.skipUnless(hasattr(os, 'pipe'), "need os.pipe()")
|
||||
def test_isfile_anonymous_pipe(self):
|
||||
pr, pw = os.pipe()
|
||||
try:
|
||||
self.assertFalse(ntpath.isfile(pr))
|
||||
finally:
|
||||
os.close(pr)
|
||||
os.close(pw)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
|
||||
@unittest.skipIf(sys.platform != 'win32', "windows only")
|
||||
def test_isfile_named_pipe(self):
|
||||
import _winapi
|
||||
named_pipe = f'//./PIPE/python_isfile_test_{os.getpid()}'
|
||||
h = _winapi.CreateNamedPipe(named_pipe,
|
||||
_winapi.PIPE_ACCESS_INBOUND,
|
||||
0, 1, 0, 0, 0, 0)
|
||||
try:
|
||||
self.assertFalse(ntpath.isfile(named_pipe))
|
||||
finally:
|
||||
_winapi.CloseHandle(h)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.skipIf(sys.platform != 'win32', "windows only")
|
||||
@@ -996,14 +1473,22 @@ class TestNtpath(NtpathTestCase):
|
||||
# There are fast paths of these functions implemented in posixmodule.c.
|
||||
# Confirm that they are being used, and not the Python fallbacks in
|
||||
# genericpath.py.
|
||||
self.assertTrue(os.path.splitroot is nt._path_splitroot_ex)
|
||||
self.assertFalse(inspect.isfunction(os.path.splitroot))
|
||||
self.assertTrue(os.path.normpath is nt._path_normpath)
|
||||
self.assertFalse(inspect.isfunction(os.path.normpath))
|
||||
self.assertTrue(os.path.isdir is nt._path_isdir)
|
||||
self.assertFalse(inspect.isfunction(os.path.isdir))
|
||||
self.assertTrue(os.path.isfile is nt._path_isfile)
|
||||
self.assertFalse(inspect.isfunction(os.path.isfile))
|
||||
self.assertTrue(os.path.islink is nt._path_islink)
|
||||
self.assertFalse(inspect.isfunction(os.path.islink))
|
||||
self.assertTrue(os.path.isjunction is nt._path_isjunction)
|
||||
self.assertFalse(inspect.isfunction(os.path.isjunction))
|
||||
self.assertTrue(os.path.exists is nt._path_exists)
|
||||
self.assertFalse(inspect.isfunction(os.path.exists))
|
||||
self.assertTrue(os.path.lexists is nt._path_lexists)
|
||||
self.assertFalse(inspect.isfunction(os.path.lexists))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@@ -1033,16 +1518,14 @@ class NtCommonTest(test_genericpath.CommonTest, unittest.TestCase):
|
||||
attributes = ['relpath']
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
if sys.platform == "win32":
|
||||
# TODO: RUSTPYTHON, ValueError: illegal environment variable name
|
||||
@unittest.expectedFailure
|
||||
def test_expandvars(self): # TODO: RUSTPYTHON; remove when done
|
||||
super().test_expandvars()
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; ValueError: illegal environment variable name")
|
||||
def test_expandvars(self):
|
||||
return super().test_expandvars()
|
||||
|
||||
# TODO: RUSTPYTHON, ValueError: illegal environment variable name
|
||||
@unittest.expectedFailure
|
||||
def test_expandvars_nonascii(self): # TODO: RUSTPYTHON; remove when done
|
||||
super().test_expandvars_nonascii()
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; ValueError: illegal environment variable name")
|
||||
def test_expandvars_nonascii(self):
|
||||
return super().test_expandvars_nonascii()
|
||||
|
||||
|
||||
class PathLikeTests(NtpathTestCase):
|
||||
@@ -1059,12 +1542,8 @@ class PathLikeTests(NtpathTestCase):
|
||||
def _check_function(self, func):
|
||||
self.assertPathEqual(func(self.file_path), func(self.file_name))
|
||||
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; AssertionError: 'ωω' != 'ωΩ'")
|
||||
def test_path_normcase(self):
|
||||
self._check_function(self.path.normcase)
|
||||
if sys.platform == 'win32':
|
||||
self.assertEqual(ntpath.normcase('\u03a9\u2126'), 'ωΩ')
|
||||
self.assertEqual(ntpath.normcase('abc\x00def'), 'abc\x00def')
|
||||
|
||||
def test_path_isabs(self):
|
||||
self._check_function(self.path.isabs)
|
||||
|
||||
587
Lib/test/test_posixpath.py
vendored
587
Lib/test/test_posixpath.py
vendored
@@ -1,12 +1,16 @@
|
||||
import inspect
|
||||
import os
|
||||
import posixpath
|
||||
import random
|
||||
import sys
|
||||
import unittest
|
||||
from posixpath import realpath, abspath, dirname, basename
|
||||
from functools import partial
|
||||
from posixpath import realpath, abspath, dirname, basename, ALLOW_MISSING
|
||||
from test import support
|
||||
from test import test_genericpath
|
||||
from test.support import import_helper
|
||||
from test.support import os_helper
|
||||
from test.support.os_helper import FakePath
|
||||
from test.support.os_helper import FakePath, TESTFN
|
||||
from unittest import mock
|
||||
|
||||
try:
|
||||
@@ -18,7 +22,7 @@ except ImportError:
|
||||
# An absolute path to a temporary filename for testing. We can't rely on TESTFN
|
||||
# being an absolute path, so we need this.
|
||||
|
||||
ABSTFN = abspath(os_helper.TESTFN)
|
||||
ABSTFN = abspath(TESTFN)
|
||||
|
||||
def skip_if_ABSTFN_contains_backslash(test):
|
||||
"""
|
||||
@@ -30,35 +34,40 @@ def skip_if_ABSTFN_contains_backslash(test):
|
||||
msg = "ABSTFN is not a posix path - tests fail"
|
||||
return [test, unittest.skip(msg)(test)][found_backslash]
|
||||
|
||||
def safe_rmdir(dirname):
|
||||
try:
|
||||
os.rmdir(dirname)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def _parameterize(*parameters):
|
||||
return support.subTests('kwargs', parameters)
|
||||
|
||||
|
||||
class PosixPathTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.tearDown()
|
||||
|
||||
def tearDown(self):
|
||||
for suffix in ["", "1", "2"]:
|
||||
os_helper.unlink(os_helper.TESTFN + suffix)
|
||||
safe_rmdir(os_helper.TESTFN + suffix)
|
||||
self.assertFalse(posixpath.lexists(ABSTFN + suffix))
|
||||
|
||||
def test_join(self):
|
||||
self.assertEqual(posixpath.join("/foo", "bar", "/bar", "baz"),
|
||||
"/bar/baz")
|
||||
self.assertEqual(posixpath.join("/foo", "bar", "baz"), "/foo/bar/baz")
|
||||
self.assertEqual(posixpath.join("/foo/", "bar/", "baz/"),
|
||||
"/foo/bar/baz/")
|
||||
fn = posixpath.join
|
||||
self.assertEqual(fn("/foo", "bar", "/bar", "baz"), "/bar/baz")
|
||||
self.assertEqual(fn("/foo", "bar", "baz"), "/foo/bar/baz")
|
||||
self.assertEqual(fn("/foo/", "bar/", "baz/"), "/foo/bar/baz/")
|
||||
|
||||
self.assertEqual(posixpath.join(b"/foo", b"bar", b"/bar", b"baz"),
|
||||
b"/bar/baz")
|
||||
self.assertEqual(posixpath.join(b"/foo", b"bar", b"baz"),
|
||||
b"/foo/bar/baz")
|
||||
self.assertEqual(posixpath.join(b"/foo/", b"bar/", b"baz/"),
|
||||
b"/foo/bar/baz/")
|
||||
self.assertEqual(fn(b"/foo", b"bar", b"/bar", b"baz"), b"/bar/baz")
|
||||
self.assertEqual(fn(b"/foo", b"bar", b"baz"), b"/foo/bar/baz")
|
||||
self.assertEqual(fn(b"/foo/", b"bar/", b"baz/"), b"/foo/bar/baz/")
|
||||
|
||||
self.assertEqual(fn("a", ""), "a/")
|
||||
self.assertEqual(fn("a", "", ""), "a/")
|
||||
self.assertEqual(fn("a", "b"), "a/b")
|
||||
self.assertEqual(fn("a", "b/"), "a/b/")
|
||||
self.assertEqual(fn("a/", "b"), "a/b")
|
||||
self.assertEqual(fn("a/", "b/"), "a/b/")
|
||||
self.assertEqual(fn("a", "b/c", "d"), "a/b/c/d")
|
||||
self.assertEqual(fn("a", "b//c", "d"), "a/b//c/d")
|
||||
self.assertEqual(fn("a", "b/c/", "d"), "a/b/c/d")
|
||||
self.assertEqual(fn("/a", "b"), "/a/b")
|
||||
self.assertEqual(fn("/a/", "b"), "/a/b")
|
||||
self.assertEqual(fn("a", "/b", "c"), "/b/c")
|
||||
self.assertEqual(fn("a", "/b", "/c"), "/c")
|
||||
|
||||
def test_split(self):
|
||||
self.assertEqual(posixpath.split("/foo/bar"), ("/foo", "bar"))
|
||||
@@ -180,27 +189,31 @@ class PosixPathTest(unittest.TestCase):
|
||||
self.assertEqual(posixpath.dirname(b"////foo"), b"////")
|
||||
self.assertEqual(posixpath.dirname(b"//foo//bar"), b"//foo")
|
||||
|
||||
@unittest.expectedFailureIf(os.name == "nt", "TODO: RUSTPYTHON")
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
|
||||
def test_islink(self):
|
||||
self.assertIs(posixpath.islink(os_helper.TESTFN + "1"), False)
|
||||
self.assertIs(posixpath.lexists(os_helper.TESTFN + "2"), False)
|
||||
self.assertIs(posixpath.islink(TESTFN + "1"), False)
|
||||
self.assertIs(posixpath.lexists(TESTFN + "2"), False)
|
||||
|
||||
with open(os_helper.TESTFN + "1", "wb") as f:
|
||||
self.addCleanup(os_helper.unlink, TESTFN + "1")
|
||||
with open(TESTFN + "1", "wb") as f:
|
||||
f.write(b"foo")
|
||||
self.assertIs(posixpath.islink(os_helper.TESTFN + "1"), False)
|
||||
self.assertIs(posixpath.islink(TESTFN + "1"), False)
|
||||
|
||||
if os_helper.can_symlink():
|
||||
os.symlink(os_helper.TESTFN + "1", os_helper.TESTFN + "2")
|
||||
self.assertIs(posixpath.islink(os_helper.TESTFN + "2"), True)
|
||||
os.remove(os_helper.TESTFN + "1")
|
||||
self.assertIs(posixpath.islink(os_helper.TESTFN + "2"), True)
|
||||
self.assertIs(posixpath.exists(os_helper.TESTFN + "2"), False)
|
||||
self.assertIs(posixpath.lexists(os_helper.TESTFN + "2"), True)
|
||||
self.addCleanup(os_helper.unlink, TESTFN + "2")
|
||||
os.symlink(TESTFN + "1", TESTFN + "2")
|
||||
self.assertIs(posixpath.islink(TESTFN + "2"), True)
|
||||
os.remove(TESTFN + "1")
|
||||
self.assertIs(posixpath.islink(TESTFN + "2"), True)
|
||||
self.assertIs(posixpath.exists(TESTFN + "2"), False)
|
||||
self.assertIs(posixpath.lexists(TESTFN + "2"), True)
|
||||
|
||||
self.assertIs(posixpath.islink(os_helper.TESTFN + "\udfff"), False)
|
||||
self.assertIs(posixpath.islink(os.fsencode(os_helper.TESTFN) + b"\xff"), False)
|
||||
self.assertIs(posixpath.islink(os_helper.TESTFN + "\x00"), False)
|
||||
self.assertIs(posixpath.islink(os.fsencode(os_helper.TESTFN) + b"\x00"), False)
|
||||
def test_islink_invalid_paths(self):
|
||||
self.assertIs(posixpath.islink(TESTFN + "\udfff"), False)
|
||||
self.assertIs(posixpath.islink(os.fsencode(TESTFN) + b"\xff"), False)
|
||||
self.assertIs(posixpath.islink(TESTFN + "\x00"), False)
|
||||
self.assertIs(posixpath.islink(os.fsencode(TESTFN) + b"\x00"), False)
|
||||
|
||||
def test_ismount(self):
|
||||
self.assertIs(posixpath.ismount("/"), True)
|
||||
@@ -215,13 +228,15 @@ class PosixPathTest(unittest.TestCase):
|
||||
os.mkdir(ABSTFN)
|
||||
self.assertIs(posixpath.ismount(ABSTFN), False)
|
||||
finally:
|
||||
safe_rmdir(ABSTFN)
|
||||
os_helper.rmdir(ABSTFN)
|
||||
|
||||
def test_ismount_invalid_paths(self):
|
||||
self.assertIs(posixpath.ismount('/\udfff'), False)
|
||||
self.assertIs(posixpath.ismount(b'/\xff'), False)
|
||||
self.assertIs(posixpath.ismount('/\x00'), False)
|
||||
self.assertIs(posixpath.ismount(b'/\x00'), False)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
|
||||
@os_helper.skip_unless_symlink
|
||||
def test_ismount_symlinks(self):
|
||||
@@ -230,7 +245,7 @@ class PosixPathTest(unittest.TestCase):
|
||||
os.symlink("/", ABSTFN)
|
||||
self.assertIs(posixpath.ismount(ABSTFN), False)
|
||||
finally:
|
||||
os.unlink(ABSTFN)
|
||||
os_helper.unlink(ABSTFN)
|
||||
|
||||
@unittest.skipIf(posix is None, "Test requires posix module")
|
||||
def test_ismount_different_device(self):
|
||||
@@ -275,6 +290,16 @@ class PosixPathTest(unittest.TestCase):
|
||||
def test_isjunction(self):
|
||||
self.assertFalse(posixpath.isjunction(ABSTFN))
|
||||
|
||||
@unittest.skipIf(sys.platform == 'win32', "Fast paths are not for win32")
|
||||
@support.cpython_only
|
||||
def test_fast_paths_in_use(self):
|
||||
# There are fast paths of these functions implemented in posixmodule.c.
|
||||
# Confirm that they are being used, and not the Python fallbacks
|
||||
self.assertTrue(os.path.splitroot is posix._path_splitroot_ex)
|
||||
self.assertFalse(inspect.isfunction(os.path.splitroot))
|
||||
self.assertTrue(os.path.normpath is posix._path_normpath)
|
||||
self.assertFalse(inspect.isfunction(os.path.normpath))
|
||||
|
||||
def test_expanduser(self):
|
||||
self.assertEqual(posixpath.expanduser("foo"), "foo")
|
||||
self.assertEqual(posixpath.expanduser(b"foo"), b"foo")
|
||||
@@ -336,12 +361,38 @@ class PosixPathTest(unittest.TestCase):
|
||||
for path in ('~', '~/.local', '~vstinner/'):
|
||||
self.assertEqual(posixpath.expanduser(path), path)
|
||||
|
||||
@unittest.skipIf(sys.platform == "vxworks",
|
||||
"no home directory on VxWorks")
|
||||
def test_expanduser_pwd2(self):
|
||||
pwd = import_helper.import_module('pwd')
|
||||
getpwall = support.get_attribute(pwd, 'getpwall')
|
||||
names = [entry.pw_name for entry in getpwall()]
|
||||
maxusers = 1000 if support.is_resource_enabled('cpu') else 100
|
||||
if len(names) > maxusers:
|
||||
# Select random names, half of them with non-ASCII name,
|
||||
# if available.
|
||||
random.shuffle(names)
|
||||
names.sort(key=lambda name: name.isascii())
|
||||
del names[maxusers//2:-maxusers//2]
|
||||
for name in names:
|
||||
# gh-121200: pw_dir can be different between getpwall() and
|
||||
# getpwnam(), so use getpwnam() pw_dir as expanduser() does.
|
||||
entry = pwd.getpwnam(name)
|
||||
home = entry.pw_dir
|
||||
home = home.rstrip('/') or '/'
|
||||
|
||||
with self.subTest(name=name, pw_dir=entry.pw_dir):
|
||||
self.assertEqual(posixpath.expanduser('~' + name), home)
|
||||
self.assertEqual(posixpath.expanduser(os.fsencode('~' + name)),
|
||||
os.fsencode(home))
|
||||
|
||||
NORMPATH_CASES = [
|
||||
("", "."),
|
||||
("/", "/"),
|
||||
("/.", "/"),
|
||||
("/./", "/"),
|
||||
("/.//.", "/"),
|
||||
("/./foo/bar", "/foo/bar"),
|
||||
("/foo", "/foo"),
|
||||
("/foo/bar", "/foo/bar"),
|
||||
("//", "//"),
|
||||
@@ -351,6 +402,7 @@ class PosixPathTest(unittest.TestCase):
|
||||
("///..//./foo/.//bar", "/foo/bar"),
|
||||
(".", "."),
|
||||
(".//.", "."),
|
||||
("./foo/bar", "foo/bar"),
|
||||
("..", ".."),
|
||||
("../", ".."),
|
||||
("../foo", "../foo"),
|
||||
@@ -400,32 +452,35 @@ class PosixPathTest(unittest.TestCase):
|
||||
self.assertEqual(result, expected)
|
||||
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
def test_realpath_curdir(self):
|
||||
self.assertEqual(realpath('.'), os.getcwd())
|
||||
self.assertEqual(realpath('./.'), os.getcwd())
|
||||
self.assertEqual(realpath('/'.join(['.'] * 100)), os.getcwd())
|
||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
||||
def test_realpath_curdir(self, kwargs):
|
||||
self.assertEqual(realpath('.', **kwargs), os.getcwd())
|
||||
self.assertEqual(realpath('./.', **kwargs), os.getcwd())
|
||||
self.assertEqual(realpath('/'.join(['.'] * 100), **kwargs), os.getcwd())
|
||||
|
||||
self.assertEqual(realpath(b'.'), os.getcwdb())
|
||||
self.assertEqual(realpath(b'./.'), os.getcwdb())
|
||||
self.assertEqual(realpath(b'/'.join([b'.'] * 100)), os.getcwdb())
|
||||
self.assertEqual(realpath(b'.', **kwargs), os.getcwdb())
|
||||
self.assertEqual(realpath(b'./.', **kwargs), os.getcwdb())
|
||||
self.assertEqual(realpath(b'/'.join([b'.'] * 100), **kwargs), os.getcwdb())
|
||||
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
def test_realpath_pardir(self):
|
||||
self.assertEqual(realpath('..'), dirname(os.getcwd()))
|
||||
self.assertEqual(realpath('../..'), dirname(dirname(os.getcwd())))
|
||||
self.assertEqual(realpath('/'.join(['..'] * 100)), '/')
|
||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
||||
def test_realpath_pardir(self, kwargs):
|
||||
self.assertEqual(realpath('..', **kwargs), dirname(os.getcwd()))
|
||||
self.assertEqual(realpath('../..', **kwargs), dirname(dirname(os.getcwd())))
|
||||
self.assertEqual(realpath('/'.join(['..'] * 100), **kwargs), '/')
|
||||
|
||||
self.assertEqual(realpath(b'..'), dirname(os.getcwdb()))
|
||||
self.assertEqual(realpath(b'../..'), dirname(dirname(os.getcwdb())))
|
||||
self.assertEqual(realpath(b'/'.join([b'..'] * 100)), b'/')
|
||||
self.assertEqual(realpath(b'..', **kwargs), dirname(os.getcwdb()))
|
||||
self.assertEqual(realpath(b'../..', **kwargs), dirname(dirname(os.getcwdb())))
|
||||
self.assertEqual(realpath(b'/'.join([b'..'] * 100), **kwargs), b'/')
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
def test_realpath_basic(self):
|
||||
@_parameterize({}, {'strict': ALLOW_MISSING})
|
||||
def test_realpath_basic(self, kwargs):
|
||||
# Basic operation.
|
||||
try:
|
||||
os.symlink(ABSTFN+"1", ABSTFN)
|
||||
self.assertEqual(realpath(ABSTFN), ABSTFN+"1")
|
||||
self.assertEqual(realpath(ABSTFN, **kwargs), ABSTFN+"1")
|
||||
finally:
|
||||
os_helper.unlink(ABSTFN)
|
||||
|
||||
@@ -441,15 +496,122 @@ class PosixPathTest(unittest.TestCase):
|
||||
finally:
|
||||
os_helper.unlink(ABSTFN)
|
||||
|
||||
def test_realpath_invalid_paths(self):
|
||||
path = '/\x00'
|
||||
self.assertRaises(ValueError, realpath, path, strict=False)
|
||||
self.assertRaises(ValueError, realpath, path, strict=True)
|
||||
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
||||
path = b'/\x00'
|
||||
self.assertRaises(ValueError, realpath, path, strict=False)
|
||||
self.assertRaises(ValueError, realpath, path, strict=True)
|
||||
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
||||
path = '/nonexistent/x\x00'
|
||||
self.assertRaises(ValueError, realpath, path, strict=False)
|
||||
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
||||
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
||||
path = b'/nonexistent/x\x00'
|
||||
self.assertRaises(ValueError, realpath, path, strict=False)
|
||||
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
||||
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
||||
path = '/\x00/..'
|
||||
self.assertRaises(ValueError, realpath, path, strict=False)
|
||||
self.assertRaises(ValueError, realpath, path, strict=True)
|
||||
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
||||
path = b'/\x00/..'
|
||||
self.assertRaises(ValueError, realpath, path, strict=False)
|
||||
self.assertRaises(ValueError, realpath, path, strict=True)
|
||||
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
||||
|
||||
path = '/nonexistent/x\x00/..'
|
||||
self.assertRaises(ValueError, realpath, path, strict=False)
|
||||
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
||||
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
||||
path = b'/nonexistent/x\x00/..'
|
||||
self.assertRaises(ValueError, realpath, path, strict=False)
|
||||
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
||||
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
||||
|
||||
path = '/\udfff'
|
||||
if sys.platform == 'win32':
|
||||
self.assertEqual(realpath(path, strict=False), path)
|
||||
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
||||
self.assertEqual(realpath(path, strict=ALLOW_MISSING), path)
|
||||
else:
|
||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=False)
|
||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=True)
|
||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=ALLOW_MISSING)
|
||||
path = '/nonexistent/\udfff'
|
||||
if sys.platform == 'win32':
|
||||
self.assertEqual(realpath(path, strict=False), path)
|
||||
self.assertEqual(realpath(path, strict=ALLOW_MISSING), path)
|
||||
else:
|
||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=False)
|
||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=ALLOW_MISSING)
|
||||
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
||||
path = '/\udfff/..'
|
||||
if sys.platform == 'win32':
|
||||
self.assertEqual(realpath(path, strict=False), '/')
|
||||
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
||||
self.assertEqual(realpath(path, strict=ALLOW_MISSING), '/')
|
||||
else:
|
||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=False)
|
||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=True)
|
||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=ALLOW_MISSING)
|
||||
path = '/nonexistent/\udfff/..'
|
||||
if sys.platform == 'win32':
|
||||
self.assertEqual(realpath(path, strict=False), '/nonexistent')
|
||||
self.assertEqual(realpath(path, strict=ALLOW_MISSING), '/nonexistent')
|
||||
else:
|
||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=False)
|
||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=ALLOW_MISSING)
|
||||
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
||||
|
||||
path = b'/\xff'
|
||||
if sys.platform == 'win32':
|
||||
self.assertRaises(UnicodeDecodeError, realpath, path, strict=False)
|
||||
self.assertRaises(UnicodeDecodeError, realpath, path, strict=True)
|
||||
self.assertRaises(UnicodeDecodeError, realpath, path, strict=ALLOW_MISSING)
|
||||
else:
|
||||
self.assertEqual(realpath(path, strict=False), path)
|
||||
if support.is_wasi:
|
||||
self.assertRaises(OSError, realpath, path, strict=True)
|
||||
self.assertRaises(OSError, realpath, path, strict=ALLOW_MISSING)
|
||||
else:
|
||||
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
||||
self.assertEqual(realpath(path, strict=ALLOW_MISSING), path)
|
||||
path = b'/nonexistent/\xff'
|
||||
if sys.platform == 'win32':
|
||||
self.assertRaises(UnicodeDecodeError, realpath, path, strict=False)
|
||||
self.assertRaises(UnicodeDecodeError, realpath, path, strict=ALLOW_MISSING)
|
||||
else:
|
||||
self.assertEqual(realpath(path, strict=False), path)
|
||||
if support.is_wasi:
|
||||
self.assertRaises(OSError, realpath, path, strict=True)
|
||||
self.assertRaises(OSError, realpath, path, strict=ALLOW_MISSING)
|
||||
else:
|
||||
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
def test_realpath_relative(self):
|
||||
@_parameterize({}, {'strict': ALLOW_MISSING})
|
||||
def test_realpath_relative(self, kwargs):
|
||||
try:
|
||||
os.symlink(posixpath.relpath(ABSTFN+"1"), ABSTFN)
|
||||
self.assertEqual(realpath(ABSTFN), ABSTFN+"1")
|
||||
self.assertEqual(realpath(ABSTFN, **kwargs), ABSTFN+"1")
|
||||
finally:
|
||||
os_helper.unlink(ABSTFN)
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
@_parameterize({}, {'strict': ALLOW_MISSING})
|
||||
def test_realpath_missing_pardir(self, kwargs):
|
||||
try:
|
||||
os.symlink(TESTFN + "1", TESTFN)
|
||||
self.assertEqual(
|
||||
realpath("nonexistent/../" + TESTFN, **kwargs), ABSTFN + "1")
|
||||
finally:
|
||||
os_helper.unlink(TESTFN)
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
def test_realpath_symlink_loops(self):
|
||||
@@ -469,7 +631,7 @@ class PosixPathTest(unittest.TestCase):
|
||||
self.assertEqual(realpath(ABSTFN+"1/../x"), dirname(ABSTFN) + "/x")
|
||||
os.symlink(ABSTFN+"x", ABSTFN+"y")
|
||||
self.assertEqual(realpath(ABSTFN+"1/../" + basename(ABSTFN) + "y"),
|
||||
ABSTFN + "y")
|
||||
ABSTFN + "x")
|
||||
self.assertEqual(realpath(ABSTFN+"1/../" + basename(ABSTFN) + "1"),
|
||||
ABSTFN + "1")
|
||||
|
||||
@@ -493,37 +655,38 @@ class PosixPathTest(unittest.TestCase):
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
def test_realpath_symlink_loops_strict(self):
|
||||
@_parameterize({'strict': True}, {'strict': ALLOW_MISSING})
|
||||
def test_realpath_symlink_loops_strict(self, kwargs):
|
||||
# Bug #43757, raise OSError if we get into an infinite symlink loop in
|
||||
# strict mode.
|
||||
# the strict modes.
|
||||
try:
|
||||
os.symlink(ABSTFN, ABSTFN)
|
||||
self.assertRaises(OSError, realpath, ABSTFN, strict=True)
|
||||
self.assertRaises(OSError, realpath, ABSTFN, **kwargs)
|
||||
|
||||
os.symlink(ABSTFN+"1", ABSTFN+"2")
|
||||
os.symlink(ABSTFN+"2", ABSTFN+"1")
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"1", strict=True)
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"2", strict=True)
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"1", **kwargs)
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"2", **kwargs)
|
||||
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"1/x", strict=True)
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"1/..", strict=True)
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"1/../x", strict=True)
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"1/x", **kwargs)
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"1/..", **kwargs)
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"1/../x", **kwargs)
|
||||
os.symlink(ABSTFN+"x", ABSTFN+"y")
|
||||
self.assertRaises(OSError, realpath,
|
||||
ABSTFN+"1/../" + basename(ABSTFN) + "y", strict=True)
|
||||
ABSTFN+"1/../" + basename(ABSTFN) + "y", **kwargs)
|
||||
self.assertRaises(OSError, realpath,
|
||||
ABSTFN+"1/../" + basename(ABSTFN) + "1", strict=True)
|
||||
ABSTFN+"1/../" + basename(ABSTFN) + "1", **kwargs)
|
||||
|
||||
os.symlink(basename(ABSTFN) + "a/b", ABSTFN+"a")
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"a", strict=True)
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"a", **kwargs)
|
||||
|
||||
os.symlink("../" + basename(dirname(ABSTFN)) + "/" +
|
||||
basename(ABSTFN) + "c", ABSTFN+"c")
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"c", strict=True)
|
||||
self.assertRaises(OSError, realpath, ABSTFN+"c", **kwargs)
|
||||
|
||||
# Test using relative path as well.
|
||||
with os_helper.change_cwd(dirname(ABSTFN)):
|
||||
self.assertRaises(OSError, realpath, basename(ABSTFN), strict=True)
|
||||
self.assertRaises(OSError, realpath, basename(ABSTFN), **kwargs)
|
||||
finally:
|
||||
os_helper.unlink(ABSTFN)
|
||||
os_helper.unlink(ABSTFN+"1")
|
||||
@@ -534,28 +697,30 @@ class PosixPathTest(unittest.TestCase):
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
def test_realpath_repeated_indirect_symlinks(self):
|
||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
||||
def test_realpath_repeated_indirect_symlinks(self, kwargs):
|
||||
# Issue #6975.
|
||||
try:
|
||||
os.mkdir(ABSTFN)
|
||||
os.symlink('../' + basename(ABSTFN), ABSTFN + '/self')
|
||||
os.symlink('self/self/self', ABSTFN + '/link')
|
||||
self.assertEqual(realpath(ABSTFN + '/link'), ABSTFN)
|
||||
self.assertEqual(realpath(ABSTFN + '/link', **kwargs), ABSTFN)
|
||||
finally:
|
||||
os_helper.unlink(ABSTFN + '/self')
|
||||
os_helper.unlink(ABSTFN + '/link')
|
||||
safe_rmdir(ABSTFN)
|
||||
os_helper.rmdir(ABSTFN)
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
def test_realpath_deep_recursion(self):
|
||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
||||
def test_realpath_deep_recursion(self, kwargs):
|
||||
depth = 10
|
||||
try:
|
||||
os.mkdir(ABSTFN)
|
||||
for i in range(depth):
|
||||
os.symlink('/'.join(['%d' % i] * 10), ABSTFN + '/%d' % (i + 1))
|
||||
os.symlink('.', ABSTFN + '/0')
|
||||
self.assertEqual(realpath(ABSTFN + '/%d' % depth), ABSTFN)
|
||||
self.assertEqual(realpath(ABSTFN + '/%d' % depth, **kwargs), ABSTFN)
|
||||
|
||||
# Test using relative path as well.
|
||||
with os_helper.change_cwd(ABSTFN):
|
||||
@@ -563,11 +728,12 @@ class PosixPathTest(unittest.TestCase):
|
||||
finally:
|
||||
for i in range(depth + 1):
|
||||
os_helper.unlink(ABSTFN + '/%d' % i)
|
||||
safe_rmdir(ABSTFN)
|
||||
os_helper.rmdir(ABSTFN)
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
def test_realpath_resolve_parents(self):
|
||||
@_parameterize({}, {'strict': ALLOW_MISSING})
|
||||
def test_realpath_resolve_parents(self, kwargs):
|
||||
# We also need to resolve any symlinks in the parents of a relative
|
||||
# path passed to realpath. E.g.: current working directory is
|
||||
# /usr/doc with 'doc' being a symlink to /usr/share/doc. We call
|
||||
@@ -578,15 +744,17 @@ class PosixPathTest(unittest.TestCase):
|
||||
os.symlink(ABSTFN + "/y", ABSTFN + "/k")
|
||||
|
||||
with os_helper.change_cwd(ABSTFN + "/k"):
|
||||
self.assertEqual(realpath("a"), ABSTFN + "/y/a")
|
||||
self.assertEqual(realpath("a", **kwargs),
|
||||
ABSTFN + "/y/a")
|
||||
finally:
|
||||
os_helper.unlink(ABSTFN + "/k")
|
||||
safe_rmdir(ABSTFN + "/y")
|
||||
safe_rmdir(ABSTFN)
|
||||
os_helper.rmdir(ABSTFN + "/y")
|
||||
os_helper.rmdir(ABSTFN)
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
def test_realpath_resolve_before_normalizing(self):
|
||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
||||
def test_realpath_resolve_before_normalizing(self, kwargs):
|
||||
# Bug #990669: Symbolic links should be resolved before we
|
||||
# normalize the path. E.g.: if we have directories 'a', 'k' and 'y'
|
||||
# in the following hierarchy:
|
||||
@@ -601,20 +769,21 @@ class PosixPathTest(unittest.TestCase):
|
||||
os.symlink(ABSTFN + "/k/y", ABSTFN + "/link-y")
|
||||
|
||||
# Absolute path.
|
||||
self.assertEqual(realpath(ABSTFN + "/link-y/.."), ABSTFN + "/k")
|
||||
self.assertEqual(realpath(ABSTFN + "/link-y/..", **kwargs), ABSTFN + "/k")
|
||||
# Relative path.
|
||||
with os_helper.change_cwd(dirname(ABSTFN)):
|
||||
self.assertEqual(realpath(basename(ABSTFN) + "/link-y/.."),
|
||||
self.assertEqual(realpath(basename(ABSTFN) + "/link-y/..", **kwargs),
|
||||
ABSTFN + "/k")
|
||||
finally:
|
||||
os_helper.unlink(ABSTFN + "/link-y")
|
||||
safe_rmdir(ABSTFN + "/k/y")
|
||||
safe_rmdir(ABSTFN + "/k")
|
||||
safe_rmdir(ABSTFN)
|
||||
os_helper.rmdir(ABSTFN + "/k/y")
|
||||
os_helper.rmdir(ABSTFN + "/k")
|
||||
os_helper.rmdir(ABSTFN)
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
def test_realpath_resolve_first(self):
|
||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
||||
def test_realpath_resolve_first(self, kwargs):
|
||||
# Bug #1213894: The first component of the path, if not absolute,
|
||||
# must be resolved too.
|
||||
|
||||
@@ -624,17 +793,192 @@ class PosixPathTest(unittest.TestCase):
|
||||
os.symlink(ABSTFN, ABSTFN + "link")
|
||||
with os_helper.change_cwd(dirname(ABSTFN)):
|
||||
base = basename(ABSTFN)
|
||||
self.assertEqual(realpath(base + "link"), ABSTFN)
|
||||
self.assertEqual(realpath(base + "link/k"), ABSTFN + "/k")
|
||||
self.assertEqual(realpath(base + "link", **kwargs), ABSTFN)
|
||||
self.assertEqual(realpath(base + "link/k", **kwargs), ABSTFN + "/k")
|
||||
finally:
|
||||
os_helper.unlink(ABSTFN + "link")
|
||||
safe_rmdir(ABSTFN + "/k")
|
||||
safe_rmdir(ABSTFN)
|
||||
os_helper.rmdir(ABSTFN + "/k")
|
||||
os_helper.rmdir(ABSTFN)
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
@unittest.skipIf(os.chmod not in os.supports_follow_symlinks, "Can't set symlink permissions")
|
||||
@unittest.skipIf(sys.platform != "darwin", "only macOS requires read permission to readlink()")
|
||||
def test_realpath_unreadable_symlink(self):
|
||||
try:
|
||||
os.symlink(ABSTFN+"1", ABSTFN)
|
||||
os.chmod(ABSTFN, 0o000, follow_symlinks=False)
|
||||
self.assertEqual(realpath(ABSTFN), ABSTFN)
|
||||
self.assertEqual(realpath(ABSTFN + '/foo'), ABSTFN + '/foo')
|
||||
self.assertEqual(realpath(ABSTFN + '/../foo'), dirname(ABSTFN) + '/foo')
|
||||
self.assertEqual(realpath(ABSTFN + '/foo/..'), ABSTFN)
|
||||
finally:
|
||||
os.chmod(ABSTFN, 0o755, follow_symlinks=False)
|
||||
os_helper.unlink(ABSTFN)
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
@unittest.skipIf(os.chmod not in os.supports_follow_symlinks, "Can't set symlink permissions")
|
||||
@unittest.skipIf(sys.platform != "darwin", "only macOS requires read permission to readlink()")
|
||||
@_parameterize({'strict': True}, {'strict': ALLOW_MISSING})
|
||||
def test_realpath_unreadable_symlink_strict(self, kwargs):
|
||||
try:
|
||||
os.symlink(ABSTFN+"1", ABSTFN)
|
||||
os.chmod(ABSTFN, 0o000, follow_symlinks=False)
|
||||
with self.assertRaises(PermissionError):
|
||||
realpath(ABSTFN, **kwargs)
|
||||
with self.assertRaises(PermissionError):
|
||||
realpath(ABSTFN + '/foo', **kwargs),
|
||||
with self.assertRaises(PermissionError):
|
||||
realpath(ABSTFN + '/../foo', **kwargs)
|
||||
with self.assertRaises(PermissionError):
|
||||
realpath(ABSTFN + '/foo/..', **kwargs)
|
||||
finally:
|
||||
os.chmod(ABSTFN, 0o755, follow_symlinks=False)
|
||||
os.unlink(ABSTFN)
|
||||
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
@os_helper.skip_unless_symlink
|
||||
def test_realpath_unreadable_directory(self):
|
||||
try:
|
||||
os.mkdir(ABSTFN)
|
||||
os.mkdir(ABSTFN + '/k')
|
||||
os.chmod(ABSTFN, 0o000)
|
||||
self.assertEqual(realpath(ABSTFN, strict=False), ABSTFN)
|
||||
self.assertEqual(realpath(ABSTFN, strict=True), ABSTFN)
|
||||
self.assertEqual(realpath(ABSTFN, strict=ALLOW_MISSING), ABSTFN)
|
||||
|
||||
try:
|
||||
os.stat(ABSTFN)
|
||||
except PermissionError:
|
||||
pass
|
||||
else:
|
||||
self.skipTest('Cannot block permissions')
|
||||
|
||||
self.assertEqual(realpath(ABSTFN + '/k', strict=False),
|
||||
ABSTFN + '/k')
|
||||
self.assertRaises(PermissionError, realpath, ABSTFN + '/k',
|
||||
strict=True)
|
||||
self.assertRaises(PermissionError, realpath, ABSTFN + '/k',
|
||||
strict=ALLOW_MISSING)
|
||||
|
||||
self.assertEqual(realpath(ABSTFN + '/missing', strict=False),
|
||||
ABSTFN + '/missing')
|
||||
self.assertRaises(PermissionError, realpath, ABSTFN + '/missing',
|
||||
strict=True)
|
||||
self.assertRaises(PermissionError, realpath, ABSTFN + '/missing',
|
||||
strict=ALLOW_MISSING)
|
||||
finally:
|
||||
os.chmod(ABSTFN, 0o755)
|
||||
os_helper.rmdir(ABSTFN + '/k')
|
||||
os_helper.rmdir(ABSTFN)
|
||||
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
def test_realpath_nonterminal_file(self):
|
||||
try:
|
||||
with open(ABSTFN, 'w') as f:
|
||||
f.write('test_posixpath wuz ere')
|
||||
self.assertEqual(realpath(ABSTFN, strict=False), ABSTFN)
|
||||
self.assertEqual(realpath(ABSTFN, strict=True), ABSTFN)
|
||||
self.assertEqual(realpath(ABSTFN, strict=ALLOW_MISSING), ABSTFN)
|
||||
|
||||
self.assertEqual(realpath(ABSTFN + "/", strict=False), ABSTFN)
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/", strict=True)
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/",
|
||||
strict=ALLOW_MISSING)
|
||||
|
||||
self.assertEqual(realpath(ABSTFN + "/.", strict=False), ABSTFN)
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.", strict=True)
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.",
|
||||
strict=ALLOW_MISSING)
|
||||
|
||||
self.assertEqual(realpath(ABSTFN + "/..", strict=False), dirname(ABSTFN))
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..", strict=True)
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..",
|
||||
strict=ALLOW_MISSING)
|
||||
|
||||
self.assertEqual(realpath(ABSTFN + "/subdir", strict=False), ABSTFN + "/subdir")
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir", strict=True)
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir",
|
||||
strict=ALLOW_MISSING)
|
||||
finally:
|
||||
os_helper.unlink(ABSTFN)
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
def test_realpath_nonterminal_symlink_to_file(self):
|
||||
try:
|
||||
with open(ABSTFN + "1", 'w') as f:
|
||||
f.write('test_posixpath wuz ere')
|
||||
os.symlink(ABSTFN + "1", ABSTFN)
|
||||
self.assertEqual(realpath(ABSTFN, strict=False), ABSTFN + "1")
|
||||
self.assertEqual(realpath(ABSTFN, strict=True), ABSTFN + "1")
|
||||
self.assertEqual(realpath(ABSTFN, strict=ALLOW_MISSING), ABSTFN + "1")
|
||||
|
||||
self.assertEqual(realpath(ABSTFN + "/", strict=False), ABSTFN + "1")
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/", strict=True)
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/",
|
||||
strict=ALLOW_MISSING)
|
||||
|
||||
self.assertEqual(realpath(ABSTFN + "/.", strict=False), ABSTFN + "1")
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.", strict=True)
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.",
|
||||
strict=ALLOW_MISSING)
|
||||
|
||||
self.assertEqual(realpath(ABSTFN + "/..", strict=False), dirname(ABSTFN))
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..", strict=True)
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..",
|
||||
strict=ALLOW_MISSING)
|
||||
|
||||
self.assertEqual(realpath(ABSTFN + "/subdir", strict=False), ABSTFN + "1/subdir")
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir", strict=True)
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir",
|
||||
strict=ALLOW_MISSING)
|
||||
finally:
|
||||
os_helper.unlink(ABSTFN)
|
||||
os_helper.unlink(ABSTFN + "1")
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@skip_if_ABSTFN_contains_backslash
|
||||
def test_realpath_nonterminal_symlink_to_symlinks_to_file(self):
|
||||
try:
|
||||
with open(ABSTFN + "2", 'w') as f:
|
||||
f.write('test_posixpath wuz ere')
|
||||
os.symlink(ABSTFN + "2", ABSTFN + "1")
|
||||
os.symlink(ABSTFN + "1", ABSTFN)
|
||||
self.assertEqual(realpath(ABSTFN, strict=False), ABSTFN + "2")
|
||||
self.assertEqual(realpath(ABSTFN, strict=True), ABSTFN + "2")
|
||||
self.assertEqual(realpath(ABSTFN, strict=True), ABSTFN + "2")
|
||||
|
||||
self.assertEqual(realpath(ABSTFN + "/", strict=False), ABSTFN + "2")
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/", strict=True)
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/",
|
||||
strict=ALLOW_MISSING)
|
||||
|
||||
self.assertEqual(realpath(ABSTFN + "/.", strict=False), ABSTFN + "2")
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.", strict=True)
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.",
|
||||
strict=ALLOW_MISSING)
|
||||
|
||||
self.assertEqual(realpath(ABSTFN + "/..", strict=False), dirname(ABSTFN))
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..", strict=True)
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..",
|
||||
strict=ALLOW_MISSING)
|
||||
|
||||
self.assertEqual(realpath(ABSTFN + "/subdir", strict=False), ABSTFN + "2/subdir")
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir", strict=True)
|
||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir",
|
||||
strict=ALLOW_MISSING)
|
||||
finally:
|
||||
os_helper.unlink(ABSTFN)
|
||||
os_helper.unlink(ABSTFN + "1")
|
||||
os_helper.unlink(ABSTFN + "2")
|
||||
|
||||
def test_relpath(self):
|
||||
(real_getcwd, os.getcwd) = (os.getcwd, lambda: r"/home/user/bar")
|
||||
try:
|
||||
curdir = os.path.split(os.getcwd())[-1]
|
||||
self.assertRaises(TypeError, posixpath.relpath, None)
|
||||
self.assertRaises(ValueError, posixpath.relpath, "")
|
||||
self.assertEqual(posixpath.relpath("a"), "a")
|
||||
self.assertEqual(posixpath.relpath(posixpath.abspath("a")), "a")
|
||||
@@ -697,7 +1041,9 @@ class PosixPathTest(unittest.TestCase):
|
||||
self.assertRaises(exc, posixpath.commonpath,
|
||||
[os.fsencode(p) for p in paths])
|
||||
|
||||
self.assertRaises(TypeError, posixpath.commonpath, None)
|
||||
self.assertRaises(ValueError, posixpath.commonpath, [])
|
||||
self.assertRaises(ValueError, posixpath.commonpath, iter([]))
|
||||
check_error(ValueError, ['/usr', 'usr'])
|
||||
check_error(ValueError, ['usr', '/usr'])
|
||||
|
||||
@@ -742,62 +1088,22 @@ class PosixPathTest(unittest.TestCase):
|
||||
['usr/lib/', b'/usr/lib/python3'])
|
||||
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.skip("TODO: RUSTPYTHON, flaky tests")
|
||||
class PosixCommonTest(test_genericpath.CommonTest, unittest.TestCase):
|
||||
pathmodule = posixpath
|
||||
attributes = ['relpath', 'samefile', 'sameopenfile', 'samestat']
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
if os.name == "posix" and os.getenv("CI"):
|
||||
@unittest.expectedFailure
|
||||
def test_exists(self):
|
||||
super().test_exists()
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
import sys
|
||||
@unittest.skipIf(sys.platform.startswith("linux") and os.getenv("CI"), "TODO: RUSTPYTHON, flaky test")
|
||||
def test_filetime(self):
|
||||
super().test_filetime()
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
if sys.platform.startswith("linux"):
|
||||
@unittest.expectedFailure
|
||||
def test_nonascii_abspath(self):
|
||||
super().test_nonascii_abspath()
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
if os.name == "nt":
|
||||
@unittest.expectedFailure
|
||||
def test_samefile(self):
|
||||
super().test_samefile()
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
if os.name == "nt":
|
||||
@unittest.expectedFailure
|
||||
def test_samefile_on_link(self):
|
||||
super().test_samefile_on_link()
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
if os.name == "nt":
|
||||
@unittest.expectedFailure
|
||||
def test_samestat(self):
|
||||
super().test_samestat()
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
if os.name == "nt":
|
||||
@unittest.expectedFailure
|
||||
def test_samestat_on_link(self):
|
||||
super().test_samestat_on_link()
|
||||
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.skipIf(os.getenv("CI"), "TODO: RUSTPYTHON, FileExistsError: (17, 'File exists (os error 17)')")
|
||||
class PathLikeTests(unittest.TestCase):
|
||||
|
||||
path = posixpath
|
||||
|
||||
def setUp(self):
|
||||
self.file_name = os_helper.TESTFN
|
||||
self.file_path = FakePath(os_helper.TESTFN)
|
||||
self.file_name = TESTFN
|
||||
self.file_path = FakePath(TESTFN)
|
||||
self.addCleanup(os_helper.unlink, self.file_name)
|
||||
with open(self.file_name, 'xb', 0) as file:
|
||||
file.write(b"test_posixpath.PathLikeTests")
|
||||
@@ -854,9 +1160,12 @@ class PathLikeTests(unittest.TestCase):
|
||||
def test_path_abspath(self):
|
||||
self.assertPathEqual(self.path.abspath)
|
||||
|
||||
def test_path_realpath(self):
|
||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
||||
def test_path_realpath(self, kwargs):
|
||||
self.assertPathEqual(self.path.realpath)
|
||||
|
||||
self.assertPathEqual(partial(self.path.realpath, **kwargs))
|
||||
|
||||
def test_path_relpath(self):
|
||||
self.assertPathEqual(self.path.relpath)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user