From 625403a9c46bdcf97fe71c5125a8d4dffe62e930 Mon Sep 17 00:00:00 2001 From: Fredrik Roubert Date: Tue, 14 Jan 2025 03:32:30 +0900 Subject: [PATCH] Switch to using lstat() instead of stat() to not match symlink targets. The convenience function samefile() calls stat() and samestat(), but this leads to treating a symlink and its target as the same which is unlikely to be intentional here as that doesn't work well with venv. --- news/13156.bugfix.rst | 1 + src/pip/_internal/utils/entrypoints.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 news/13156.bugfix.rst diff --git a/news/13156.bugfix.rst b/news/13156.bugfix.rst new file mode 100644 index 00000000000..7a2470c9208 --- /dev/null +++ b/news/13156.bugfix.rst @@ -0,0 +1 @@ +Show the correct path to the interpreter also when it's a symlink in a venv. diff --git a/src/pip/_internal/utils/entrypoints.py b/src/pip/_internal/utils/entrypoints.py index 15013693854..696148c5097 100644 --- a/src/pip/_internal/utils/entrypoints.py +++ b/src/pip/_internal/utils/entrypoints.py @@ -77,7 +77,10 @@ def get_best_invocation_for_this_python() -> str: # Try to use the basename, if it's the first executable. found_executable = shutil.which(exe_name) - if found_executable and os.path.samefile(found_executable, exe): + # Virtual environments often symlink to their parent Python binaries, but we don't + # want to treat the Python binaries as equivalent when the environment's Python is + # not on PATH (not activated). Thus, we don't follow symlinks. + if found_executable and os.path.samestat(os.lstat(found_executable), os.lstat(exe)): return exe_name # Use the full executable name, because we couldn't find something simpler.