Skip to content

Commit 72b32a4

Browse files
itamaroclaude
andcommitted
Keep the resolved base executable directory for exec_prefix discovery
Even when stdlib discovery falls back to 'home', the resolved base executable may live under a separate exec_prefix (e.g. ./configure --exec-prefix), so search there for platform dependent libraries before falling back to the compiled-in EXEC_PREFIX. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A93JzpSGH27i6PNX8re4YV
1 parent a7395af commit 72b32a4

2 files changed

Lines changed: 42 additions & 0 deletions

File tree

‎Lib/test/test_getpath.py‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,40 @@ def test_venv_symlink_to_launcher_outside_runtime_posix(self):
508508
actual = getpath(ns, expected)
509509
self.assertEqual(expected, actual)
510510

511+
def test_venv_symlink_to_separate_exec_prefix_posix(self):
512+
"Test a venv whose base executable lives under a separate exec_prefix."
513+
ns = MockPosixNamespace(
514+
argv0="/venv/bin/python",
515+
PREFIX="/usr",
516+
EXEC_PREFIX="/usr",
517+
)
518+
ns.add_known_xfile("/exec/bin/python")
519+
ns.add_known_xfile("/runtime/bin/python")
520+
ns.add_known_link("/runtime/bin/python", "/exec/bin/python")
521+
ns.add_known_xfile("/venv/bin/python")
522+
ns.add_known_link("/venv/bin/python", "/runtime/bin/python")
523+
ns.add_known_file("/runtime/lib/python9.8/os.py")
524+
ns.add_known_dir("/exec/lib/python9.8/lib-dynload")
525+
ns.add_known_file("/venv/pyvenv.cfg", [
526+
"home = /runtime/bin",
527+
])
528+
expected = dict(
529+
executable="/venv/bin/python",
530+
prefix="/venv",
531+
exec_prefix="/venv",
532+
base_executable="/exec/bin/python",
533+
base_prefix="/runtime",
534+
base_exec_prefix="/exec",
535+
module_search_paths_set=1,
536+
module_search_paths=[
537+
"/runtime/lib/python98.zip",
538+
"/runtime/lib/python9.8",
539+
"/exec/lib/python9.8/lib-dynload",
540+
],
541+
)
542+
actual = getpath(ns, expected)
543+
self.assertEqual(expected, actual)
544+
511545
def test_venv_non_installed_zip_path_posix(self):
512546
"Test a venv created from non-installed python has correct zip path."""
513547
ns = MockPosixNamespace(

‎Modules/getpath.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ def search_up(prefix, *landmarks, test=isfile):
232232
stdlib_dir_was_set_in_config = bool(stdlib_dir)
233233

234234
real_executable_dir = None
235+
base_executable_dir = None
235236
platstdlib_dir = None
236237
stdlib_zip = None
237238

@@ -415,6 +416,8 @@ def search_up(prefix, *landmarks, test=isfile):
415416
# If nothing there locates a standard library (e.g. a
416417
# launcher binary stored outside the installation that
417418
# 'home' points into), keep searching from 'home'.
419+
# base_executable_dir is still used to find platform
420+
# dependent libraries (exec_prefix) in that case.
418421
base_executable_dir = dirname(base_executable)
419422
if (
420423
isfile(joinpath(base_executable_dir, BUILDDIR_TXT))
@@ -632,6 +635,11 @@ def search_up(prefix, *landmarks, test=isfile):
632635
exec_prefix = prefix
633636
if not exec_prefix and executable_dir:
634637
exec_prefix = search_up(executable_dir, PLATSTDLIB_LANDMARK, test=isdir)
638+
if not exec_prefix and base_executable_dir and base_executable_dir != executable_dir:
639+
# The venv's resolved base executable may live under a separate
640+
# exec_prefix (e.g. ./configure --exec-prefix) even when the
641+
# stdlib was found from 'home'.
642+
exec_prefix = search_up(base_executable_dir, PLATSTDLIB_LANDMARK, test=isdir)
635643
if not exec_prefix and EXEC_PREFIX:
636644
exec_prefix = EXEC_PREFIX
637645
if not exec_prefix or not isdir(joinpath(exec_prefix, PLATSTDLIB_LANDMARK)):

0 commit comments

Comments
 (0)