From a124c42c9021d5c26df887007855dfd945f42f91 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Tue, 3 Jun 2025 01:14:30 +0200 Subject: [PATCH] Switch to singleton Co-authored-by: Serhiy Storchaka --- Doc/library/os.path.rst | 10 +++- Doc/whatsnew/3.15.rst | 2 +- Lib/genericpath.py | 11 +++- Lib/ntpath.py | 4 +- Lib/posixpath.py | 4 +- Lib/tarfile.py | 7 +-- Lib/test/test_ntpath.py | 67 ++++++++++++------------ Lib/test/test_posixpath.py | 104 ++++++++++++++++++------------------- 8 files changed, 113 insertions(+), 96 deletions(-) diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst index 70ce36e9320552..4c044119d52194 100644 --- a/Doc/library/os.path.rst +++ b/Doc/library/os.path.rst @@ -424,7 +424,7 @@ the :mod:`glob` module.) In particular, :exc:`FileNotFoundError` is raised if *path* does not exist, or another :exc:`OSError` if it is otherwise inaccessible. - If *strict* is the string ``'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``). Thus, the returned path will not contain any symbolic links, but the named file and some of its parent directories may be missing. @@ -447,7 +447,13 @@ the :mod:`glob` module.) The *strict* parameter was added. .. versionchanged:: next - The ``'allow_missing'`` value for *strict* parameter was added. + The :py:data:`~ntpath.ALLOW_MISSING` value for *strict* parameter was added. + +.. data:: ALLOW_MISSING + + Special value used for the *strict* argument in :func:`realpath`. + + .. versionadded:: next .. function:: relpath(path, start=os.curdir) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index ff1aa259c3fe69..daf0b2b8d65b26 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -116,7 +116,7 @@ os.path ------- * The *strict* parameter to :func:`os.path.realpath` accepts a new value, - ``'allow_missing'``. + :data:`os.path.ALLOW_MISSING`. If used, errors other than :exc:`FileNotFoundError` will be re-raised; the resulting path can be missing but it will be free of symlinks. (Contributed by Petr Viktorin for :cve:`2025-4517`.) diff --git a/Lib/genericpath.py b/Lib/genericpath.py index ba7b0a13c7f81d..9363f564aab7a6 100644 --- a/Lib/genericpath.py +++ b/Lib/genericpath.py @@ -8,7 +8,7 @@ __all__ = ['commonprefix', 'exists', 'getatime', 'getctime', 'getmtime', 'getsize', 'isdevdrive', 'isdir', 'isfile', 'isjunction', 'islink', - 'lexists', 'samefile', 'sameopenfile', 'samestat'] + 'lexists', 'samefile', 'sameopenfile', 'samestat', 'ALLOW_MISSING'] # Does a path exist? @@ -189,3 +189,12 @@ def _check_arg_types(funcname, *args): f'os.PathLike object, not {s.__class__.__name__!r}') from None if hasstr and hasbytes: raise TypeError("Can't mix strings and bytes in path components") from None + +# A singleton with a true boolean value. +@object.__new__ +class ALLOW_MISSING: + """Special value for use in realpath().""" + def __repr__(self): + return 'os.path.ALLOW_MISSING' + def __reduce__(self): + return self.__class__.__name__ diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 82a72978175662..9cdc16480f9afe 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -29,7 +29,7 @@ "abspath","curdir","pardir","sep","pathsep","defpath","altsep", "extsep","devnull","realpath","supports_unicode_filenames","relpath", "samefile", "sameopenfile", "samestat", "commonpath", "isjunction", - "isdevdrive"] + "isdevdrive", "ALLOW_MISSING"] def _get_bothseps(path): if isinstance(path, bytes): @@ -724,7 +724,7 @@ def realpath(path, *, strict=False): return '\\\\.\\NUL' had_prefix = path.startswith(prefix) - if strict == 'allow_missing': + if strict is ALLOW_MISSING: ignored_error = FileNotFoundError strict = True elif strict: diff --git a/Lib/posixpath.py b/Lib/posixpath.py index 163bd79ccade18..d38f3bd5872bcd 100644 --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -36,7 +36,7 @@ "samefile","sameopenfile","samestat", "curdir","pardir","sep","pathsep","defpath","altsep","extsep", "devnull","realpath","supports_unicode_filenames","relpath", - "commonpath", "isjunction","isdevdrive"] + "commonpath", "isjunction","isdevdrive","ALLOW_MISSING"] def _get_sep(path): @@ -402,7 +402,7 @@ def realpath(filename, *, strict=False): curdir = '.' pardir = '..' getcwd = os.getcwd - if strict == 'allow_missing': + if strict is ALLOW_MISSING: ignored_error = FileNotFoundError strict = True elif strict: diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 8e42e853218108..068aa13ed70356 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -781,7 +781,7 @@ def __init__(self, tarinfo, path): def _get_filtered_attrs(member, dest_path, for_data=True): new_attrs = {} name = member.name - dest_path = os.path.realpath(dest_path, strict='allow_missing') + dest_path = os.path.realpath(dest_path, strict=os.path.ALLOW_MISSING) # Strip leading / (tar's directory separator) from filenames. # Include os.sep (target OS directory separator) as well. if name.startswith(('/', os.sep)): @@ -792,7 +792,7 @@ def _get_filtered_attrs(member, dest_path, for_data=True): raise AbsolutePathError(member) # Ensure we stay in the destination target_path = os.path.realpath(os.path.join(dest_path, name), - strict='allow_missing') + strict=os.path.ALLOW_MISSING) if os.path.commonpath([target_path, dest_path]) != dest_path: raise OutsideDestinationError(member, target_path) # Limit permissions (no high bits, and go-w) @@ -840,7 +840,8 @@ def _get_filtered_attrs(member, dest_path, for_data=True): else: target_path = os.path.join(dest_path, member.linkname) - target_path = os.path.realpath(target_path, strict='allow_missing') + target_path = os.path.realpath(target_path, + strict=os.path.ALLOW_MISSING) if os.path.commonpath([target_path, dest_path]) != dest_path: raise LinkOutsideDestinationError(member, target_path) return new_attrs diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index db5f5d574e2bde..b891d0734ca0a6 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -6,6 +6,7 @@ import sys import unittest import warnings +from ntpath import ALLOW_MISSING from test.support import TestFailed, cpython_only, os_helper from test.support.os_helper import FakePath from test import test_genericpath @@ -505,15 +506,15 @@ def test_realpath_curdir_strict(self): def test_realpath_curdir_missing_ok(self): expected = ntpath.normpath(os.getcwd()) - tester("ntpath.realpath('.', strict='allow_missing')", + tester("ntpath.realpath('.', strict=ALLOW_MISSING)", expected) - tester("ntpath.realpath('./.', strict='allow_missing')", + tester("ntpath.realpath('./.', strict=ALLOW_MISSING)", expected) - tester("ntpath.realpath('/'.join(['.'] * 100), strict='allow_missing')", + tester("ntpath.realpath('/'.join(['.'] * 100), strict=ALLOW_MISSING)", expected) - tester("ntpath.realpath('.\\.', strict='allow_missing')", + tester("ntpath.realpath('.\\.', strict=ALLOW_MISSING)", expected) - tester("ntpath.realpath('\\'.join(['.'] * 100), strict='allow_missing')", + tester("ntpath.realpath('\\'.join(['.'] * 100), strict=ALLOW_MISSING)", expected) def test_realpath_pardir(self): @@ -542,20 +543,20 @@ def test_realpath_pardir_strict(self): def test_realpath_pardir_missing_ok(self): expected = ntpath.normpath(os.getcwd()) - tester("ntpath.realpath('..', strict='allow_missing')", + tester("ntpath.realpath('..', strict=ALLOW_MISSING)", ntpath.dirname(expected)) - tester("ntpath.realpath('../..', strict='allow_missing')", + tester("ntpath.realpath('../..', strict=ALLOW_MISSING)", ntpath.dirname(ntpath.dirname(expected))) - tester("ntpath.realpath('/'.join(['..'] * 50), strict='allow_missing')", + tester("ntpath.realpath('/'.join(['..'] * 50), strict=ALLOW_MISSING)", ntpath.splitdrive(expected)[0] + '\\') - tester("ntpath.realpath('..\\..', strict='allow_missing')", + tester("ntpath.realpath('..\\..', strict=ALLOW_MISSING)", ntpath.dirname(ntpath.dirname(expected))) - tester("ntpath.realpath('\\'.join(['..'] * 50), strict='allow_missing')", + tester("ntpath.realpath('\\'.join(['..'] * 50), strict=ALLOW_MISSING)", ntpath.splitdrive(expected)[0] + '\\') @os_helper.skip_unless_symlink @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') - @_parameterize({}, {'strict': True}, {'strict': 'allow_missing'}) + @_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING}) def test_realpath_basic(self, kwargs): ABSTFN = ntpath.abspath(os_helper.TESTFN) open(ABSTFN, "wb").close() @@ -603,38 +604,38 @@ def test_realpath_invalid_paths(self): self.assertEqual(realpath(path, strict=False), path) # gh-106242: Embedded nulls should raise OSError (not ValueError) 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' self.assertEqual(realpath(path, strict=False), path) 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' self.assertEqual(realpath(path, strict=False), path) 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' self.assertEqual(realpath(path, strict=False), path) 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\\..' 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()) + 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()) + 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') + 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') + self.assertEqual(realpath(path, strict=ALLOW_MISSING), ABSTFNb + b'\\nonexistent') @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') - @_parameterize({}, {'strict': True}, {'strict': 'allow_missing'}) + @_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING}) def test_realpath_invalid_unicode_paths(self, kwargs): realpath = ntpath.realpath ABSTFN = ntpath.abspath(os_helper.TESTFN) @@ -654,7 +655,7 @@ def test_realpath_invalid_unicode_paths(self, kwargs): @os_helper.skip_unless_symlink @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') - @_parameterize({}, {'strict': True}, {'strict': 'allow_missing'}) + @_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING}) def test_realpath_relative(self, kwargs): ABSTFN = ntpath.abspath(os_helper.TESTFN) open(ABSTFN, "wb").close() @@ -815,7 +816,7 @@ def test_realpath_symlink_loops_strict(self): @os_helper.skip_unless_symlink @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') def test_realpath_symlink_loops_raise(self): - # Symlink loops raise OSError in 'allow_missing' mode + # 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") @@ -826,16 +827,16 @@ def test_realpath_symlink_loops_raise(self): self.addCleanup(os_helper.unlink, ABSTFN + "x") os.symlink(ABSTFN, ABSTFN) - self.assertRaises(OSError, ntpath.realpath, ABSTFN, strict='allow_missing') + 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') + strict=ALLOW_MISSING) self.assertRaises(OSError, ntpath.realpath, ABSTFN + "2", - strict='allow_missing') + strict=ALLOW_MISSING) self.assertRaises(OSError, ntpath.realpath, ABSTFN + "1\\x", - strict='allow_missing') + strict=ALLOW_MISSING) # Windows eliminates '..' components before resolving links; # realpath is not expected to raise if this removes the loop. @@ -851,24 +852,24 @@ def test_realpath_symlink_loops_raise(self): self.assertRaises( OSError, ntpath.realpath, ABSTFN + "1\\..\\" + ntpath.basename(ABSTFN) + "1", - strict='allow_missing') + strict=ALLOW_MISSING) os.symlink(ntpath.basename(ABSTFN) + "a\\b", ABSTFN + "a") self.assertRaises(OSError, ntpath.realpath, ABSTFN + "a", - strict='allow_missing') + 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') + strict=ALLOW_MISSING) # Test using relative path as well. self.assertRaises(OSError, ntpath.realpath, ntpath.basename(ABSTFN), - strict='allow_missing') + strict=ALLOW_MISSING) @os_helper.skip_unless_symlink @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') - @_parameterize({}, {'strict': True}, {'strict': 'allow_missing'}) + @_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") @@ -906,7 +907,7 @@ 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') + tester("ntpath.realpath('NUL', strict=ALLOW_MISSING)", r'\\.\NUL') @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') @unittest.skipUnless(HAVE_GETSHORTPATHNAME, 'need _getshortpathname') @@ -930,7 +931,7 @@ def test_realpath_cwd(self): self.assertPathEqual(test_file_long, ntpath.realpath(test_file_short)) - for kwargs in {}, {'strict': True}, {'strict': 'allow_missing'}: + for kwargs in {}, {'strict': True}, {'strict': ALLOW_MISSING}: with self.subTest(**kwargs): with os_helper.change_cwd(test_dir_long): self.assertPathEqual( diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py index 255f53a49648b9..5961cd2dbebb3c 100644 --- a/Lib/test/test_posixpath.py +++ b/Lib/test/test_posixpath.py @@ -5,7 +5,7 @@ import sys import unittest from functools import partial -from posixpath import realpath, abspath, dirname, basename +from posixpath import realpath, abspath, dirname, basename, ALLOW_MISSING from test import support from test import test_genericpath from test.support import import_helper @@ -464,7 +464,7 @@ def test_normpath(self): self.assertEqual(result, expected) @skip_if_ABSTFN_contains_backslash - @_parameterize({}, {'strict': True}, {'strict': 'allow_missing'}) + @_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING}) def test_realpath_curdir(self, kwargs): self.assertEqual(realpath('.', **kwargs), os.getcwd()) self.assertEqual(realpath('./.', **kwargs), os.getcwd()) @@ -475,7 +475,7 @@ def test_realpath_curdir(self, kwargs): self.assertEqual(realpath(b'/'.join([b'.'] * 100), **kwargs), os.getcwdb()) @skip_if_ABSTFN_contains_backslash - @_parameterize({}, {'strict': True}, {'strict': 'allow_missing'}) + @_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()))) @@ -487,7 +487,7 @@ def test_realpath_pardir(self, kwargs): @os_helper.skip_unless_symlink @skip_if_ABSTFN_contains_backslash - @_parameterize({}, {'strict': 'allow_missing'}) + @_parameterize({}, {'strict': ALLOW_MISSING}) def test_realpath_basic(self, kwargs): # Basic operation. try: @@ -512,100 +512,100 @@ 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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') + 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) + 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') + 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) + 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(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'), '/') + 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') + 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') + 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(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') + 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') + self.assertRaises(OSError, realpath, path, strict=ALLOW_MISSING) else: 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' if sys.platform == 'win32': self.assertRaises(UnicodeDecodeError, realpath, path, strict=False) - self.assertRaises(UnicodeDecodeError, realpath, path, strict='allow_missing') + 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') + 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 - @_parameterize({}, {'strict': 'allow_missing'}) + @_parameterize({}, {'strict': ALLOW_MISSING}) def test_realpath_relative(self, kwargs): try: os.symlink(posixpath.relpath(ABSTFN+"1"), ABSTFN) @@ -615,7 +615,7 @@ def test_realpath_relative(self, kwargs): @os_helper.skip_unless_symlink @skip_if_ABSTFN_contains_backslash - @_parameterize({}, {'strict': 'allow_missing'}) + @_parameterize({}, {'strict': ALLOW_MISSING}) def test_realpath_missing_pardir(self, kwargs): try: os.symlink(TESTFN + "1", TESTFN) @@ -667,7 +667,7 @@ def test_realpath_symlink_loops(self): @os_helper.skip_unless_symlink @skip_if_ABSTFN_contains_backslash - @_parameterize({'strict': True}, {'strict': 'allow_missing'}) + @_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 # the strict modes. @@ -709,7 +709,7 @@ def test_realpath_symlink_loops_strict(self, kwargs): @os_helper.skip_unless_symlink @skip_if_ABSTFN_contains_backslash - @_parameterize({}, {'strict': True}, {'strict': 'allow_missing'}) + @_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING}) def test_realpath_repeated_indirect_symlinks(self, kwargs): # Issue #6975. try: @@ -724,7 +724,7 @@ def test_realpath_repeated_indirect_symlinks(self, kwargs): @os_helper.skip_unless_symlink @skip_if_ABSTFN_contains_backslash - @_parameterize({}, {'strict': True}, {'strict': 'allow_missing'}) + @_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING}) def test_realpath_deep_recursion(self, kwargs): depth = 10 try: @@ -744,7 +744,7 @@ def test_realpath_deep_recursion(self, kwargs): @os_helper.skip_unless_symlink @skip_if_ABSTFN_contains_backslash - @_parameterize({}, {'strict': 'allow_missing'}) + @_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 @@ -765,7 +765,7 @@ def test_realpath_resolve_parents(self, kwargs): @os_helper.skip_unless_symlink @skip_if_ABSTFN_contains_backslash - @_parameterize({}, {'strict': True}, {'strict': 'allow_missing'}) + @_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' @@ -794,7 +794,7 @@ def test_realpath_resolve_before_normalizing(self, kwargs): @os_helper.skip_unless_symlink @skip_if_ABSTFN_contains_backslash - @_parameterize({}, {'strict': True}, {'strict': 'allow_missing'}) + @_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. @@ -832,7 +832,7 @@ def test_realpath_unreadable_symlink(self): @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'}) + @_parameterize({'strict': True}, {'strict': ALLOW_MISSING}) def test_realpath_unreadable_symlink_strict(self, kwargs): try: os.symlink(ABSTFN+"1", ABSTFN) @@ -858,21 +858,21 @@ def test_realpath_unreadable_directory(self): 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) + self.assertEqual(realpath(ABSTFN, strict=ALLOW_MISSING), ABSTFN) 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') + 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') + strict=ALLOW_MISSING) finally: os.chmod(ABSTFN, 0o755) os_helper.rmdir(ABSTFN + '/k') @@ -885,27 +885,27 @@ def test_realpath_nonterminal_file(self): 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=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') + 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') + 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') + 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') + strict=ALLOW_MISSING) finally: os_helper.unlink(ABSTFN) @@ -918,27 +918,27 @@ def test_realpath_nonterminal_symlink_to_file(self): 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=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') + 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') + 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') + 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') + strict=ALLOW_MISSING) finally: os_helper.unlink(ABSTFN) os_helper.unlink(ABSTFN + "1") @@ -958,22 +958,22 @@ def test_realpath_nonterminal_symlink_to_symlinks_to_file(self): self.assertEqual(realpath(ABSTFN + "/", strict=False), ABSTFN + "2") self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/", strict=True) self.assertRaises(NotADirectoryError, realpath, ABSTFN + "/", - strict='allow_missing') + 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') + 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') + 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') + strict=ALLOW_MISSING) finally: os_helper.unlink(ABSTFN) os_helper.unlink(ABSTFN + "1") @@ -1161,7 +1161,7 @@ def test_path_normpath(self): def test_path_abspath(self): self.assertPathEqual(self.path.abspath) - @_parameterize({}, {'strict': True}, {'strict': 'allow_missing'}) + @_parameterize({}, {'strict': True}, {'strict': ALLOW_MISSING}) def test_path_realpath(self, kwargs): self.assertPathEqual(self.path.realpath)