Prefer `python` in a later PATH entry over `pythonX.Y` in an earlier entry
Originally discussed at https://github.com/astral-sh/uv/issues/6348#issuecomment-2304993544
While I don't think it's necessary for the documentation to give every detail of the discovery process, this presumes that discovery is intuitive - and IMO, defaulting to an older version of Python when there's no python command on the PATH (and hence no "default Python" at the command line) is not intuitive. I don't think the existence of python3.x on PATH should ever influence the decision on what the default Python version should be - by having an explicit version in the executable name, it's by definition not used as a default...
I think the problem is we look for all valid Python executable names on the PATH one directory at a time. Instead, pythonX.Y should only be used if we can't find any Python executable on the PATH with the name python or python3 or if you specifically request --python X.Y. This will be a little tricky to do in a performant manner, i.e., we don't want to list and parse the members of the directories on the PATH repeatedly.
Arguably a breaking change.
For troubleshooting issues it is better to have well-defined logic:
- Look for
python. - If not found, look for
python3.
Also, where is the performance problem here?
For troubleshooting issues it is better to have well-defined logic:
We do have well-defined logic: look for compatible Python executables in each directory on the PATH, in-order, taking the first match.
Also, where is the performance problem here?
We would need to list every directory on the PATH instead of just the first one to discover python3.
We do have well-defined logic: look for compatible Python executables in each directory on the PATH, in-order, taking the first match.
Okay, well-established may sound better. For me well established logic for shell scripts is to check type python (or which python), then type python3. But not in each dir look for python or python3.
We would need to list every directory on the PATH instead of just the first one to discover python3.
And what is the performance loss here? Also, how different would it be to call type python instead of manual search?
I agree that the current system might cause unwanted behaviors. For instance, I use brew, which installs its own python executables when you download a formula, but asdf as a global package manager.
I want uv to use asdf installed python when I run uv venv, but instead it ends up using the brew one as they come before on the list:
❯ uv python list
cpython-3.14.0a4+freethreaded-macos-aarch64-none <download available>
cpython-3.14.0a4-macos-aarch64-none <download available>
cpython-3.13.1+freethreaded-macos-aarch64-none <download available>
cpython-3.13.1-macos-aarch64-none /opt/homebrew/opt/[email protected]/bin/python3.13 -> ../Frameworks/Python.framework/Versions/3.13/bin/python3.13
cpython-3.13.1-macos-aarch64-none <download available>
cpython-3.12.8-macos-aarch64-none /opt/homebrew/opt/[email protected]/bin/python3.12 -> ../Frameworks/Python.framework/Versions/3.12/bin/python3.12
cpython-3.12.8-macos-aarch64-none <download available>
cpython-3.11.11-macos-aarch64-none <download available>
cpython-3.11.10-macos-aarch64-none /opt/homebrew/opt/[email protected]/bin/python3.11 -> ../Frameworks/Python.framework/Versions/3.11/bin/python3.11
cpython-3.11.7-macos-aarch64-none /Users/wtfzambo/.asdf/installs/python/3.11.7/bin/python3.11
cpython-3.11.7-macos-aarch64-none /Users/wtfzambo/.asdf/installs/python/3.11.7/bin/python3 -> python3.11
cpython-3.11.7-macos-aarch64-none /Users/wtfzambo/.asdf/installs/python/3.11.7/bin/python -> python3.11
...
The current workaround for me is to run venv like this
uv venv --python=$(asdf where python)
Or alternatively, to set UV_PYTHON env variable. Not game breaking, but a bit inconvenient for sure.
Saw you link this issue from elsewhere, I think this could make sense! pyright prefers pythonX.Y in earlier entry and that caused confusion at work earlier this week