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
28 changes: 28 additions & 0 deletions Lib/test/test_getpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,34 @@ def test_symlink_normal_posix(self):
actual = getpath(ns, expected)
self.assertEqual(expected, actual)

def test_bad_argv0_posix(self):
"""Test that executable resolves correctly if argv0 is not Python and we
know real_executable (getpath.c computes it from readlink(/proc/self/exe)).
"""
ns = MockPosixNamespace(
PREFIX="/usr",
argv0="not-python",
real_executable="/usr/bin/python",
)
ns.add_known_xfile("/usr/bin/python")
ns.add_known_file("/usr/lib/python9.8/os.py")
ns.add_known_dir("/usr/lib/python9.8/lib-dynload")
expected = dict(
executable="/usr/bin/python",
base_executable="/usr/bin/python",
prefix="/usr",
exec_prefix="/usr",
module_search_paths_set=1,
module_search_paths=[
"/usr/lib/python98.zip",
"/usr/lib/python9.8",
"/usr/lib/python9.8/lib-dynload",
],
)
actual = getpath(ns, expected)
self.assertEqual(expected, actual)


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

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
On POSIX, we now try to read the symlink target from ``/proc/self/exe`` to
determine :data:`sys.executable`.
5 changes: 5 additions & 0 deletions Modules/getpath.c
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,11 @@ progname_to_dict(PyObject *dict, const char *key)
PyMem_RawFree(path);
break;
}
#elif defined(HAVE_READLINK)
wchar_t resolved[MAXPATHLEN + 1];
if (_Py_wreadlink(L"/proc/self/exe", resolved, Py_ARRAY_LENGTH(resolved)) > 0) {
return wchar_to_dict(dict, key, resolved);
}
#endif
return PyDict_SetItemString(dict, key, Py_None) == 0;
}
Expand Down
11 changes: 11 additions & 0 deletions Modules/getpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,17 @@ def search_up(prefix, *landmarks, test=isfile):
# whether we are in a build tree. This is true even if the
# executable path was provided in the config.
real_executable = executable
elif os_name == 'posix' and real_executable:
# real_executable is more accurate than the value we have computed for
# executable, so use it instead if it resolves to a different path
# (eg. GH-124241).
# If real_executable and executable resolve to the same path, prefer
# executable, as that is much more likely to be the path the user is using.
try:
if realpath(executable) != real_executable:
executable = real_executable
except OSError:
pass

if not executable and program_name and ENV_PATH:
# Resolve names against PATH.
Expand Down
Loading