diff options
author | Barney Gale <barney.gale@gmail.com> | 2023-02-17 14:08:14 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-02-17 14:08:14 (GMT) |
commit | 072011b3c38f871cdc3ab62630ea2234d09456d1 (patch) | |
tree | 5305bd780eb338a27ce67428077773bf0565a5f5 /Lib/test/support | |
parent | d401b20630965c0e1d2a5a0d60d5fc51aa5a8d80 (diff) | |
download | cpython-072011b3c38f871cdc3ab62630ea2234d09456d1.zip cpython-072011b3c38f871cdc3ab62630ea2234d09456d1.tar.gz cpython-072011b3c38f871cdc3ab62630ea2234d09456d1.tar.bz2 |
gh-100809: Fix handling of drive-relative paths in pathlib.Path.absolute() (GH-100812)
Resolving the drive independently uses the OS API, which ensures it starts from the current directory on that drive.
Diffstat (limited to 'Lib/test/support')
-rw-r--r-- | Lib/test/support/os_helper.py | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/Lib/test/support/os_helper.py b/Lib/test/support/os_helper.py index 2d4356a..821a4b1 100644 --- a/Lib/test/support/os_helper.py +++ b/Lib/test/support/os_helper.py @@ -4,6 +4,7 @@ import errno import os import re import stat +import string import sys import time import unittest @@ -716,3 +717,37 @@ class EnvironmentVarGuard(collections.abc.MutableMapping): else: self._environ[k] = v os.environ = self._environ + + +try: + import ctypes + kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) + + ERROR_FILE_NOT_FOUND = 2 + DDD_REMOVE_DEFINITION = 2 + DDD_EXACT_MATCH_ON_REMOVE = 4 + DDD_NO_BROADCAST_SYSTEM = 8 +except (ImportError, AttributeError): + def subst_drive(path): + raise unittest.SkipTest('ctypes or kernel32 is not available') +else: + @contextlib.contextmanager + def subst_drive(path): + """Temporarily yield a substitute drive for a given path.""" + for c in reversed(string.ascii_uppercase): + drive = f'{c}:' + if (not kernel32.QueryDosDeviceW(drive, None, 0) and + ctypes.get_last_error() == ERROR_FILE_NOT_FOUND): + break + else: + raise unittest.SkipTest('no available logical drive') + if not kernel32.DefineDosDeviceW( + DDD_NO_BROADCAST_SYSTEM, drive, path): + raise ctypes.WinError(ctypes.get_last_error()) + try: + yield drive + finally: + if not kernel32.DefineDosDeviceW( + DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE, + drive, path): + raise ctypes.WinError(ctypes.get_last_error()) |