Prioritize `PATH` over `py --list-paths` in Windows selection (#2057)

`uv --system` is failing in GitHub Actions, because `py --list-paths`
returns all the pre-cached Pythons:

```
-V:3.12 *        C:\hostedtoolcache\windows\Python\3.12.2\x64\python.exe
-V:3.12-32       C:\hostedtoolcache\windows\Python\3.12.2\x86\python.exe
-V:3.11          C:\hostedtoolcache\windows\Python\3.11.8\x64\python.exe
-V:3.11-32       C:\hostedtoolcache\windows\Python\3.11.8\x86\python.exe
-V:3.10          C:\hostedtoolcache\windows\Python\3.10.11\x64\python.exe
-V:3.10-32       C:\hostedtoolcache\windows\Python\3.10.11\x86\python.exe
-V:3.9           C:\hostedtoolcache\windows\Python\3.9.13\x64\python.exe
-V:3.9-32        C:\hostedtoolcache\windows\Python\3.9.13\x86\python.exe
-V:3.8           C:\hostedtoolcache\windows\Python\3.8.10\x64\python.exe
-V:3.8-32        C:\hostedtoolcache\windows\Python\3.8.10\x86\python.exe
-V:3.7           C:\hostedtoolcache\windows\Python\3.7.9\x64\python.exe
-V:3.7-32        C:\hostedtoolcache\windows\Python\3.7.9\x86\python.exe
```

So, our default selector returns the first entry here. But none of these
are actually in `PATH` except the one that the user installed via
`actions/setup-python@v5` -- that's the point of the action, that it
puts the correct versions in `PATH`.

It seems to me like we should prioritize `PATH` over `py --list-paths`.
Is there a good reason not to do this?

Closes: https://github.com/astral-sh/uv/issues/2056
This commit is contained in:
Charlie Marsh 2024-02-29 10:06:29 -05:00 committed by GitHub
parent 0fbfa11013
commit b983ff4fa7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 23 additions and 24 deletions

View File

@ -67,8 +67,9 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
# - name: "Install Python" - uses: actions/setup-python@v5
# run: choco install python with:
python-version: "3.10"
- name: "Install Rust toolchain" - name: "Install Rust toolchain"
run: rustup show run: rustup show
@ -82,7 +83,7 @@ jobs:
run: echo $(which python) run: echo $(which python)
- name: "Validate global Python install" - name: "Validate global Python install"
run: py -3.12 ./scripts/check_system_python.py --uv ./target/debug/uv run: py -3.10 ./scripts/check_system_python.py --uv ./target/debug/uv
install-pyenv: install-pyenv:
name: "Install Python using pyenv" name: "Install Python using pyenv"

View File

@ -164,10 +164,10 @@ search for a Python interpreter matching that version in the following order:
- An activated virtual environment based on the `VIRTUAL_ENV` environment variable. - An activated virtual environment based on the `VIRTUAL_ENV` environment variable.
- An activated Conda environment based on the `CONDA_PREFIX` environment variable. - An activated Conda environment based on the `CONDA_PREFIX` environment variable.
- A virtual environment at `.venv` in the current directory, or in the nearest parent directory. - A virtual environment at `.venv` in the current directory, or in the nearest parent directory.
- The Python interpreter available as, e.g., `python3.7` on macOS and Linux. On Windows, uv - The Python interpreter available as, e.g., `python3.7` on macOS and Linux.
will use the same mechanism as `py --list-paths` to discover all available Python interpreters,
and will select the first interpreter matching the requested version.
- The Python interpreter available as `python3` on macOS and Linux, or `python.exe` on Windows. - The Python interpreter available as `python3` on macOS and Linux, or `python.exe` on Windows.
- On Windows, the Python interpreter returned by `py --list-paths` that matches the requested
version.
Since uv has no dependency on Python, it can even install into virtual environments other than Since uv has no dependency on Python, it can even install into virtual environments other than
its own. For example, setting `VIRTUAL_ENV=/path/to/venv` will cause uv to install into its own. For example, setting `VIRTUAL_ENV=/path/to/venv` will cause uv to install into

View File

@ -96,7 +96,6 @@ pub(crate) fn try_find_default_python(
/// Finds a python version matching `selector`. /// Finds a python version matching `selector`.
/// It searches for an existing installation in the following order: /// It searches for an existing installation in the following order:
/// * (windows): Discover installations using `py --list-paths` (PEP514). Continue if `py` is not installed.
/// * Search for the python binary in `PATH` (or `UV_TEST_PYTHON_PATH` if set). Visits each path and for each path resolves the /// * Search for the python binary in `PATH` (or `UV_TEST_PYTHON_PATH` if set). Visits each path and for each path resolves the
/// files in the following order: /// files in the following order:
/// * Major.Minor.Patch: `pythonx.y.z`, `pythonx.y`, `python.x`, `python` /// * Major.Minor.Patch: `pythonx.y.z`, `pythonx.y`, `python.x`, `python`
@ -104,6 +103,7 @@ pub(crate) fn try_find_default_python(
/// * Major: `pythonx`, `python` /// * Major: `pythonx`, `python`
/// * Default: `python3`, `python` /// * Default: `python3`, `python`
/// * (windows): For each of the above, test for the existence of `python.bat` shim (pyenv-windows) last. /// * (windows): For each of the above, test for the existence of `python.bat` shim (pyenv-windows) last.
/// * (windows): Discover installations using `py --list-paths` (PEP514). Continue if `py` is not installed.
/// ///
/// (Windows): Filter out the windows store shim (Enabled in Settings/Apps/Advanced app settings/App execution aliases). /// (Windows): Filter out the windows store shim (Enabled in Settings/Apps/Advanced app settings/App execution aliases).
fn find_python( fn find_python(
@ -114,23 +114,7 @@ fn find_python(
#[allow(non_snake_case)] #[allow(non_snake_case)]
let UV_TEST_PYTHON_PATH = env::var_os("UV_TEST_PYTHON_PATH"); let UV_TEST_PYTHON_PATH = env::var_os("UV_TEST_PYTHON_PATH");
if cfg!(windows) && UV_TEST_PYTHON_PATH.is_none() { let override_path = UV_TEST_PYTHON_PATH.is_some();
// Use `py` to find the python installation on the system.
match windows::py_list_paths(selector, platform, cache) {
Ok(Some(interpreter)) => return Ok(Some(interpreter)),
Ok(None) => {
// No matching Python version found, continue searching PATH
}
Err(Error::PyList(error)) => {
if error.kind() == std::io::ErrorKind::NotFound {
debug!("`py` is not installed. Falling back to searching Python on the path");
// Continue searching for python installations on the path.
}
}
Err(error) => return Err(error),
}
}
let possible_names = selector.possible_names(); let possible_names = selector.possible_names();
#[allow(non_snake_case)] #[allow(non_snake_case)]
@ -197,6 +181,20 @@ fn find_python(
} }
} }
if cfg!(windows) && !override_path {
// Use `py` to find the python installation on the system.
match windows::py_list_paths(selector, platform, cache) {
Ok(Some(interpreter)) => return Ok(Some(interpreter)),
Ok(None) => {}
Err(Error::PyList(error)) => {
if error.kind() == std::io::ErrorKind::NotFound {
debug!("`py` is not installed");
}
}
Err(error) => return Err(error),
}
}
Ok(None) Ok(None)
} }