Skip to content
Merged
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
177 changes: 177 additions & 0 deletions Lib/test/test_getpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,182 @@ def test_custom_platlibdir_posix(self):
actual = getpath(ns, expected)
self.assertEqual(expected, actual)

def test_framework_macos(self):
""" Test framework layout on macOS

This layout is primarily detected using a compile-time option
(WITH_NEXT_FRAMEWORK).
"""
ns = MockPosixNamespace(
os_name="darwin",
argv0="/Library/Frameworks/Python.framework/Versions/9.8/Resources/Python.app/Contents/MacOS/Python",
WITH_NEXT_FRAMEWORK=1,
PREFIX="/Library/Frameworks/Python.framework/Versions/9.8",
EXEC_PREFIX="/Library/Frameworks/Python.framework/Versions/9.8",
ENV___PYVENV_LAUNCHER__="/Library/Frameworks/Python.framework/Versions/9.8/bin/python9.8",
real_executable="/Library/Frameworks/Python.framework/Versions/9.8/Resources/Python.app/Contents/MacOS/Python",
library="/Library/Frameworks/Python.framework/Versions/9.8/Python",
)
ns.add_known_xfile("/Library/Frameworks/Python.framework/Versions/9.8/Resources/Python.app/Contents/MacOS/Python")
ns.add_known_xfile("/Library/Frameworks/Python.framework/Versions/9.8/bin/python9.8")
ns.add_known_dir("/Library/Frameworks/Python.framework/Versions/9.8/lib/python9.8/lib-dynload")
ns.add_known_file("/Library/Frameworks/Python.framework/Versions/9.8/lib/python9.8/os.py")

# This is definitely not the stdlib (see discusion in bpo-46890)
#ns.add_known_file("/Library/Frameworks/lib/python98.zip")

expected = dict(
executable="/Library/Frameworks/Python.framework/Versions/9.8/bin/python9.8",
prefix="/Library/Frameworks/Python.framework/Versions/9.8",
exec_prefix="/Library/Frameworks/Python.framework/Versions/9.8",
base_executable="/Library/Frameworks/Python.framework/Versions/9.8/bin/python9.8",
base_prefix="/Library/Frameworks/Python.framework/Versions/9.8",
base_exec_prefix="/Library/Frameworks/Python.framework/Versions/9.8",
module_search_paths_set=1,
module_search_paths=[
"/Library/Frameworks/Python.framework/Versions/9.8/lib/python98.zip",
"/Library/Frameworks/Python.framework/Versions/9.8/lib/python9.8",
"/Library/Frameworks/Python.framework/Versions/9.8/lib/python9.8/lib-dynload",
],
)
actual = getpath(ns, expected)
self.assertEqual(expected, actual)

def test_alt_framework_macos(self):
""" Test framework layout on macOS with alternate framework name

``--with-framework-name=DebugPython``

This layout is primarily detected using a compile-time option
(WITH_NEXT_FRAMEWORK).
"""
ns = MockPosixNamespace(
argv0="/Library/Frameworks/DebugPython.framework/Versions/9.8/Resources/Python.app/Contents/MacOS/DebugPython",
os_name="darwin",
WITH_NEXT_FRAMEWORK=1,
PREFIX="/Library/Frameworks/DebugPython.framework/Versions/9.8",
EXEC_PREFIX="/Library/Frameworks/DebugPython.framework/Versions/9.8",
ENV___PYVENV_LAUNCHER__="/Library/Frameworks/DebugPython.framework/Versions/9.8/bin/python9.8",
real_executable="/Library/Frameworks/DebugPython.framework/Versions/9.8/Resources/Python.app/Contents/MacOS/DebugPython",
library="/Library/Frameworks/DebugPython.framework/Versions/9.8/DebugPython",
PYTHONPATH=None,
ENV_PYTHONHOME=None,
ENV_PYTHONEXECUTABLE=None,
executable_dir=None,
py_setpath=None,
)
ns.add_known_xfile("/Library/Frameworks/DebugPython.framework/Versions/9.8/Resources/Python.app/Contents/MacOS/DebugPython")
ns.add_known_xfile("/Library/Frameworks/DebugPython.framework/Versions/9.8/bin/python9.8")
ns.add_known_dir("/Library/Frameworks/DebugPython.framework/Versions/9.8/lib/python9.8/lib-dynload")
ns.add_known_xfile("/Library/Frameworks/DebugPython.framework/Versions/9.8/lib/python9.8/os.py")

