mirror of
https://github.com/python/cpython.git
synced 2025-12-10 19:10:59 +00:00
gh-71189: Support all-but-last mode in os.path.realpath() (GH-117562)
Some checks are pending
Tests / Change detection (push) Waiting to run
Tests / Docs (push) Blocked by required conditions
Tests / Windows MSI (push) Blocked by required conditions
Tests / Check if Autoconf files are up to date (push) Blocked by required conditions
Tests / Check if generated files are up to date (push) Blocked by required conditions
Tests / (push) Blocked by required conditions
Tests / Ubuntu SSL tests with OpenSSL (push) Blocked by required conditions
Tests / Ubuntu SSL tests with AWS-LC (push) Blocked by required conditions
Tests / WASI (push) Blocked by required conditions
Tests / Hypothesis tests on Ubuntu (push) Blocked by required conditions
Tests / Address sanitizer (push) Blocked by required conditions
Tests / Sanitizers (push) Blocked by required conditions
Tests / Cross build Linux (push) Blocked by required conditions
Tests / CIFuzz (push) Blocked by required conditions
Tests / All required checks pass (push) Blocked by required conditions
Lint / lint (push) Waiting to run
mypy / Run mypy on Lib/_pyrepl (push) Waiting to run
mypy / Run mypy on Lib/test/libregrtest (push) Waiting to run
mypy / Run mypy on Lib/tomllib (push) Waiting to run
mypy / Run mypy on Tools/build (push) Waiting to run
mypy / Run mypy on Tools/cases_generator (push) Waiting to run
mypy / Run mypy on Tools/clinic (push) Waiting to run
mypy / Run mypy on Tools/jit (push) Waiting to run
mypy / Run mypy on Tools/peg_generator (push) Waiting to run
Some checks are pending
Tests / Change detection (push) Waiting to run
Tests / Docs (push) Blocked by required conditions
Tests / Windows MSI (push) Blocked by required conditions
Tests / Check if Autoconf files are up to date (push) Blocked by required conditions
Tests / Check if generated files are up to date (push) Blocked by required conditions
Tests / (push) Blocked by required conditions
Tests / Ubuntu SSL tests with OpenSSL (push) Blocked by required conditions
Tests / Ubuntu SSL tests with AWS-LC (push) Blocked by required conditions
Tests / WASI (push) Blocked by required conditions
Tests / Hypothesis tests on Ubuntu (push) Blocked by required conditions
Tests / Address sanitizer (push) Blocked by required conditions
Tests / Sanitizers (push) Blocked by required conditions
Tests / Cross build Linux (push) Blocked by required conditions
Tests / CIFuzz (push) Blocked by required conditions
Tests / All required checks pass (push) Blocked by required conditions
Lint / lint (push) Waiting to run
mypy / Run mypy on Lib/_pyrepl (push) Waiting to run
mypy / Run mypy on Lib/test/libregrtest (push) Waiting to run
mypy / Run mypy on Lib/tomllib (push) Waiting to run
mypy / Run mypy on Tools/build (push) Waiting to run
mypy / Run mypy on Tools/cases_generator (push) Waiting to run
mypy / Run mypy on Tools/clinic (push) Waiting to run
mypy / Run mypy on Tools/jit (push) Waiting to run
mypy / Run mypy on Tools/peg_generator (push) Waiting to run
This commit is contained in:
parent
5236b0281b
commit
9d3b53c47f
9 changed files with 332 additions and 37 deletions
|
|
@ -424,6 +424,8 @@ the :mod:`glob` module.)
|
||||||
re-raised.
|
re-raised.
|
||||||
In particular, :exc:`FileNotFoundError` is raised if *path* does not exist,
|
In particular, :exc:`FileNotFoundError` is raised if *path* does not exist,
|
||||||
or another :exc:`OSError` if it is otherwise inaccessible.
|
or another :exc:`OSError` if it is otherwise inaccessible.
|
||||||
|
If *strict* is :data:`ALL_BUT_LAST`, the last component of the path
|
||||||
|
is allowed to be missing, but all other errors are raised.
|
||||||
|
|
||||||
If *strict* is :py:data:`os.path.ALLOW_MISSING`, errors other than
|
If *strict* is :py:data:`os.path.ALLOW_MISSING`, errors other than
|
||||||
:exc:`FileNotFoundError` are re-raised (as with ``strict=True``).
|
:exc:`FileNotFoundError` are re-raised (as with ``strict=True``).
|
||||||
|
|
@ -448,8 +450,14 @@ the :mod:`glob` module.)
|
||||||
The *strict* parameter was added.
|
The *strict* parameter was added.
|
||||||
|
|
||||||
.. versionchanged:: next
|
.. versionchanged:: next
|
||||||
The :py:data:`~os.path.ALLOW_MISSING` value for the *strict* parameter
|
The :data:`ALL_BUT_LAST` and :data:`ALLOW_MISSING` values for
|
||||||
was added.
|
the *strict* parameter was added.
|
||||||
|
|
||||||
|
.. data:: ALL_BUT_LAST
|
||||||
|
|
||||||
|
Special value used for the *strict* argument in :func:`realpath`.
|
||||||
|
|
||||||
|
.. versionadded:: next
|
||||||
|
|
||||||
.. data:: ALLOW_MISSING
|
.. data:: ALLOW_MISSING
|
||||||
|
|
||||||
|
|
@ -457,6 +465,7 @@ the :mod:`glob` module.)
|
||||||
|
|
||||||
.. versionadded:: next
|
.. versionadded:: next
|
||||||
|
|
||||||
|
|
||||||
.. function:: relpath(path, start=os.curdir)
|
.. function:: relpath(path, start=os.curdir)
|
||||||
|
|
||||||
Return a relative filepath to *path* either from the current directory or
|
Return a relative filepath to *path* either from the current directory or
|
||||||
|
|
|
||||||
|
|
@ -264,13 +264,15 @@ math
|
||||||
os.path
|
os.path
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
* Add support of the all-but-last mode in :func:`~os.path.realpath`.
|
||||||
|
(Contributed by Serhiy Storchaka in :gh:`71189`.)
|
||||||
|
|
||||||
* The *strict* parameter to :func:`os.path.realpath` accepts a new value,
|
* The *strict* parameter to :func:`os.path.realpath` accepts a new value,
|
||||||
:data:`os.path.ALLOW_MISSING`.
|
:data:`os.path.ALLOW_MISSING`.
|
||||||
If used, errors other than :exc:`FileNotFoundError` will be re-raised;
|
If used, errors other than :exc:`FileNotFoundError` will be re-raised;
|
||||||
the resulting path can be missing but it will be free of symlinks.
|
the resulting path can be missing but it will be free of symlinks.
|
||||||
(Contributed by Petr Viktorin for :cve:`2025-4517`.)
|
(Contributed by Petr Viktorin for :cve:`2025-4517`.)
|
||||||
|
|
||||||
|
|
||||||
shelve
|
shelve
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@ import stat
|
||||||
|
|
||||||
__all__ = ['commonprefix', 'exists', 'getatime', 'getctime', 'getmtime',
|
__all__ = ['commonprefix', 'exists', 'getatime', 'getctime', 'getmtime',
|
||||||
'getsize', 'isdevdrive', 'isdir', 'isfile', 'isjunction', 'islink',
|
'getsize', 'isdevdrive', 'isdir', 'isfile', 'isjunction', 'islink',
|
||||||
'lexists', 'samefile', 'sameopenfile', 'samestat', 'ALLOW_MISSING']
|
'lexists', 'samefile', 'sameopenfile', 'samestat',
|
||||||
|
'ALL_BUT_LAST', 'ALLOW_MISSING']
|
||||||
|
|
||||||
|
|
||||||
# Does a path exist?
|
# Does a path exist?
|
||||||
|
|
@ -190,7 +191,17 @@ def _check_arg_types(funcname, *args):
|
||||||
if hasstr and hasbytes:
|
if hasstr and hasbytes:
|
||||||
raise TypeError("Can't mix strings and bytes in path components") from None
|
raise TypeError("Can't mix strings and bytes in path components") from None
|
||||||
|
|
||||||
# A singleton with a true boolean value.
|
|
||||||
|
# Singletons with a true boolean value.
|
||||||
|
|
||||||
|
@object.__new__
|
||||||
|
class ALL_BUT_LAST:
|
||||||
|
"""Special value for use in realpath()."""
|
||||||
|
def __repr__(self):
|
||||||
|
return 'os.path.ALL_BUT_LAST'
|
||||||
|
def __reduce__(self):
|
||||||
|
return self.__class__.__name__
|
||||||
|
|
||||||
@object.__new__
|
@object.__new__
|
||||||
class ALLOW_MISSING:
|
class ALLOW_MISSING:
|
||||||
"""Special value for use in realpath()."""
|
"""Special value for use in realpath()."""
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ __all__ = ["normcase","isabs","join","splitdrive","splitroot","split","splitext"
|
||||||
"abspath","curdir","pardir","sep","pathsep","defpath","altsep",
|
"abspath","curdir","pardir","sep","pathsep","defpath","altsep",
|
||||||
"extsep","devnull","realpath","supports_unicode_filenames","relpath",
|
"extsep","devnull","realpath","supports_unicode_filenames","relpath",
|
||||||
"samefile", "sameopenfile", "samestat", "commonpath", "isjunction",
|
"samefile", "sameopenfile", "samestat", "commonpath", "isjunction",
|
||||||
"isdevdrive", "ALLOW_MISSING"]
|
"isdevdrive", "ALL_BUT_LAST", "ALLOW_MISSING"]
|
||||||
|
|
||||||
def _get_bothseps(path):
|
def _get_bothseps(path):
|
||||||
if isinstance(path, bytes):
|
if isinstance(path, bytes):
|
||||||
|
|
@ -726,7 +726,8 @@ else:
|
||||||
|
|
||||||
if strict is ALLOW_MISSING:
|
if strict is ALLOW_MISSING:
|
||||||
ignored_error = FileNotFoundError
|
ignored_error = FileNotFoundError
|
||||||
strict = True
|
elif strict is ALL_BUT_LAST:
|
||||||
|
ignored_error = FileNotFoundError
|
||||||
elif strict:
|
elif strict:
|
||||||
ignored_error = ()
|
ignored_error = ()
|
||||||
else:
|
else:
|
||||||
|
|
@ -746,6 +747,12 @@ else:
|
||||||
raise OSError(str(ex)) from None
|
raise OSError(str(ex)) from None
|
||||||
path = normpath(path)
|
path = normpath(path)
|
||||||
except ignored_error as ex:
|
except ignored_error as ex:
|
||||||
|
if strict is ALL_BUT_LAST:
|
||||||
|
dirname, basename = split(path)
|
||||||
|
if not basename:
|
||||||
|
dirname, basename = split(path)
|
||||||
|
if not isdir(dirname):
|
||||||
|
raise
|
||||||
initial_winerror = ex.winerror
|
initial_winerror = ex.winerror
|
||||||
path = _getfinalpathname_nonstrict(path,
|
path = _getfinalpathname_nonstrict(path,
|
||||||
ignored_error=ignored_error)
|
ignored_error=ignored_error)
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,8 @@ __all__ = ["normcase","isabs","join","splitdrive","splitroot","split","splitext"
|
||||||
"samefile","sameopenfile","samestat",
|
"samefile","sameopenfile","samestat",
|
||||||
"curdir","pardir","sep","pathsep","defpath","altsep","extsep",
|
"curdir","pardir","sep","pathsep","defpath","altsep","extsep",
|
||||||
"devnull","realpath","supports_unicode_filenames","relpath",
|
"devnull","realpath","supports_unicode_filenames","relpath",
|
||||||
"commonpath", "isjunction","isdevdrive","ALLOW_MISSING"]
|
"commonpath","isjunction","isdevdrive",
|
||||||
|
"ALL_BUT_LAST","ALLOW_MISSING"]
|
||||||
|
|
||||||
|
|
||||||
def _get_sep(path):
|
def _get_sep(path):
|
||||||
|
|
@ -404,7 +405,8 @@ symbolic links encountered in the path."""
|
||||||
getcwd = os.getcwd
|
getcwd = os.getcwd
|
||||||
if strict is ALLOW_MISSING:
|
if strict is ALLOW_MISSING:
|
||||||
ignored_error = FileNotFoundError
|
ignored_error = FileNotFoundError
|
||||||
strict = True
|
elif strict is ALL_BUT_LAST:
|
||||||
|
ignored_error = FileNotFoundError
|
||||||
elif strict:
|
elif strict:
|
||||||
ignored_error = ()
|
ignored_error = ()
|
||||||
else:
|
else:
|
||||||
|
|
@ -418,7 +420,7 @@ symbolic links encountered in the path."""
|
||||||
# indicates that a symlink target has been resolved, and that the original
|
# 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
|
# symlink path can be retrieved by popping again. The [::-1] slice is a
|
||||||
# very fast way of spelling list(reversed(...)).
|
# very fast way of spelling list(reversed(...)).
|
||||||
rest = filename.split(sep)[::-1]
|
rest = filename.rstrip(sep).split(sep)[::-1]
|
||||||
|
|
||||||
# Number of unprocessed parts in 'rest'. This can differ from len(rest)
|
# Number of unprocessed parts in 'rest'. This can differ from len(rest)
|
||||||
# later, because 'rest' might contain markers for unresolved symlinks.
|
# later, because 'rest' might contain markers for unresolved symlinks.
|
||||||
|
|
@ -427,6 +429,7 @@ symbolic links encountered in the path."""
|
||||||
# The resolved path, which is absolute throughout this function.
|
# The resolved path, which is absolute throughout this function.
|
||||||
# Note: getcwd() returns a normalized and symlink-free path.
|
# Note: getcwd() returns a normalized and symlink-free path.
|
||||||
path = sep if filename.startswith(sep) else getcwd()
|
path = sep if filename.startswith(sep) else getcwd()
|
||||||
|
trailing_sep = filename.endswith(sep)
|
||||||
|
|
||||||
# Mapping from symlink paths to *fully resolved* symlink targets. If a
|
# Mapping from symlink paths to *fully resolved* symlink targets. If a
|
||||||
# symlink is encountered but not yet resolved, the value is None. This is
|
# symlink is encountered but not yet resolved, the value is None. This is
|
||||||
|
|
@ -459,7 +462,8 @@ symbolic links encountered in the path."""
|
||||||
try:
|
try:
|
||||||
st_mode = lstat(newpath).st_mode
|
st_mode = lstat(newpath).st_mode
|
||||||
if not stat.S_ISLNK(st_mode):
|
if not stat.S_ISLNK(st_mode):
|
||||||
if strict and part_count and not stat.S_ISDIR(st_mode):
|
if (strict and (part_count or trailing_sep)
|
||||||
|
and not stat.S_ISDIR(st_mode)):
|
||||||
raise OSError(errno.ENOTDIR, os.strerror(errno.ENOTDIR),
|
raise OSError(errno.ENOTDIR, os.strerror(errno.ENOTDIR),
|
||||||
newpath)
|
newpath)
|
||||||
path = newpath
|
path = newpath
|
||||||
|
|
@ -486,7 +490,8 @@ symbolic links encountered in the path."""
|
||||||
continue
|
continue
|
||||||
target = readlink(newpath)
|
target = readlink(newpath)
|
||||||
except ignored_error:
|
except ignored_error:
|
||||||
pass
|
if strict is ALL_BUT_LAST and part_count:
|
||||||
|
raise
|
||||||
else:
|
else:
|
||||||
# Resolve the symbolic link
|
# Resolve the symbolic link
|
||||||
if target.startswith(sep):
|
if target.startswith(sep):
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,10 @@
|
||||||
Tests common to genericpath, ntpath and posixpath
|
Tests common to genericpath, ntpath and posixpath
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import copy
|
||||||
import genericpath
|
import genericpath
|
||||||
import os
|
import os
|
||||||
|
import pickle
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
import warnings
|
import warnings
|
||||||
|
|
@ -320,6 +322,21 @@ class GenericTest:
|
||||||
fd2 = fp2.fileno()
|
fd2 = fp2.fileno()
|
||||||
self.assertTrue(self.pathmodule.sameopenfile(fd1, fd2))
|
self.assertTrue(self.pathmodule.sameopenfile(fd1, fd2))
|
||||||
|
|
||||||
|
def test_realpath_mode_values(self):
|
||||||
|
for name in 'ALL_BUT_LAST', 'ALLOW_MISSING':
|
||||||
|
with self.subTest(name):
|
||||||
|
mode = getattr(self.pathmodule, name)
|
||||||
|
self.assertEqual(repr(mode), 'os.path.' + name)
|
||||||
|
self.assertEqual(str(mode), 'os.path.' + name)
|
||||||
|
self.assertTrue(mode)
|
||||||
|
self.assertIs(copy.copy(mode), mode)
|
||||||
|
self.assertIs(copy.deepcopy(mode), mode)
|
||||||
|
for proto in range(pickle.HIGHEST_PROTOCOL+1):
|
||||||
|
with self.subTest(protocol=proto):
|
||||||
|
pickled = pickle.dumps(mode, proto)
|
||||||
|
unpickled = pickle.loads(pickled)
|
||||||
|
self.assertIs(unpickled, mode)
|
||||||
|
|
||||||
|
|
||||||
class TestGenericTest(GenericTest, unittest.TestCase):
|
class TestGenericTest(GenericTest, unittest.TestCase):
|
||||||
# Issue 16852: GenericTest can't inherit from unittest.TestCase
|
# Issue 16852: GenericTest can't inherit from unittest.TestCase
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import errno
|
||||||
import inspect
|
import inspect
|
||||||
import ntpath
|
import ntpath
|
||||||
import os
|
import os
|
||||||
|
|
@ -6,7 +7,7 @@ import subprocess
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
import warnings
|
import warnings
|
||||||
from ntpath import ALLOW_MISSING
|
from ntpath import ALL_BUT_LAST, ALLOW_MISSING
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import TestFailed, cpython_only, os_helper
|
from test.support import TestFailed, cpython_only, os_helper
|
||||||
from test.support.os_helper import FakePath
|
from test.support.os_helper import FakePath
|
||||||
|
|
@ -587,59 +588,63 @@ class TestNtpath(NtpathTestCase):
|
||||||
# gh-106242: Embedded nulls and non-strict fallback to abspath
|
# gh-106242: Embedded nulls and non-strict fallback to abspath
|
||||||
self.assertEqual(realpath(path, strict=False), path)
|
self.assertEqual(realpath(path, strict=False), path)
|
||||||
# gh-106242: Embedded nulls should raise OSError (not ValueError)
|
# gh-106242: Embedded nulls should raise OSError (not ValueError)
|
||||||
|
self.assertRaises(OSError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(OSError, realpath, path, strict=True)
|
self.assertRaises(OSError, realpath, path, strict=True)
|
||||||
self.assertRaises(OSError, realpath, path, strict=ALLOW_MISSING)
|
self.assertRaises(OSError, realpath, path, strict=ALLOW_MISSING)
|
||||||
path = ABSTFNb + b'\x00'
|
path = ABSTFNb + b'\x00'
|
||||||
self.assertEqual(realpath(path, strict=False), path)
|
self.assertEqual(realpath(path, strict=False), path)
|
||||||
|
self.assertRaises(OSError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(OSError, realpath, path, strict=True)
|
self.assertRaises(OSError, realpath, path, strict=True)
|
||||||
self.assertRaises(OSError, realpath, path, strict=ALLOW_MISSING)
|
self.assertRaises(OSError, realpath, path, strict=ALLOW_MISSING)
|
||||||
path = ABSTFN + '\\nonexistent\\x\x00'
|
path = ABSTFN + '\\nonexistent\\x\x00'
|
||||||
self.assertEqual(realpath(path, strict=False), path)
|
self.assertEqual(realpath(path, strict=False), path)
|
||||||
|
self.assertRaises(OSError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(OSError, realpath, path, strict=True)
|
self.assertRaises(OSError, realpath, path, strict=True)
|
||||||
self.assertRaises(OSError, realpath, path, strict=ALLOW_MISSING)
|
self.assertRaises(OSError, realpath, path, strict=ALLOW_MISSING)
|
||||||
path = ABSTFNb + b'\\nonexistent\\x\x00'
|
path = ABSTFNb + b'\\nonexistent\\x\x00'
|
||||||
self.assertEqual(realpath(path, strict=False), path)
|
self.assertEqual(realpath(path, strict=False), path)
|
||||||
|
self.assertRaises(OSError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(OSError, realpath, path, strict=True)
|
self.assertRaises(OSError, realpath, path, strict=True)
|
||||||
self.assertRaises(OSError, realpath, path, strict=ALLOW_MISSING)
|
self.assertRaises(OSError, realpath, path, strict=ALLOW_MISSING)
|
||||||
path = ABSTFN + '\x00\\..'
|
path = ABSTFN + '\x00\\..'
|
||||||
self.assertEqual(realpath(path, strict=False), os.getcwd())
|
self.assertEqual(realpath(path, strict=False), os.getcwd())
|
||||||
|
self.assertEqual(realpath(path, strict=ALL_BUT_LAST), os.getcwd())
|
||||||
self.assertEqual(realpath(path, strict=True), os.getcwd())
|
self.assertEqual(realpath(path, strict=True), os.getcwd())
|
||||||
self.assertEqual(realpath(path, strict=ALLOW_MISSING), os.getcwd())
|
self.assertEqual(realpath(path, strict=ALLOW_MISSING), os.getcwd())
|
||||||
path = ABSTFNb + b'\x00\\..'
|
path = ABSTFNb + b'\x00\\..'
|
||||||
self.assertEqual(realpath(path, strict=False), os.getcwdb())
|
self.assertEqual(realpath(path, strict=False), os.getcwdb())
|
||||||
|
self.assertEqual(realpath(path, strict=ALL_BUT_LAST), os.getcwdb())
|
||||||
self.assertEqual(realpath(path, strict=True), os.getcwdb())
|
self.assertEqual(realpath(path, strict=True), os.getcwdb())
|
||||||
self.assertEqual(realpath(path, strict=ALLOW_MISSING), os.getcwdb())
|
self.assertEqual(realpath(path, strict=ALLOW_MISSING), os.getcwdb())
|
||||||
path = ABSTFN + '\\nonexistent\\x\x00\\..'
|
path = ABSTFN + '\\nonexistent\\x\x00\\..'
|
||||||
self.assertEqual(realpath(path, strict=False), ABSTFN + '\\nonexistent')
|
self.assertEqual(realpath(path, strict=False), ABSTFN + '\\nonexistent')
|
||||||
|
self.assertRaises(OSError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(OSError, realpath, path, strict=True)
|
self.assertRaises(OSError, realpath, path, strict=True)
|
||||||
self.assertEqual(realpath(path, strict=ALLOW_MISSING), ABSTFN + '\\nonexistent')
|
self.assertEqual(realpath(path, strict=ALLOW_MISSING), ABSTFN + '\\nonexistent')
|
||||||
path = ABSTFNb + b'\\nonexistent\\x\x00\\..'
|
path = ABSTFNb + b'\\nonexistent\\x\x00\\..'
|
||||||
self.assertEqual(realpath(path, strict=False), ABSTFNb + b'\\nonexistent')
|
self.assertEqual(realpath(path, strict=False), ABSTFNb + b'\\nonexistent')
|
||||||
|
self.assertRaises(OSError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(OSError, realpath, path, strict=True)
|
self.assertRaises(OSError, realpath, path, strict=True)
|
||||||
self.assertEqual(realpath(path, strict=ALLOW_MISSING), ABSTFNb + b'\\nonexistent')
|
self.assertEqual(realpath(path, strict=ALLOW_MISSING), ABSTFNb + b'\\nonexistent')
|
||||||
|
|
||||||
@unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
|
@unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
|
||||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
@_parameterize({}, {'strict': True}, {'strict': ALL_BUT_LAST}, {'strict': ALLOW_MISSING})
|
||||||
def test_realpath_invalid_unicode_paths(self, kwargs):
|
def test_realpath_invalid_unicode_paths(self, kwargs):
|
||||||
realpath = ntpath.realpath
|
realpath = ntpath.realpath
|
||||||
ABSTFN = ntpath.abspath(os_helper.TESTFN)
|
ABSTFN = ntpath.abspath(os_helper.TESTFN)
|
||||||
ABSTFNb = os.fsencode(ABSTFN)
|
ABSTFNb = os.fsencode(ABSTFN)
|
||||||
path = ABSTFNb + b'\xff'
|
path = ABSTFNb + b'\xff'
|
||||||
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
||||||
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
|
||||||
path = ABSTFNb + b'\\nonexistent\\\xff'
|
path = ABSTFNb + b'\\nonexistent\\\xff'
|
||||||
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
||||||
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
|
||||||
path = ABSTFNb + b'\xff\\..'
|
path = ABSTFNb + b'\xff\\..'
|
||||||
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
||||||
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
|
||||||
path = ABSTFNb + b'\\nonexistent\\\xff\\..'
|
path = ABSTFNb + b'\\nonexistent\\\xff\\..'
|
||||||
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
||||||
self.assertRaises(UnicodeDecodeError, realpath, path, **kwargs)
|
|
||||||
|
|
||||||
@os_helper.skip_unless_symlink
|
@os_helper.skip_unless_symlink
|
||||||
@unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
|
@unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
|
||||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
@_parameterize({}, {'strict': True}, {'strict': ALL_BUT_LAST}, {'strict': ALLOW_MISSING})
|
||||||
def test_realpath_relative(self, kwargs):
|
def test_realpath_relative(self, kwargs):
|
||||||
ABSTFN = ntpath.abspath(os_helper.TESTFN)
|
ABSTFN = ntpath.abspath(os_helper.TESTFN)
|
||||||
open(ABSTFN, "wb").close()
|
open(ABSTFN, "wb").close()
|
||||||
|
|
@ -766,34 +771,53 @@ class TestNtpath(NtpathTestCase):
|
||||||
self.addCleanup(os_helper.unlink, ABSTFN + "a")
|
self.addCleanup(os_helper.unlink, ABSTFN + "a")
|
||||||
|
|
||||||
os.symlink(ABSTFN, ABSTFN)
|
os.symlink(ABSTFN, ABSTFN)
|
||||||
|
self.assertRaises(OSError, ntpath.realpath, ABSTFN, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(OSError, ntpath.realpath, ABSTFN, strict=True)
|
self.assertRaises(OSError, ntpath.realpath, ABSTFN, strict=True)
|
||||||
|
|
||||||
os.symlink(ABSTFN + "1", ABSTFN + "2")
|
os.symlink(ABSTFN + "1", ABSTFN + "2")
|
||||||
os.symlink(ABSTFN + "2", ABSTFN + "1")
|
os.symlink(ABSTFN + "2", ABSTFN + "1")
|
||||||
|
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1", strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1", strict=True)
|
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1", strict=True)
|
||||||
|
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "2", strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "2", strict=True)
|
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "2", strict=True)
|
||||||
|
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1\\x", strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1\\x", strict=True)
|
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1\\x", strict=True)
|
||||||
# Windows eliminates '..' components before resolving links, so the
|
# Windows eliminates '..' components before resolving links, so the
|
||||||
# following call is not expected to raise.
|
# following call is not expected to raise.
|
||||||
|
self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\..", strict=ALL_BUT_LAST),
|
||||||
|
ntpath.dirname(ABSTFN))
|
||||||
self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\..", strict=True),
|
self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\..", strict=True),
|
||||||
ntpath.dirname(ABSTFN))
|
ntpath.dirname(ABSTFN))
|
||||||
|
self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\..\\x", strict=ALL_BUT_LAST),
|
||||||
|
ntpath.dirname(ABSTFN) + "\\x")
|
||||||
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1\\..\\x", strict=True)
|
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1\\..\\x", strict=True)
|
||||||
os.symlink(ABSTFN + "x", ABSTFN + "y")
|
os.symlink(ABSTFN + "x", ABSTFN + "y")
|
||||||
|
self.assertPathEqual(ntpath.realpath(ABSTFN + "1\\..\\"
|
||||||
|
+ ntpath.basename(ABSTFN) + "y",
|
||||||
|
strict=ALL_BUT_LAST),
|
||||||
|
ABSTFN + "x")
|
||||||
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1\\..\\"
|
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1\\..\\"
|
||||||
+ ntpath.basename(ABSTFN) + "y",
|
+ ntpath.basename(ABSTFN) + "y",
|
||||||
strict=True)
|
strict=True)
|
||||||
|
self.assertRaises(OSError, ntpath.realpath,
|
||||||
|
ABSTFN + "1\\..\\" + ntpath.basename(ABSTFN) + "1",
|
||||||
|
strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(OSError, ntpath.realpath,
|
self.assertRaises(OSError, ntpath.realpath,
|
||||||
ABSTFN + "1\\..\\" + ntpath.basename(ABSTFN) + "1",
|
ABSTFN + "1\\..\\" + ntpath.basename(ABSTFN) + "1",
|
||||||
strict=True)
|
strict=True)
|
||||||
|
|
||||||
os.symlink(ntpath.basename(ABSTFN) + "a\\b", ABSTFN + "a")
|
os.symlink(ntpath.basename(ABSTFN) + "a\\b", ABSTFN + "a")
|
||||||
|
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "a", strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "a", strict=True)
|
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "a", strict=True)
|
||||||
|
|
||||||
os.symlink("..\\" + ntpath.basename(ntpath.dirname(ABSTFN))
|
os.symlink("..\\" + ntpath.basename(ntpath.dirname(ABSTFN))
|
||||||
+ "\\" + ntpath.basename(ABSTFN) + "c", ABSTFN + "c")
|
+ "\\" + ntpath.basename(ABSTFN) + "c", ABSTFN + "c")
|
||||||
|
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "c", strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "c", strict=True)
|
self.assertRaises(OSError, ntpath.realpath, ABSTFN + "c", strict=True)
|
||||||
|
|
||||||
# Test using relative path as well.
|
# Test using relative path as well.
|
||||||
|
self.assertRaises(OSError, ntpath.realpath, ntpath.basename(ABSTFN),
|
||||||
|
strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(OSError, ntpath.realpath, ntpath.basename(ABSTFN),
|
self.assertRaises(OSError, ntpath.realpath, ntpath.basename(ABSTFN),
|
||||||
strict=True)
|
strict=True)
|
||||||
|
|
||||||
|
|
@ -853,7 +877,7 @@ class TestNtpath(NtpathTestCase):
|
||||||
|
|
||||||
@os_helper.skip_unless_symlink
|
@os_helper.skip_unless_symlink
|
||||||
@unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
|
@unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
|
||||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
@_parameterize({}, {'strict': True}, {'strict': ALL_BUT_LAST}, {'strict': ALLOW_MISSING})
|
||||||
def test_realpath_symlink_prefix(self, kwargs):
|
def test_realpath_symlink_prefix(self, kwargs):
|
||||||
ABSTFN = ntpath.abspath(os_helper.TESTFN)
|
ABSTFN = ntpath.abspath(os_helper.TESTFN)
|
||||||
self.addCleanup(os_helper.unlink, ABSTFN + "3")
|
self.addCleanup(os_helper.unlink, ABSTFN + "3")
|
||||||
|
|
@ -891,6 +915,7 @@ class TestNtpath(NtpathTestCase):
|
||||||
tester("ntpath.realpath('NUL')", r'\\.\NUL')
|
tester("ntpath.realpath('NUL')", r'\\.\NUL')
|
||||||
tester("ntpath.realpath('NUL', strict=False)", r'\\.\NUL')
|
tester("ntpath.realpath('NUL', strict=False)", r'\\.\NUL')
|
||||||
tester("ntpath.realpath('NUL', strict=True)", r'\\.\NUL')
|
tester("ntpath.realpath('NUL', strict=True)", r'\\.\NUL')
|
||||||
|
tester("ntpath.realpath('NUL', strict=ALL_BUT_LAST)", r'\\.\NUL')
|
||||||
tester("ntpath.realpath('NUL', strict=ALLOW_MISSING)", r'\\.\NUL')
|
tester("ntpath.realpath('NUL', strict=ALLOW_MISSING)", r'\\.\NUL')
|
||||||
|
|
||||||
@unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
|
@unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
|
||||||
|
|
@ -915,7 +940,7 @@ class TestNtpath(NtpathTestCase):
|
||||||
|
|
||||||
self.assertPathEqual(test_file_long, ntpath.realpath(test_file_short))
|
self.assertPathEqual(test_file_long, ntpath.realpath(test_file_short))
|
||||||
|
|
||||||
for kwargs in {}, {'strict': True}, {'strict': ALLOW_MISSING}:
|
for kwargs in {}, {'strict': True}, {'strict': ALL_BUT_LAST}, {'strict': ALLOW_MISSING}:
|
||||||
with self.subTest(**kwargs):
|
with self.subTest(**kwargs):
|
||||||
with os_helper.change_cwd(test_dir_long):
|
with os_helper.change_cwd(test_dir_long):
|
||||||
self.assertPathEqual(
|
self.assertPathEqual(
|
||||||
|
|
@ -975,6 +1000,93 @@ class TestNtpath(NtpathTestCase):
|
||||||
|
|
||||||
self.assertPathEqual(test_file, ntpath.realpath(test_file_short))
|
self.assertPathEqual(test_file, ntpath.realpath(test_file_short))
|
||||||
|
|
||||||
|
@os_helper.skip_unless_symlink
|
||||||
|
@unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname')
|
||||||
|
def test_realpath_mode(self):
|
||||||
|
realpath = ntpath.realpath
|
||||||
|
ABSTFN = ntpath.abspath(os_helper.TESTFN)
|
||||||
|
self.addCleanup(os_helper.rmdir, ABSTFN)
|
||||||
|
self.addCleanup(os_helper.rmdir, ABSTFN + "/dir")
|
||||||
|
self.addCleanup(os_helper.unlink, ABSTFN + "/file")
|
||||||
|
self.addCleanup(os_helper.unlink, ABSTFN + "/dir/file2")
|
||||||
|
self.addCleanup(os_helper.unlink, ABSTFN + "/link")
|
||||||
|
self.addCleanup(os_helper.unlink, ABSTFN + "/link2")
|
||||||
|
self.addCleanup(os_helper.unlink, ABSTFN + "/broken")
|
||||||
|
self.addCleanup(os_helper.unlink, ABSTFN + "/cycle")
|
||||||
|
|
||||||
|
os.mkdir(ABSTFN)
|
||||||
|
os.mkdir(ABSTFN + "\\dir")
|
||||||
|
open(ABSTFN + "\\file", "wb").close()
|
||||||
|
open(ABSTFN + "\\dir\\file2", "wb").close()
|
||||||
|
os.symlink("file", ABSTFN + "\\link")
|
||||||
|
os.symlink("dir", ABSTFN + "\\link2")
|
||||||
|
os.symlink("nonexistent", ABSTFN + "\\broken")
|
||||||
|
os.symlink("cycle", ABSTFN + "\\cycle")
|
||||||
|
def check(path, modes, expected, errno=None):
|
||||||
|
path = path.replace('/', '\\')
|
||||||
|
if isinstance(expected, str):
|
||||||
|
assert errno is None
|
||||||
|
expected = expected.replace('/', os.sep)
|
||||||
|
for mode in modes:
|
||||||
|
with self.subTest(mode=mode):
|
||||||
|
self.assertEqual(realpath(path, strict=mode),
|
||||||
|
ABSTFN + expected)
|
||||||
|
else:
|
||||||
|
for mode in modes:
|
||||||
|
with self.subTest(mode=mode):
|
||||||
|
with self.assertRaises(expected) as cm:
|
||||||
|
realpath(path, strict=mode)
|
||||||
|
if errno is not None:
|
||||||
|
self.assertEqual(cm.exception.errno, errno)
|
||||||
|
|
||||||
|
self.enterContext(os_helper.change_cwd(ABSTFN))
|
||||||
|
all_modes = [False, ALLOW_MISSING, ALL_BUT_LAST, True]
|
||||||
|
check("file", all_modes, "/file")
|
||||||
|
check("file/", all_modes, "/file")
|
||||||
|
check("file/file2", [False, ALLOW_MISSING], "/file/file2")
|
||||||
|
check("file/file2", [ALL_BUT_LAST, True], FileNotFoundError)
|
||||||
|
check("file/.", all_modes, "/file")
|
||||||
|
check("file/../link2", all_modes, "/dir")
|
||||||
|
|
||||||
|
check("dir", all_modes, "/dir")
|
||||||
|
check("dir/", all_modes, "/dir")
|
||||||
|
check("dir/file2", all_modes, "/dir/file2")
|
||||||
|
|
||||||
|
check("link", all_modes, "/file")
|
||||||
|
check("link/", all_modes, "/file")
|
||||||
|
check("link/file2", [False, ALLOW_MISSING], "/file/file2")
|
||||||
|
check("link/file2", [ALL_BUT_LAST, True], FileNotFoundError)
|
||||||
|
check("link/.", all_modes, "/file")
|
||||||
|
check("link/../link", all_modes, "/file")
|
||||||
|
|
||||||
|
check("link2", all_modes, "/dir")
|
||||||
|
check("link2/", all_modes, "/dir")
|
||||||
|
check("link2/file2", all_modes, "/dir/file2")
|
||||||
|
|
||||||
|
check("nonexistent", [False, ALLOW_MISSING, ALL_BUT_LAST], "/nonexistent")
|
||||||
|
check("nonexistent", [True], FileNotFoundError)
|
||||||
|
check("nonexistent/", [False, ALLOW_MISSING, ALL_BUT_LAST], "/nonexistent")
|
||||||
|
check("nonexistent/", [True], FileNotFoundError)
|
||||||
|
check("nonexistent/file", [False, ALLOW_MISSING], "/nonexistent/file")
|
||||||
|
check("nonexistent/file", [ALL_BUT_LAST, True], FileNotFoundError)
|
||||||
|
check("nonexistent/../link", all_modes, "/file")
|
||||||
|
|
||||||
|
check("broken", [False, ALLOW_MISSING, ALL_BUT_LAST], "/nonexistent")
|
||||||
|
check("broken", [True], FileNotFoundError)
|
||||||
|
check("broken/", [False, ALLOW_MISSING, ALL_BUT_LAST], "/nonexistent")
|
||||||
|
check("broken/", [True], FileNotFoundError)
|
||||||
|
check("broken/file", [False, ALLOW_MISSING], "/nonexistent/file")
|
||||||
|
check("broken/file", [ALL_BUT_LAST, True], FileNotFoundError)
|
||||||
|
check("broken/../link", all_modes, "/file")
|
||||||
|
|
||||||
|
check("cycle", [False], "/cycle")
|
||||||
|
check("cycle", [ALLOW_MISSING, ALL_BUT_LAST, True], OSError, errno.EINVAL)
|
||||||
|
check("cycle/", [False], "/cycle")
|
||||||
|
check("cycle/", [ALLOW_MISSING, ALL_BUT_LAST, True], OSError, errno.EINVAL)
|
||||||
|
check("cycle/file", [False], "/cycle/file")
|
||||||
|
check("cycle/file", [ALLOW_MISSING, ALL_BUT_LAST, True], OSError, errno.EINVAL)
|
||||||
|
check("cycle/../link", all_modes, "/file")
|
||||||
|
|
||||||
def test_expandvars(self):
|
def test_expandvars(self):
|
||||||
with os_helper.EnvironmentVarGuard() as env:
|
with os_helper.EnvironmentVarGuard() as env:
|
||||||
env.clear()
|
env.clear()
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import errno
|
||||||
import inspect
|
import inspect
|
||||||
import os
|
import os
|
||||||
import posixpath
|
import posixpath
|
||||||
|
|
@ -5,7 +6,7 @@ import random
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from posixpath import realpath, abspath, dirname, basename, ALLOW_MISSING
|
from posixpath import realpath, abspath, dirname, basename, ALL_BUT_LAST, ALLOW_MISSING
|
||||||
from test import support
|
from test import support
|
||||||
from test import test_genericpath
|
from test import test_genericpath
|
||||||
from test.support import import_helper
|
from test.support import import_helper
|
||||||
|
|
@ -448,7 +449,7 @@ class PosixPathTest(unittest.TestCase):
|
||||||
self.assertEqual(result, expected)
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
@skip_if_ABSTFN_contains_backslash
|
@skip_if_ABSTFN_contains_backslash
|
||||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
@_parameterize({}, {'strict': True}, {'strict': ALL_BUT_LAST}, {'strict': ALLOW_MISSING})
|
||||||
def test_realpath_curdir(self, kwargs):
|
def test_realpath_curdir(self, kwargs):
|
||||||
self.assertEqual(realpath('.', **kwargs), os.getcwd())
|
self.assertEqual(realpath('.', **kwargs), os.getcwd())
|
||||||
self.assertEqual(realpath('./.', **kwargs), os.getcwd())
|
self.assertEqual(realpath('./.', **kwargs), os.getcwd())
|
||||||
|
|
@ -459,7 +460,7 @@ class PosixPathTest(unittest.TestCase):
|
||||||
self.assertEqual(realpath(b'/'.join([b'.'] * 100), **kwargs), os.getcwdb())
|
self.assertEqual(realpath(b'/'.join([b'.'] * 100), **kwargs), os.getcwdb())
|
||||||
|
|
||||||
@skip_if_ABSTFN_contains_backslash
|
@skip_if_ABSTFN_contains_backslash
|
||||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
@_parameterize({}, {'strict': True}, {'strict': ALL_BUT_LAST}, {'strict': ALLOW_MISSING})
|
||||||
def test_realpath_pardir(self, kwargs):
|
def test_realpath_pardir(self, kwargs):
|
||||||
self.assertEqual(realpath('..', **kwargs), dirname(os.getcwd()))
|
self.assertEqual(realpath('..', **kwargs), dirname(os.getcwd()))
|
||||||
self.assertEqual(realpath('../..', **kwargs), dirname(dirname(os.getcwd())))
|
self.assertEqual(realpath('../..', **kwargs), dirname(dirname(os.getcwd())))
|
||||||
|
|
@ -495,35 +496,43 @@ class PosixPathTest(unittest.TestCase):
|
||||||
def test_realpath_invalid_paths(self):
|
def test_realpath_invalid_paths(self):
|
||||||
path = '/\x00'
|
path = '/\x00'
|
||||||
self.assertRaises(ValueError, realpath, path, strict=False)
|
self.assertRaises(ValueError, realpath, path, strict=False)
|
||||||
|
self.assertRaises(ValueError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(ValueError, realpath, path, strict=True)
|
self.assertRaises(ValueError, realpath, path, strict=True)
|
||||||
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
||||||
path = b'/\x00'
|
path = b'/\x00'
|
||||||
self.assertRaises(ValueError, realpath, path, strict=False)
|
self.assertRaises(ValueError, realpath, path, strict=False)
|
||||||
|
self.assertRaises(ValueError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(ValueError, realpath, path, strict=True)
|
self.assertRaises(ValueError, realpath, path, strict=True)
|
||||||
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
||||||
path = '/nonexistent/x\x00'
|
path = '/nonexistent/x\x00'
|
||||||
self.assertRaises(ValueError, realpath, path, strict=False)
|
self.assertRaises(ValueError, realpath, path, strict=False)
|
||||||
|
self.assertRaises(FileNotFoundError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
||||||
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
||||||
path = b'/nonexistent/x\x00'
|
path = b'/nonexistent/x\x00'
|
||||||
self.assertRaises(ValueError, realpath, path, strict=False)
|
self.assertRaises(ValueError, realpath, path, strict=False)
|
||||||
|
self.assertRaises(FileNotFoundError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
||||||
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
||||||
path = '/\x00/..'
|
path = '/\x00/..'
|
||||||
self.assertRaises(ValueError, realpath, path, strict=False)
|
self.assertRaises(ValueError, realpath, path, strict=False)
|
||||||
|
self.assertRaises(ValueError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(ValueError, realpath, path, strict=True)
|
self.assertRaises(ValueError, realpath, path, strict=True)
|
||||||
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
||||||
path = b'/\x00/..'
|
path = b'/\x00/..'
|
||||||
self.assertRaises(ValueError, realpath, path, strict=False)
|
self.assertRaises(ValueError, realpath, path, strict=False)
|
||||||
|
self.assertRaises(ValueError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(ValueError, realpath, path, strict=True)
|
self.assertRaises(ValueError, realpath, path, strict=True)
|
||||||
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
||||||
|
|
||||||
path = '/nonexistent/x\x00/..'
|
path = '/nonexistent/x\x00/..'
|
||||||
self.assertRaises(ValueError, realpath, path, strict=False)
|
self.assertRaises(ValueError, realpath, path, strict=False)
|
||||||
|
self.assertRaises(FileNotFoundError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
||||||
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
||||||
path = b'/nonexistent/x\x00/..'
|
path = b'/nonexistent/x\x00/..'
|
||||||
self.assertRaises(ValueError, realpath, path, strict=False)
|
self.assertRaises(ValueError, realpath, path, strict=False)
|
||||||
|
self.assertRaises(FileNotFoundError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
||||||
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
self.assertRaises(ValueError, realpath, path, strict=ALLOW_MISSING)
|
||||||
|
|
||||||
|
|
@ -534,6 +543,7 @@ class PosixPathTest(unittest.TestCase):
|
||||||
self.assertEqual(realpath(path, strict=ALLOW_MISSING), path)
|
self.assertEqual(realpath(path, strict=ALLOW_MISSING), path)
|
||||||
else:
|
else:
|
||||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=False)
|
self.assertRaises(UnicodeEncodeError, realpath, path, strict=False)
|
||||||
|
self.assertRaises(UnicodeEncodeError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=True)
|
self.assertRaises(UnicodeEncodeError, realpath, path, strict=True)
|
||||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=ALLOW_MISSING)
|
self.assertRaises(UnicodeEncodeError, realpath, path, strict=ALLOW_MISSING)
|
||||||
path = '/nonexistent/\udfff'
|
path = '/nonexistent/\udfff'
|
||||||
|
|
@ -543,6 +553,7 @@ class PosixPathTest(unittest.TestCase):
|
||||||
else:
|
else:
|
||||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=False)
|
self.assertRaises(UnicodeEncodeError, realpath, path, strict=False)
|
||||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=ALLOW_MISSING)
|
self.assertRaises(UnicodeEncodeError, realpath, path, strict=ALLOW_MISSING)
|
||||||
|
self.assertRaises(FileNotFoundError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
||||||
path = '/\udfff/..'
|
path = '/\udfff/..'
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
|
|
@ -551,6 +562,7 @@ class PosixPathTest(unittest.TestCase):
|
||||||
self.assertEqual(realpath(path, strict=ALLOW_MISSING), '/')
|
self.assertEqual(realpath(path, strict=ALLOW_MISSING), '/')
|
||||||
else:
|
else:
|
||||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=False)
|
self.assertRaises(UnicodeEncodeError, realpath, path, strict=False)
|
||||||
|
self.assertRaises(UnicodeEncodeError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=True)
|
self.assertRaises(UnicodeEncodeError, realpath, path, strict=True)
|
||||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=ALLOW_MISSING)
|
self.assertRaises(UnicodeEncodeError, realpath, path, strict=ALLOW_MISSING)
|
||||||
path = '/nonexistent/\udfff/..'
|
path = '/nonexistent/\udfff/..'
|
||||||
|
|
@ -560,6 +572,7 @@ class PosixPathTest(unittest.TestCase):
|
||||||
else:
|
else:
|
||||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=False)
|
self.assertRaises(UnicodeEncodeError, realpath, path, strict=False)
|
||||||
self.assertRaises(UnicodeEncodeError, realpath, path, strict=ALLOW_MISSING)
|
self.assertRaises(UnicodeEncodeError, realpath, path, strict=ALLOW_MISSING)
|
||||||
|
self.assertRaises(FileNotFoundError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
||||||
|
|
||||||
path = b'/\xff'
|
path = b'/\xff'
|
||||||
|
|
@ -570,9 +583,11 @@ class PosixPathTest(unittest.TestCase):
|
||||||
else:
|
else:
|
||||||
self.assertEqual(realpath(path, strict=False), path)
|
self.assertEqual(realpath(path, strict=False), path)
|
||||||
if support.is_wasi:
|
if support.is_wasi:
|
||||||
|
self.assertRaises(OSError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(OSError, realpath, path, strict=True)
|
self.assertRaises(OSError, realpath, path, strict=True)
|
||||||
self.assertRaises(OSError, realpath, path, strict=ALLOW_MISSING)
|
self.assertRaises(OSError, realpath, path, strict=ALLOW_MISSING)
|
||||||
else:
|
else:
|
||||||
|
self.assertEqual(realpath(path, strict=ALL_BUT_LAST), path)
|
||||||
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
||||||
self.assertEqual(realpath(path, strict=ALLOW_MISSING), path)
|
self.assertEqual(realpath(path, strict=ALLOW_MISSING), path)
|
||||||
path = b'/nonexistent/\xff'
|
path = b'/nonexistent/\xff'
|
||||||
|
|
@ -582,14 +597,16 @@ class PosixPathTest(unittest.TestCase):
|
||||||
else:
|
else:
|
||||||
self.assertEqual(realpath(path, strict=False), path)
|
self.assertEqual(realpath(path, strict=False), path)
|
||||||
if support.is_wasi:
|
if support.is_wasi:
|
||||||
|
self.assertRaises(OSError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(OSError, realpath, path, strict=True)
|
self.assertRaises(OSError, realpath, path, strict=True)
|
||||||
self.assertRaises(OSError, realpath, path, strict=ALLOW_MISSING)
|
self.assertRaises(OSError, realpath, path, strict=ALLOW_MISSING)
|
||||||
else:
|
else:
|
||||||
|
self.assertRaises(FileNotFoundError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
||||||
|
|
||||||
@os_helper.skip_unless_symlink
|
@os_helper.skip_unless_symlink
|
||||||
@skip_if_ABSTFN_contains_backslash
|
@skip_if_ABSTFN_contains_backslash
|
||||||
@_parameterize({}, {'strict': ALLOW_MISSING})
|
@_parameterize({}, {'strict': ALL_BUT_LAST}, {'strict': ALLOW_MISSING})
|
||||||
def test_realpath_relative(self, kwargs):
|
def test_realpath_relative(self, kwargs):
|
||||||
try:
|
try:
|
||||||
os.symlink(posixpath.relpath(ABSTFN+"1"), ABSTFN)
|
os.symlink(posixpath.relpath(ABSTFN+"1"), ABSTFN)
|
||||||
|
|
@ -599,12 +616,14 @@ class PosixPathTest(unittest.TestCase):
|
||||||
|
|
||||||
@os_helper.skip_unless_symlink
|
@os_helper.skip_unless_symlink
|
||||||
@skip_if_ABSTFN_contains_backslash
|
@skip_if_ABSTFN_contains_backslash
|
||||||
@_parameterize({}, {'strict': ALLOW_MISSING})
|
def test_realpath_missing_pardir(self):
|
||||||
def test_realpath_missing_pardir(self, kwargs):
|
|
||||||
try:
|
try:
|
||||||
os.symlink(TESTFN + "1", TESTFN)
|
os.symlink(TESTFN + "1", TESTFN)
|
||||||
self.assertEqual(
|
path = "nonexistent/../" + TESTFN
|
||||||
realpath("nonexistent/../" + TESTFN, **kwargs), ABSTFN + "1")
|
self.assertEqual(realpath(path), ABSTFN + "1")
|
||||||
|
self.assertEqual(realpath(path, strict=ALLOW_MISSING), ABSTFN + "1")
|
||||||
|
self.assertRaises(FileNotFoundError, realpath, path, strict=ALL_BUT_LAST)
|
||||||
|
self.assertRaises(FileNotFoundError, realpath, path, strict=True)
|
||||||
finally:
|
finally:
|
||||||
os_helper.unlink(TESTFN)
|
os_helper.unlink(TESTFN)
|
||||||
|
|
||||||
|
|
@ -651,7 +670,7 @@ class PosixPathTest(unittest.TestCase):
|
||||||
|
|
||||||
@os_helper.skip_unless_symlink
|
@os_helper.skip_unless_symlink
|
||||||
@skip_if_ABSTFN_contains_backslash
|
@skip_if_ABSTFN_contains_backslash
|
||||||
@_parameterize({'strict': True}, {'strict': ALLOW_MISSING})
|
@_parameterize({'strict': True}, {'strict': ALL_BUT_LAST}, {'strict': ALLOW_MISSING})
|
||||||
def test_realpath_symlink_loops_strict(self, kwargs):
|
def test_realpath_symlink_loops_strict(self, kwargs):
|
||||||
# Bug #43757, raise OSError if we get into an infinite symlink loop in
|
# Bug #43757, raise OSError if we get into an infinite symlink loop in
|
||||||
# the strict modes.
|
# the strict modes.
|
||||||
|
|
@ -693,7 +712,7 @@ class PosixPathTest(unittest.TestCase):
|
||||||
|
|
||||||
@os_helper.skip_unless_symlink
|
@os_helper.skip_unless_symlink
|
||||||
@skip_if_ABSTFN_contains_backslash
|
@skip_if_ABSTFN_contains_backslash
|
||||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
@_parameterize({}, {'strict': True}, {'strict': ALL_BUT_LAST}, {'strict': ALLOW_MISSING})
|
||||||
def test_realpath_repeated_indirect_symlinks(self, kwargs):
|
def test_realpath_repeated_indirect_symlinks(self, kwargs):
|
||||||
# Issue #6975.
|
# Issue #6975.
|
||||||
try:
|
try:
|
||||||
|
|
@ -708,7 +727,7 @@ class PosixPathTest(unittest.TestCase):
|
||||||
|
|
||||||
@os_helper.skip_unless_symlink
|
@os_helper.skip_unless_symlink
|
||||||
@skip_if_ABSTFN_contains_backslash
|
@skip_if_ABSTFN_contains_backslash
|
||||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
@_parameterize({}, {'strict': True}, {'strict': ALL_BUT_LAST}, {'strict': ALLOW_MISSING})
|
||||||
def test_realpath_deep_recursion(self, kwargs):
|
def test_realpath_deep_recursion(self, kwargs):
|
||||||
depth = 10
|
depth = 10
|
||||||
try:
|
try:
|
||||||
|
|
@ -728,7 +747,7 @@ class PosixPathTest(unittest.TestCase):
|
||||||
|
|
||||||
@os_helper.skip_unless_symlink
|
@os_helper.skip_unless_symlink
|
||||||
@skip_if_ABSTFN_contains_backslash
|
@skip_if_ABSTFN_contains_backslash
|
||||||
@_parameterize({}, {'strict': ALLOW_MISSING})
|
@_parameterize({}, {'strict': ALL_BUT_LAST}, {'strict': ALLOW_MISSING})
|
||||||
def test_realpath_resolve_parents(self, kwargs):
|
def test_realpath_resolve_parents(self, kwargs):
|
||||||
# We also need to resolve any symlinks in the parents of a relative
|
# We also need to resolve any symlinks in the parents of a relative
|
||||||
# path passed to realpath. E.g.: current working directory is
|
# path passed to realpath. E.g.: current working directory is
|
||||||
|
|
@ -749,7 +768,7 @@ class PosixPathTest(unittest.TestCase):
|
||||||
|
|
||||||
@os_helper.skip_unless_symlink
|
@os_helper.skip_unless_symlink
|
||||||
@skip_if_ABSTFN_contains_backslash
|
@skip_if_ABSTFN_contains_backslash
|
||||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
@_parameterize({}, {'strict': True}, {'strict': ALL_BUT_LAST}, {'strict': ALLOW_MISSING})
|
||||||
def test_realpath_resolve_before_normalizing(self, kwargs):
|
def test_realpath_resolve_before_normalizing(self, kwargs):
|
||||||
# Bug #990669: Symbolic links should be resolved before we
|
# Bug #990669: Symbolic links should be resolved before we
|
||||||
# normalize the path. E.g.: if we have directories 'a', 'k' and 'y'
|
# normalize the path. E.g.: if we have directories 'a', 'k' and 'y'
|
||||||
|
|
@ -778,7 +797,7 @@ class PosixPathTest(unittest.TestCase):
|
||||||
|
|
||||||
@os_helper.skip_unless_symlink
|
@os_helper.skip_unless_symlink
|
||||||
@skip_if_ABSTFN_contains_backslash
|
@skip_if_ABSTFN_contains_backslash
|
||||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
@_parameterize({}, {'strict': True}, {'strict': ALL_BUT_LAST}, {'strict': ALLOW_MISSING})
|
||||||
def test_realpath_resolve_first(self, kwargs):
|
def test_realpath_resolve_first(self, kwargs):
|
||||||
# Bug #1213894: The first component of the path, if not absolute,
|
# Bug #1213894: The first component of the path, if not absolute,
|
||||||
# must be resolved too.
|
# must be resolved too.
|
||||||
|
|
@ -816,7 +835,7 @@ class PosixPathTest(unittest.TestCase):
|
||||||
@skip_if_ABSTFN_contains_backslash
|
@skip_if_ABSTFN_contains_backslash
|
||||||
@unittest.skipIf(os.chmod not in os.supports_follow_symlinks, "Can't set symlink permissions")
|
@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()")
|
@unittest.skipIf(sys.platform != "darwin", "only macOS requires read permission to readlink()")
|
||||||
@_parameterize({'strict': True}, {'strict': ALLOW_MISSING})
|
@_parameterize({'strict': True}, {'strict': ALL_BUT_LAST}, {'strict': ALLOW_MISSING})
|
||||||
def test_realpath_unreadable_symlink_strict(self, kwargs):
|
def test_realpath_unreadable_symlink_strict(self, kwargs):
|
||||||
try:
|
try:
|
||||||
os.symlink(ABSTFN+"1", ABSTFN)
|
os.symlink(ABSTFN+"1", ABSTFN)
|
||||||
|
|
@ -842,6 +861,7 @@ class PosixPathTest(unittest.TestCase):
|
||||||
os.chmod(ABSTFN, 0o000)
|
os.chmod(ABSTFN, 0o000)
|
||||||
self.assertEqual(realpath(ABSTFN, strict=False), ABSTFN)
|
self.assertEqual(realpath(ABSTFN, strict=False), ABSTFN)
|
||||||
self.assertEqual(realpath(ABSTFN, strict=True), ABSTFN)
|
self.assertEqual(realpath(ABSTFN, strict=True), ABSTFN)
|
||||||
|
self.assertEqual(realpath(ABSTFN, strict=ALL_BUT_LAST), ABSTFN)
|
||||||
self.assertEqual(realpath(ABSTFN, strict=ALLOW_MISSING), ABSTFN)
|
self.assertEqual(realpath(ABSTFN, strict=ALLOW_MISSING), ABSTFN)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -855,6 +875,8 @@ class PosixPathTest(unittest.TestCase):
|
||||||
ABSTFN + '/k')
|
ABSTFN + '/k')
|
||||||
self.assertRaises(PermissionError, realpath, ABSTFN + '/k',
|
self.assertRaises(PermissionError, realpath, ABSTFN + '/k',
|
||||||
strict=True)
|
strict=True)
|
||||||
|
self.assertRaises(PermissionError, realpath, ABSTFN + '/k',
|
||||||
|
strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(PermissionError, realpath, ABSTFN + '/k',
|
self.assertRaises(PermissionError, realpath, ABSTFN + '/k',
|
||||||
strict=ALLOW_MISSING)
|
strict=ALLOW_MISSING)
|
||||||
|
|
||||||
|
|
@ -862,6 +884,8 @@ class PosixPathTest(unittest.TestCase):
|
||||||
ABSTFN + '/missing')
|
ABSTFN + '/missing')
|
||||||
self.assertRaises(PermissionError, realpath, ABSTFN + '/missing',
|
self.assertRaises(PermissionError, realpath, ABSTFN + '/missing',
|
||||||
strict=True)
|
strict=True)
|
||||||
|
self.assertRaises(PermissionError, realpath, ABSTFN + '/missing',
|
||||||
|
strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(PermissionError, realpath, ABSTFN + '/missing',
|
self.assertRaises(PermissionError, realpath, ABSTFN + '/missing',
|
||||||
strict=ALLOW_MISSING)
|
strict=ALLOW_MISSING)
|
||||||
finally:
|
finally:
|
||||||
|
|
@ -875,25 +899,30 @@ class PosixPathTest(unittest.TestCase):
|
||||||
with open(ABSTFN, 'w') as f:
|
with open(ABSTFN, 'w') as f:
|
||||||
f.write('test_posixpath wuz ere')
|
f.write('test_posixpath wuz ere')
|
||||||
self.assertEqual(realpath(ABSTFN, strict=False), ABSTFN)
|
self.assertEqual(realpath(ABSTFN, strict=False), ABSTFN)
|
||||||
|
self.assertEqual(realpath(ABSTFN, strict=ALL_BUT_LAST), ABSTFN)
|
||||||
self.assertEqual(realpath(ABSTFN, strict=True), ABSTFN)
|
self.assertEqual(realpath(ABSTFN, strict=True), ABSTFN)
|
||||||
self.assertEqual(realpath(ABSTFN, strict=ALLOW_MISSING), ABSTFN)
|
self.assertEqual(realpath(ABSTFN, strict=ALLOW_MISSING), ABSTFN)
|
||||||
|
|
||||||
self.assertEqual(realpath(ABSTFN + "/", strict=False), ABSTFN)
|
self.assertEqual(realpath(ABSTFN + "/", strict=False), ABSTFN)
|
||||||
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/", strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/", strict=True)
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/", strict=True)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/",
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/",
|
||||||
strict=ALLOW_MISSING)
|
strict=ALLOW_MISSING)
|
||||||
|
|
||||||
self.assertEqual(realpath(ABSTFN + "/.", strict=False), ABSTFN)
|
self.assertEqual(realpath(ABSTFN + "/.", strict=False), ABSTFN)
|
||||||
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.", strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.", strict=True)
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.", strict=True)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.",
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.",
|
||||||
strict=ALLOW_MISSING)
|
strict=ALLOW_MISSING)
|
||||||
|
|
||||||
self.assertEqual(realpath(ABSTFN + "/..", strict=False), dirname(ABSTFN))
|
self.assertEqual(realpath(ABSTFN + "/..", strict=False), dirname(ABSTFN))
|
||||||
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..", strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..", strict=True)
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..", strict=True)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..",
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..",
|
||||||
strict=ALLOW_MISSING)
|
strict=ALLOW_MISSING)
|
||||||
|
|
||||||
self.assertEqual(realpath(ABSTFN + "/subdir", strict=False), ABSTFN + "/subdir")
|
self.assertEqual(realpath(ABSTFN + "/subdir", strict=False), ABSTFN + "/subdir")
|
||||||
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir", strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir", strict=True)
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir", strict=True)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir",
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir",
|
||||||
strict=ALLOW_MISSING)
|
strict=ALLOW_MISSING)
|
||||||
|
|
@ -908,25 +937,30 @@ class PosixPathTest(unittest.TestCase):
|
||||||
f.write('test_posixpath wuz ere')
|
f.write('test_posixpath wuz ere')
|
||||||
os.symlink(ABSTFN + "1", ABSTFN)
|
os.symlink(ABSTFN + "1", ABSTFN)
|
||||||
self.assertEqual(realpath(ABSTFN, strict=False), ABSTFN + "1")
|
self.assertEqual(realpath(ABSTFN, strict=False), ABSTFN + "1")
|
||||||
|
self.assertEqual(realpath(ABSTFN, strict=ALL_BUT_LAST), ABSTFN + "1")
|
||||||
self.assertEqual(realpath(ABSTFN, strict=True), ABSTFN + "1")
|
self.assertEqual(realpath(ABSTFN, strict=True), ABSTFN + "1")
|
||||||
self.assertEqual(realpath(ABSTFN, strict=ALLOW_MISSING), ABSTFN + "1")
|
self.assertEqual(realpath(ABSTFN, strict=ALLOW_MISSING), ABSTFN + "1")
|
||||||
|
|
||||||
self.assertEqual(realpath(ABSTFN + "/", strict=False), ABSTFN + "1")
|
self.assertEqual(realpath(ABSTFN + "/", strict=False), ABSTFN + "1")
|
||||||
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/", strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/", strict=True)
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/", strict=True)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/",
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/",
|
||||||
strict=ALLOW_MISSING)
|
strict=ALLOW_MISSING)
|
||||||
|
|
||||||
self.assertEqual(realpath(ABSTFN + "/.", strict=False), ABSTFN + "1")
|
self.assertEqual(realpath(ABSTFN + "/.", strict=False), ABSTFN + "1")
|
||||||
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.", strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.", strict=True)
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.", strict=True)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.",
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.",
|
||||||
strict=ALLOW_MISSING)
|
strict=ALLOW_MISSING)
|
||||||
|
|
||||||
self.assertEqual(realpath(ABSTFN + "/..", strict=False), dirname(ABSTFN))
|
self.assertEqual(realpath(ABSTFN + "/..", strict=False), dirname(ABSTFN))
|
||||||
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..", strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..", strict=True)
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..", strict=True)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..",
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..",
|
||||||
strict=ALLOW_MISSING)
|
strict=ALLOW_MISSING)
|
||||||
|
|
||||||
self.assertEqual(realpath(ABSTFN + "/subdir", strict=False), ABSTFN + "1/subdir")
|
self.assertEqual(realpath(ABSTFN + "/subdir", strict=False), ABSTFN + "1/subdir")
|
||||||
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir", strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir", strict=True)
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir", strict=True)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir",
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir",
|
||||||
strict=ALLOW_MISSING)
|
strict=ALLOW_MISSING)
|
||||||
|
|
@ -943,25 +977,30 @@ class PosixPathTest(unittest.TestCase):
|
||||||
os.symlink(ABSTFN + "2", ABSTFN + "1")
|
os.symlink(ABSTFN + "2", ABSTFN + "1")
|
||||||
os.symlink(ABSTFN + "1", ABSTFN)
|
os.symlink(ABSTFN + "1", ABSTFN)
|
||||||
self.assertEqual(realpath(ABSTFN, strict=False), ABSTFN + "2")
|
self.assertEqual(realpath(ABSTFN, strict=False), ABSTFN + "2")
|
||||||
|
self.assertEqual(realpath(ABSTFN, strict=ALL_BUT_LAST), ABSTFN + "2")
|
||||||
self.assertEqual(realpath(ABSTFN, strict=True), ABSTFN + "2")
|
self.assertEqual(realpath(ABSTFN, strict=True), 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.assertEqual(realpath(ABSTFN + "/", strict=False), ABSTFN + "2")
|
||||||
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/", strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/", strict=True)
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/", strict=True)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/",
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/",
|
||||||
strict=ALLOW_MISSING)
|
strict=ALLOW_MISSING)
|
||||||
|
|
||||||
self.assertEqual(realpath(ABSTFN + "/.", strict=False), ABSTFN + "2")
|
self.assertEqual(realpath(ABSTFN + "/.", strict=False), ABSTFN + "2")
|
||||||
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.", strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.", strict=True)
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.", strict=True)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.",
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/.",
|
||||||
strict=ALLOW_MISSING)
|
strict=ALLOW_MISSING)
|
||||||
|
|
||||||
self.assertEqual(realpath(ABSTFN + "/..", strict=False), dirname(ABSTFN))
|
self.assertEqual(realpath(ABSTFN + "/..", strict=False), dirname(ABSTFN))
|
||||||
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..", strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..", strict=True)
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..", strict=True)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..",
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/..",
|
||||||
strict=ALLOW_MISSING)
|
strict=ALLOW_MISSING)
|
||||||
|
|
||||||
self.assertEqual(realpath(ABSTFN + "/subdir", strict=False), ABSTFN + "2/subdir")
|
self.assertEqual(realpath(ABSTFN + "/subdir", strict=False), ABSTFN + "2/subdir")
|
||||||
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir", strict=ALL_BUT_LAST)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir", strict=True)
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir", strict=True)
|
||||||
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir",
|
self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/subdir",
|
||||||
strict=ALLOW_MISSING)
|
strict=ALLOW_MISSING)
|
||||||
|
|
@ -970,6 +1009,98 @@ class PosixPathTest(unittest.TestCase):
|
||||||
os_helper.unlink(ABSTFN + "1")
|
os_helper.unlink(ABSTFN + "1")
|
||||||
os_helper.unlink(ABSTFN + "2")
|
os_helper.unlink(ABSTFN + "2")
|
||||||
|
|
||||||
|
@os_helper.skip_unless_symlink
|
||||||
|
def test_realpath_mode(self):
|
||||||
|
self.addCleanup(os_helper.rmdir, ABSTFN)
|
||||||
|
self.addCleanup(os_helper.rmdir, ABSTFN + "/dir")
|
||||||
|
self.addCleanup(os_helper.unlink, ABSTFN + "/file")
|
||||||
|
self.addCleanup(os_helper.unlink, ABSTFN + "/dir/file2")
|
||||||
|
self.addCleanup(os_helper.unlink, ABSTFN + "/link")
|
||||||
|
self.addCleanup(os_helper.unlink, ABSTFN + "/link2")
|
||||||
|
self.addCleanup(os_helper.unlink, ABSTFN + "/broken")
|
||||||
|
self.addCleanup(os_helper.unlink, ABSTFN + "/cycle")
|
||||||
|
|
||||||
|
os.mkdir(ABSTFN)
|
||||||
|
os.mkdir(ABSTFN + "/dir")
|
||||||
|
open(ABSTFN + "/file", "wb").close()
|
||||||
|
open(ABSTFN + "/dir/file2", "wb").close()
|
||||||
|
os.symlink("file", ABSTFN + "/link")
|
||||||
|
os.symlink("dir", ABSTFN + "/link2")
|
||||||
|
os.symlink("nonexistent", ABSTFN + "/broken")
|
||||||
|
os.symlink("cycle", ABSTFN + "/cycle")
|
||||||
|
def check(path, modes, expected, errno=None):
|
||||||
|
if isinstance(expected, str):
|
||||||
|
assert errno is None
|
||||||
|
expected = expected.replace('/', os.sep)
|
||||||
|
for mode in modes:
|
||||||
|
with self.subTest(mode=mode):
|
||||||
|
self.assertEqual(realpath(path, strict=mode).replace('/', os.sep),
|
||||||
|
ABSTFN.replace('/', os.sep) + expected)
|
||||||
|
else:
|
||||||
|
for mode in modes:
|
||||||
|
with self.subTest(mode=mode):
|
||||||
|
with self.assertRaises(expected) as cm:
|
||||||
|
realpath(path, strict=mode)
|
||||||
|
if errno is not None:
|
||||||
|
self.assertEqual(cm.exception.errno, errno)
|
||||||
|
|
||||||
|
self.enterContext(os_helper.change_cwd(ABSTFN))
|
||||||
|
all_modes = [False, ALLOW_MISSING, ALL_BUT_LAST, True]
|
||||||
|
check("file", all_modes, "/file")
|
||||||
|
check("file/", [False], "/file")
|
||||||
|
check("file/", [ALLOW_MISSING, ALL_BUT_LAST, True], NotADirectoryError)
|
||||||
|
check("file/file2", [False], "/file/file2")
|
||||||
|
check("file/file2", [ALLOW_MISSING, ALL_BUT_LAST, True], NotADirectoryError)
|
||||||
|
check("file/.", [False], "/file")
|
||||||
|
check("file/.", [ALLOW_MISSING, ALL_BUT_LAST, True], NotADirectoryError)
|
||||||
|
check("file/../link2", [False], "/dir")
|
||||||
|
check("file/../link2", [ALLOW_MISSING, ALL_BUT_LAST, True], NotADirectoryError)
|
||||||
|
|
||||||
|
check("dir", all_modes, "/dir")
|
||||||
|
check("dir/", all_modes, "/dir")
|
||||||
|
check("dir/file2", all_modes, "/dir/file2")
|
||||||
|
|
||||||
|
check("link", all_modes, "/file")
|
||||||
|
check("link/", [False], "/file")
|
||||||
|
check("link/", [ALLOW_MISSING, ALL_BUT_LAST, True], NotADirectoryError)
|
||||||
|
check("link/file2", [False], "/file/file2")
|
||||||
|
check("link/file2", [ALLOW_MISSING, ALL_BUT_LAST, True], NotADirectoryError)
|
||||||
|
check("link/.", [False], "/file")
|
||||||
|
check("link/.", [ALLOW_MISSING, ALL_BUT_LAST, True], NotADirectoryError)
|
||||||
|
check("link/../link", [False], "/file")
|
||||||
|
check("link/../link", [ALLOW_MISSING, ALL_BUT_LAST, True], NotADirectoryError)
|
||||||
|
|
||||||
|
check("link2", all_modes, "/dir")
|
||||||
|
check("link2/", all_modes, "/dir")
|
||||||
|
check("link2/file2", all_modes, "/dir/file2")
|
||||||
|
|
||||||
|
check("nonexistent", [False, ALLOW_MISSING, ALL_BUT_LAST], "/nonexistent")
|
||||||
|
check("nonexistent", [True], FileNotFoundError)
|
||||||
|
check("nonexistent/", [False, ALLOW_MISSING, ALL_BUT_LAST], "/nonexistent")
|
||||||
|
check("nonexistent/", [True], FileNotFoundError)
|
||||||
|
check("nonexistent/file", [False, ALLOW_MISSING], "/nonexistent/file")
|
||||||
|
check("nonexistent/file", [ALL_BUT_LAST, True], FileNotFoundError)
|
||||||
|
check("nonexistent/../link", [False, ALLOW_MISSING], "/file")
|
||||||
|
check("nonexistent/../link", [ALL_BUT_LAST, True], FileNotFoundError)
|
||||||
|
|
||||||
|
check("broken", [False, ALLOW_MISSING, ALL_BUT_LAST], "/nonexistent")
|
||||||
|
check("broken", [True], FileNotFoundError)
|
||||||
|
check("broken/", [False, ALLOW_MISSING, ALL_BUT_LAST], "/nonexistent")
|
||||||
|
check("broken/", [True], FileNotFoundError)
|
||||||
|
check("broken/file", [False, ALLOW_MISSING], "/nonexistent/file")
|
||||||
|
check("broken/file", [ALL_BUT_LAST, True], FileNotFoundError)
|
||||||
|
check("broken/../link", [False, ALLOW_MISSING], "/file")
|
||||||
|
check("broken/../link", [ALL_BUT_LAST, True], FileNotFoundError)
|
||||||
|
|
||||||
|
check("cycle", [False], "/cycle")
|
||||||
|
check("cycle", [ALLOW_MISSING, ALL_BUT_LAST, True], OSError, errno.ELOOP)
|
||||||
|
check("cycle/", [False], "/cycle")
|
||||||
|
check("cycle/", [ALLOW_MISSING, ALL_BUT_LAST, True], OSError, errno.ELOOP)
|
||||||
|
check("cycle/file", [False], "/cycle/file")
|
||||||
|
check("cycle/file", [ALLOW_MISSING, ALL_BUT_LAST, True], OSError, errno.ELOOP)
|
||||||
|
check("cycle/../link", [False], "/file")
|
||||||
|
check("cycle/../link", [ALLOW_MISSING, ALL_BUT_LAST, True], OSError, errno.ELOOP)
|
||||||
|
|
||||||
def test_relpath(self):
|
def test_relpath(self):
|
||||||
(real_getcwd, os.getcwd) = (os.getcwd, lambda: r"/home/user/bar")
|
(real_getcwd, os.getcwd) = (os.getcwd, lambda: r"/home/user/bar")
|
||||||
try:
|
try:
|
||||||
|
|
@ -1152,7 +1283,7 @@ class PathLikeTests(unittest.TestCase):
|
||||||
def test_path_abspath(self):
|
def test_path_abspath(self):
|
||||||
self.assertPathEqual(self.path.abspath)
|
self.assertPathEqual(self.path.abspath)
|
||||||
|
|
||||||
@_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING})
|
@_parameterize({}, {'strict': True}, {'strict': ALL_BUT_LAST}, {'strict': ALLOW_MISSING})
|
||||||
def test_path_realpath(self, kwargs):
|
def test_path_realpath(self, kwargs):
|
||||||
self.assertPathEqual(self.path.realpath)
|
self.assertPathEqual(self.path.realpath)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Add support of the all-but-last mode in :func:`os.path.realpath`.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue