Skip to content
37 changes: 37 additions & 0 deletions Lib/test/test_getpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,43 @@ def test_venv_changed_name_posix(self):
actual = getpath(ns, expected)
self.assertEqual(expected, actual)

def test_venv_with_invalid_home_in_pyvenv_posix(self):
ns = MockPosixNamespace(
argv0="/venv/bin/python",
PREFIX="/usr",
ENV_PATH="/venv/bin:/usr/bin",
)
ns.add_known_xfile("/path/to/copy_dir/bin/python")
ns.add_known_xfile("/path/to/python-link")
ns.add_known_link("/path/to/python-link",
"/path/to/copy_dir/bin/python")

ns.add_known_xfile("/venv/bin/python")
ns.add_known_link("/venv/bin/python",
"/path/to/python-link")

ns.add_known_file("/path/to/copy_dir/lib/python9.8/os.py")
ns.add_known_dir("/path/to/copy_dir/lib/python9.8/lib-dynload")
ns.add_known_file("/venv/pyvenv.cfg", [
r"home = /"
])
expected = dict(
executable="/venv/bin/python",
prefix="/venv",
exec_prefix="/venv",
base_executable="/path/to/copy_dir/bin/python",
base_prefix="/path/to/copy_dir",
base_exec_prefix="/path/to/copy_dir",
module_search_paths_set=1,
module_search_paths=[
"/path/to/copy_dir/lib/python98.zip",
"/path/to/copy_dir/lib/python9.8",
"/path/to/copy_dir/lib/python9.8/lib-dynload",
],
)
actual = getpath(ns, expected)
self.assertEqual(expected, actual)

def test_venv_non_installed_zip_path_posix(self):
"Test a venv created from non-installed python has correct zip path."""
ns = MockPosixNamespace(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix calculation of ``base_prefix`` and ``base_exec_prefix`` when the ``home`` in ``pyvenv.cfg`` is inaccurate and the installation directory (``PREFIX``) does not exist. Calculation will try to use ``base_executable`` now. Patch by Charlie Zhao.
10 changes: 10 additions & 0 deletions Modules/getpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,13 @@ def search_up(prefix, *landmarks, test=isfile):
if prefix and not stdlib_dir:
stdlib_dir = joinpath(prefix, STDLIB_SUBDIR)

# Note: the `home` variable in pyvenv.cfg is not always accurate.
# Detect prefix by searching from *real* executable location for the stdlib_dir.
if STDLIB_SUBDIR and STDLIB_LANDMARKS and base_executable and not prefix:
prefix = search_up(base_executable, *STDLIB_LANDMARKS)
if prefix and not stdlib_dir:
stdlib_dir = joinpath(prefix, STDLIB_SUBDIR)

if PREFIX and not prefix:
prefix = PREFIX
if not any(isfile(joinpath(prefix, f)) for f in STDLIB_LANDMARKS):
Expand All @@ -612,6 +619,9 @@ def search_up(prefix, *landmarks, test=isfile):
exec_prefix = prefix
if not exec_prefix and executable_dir:
exec_prefix = search_up(executable_dir, PLATSTDLIB_LANDMARK, test=isdir)
if not exec_prefix and base_executable:
base_executable_dir = dirname(base_executable)
exec_prefix = search_up(base_executable_dir, PLATSTDLIB_LANDMARK, test=isdir)
if not exec_prefix and EXEC_PREFIX:
exec_prefix = EXEC_PREFIX
if not exec_prefix or not isdir(joinpath(exec_prefix, PLATSTDLIB_LANDMARK)):
Expand Down
Loading