Skip to content
Draft
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
93 changes: 92 additions & 1 deletion Lib/test/test_getpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,97 @@ def test_normal_posix(self):
actual = getpath(ns, expected)
self.assertEqual(expected, actual)

def test_shared_library_posix(self):
for os_name in ('posix', 'darwin'):
for platlibdir in ('lib', 'lib64'):
for argv0 in ('missing-python', '/application/bin/host'):
with self.subTest(os_name=os_name, platlibdir=platlibdir,
argv0=argv0):
ns = MockPosixNamespace(
os_name=os_name,
PREFIX='/configured',
EXEC_PREFIX='/configured',
PLATLIBDIR=platlibdir,
argv0=argv0,
library=f'/moved/bin/../{platlibdir}/libpython9.8.so',
)
ns.add_known_xfile('/application/bin/host')
for prefix in ('/configured', '/moved'):
ns.add_known_file(
f'{prefix}/{platlibdir}/python9.8/os.py')
ns.add_known_dir(
f'{prefix}/{platlibdir}/python9.8/lib-dynload')
expected = dict(
prefix='/moved',
exec_prefix='/moved',
base_prefix='/moved',
base_exec_prefix='/moved',
module_search_paths=[
f'/moved/{platlibdir}/python98.zip',
f'/moved/{platlibdir}/python9.8',
f'/moved/{platlibdir}/python9.8/lib-dynload',
],
)
self.assertEqual(expected, getpath(ns, expected))

def test_shared_library_home_posix(self):
ns = MockPosixNamespace(
PREFIX='/configured',
argv0='missing-python',
library='/moved/lib/libpython9.8.so',
ENV_PYTHONHOME='/pythonhome',
)
for prefix in ('/moved', '/pythonhome'):
ns.add_known_file(f'{prefix}/lib/python9.8/os.py')
ns.add_known_dir(f'{prefix}/lib/python9.8/lib-dynload')
expected = dict(
prefix='/pythonhome',
exec_prefix='/pythonhome',
base_prefix='/pythonhome',
base_exec_prefix='/pythonhome',
)
self.assertEqual(expected, getpath(ns, expected))

def test_shared_library_without_cwd_posix(self):
def abspath(path):
raise FileNotFoundError('working directory has been removed')

ns = MockPosixNamespace(
PREFIX='/configured',
argv0='python',
config={'executable': '/moved/bin/python'},
library='libpython9.8.so',
abspath=abspath,
)
ns.add_known_xfile('/moved/bin/python')
ns.add_known_file('/moved/lib/python9.8/os.py')
ns.add_known_dir('/moved/lib/python9.8/lib-dynload')
expected = dict(prefix='/moved', exec_prefix='/moved')
self.assertEqual(expected, getpath(ns, expected))

def test_shared_library_venv_posix(self):
ns = MockPosixNamespace(
PREFIX='/configured',
argv0='python',
ENV_PATH='/venv/bin:/moved/bin',
library='/moved/lib/libpython9.8.so',
)
ns.add_known_xfile('/moved/bin/python')
ns.add_known_xfile('/venv/bin/python')
ns.add_known_link('/venv/bin/python', '/moved/bin/python')
ns.add_known_file('/moved/lib/python9.8/os.py')
ns.add_known_dir('/moved/lib/python9.8/lib-dynload')
ns.add_known_file('/venv/pyvenv.cfg', ['home = /moved/bin'])
expected = dict(
executable='/venv/bin/python',
base_executable='/moved/bin/python',
prefix='/venv',
exec_prefix='/venv',
base_prefix='/moved',
base_exec_prefix='/moved',
)
self.assertEqual(expected, getpath(ns, expected))

def test_buildpath_posix(self):
"""Test an in-build-tree layout on POSIX.

Expand Down Expand Up @@ -1157,7 +1248,7 @@ def __missing__(self, key):

def abspath(self, path):
if self.isabs(path):
return path
return posixpath.normpath(path)
return self.joinpath("/Absolute", path)

def basename(self, path):
Expand Down
11 changes: 11 additions & 0 deletions Lib/test/test_venv.py
Original file line number Diff line number Diff line change
Expand Up @@ -1141,6 +1141,17 @@ def test_zippath_from_non_installed_posix(self):
ld_library_path = os.path.join(sys.base_exec_prefix, "lib")
if not ld_library_path or sysconfig.is_python_build():
ld_library_path = os.path.abspath(os.path.dirname(sys.executable))
if (sysconfig.get_config_var('Py_ENABLE_SHARED')
and sys.platform != 'cygwin'):
# Startup can search relative to libpython before the executable.
# Load a copy from the temporary installation to select its
# standard library.
shared_libdir = os.path.join(non_installed_dir, 'lib')
os.makedirs(shared_libdir, exist_ok=True)
instsoname = sysconfig.get_config_var('INSTSONAME')
shutil.copy2(os.path.join(ld_library_path, instsoname),
os.path.join(shared_libdir, instsoname))
ld_library_path = os.pathsep.join((shared_libdir, ld_library_path))
if sys.platform == 'darwin':
ld_library_path_env = "DYLD_LIBRARY_PATH"
else:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
On POSIX, search parent directories of the shared library path for the unpacked
standard library, as already done for the standard-library ZIP file.
18 changes: 13 additions & 5 deletions Modules/getpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -562,9 +562,14 @@ def search_up(prefix, *landmarks, test=isfile):
stdlib_dir = None


# First try to detect prefix by looking alongside our runtime library, if known
# First try to detect prefix by searching from our runtime library, if known.
if library and not prefix:
library_dir = dirname(library)
if os_name != 'nt':
try:
library_dir = abspath(library_dir)
except OSError:
pass
if ZIP_LANDMARK:
if os_name == 'nt':
# QUIRK: Windows does not search up for ZIP file
Expand All @@ -573,10 +578,13 @@ def search_up(prefix, *landmarks, test=isfile):
else:
prefix = search_up(library_dir, ZIP_LANDMARK)
if STDLIB_SUBDIR and STDLIB_LANDMARKS and not prefix:
if any(isfile(joinpath(library_dir, f)) for f in STDLIB_LANDMARKS):
prefix = library_dir
if not stdlib_dir_was_set_in_config:
stdlib_dir = joinpath(prefix, STDLIB_SUBDIR)
if os_name == 'nt':
if any(isfile(joinpath(library_dir, f)) for f in STDLIB_LANDMARKS):
prefix = library_dir
else:
prefix = search_up(library_dir, *STDLIB_LANDMARKS)
if prefix and not stdlib_dir_was_set_in_config:
stdlib_dir = joinpath(prefix, STDLIB_SUBDIR)


# Detect prefix by looking for zip file
Expand Down
Loading