Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions Lib/test/test_getpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,74 @@ def test_venv_changed_name_posix(self):
actual = getpath(ns, expected)
self.assertEqual(expected, actual)

def test_venv_relocated_base_installation_posix(self):
"Test a venv whose base installation was relocated from PREFIX."
ns = MockPosixNamespace(
argv0="/venv/bin/python",
PREFIX="/build/install",
)
ns.add_known_xfile("/relocated/bin/python3")
ns.add_known_xfile("/public/bin/python")
ns.add_known_link("/public/bin/python", "/relocated/bin/python3")
ns.add_known_xfile("/venv/bin/python")
ns.add_known_link("/venv/bin/python", "/public/bin/python")
ns.add_known_file("/relocated/lib/python9.8/os.py")
ns.add_known_dir("/relocated/lib/python9.8/lib-dynload")
ns.add_known_file("/venv/pyvenv.cfg", [
"home = /public/bin",
])
expected = dict(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the dict() calls when a dict literal would have worked?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! A dictionary literal {...} is cleaner, more pythonic, and slightly faster than calling dict(). I'll update this line to use a literal instead.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dict() call matches the pattern established in the existing tests.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(agree it makes sense to match all the other tests in the file instead)

executable="/venv/bin/python",
prefix="/venv",
exec_prefix="/venv",
base_executable="/relocated/bin/python3",
base_prefix="/relocated",
base_exec_prefix="/relocated",
module_search_paths_set=1,
module_search_paths=[
"/relocated/lib/python98.zip",
"/relocated/lib/python9.8",
"/relocated/lib/python9.8/lib-dynload",
],
)
actual = getpath(ns, expected)
self.assertEqual(expected, actual)

def test_venv_symlink_with_misleading_landmarks_posix(self):
"Test that landmarks near an external symlink do effect resolution."
ns = MockPosixNamespace(
argv0="/venv/bin/python",
PREFIX="/opt/python",
)
ns.add_known_xfile("/opt/python/bin/python3")
ns.add_known_xfile("/public/bin/python")
ns.add_known_link("/public/bin/python", "/opt/python/bin/python3")
ns.add_known_xfile("/venv/bin/python")
ns.add_known_link("/venv/bin/python", "/public/bin/python")
ns.add_known_file("/opt/python/lib/python9.8/os.py")
ns.add_known_dir("/opt/python/lib/python9.8/lib-dynload")
ns.add_known_file("/public/lib/python9.8/os.py")
ns.add_known_dir("/public/lib/python9.8/lib-dynload")
ns.add_known_file("/venv/pyvenv.cfg", [
"home = /public/bin",
])
expected = dict(
executable="/venv/bin/python",
prefix="/venv",
exec_prefix="/venv",
base_executable="/opt/python/bin/python3",
base_prefix="/opt/python",
base_exec_prefix="/opt/python",
module_search_paths_set=1,
module_search_paths=[
"/opt/python/lib/python98.zip",
"/opt/python/lib/python9.8",
"/opt/python/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 standard library discovery in virtual environments created from a Python executable symlink located outside its base installation.
4 changes: 4 additions & 0 deletions Modules/getpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,10 @@ def search_up(prefix, *landmarks, test=isfile):
if isfile(candidate):
base_executable = candidate
break
if base_executable and isfile(base_executable):
# Search relative to the resolved base executable rather
# than the potentially external symlink in pyvenv.cfg.
executable_dir = real_executable_dir = dirname(base_executable)
# home key found; stop iterating over lines
break

Expand Down
Loading