astral-sh / astral-sh/python-build-standalone
Do not canonicalize the executable in getpath quite so much
- Dominant language
- Python
- Stars
- 4.4k
- Forks
- 314
- Avg merge
- 1d 9h
- Merged PRs (30d)
- 27
Description
In #896 and subsequent PRs, we started using /proc/self/exe to locate the interpreter on Linux, which returns a fully canonicalized (symlink-resolved) path. uv now has a "transparent upgrades" feature where it creates a symlink from the major.minor directory to the major.minor.patch one (e.g., `.local/share/uv/python/cpython-3.13-linux-x86_64-gnu` -> `cpython-3.13.13-linux-x86_64-gnu`), and references the symlink wherever possible. While this generally works right (in particular, venv/bin/python and venv/pyvenv.cfg reference the symlink and so they get upgraded), we now cause `sys.base_prefix`, `sys.path`, etc. to have the fully-canonicalized path, and it was vaguely an intention of this uv feature that it would not get canonicalized.
Here's the output on my system from Python 3.9 (without the getpath fix) vs. Python 3.13:
```console
$ uvx python3.9
Python 3.9.25 (main, Oct 31 2025, 23:00:23)
[Clang 21.1.4 ] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys, http
>>> sys.base_prefix
'/home/ubuntu/.local/share/uv/python/cpython-3.9-linux-x86_64-gnu'
>>> http
$ uvx python3.13
Python 3.13.13 (main, Apr 14 2026, 14:28:56) [Clang 22.1.3 ] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys, http
>>> sys.base_prefix
'/home/ubuntu/.local/share/uv/python/cpython-3.13.13-linux-x86_64-gnu'
>>> http
```
I don't think this is a huge problem, just something I ran into in uv#19123, where I noticed this continues to behave as intended on Windows (and I took a mild risk that Windows might canonicalize the path and it's fine because nobody's complained on Linux yet).
I believe some of the Bazel folks also have a use case for under-canonicalizing the path so that it stays within the Bazel workspace/sandbox or something, I can try to remember the details.
Doing this right is a little tricky. I think maybe the answer is we want to calculate a path via the current/upstream getpath rules, _also_ calculate /proc/self/exe, and only use the latter if it's genuinely a different file (e.g., argv[0] or $PATH is bogus) or if upstream getpath failed to return a result at all.
Contributor guide
Research direction
Start by tracing the upstream getpath rules alongside the Linux /proc/self/exe handling, including how argv[0] and PATH are considered. Done means preserving the intended symlink-based path for sys.base_prefix and sys.path, while using /proc/self/exe only when the normal calculation is invalid or unavailable.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- linux, python
- Domain
- operating-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100