# This is definitely not the stdlib (see discusion in bpo-46890)
#ns.add_known_xfile("/Library/lib/python98.zip")
expected = dict(
executable="/Library/Frameworks/DebugPython.framework/Versions/9.8/bin/python9.8",
prefix="/Library/Frameworks/DebugPython.framework/Versions/9.8",
exec_prefix="/Library/Frameworks/DebugPython.framework/Versions/9.8",
base_executable="/Library/Frameworks/DebugPython.framework/Versions/9.8/bin/python9.8",
base_prefix="/Library/Frameworks/DebugPython.framework/Versions/9.8",
base_exec_prefix="/Library/Frameworks/DebugPython.framework/Versions/9.8",
module_search_paths_set=1,
module_search_paths=[
"/Library/Frameworks/DebugPython.framework/Versions/9.8/lib/python98.zip",
"/Library/Frameworks/DebugPython.framework/Versions/9.8/lib/python9.8",
"/Library/Frameworks/DebugPython.framework/Versions/9.8/lib/python9.8/lib-dynload",
],
)
actual = getpath(ns, expected)
self.assertEqual(expected, actual)

def test_venv_framework_macos(self):
"""Test a venv layout on macOS using a framework build
"""
venv_path = "/tmp/workdir/venv"
ns = MockPosixNamespace(
os_name="darwin",
argv0="/Library/Frameworks/Python.framework/Versions/9.8/Resources/Python.app/Contents/MacOS/Python",
WITH_NEXT_FRAMEWORK=1,
PREFIX="/Library/Frameworks/Python.framework/Versions/9.8",
EXEC_PREFIX="/Library/Frameworks/Python.framework/Versions/9.8",
ENV___PYVENV_LAUNCHER__=f"{venv_path}/bin/python",
real_executable="/Library/Frameworks/Python.framework/Versions/9.8/Resources/Python.app/Contents/MacOS/Python",
library="/Library/Frameworks/Python.framework/Versions/9.8/Python",
)
ns.add_known_dir(venv_path)
ns.add_known_dir(f"{venv_path}/bin")
ns.add_known_dir(f"{venv_path}/lib")
ns.add_known_dir(f"{venv_path}/lib/python9.8")
ns.add_known_xfile(f"{venv_path}/bin/python")
ns.add_known_xfile("/Library/Frameworks/Python.framework/Versions/9.8/Resources/Python.app/Contents/MacOS/Python")
ns.add_known_xfile("/Library/Frameworks/Python.framework/Versions/9.8/bin/python9.8")
ns.add_known_dir("/Library/Frameworks/Python.framework/Versions/9.8/lib/python9.8/lib-dynload")
ns.add_known_xfile("/Library/Frameworks/Python.framework/Versions/9.8/lib/python9.8/os.py")
ns.add_known_file(f"{venv_path}/pyvenv.cfg", [
"home = /Library/Frameworks/Python.framework/Versions/9.8/bin"
])
expected = dict(
executable=f"{venv_path}/bin/python",
prefix="/Library/Frameworks/Python.framework/Versions/9.8",
exec_prefix="/Library/Frameworks/Python.framework/Versions/9.8",
base_executable="/Library/Frameworks/Python.framework/Versions/9.8/bin/python9.8",
base_prefix="/Library/Frameworks/Python.framework/Versions/9.8",
base_exec_prefix="/Library/Frameworks/Python.framework/Versions/9.8",
module_search_paths_set=1,
module_search_paths=[
"/Library/Frameworks/Python.framework/Versions/9.8/lib/python98.zip",
"/Library/Frameworks/Python.framework/Versions/9.8/lib/python9.8",
"/Library/Frameworks/Python.framework/Versions/9.8/lib/python9.8/lib-dynload",
],
)
actual = getpath(ns, expected)
self.assertEqual(expected, actual)

def test_venv_alt_framework_macos(self):
"""Test a venv layout on macOS using a framework build

``--with-framework-name=DebugPython``
"""
venv_path = "/tmp/workdir/venv"
ns = MockPosixNamespace(
os_name="darwin",
argv0="/Library/Frameworks/DebugPython.framework/Versions/9.8/Resources/Python.app/Contents/MacOS/DebugPython",
WITH_NEXT_FRAMEWORK=1,
PREFIX="/Library/Frameworks/DebugPython.framework/Versions/9.8",
EXEC_PREFIX="/Library/Frameworks/DebugPython.framework/Versions/9.8",
ENV___PYVENV_LAUNCHER__=f"{venv_path}/bin/python",
real_executable="/Library/Frameworks/DebugPython.framework/Versions/9.8/Resources/Python.app/Contents/MacOS/DebugPython",
library="/Library/Frameworks/DebugPython.framework/Versions/9.8/DebugPython",
)
ns.add_known_dir(venv_path)
ns.add_known_dir(f"{venv_path}/bin")
ns.add_known_dir(f"{venv_path}/lib")
ns.add_known_dir(f"{venv_path}/lib/python9.8")
ns.add_known_xfile(f"{venv_path}/bin/python")
ns.add_known_xfile("/Library/Frameworks/DebugPython.framework/Versions/9.8/Resources/Python.app/Contents/MacOS/DebugPython")
ns.add_known_xfile("/Library/Frameworks/DebugPython.framework/Versions/9.8/bin/python9.8")
ns.add_known_dir("/Library/Frameworks/DebugPython.framework/Versions/9.8/lib/python9.8/lib-dynload")
ns.add_known_xfile("/Library/Frameworks/DebugPython.framework/Versions/9.8/lib/python9.8/os.py")
ns.add_known_file(f"{venv_path}/pyvenv.cfg", [
"home = /Library/Frameworks/DebugPython.framework/Versions/9.8/bin"
])
expected = dict(
executable=f"{venv_path}/bin/python",
prefix="/Library/Frameworks/DebugPython.framework/Versions/9.8",
exec_prefix="/Library/Frameworks/DebugPython.framework/Versions/9.8",
base_executable="/Library/Frameworks/DebugPython.framework/Versions/9.8/bin/python9.8",
base_prefix="/Library/Frameworks/DebugPython.framework/Versions/9.8",
base_exec_prefix="/Library/Frameworks/DebugPython.framework/Versions/9.8",
module_search_paths_set=1,
module_search_paths=[
"/Library/Frameworks/DebugPython.framework/Versions/9.8/lib/python98.zip",
"/Library/Frameworks/DebugPython.framework/Versions/9.8/lib/python9.8",
"/Library/Frameworks/DebugPython.framework/Versions/9.8/lib/python9.8/lib-dynload",
],
)
actual = getpath(ns, expected)
self.assertEqual(expected, actual)

