mirror of https://github.com/python/cpython
gh-86179: Implement realpath() on Windows for getpath.py calculations (GH-113033)
This commit is contained in:
parent
41c18aacc7
commit
fddc829236
|
@ -404,16 +404,7 @@ def get_config_h_filename():
|
|||
"""Return the path of pyconfig.h."""
|
||||
if _PYTHON_BUILD:
|
||||
if os.name == "nt":
|
||||
# This ought to be as simple as dirname(sys._base_executable), but
|
||||
# if a venv uses symlinks to a build in the source tree, then this
|
||||
# fails. So instead we guess the subdirectory name from sys.winver
|
||||
if sys.winver.endswith('-32'):
|
||||
arch = 'win32'
|
||||
elif sys.winver.endswith('-arm64'):
|
||||
arch = 'arm64'
|
||||
else:
|
||||
arch = 'amd64'
|
||||
inc_dir = os.path.join(_PROJECT_BASE, 'PCbuild', arch)
|
||||
inc_dir = os.path.dirname(sys._base_executable)
|
||||
else:
|
||||
inc_dir = _PROJECT_BASE
|
||||
else:
|
||||
|
|
|
@ -46,7 +46,8 @@ if is_emscripten or is_wasi:
|
|||
def check_output(cmd, encoding=None):
|
||||
p = subprocess.Popen(cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
stderr=subprocess.PIPE,
|
||||
env={**os.environ, "PYTHONHOME": ""})
|
||||
out, err = p.communicate()
|
||||
if p.returncode:
|
||||
if verbose and err:
|
||||
|
@ -287,6 +288,16 @@ class BasicTest(BaseTest):
|
|||
cmd[2] = 'import sysconfig; print(sysconfig.%s)' % call
|
||||
out, err = check_output(cmd, encoding='utf-8')
|
||||
self.assertEqual(out.strip(), expected, err)
|
||||
for attr, expected in (
|
||||
('executable', self.envpy()),
|
||||
# Usually compare to sys.executable, but if we're running in our own
|
||||
# venv then we really need to compare to our base executable
|
||||
('_base_executable', sys._base_executable),
|
||||
):
|
||||
with self.subTest(attr):
|
||||
cmd[2] = f'import sys; print(sys.{attr})'
|
||||
out, err = check_output(cmd, encoding='utf-8')
|
||||
self.assertEqual(out.strip(), expected, err)
|
||||
|
||||
@requireVenvCreate
|
||||
@unittest.skipUnless(can_symlink(), 'Needs symlinks')
|
||||
|
@ -309,6 +320,16 @@ class BasicTest(BaseTest):
|
|||
cmd[2] = 'import sysconfig; print(sysconfig.%s)' % call
|
||||
out, err = check_output(cmd, encoding='utf-8')
|
||||
self.assertEqual(out.strip(), expected, err)
|
||||
for attr, expected in (
|
||||
('executable', self.envpy()),
|
||||
# Usually compare to sys.executable, but if we're running in our own
|
||||
# venv then we really need to compare to our base executable
|
||||
('_base_executable', sys._base_executable),
|
||||
):
|
||||
with self.subTest(attr):
|
||||
cmd[2] = f'import sys; print(sys.{attr})'
|
||||
out, err = check_output(cmd, encoding='utf-8')
|
||||
self.assertEqual(out.strip(), expected, err)
|
||||
|
||||
if sys.platform == 'win32':
|
||||
ENV_SUBDIRS = (
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Fixes path calculations when launching Python on Windows through a symlink.
|
|
@ -502,6 +502,45 @@ done:
|
|||
PyMem_Free((void *)path);
|
||||
PyMem_Free((void *)narrow);
|
||||
return r;
|
||||
#elif defined(MS_WINDOWS)
|
||||
HANDLE hFile;
|
||||
wchar_t resolved[MAXPATHLEN+1];
|
||||
int len = 0, err;
|
||||
PyObject *result;
|
||||
|
||||
wchar_t *path = PyUnicode_AsWideCharString(pathobj, NULL);
|
||||
if (!path) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
hFile = CreateFileW(path, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||
if (hFile != INVALID_HANDLE_VALUE) {
|
||||
len = GetFinalPathNameByHandleW(hFile, resolved, MAXPATHLEN, VOLUME_NAME_DOS);
|
||||
err = len ? 0 : GetLastError();
|
||||
CloseHandle(hFile);
|
||||
} else {
|
||||
err = GetLastError();
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (err) {
|
||||
PyErr_SetFromWindowsErr(err);
|
||||
result = NULL;
|
||||
} else if (len <= MAXPATHLEN) {
|
||||
const wchar_t *p = resolved;
|
||||
if (0 == wcsncmp(p, L"\\\\?\\", 4)) {
|
||||
if (GetFileAttributesW(&p[4]) != INVALID_FILE_ATTRIBUTES) {
|
||||
p += 4;
|
||||
len -= 4;
|
||||
}
|
||||
}
|
||||
result = PyUnicode_FromWideChar(p, len);
|
||||
} else {
|
||||
result = Py_NewRef(pathobj);
|
||||
}
|
||||
PyMem_Free(path);
|
||||
return result;
|
||||
#endif
|
||||
|
||||
return Py_NewRef(pathobj);
|
||||
|
|
Loading…
Reference in New Issue