def test_venv_macos(self):
"""Test a venv layout on macOS.

Expand Down Expand Up @@ -787,6 +963,7 @@ def __init__(self, *a, argv0=None, config=None, **kw):
self["config"] = DEFAULT_CONFIG.copy()
self["os_name"] = "posix"
self["PLATLIBDIR"] = "lib"
self["WITH_NEXT_FRAMEWORK"] = 0
super().__init__(*a, **kw)
if argv0:
self["config"]["orig_argv"] = [argv0]
Expand Down
1 change: 1 addition & 0 deletions Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -1221,6 +1221,7 @@ Modules/getpath.o: $(srcdir)/Modules/getpath.c Python/frozen_modules/getpath.h M
-DVERSION='"$(VERSION)"' \
-DVPATH='"$(VPATH)"' \
-DPLATLIBDIR='"$(PLATLIBDIR)"' \
-DPYTHONFRAMEWORK='"$(PYTHONFRAMEWORK)"' \
-o $@ $(srcdir)/Modules/getpath.c

Programs/python.o: $(srcdir)/Programs/python.c
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix a regression in the setting of ``sys._base_executable`` in framework
builds, and thereby fix a regression in :mod:`venv` virtual environments
with such builds.
6 changes: 6 additions & 0 deletions Modules/getpath.c
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,11 @@ _PyConfig_InitPathConfig(PyConfig *config, int compute_path_config)
!decode_to_dict(dict, "os_name", "darwin") ||
#else
!decode_to_dict(dict, "os_name", "posix") ||
#endif
#ifdef WITH_NEXT_FRAMEWORK
!int_to_dict(dict, "WITH_NEXT_FRAMEWORK", 1) ||
#else
!int_to_dict(dict, "WITH_NEXT_FRAMEWORK", 0) ||
#endif
Comment thread
ronaldoussoren marked this conversation as resolved.
Outdated
!decode_to_dict(dict, "PREFIX", PREFIX) ||
!decode_to_dict(dict, "EXEC_PREFIX", EXEC_PREFIX) ||
Expand Down Expand Up @@ -943,3 +948,4 @@ _PyConfig_InitPathConfig(PyConfig *config, int compute_path_config)

return _PyStatus_OK();
}

15 changes: 13 additions & 2 deletions Modules/getpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
# PREFIX -- [in] sysconfig.get_config_var(...)
# EXEC_PREFIX -- [in] sysconfig.get_config_var(...)
# PYTHONPATH -- [in] sysconfig.get_config_var(...)
# WITH_NEXT_FRAMEWORK -- [in] sysconfig.get_config_var(...)
# VPATH -- [in] sysconfig.get_config_var(...)
# PLATLIBDIR -- [in] sysconfig.get_config_var(...)
# PYDEBUGEXT -- [in, opt] '_d' on Windows for debug builds
Expand Down Expand Up @@ -301,9 +302,19 @@ def search_up(prefix, *landmarks, test=isfile):
# If set, these variables imply that we should be using them as
# sys.executable and when searching for venvs. However, we should
# use the argv0 path for prefix calculation
base_executable = executable

if os_name == 'darwin' and WITH_NEXT_FRAMEWORK:
# In a framework build the binary in {sys.exec_prefix}/bin is
# a stub executable that execs the real interpreter in an
# embedded app bundle. That bundle is an implementation detail
# and should not affect base_executable.
base_executable = f"{dirname(library)}/bin/python{VERSION_MAJOR}.{VERSION_MINOR}"
else:
base_executable = executable

if not real_executable:
real_executable = executable
real_executable = base_executable
#real_executable_dir = dirname(real_executable)
executable = ENV_PYTHONEXECUTABLE or ENV___PYVENV_LAUNCHER__
executable_dir = dirname(executable)

Expand Down