Skip to content

Commit 01ebaef

Browse files
Avoid Windows Store shims in --python python3-like invocations (#2212)
## Summary We have logic in `python_query.rs` to filter out Windows Store shims when you use invocations like `-p 3.10`, but not `--python python3`, which is uncommon but allowed on Windows. Closes #2211.
1 parent cf94df7 commit 01ebaef

File tree

2 files changed

+37
-21
lines changed

2 files changed

+37
-21
lines changed

crates/uv-interpreter/src/interpreter.rs

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use std::ffi::{OsStr, OsString};
21
use std::io::Write;
32
use std::path::{Path, PathBuf};
43
use std::process::Command;
@@ -200,25 +199,6 @@ impl Interpreter {
200199
}
201200
}
202201

203-
/// Find the Python interpreter in `PATH`, respecting `UV_PYTHON_PATH`.
204-
///
205-
/// Returns `Ok(None)` if not found.
206-
pub(crate) fn find_executable<R: AsRef<OsStr> + Into<OsString> + Copy>(
207-
requested: R,
208-
) -> Result<Option<PathBuf>, Error> {
209-
let result = if let Some(isolated) = std::env::var_os("UV_TEST_PYTHON_PATH") {
210-
which::which_in(requested, Some(isolated), std::env::current_dir()?)
211-
} else {
212-
which::which(requested)
213-
};
214-
215-
match result {
216-
Err(which::Error::CannotFindBinaryPath) => Ok(None),
217-
Err(err) => Err(Error::WhichError(requested.into(), err)),
218-
Ok(path) => Ok(Some(path)),
219-
}
220-
}
221-
222202
/// Returns the path to the Python virtual environment.
223203
#[inline]
224204
pub fn platform(&self) -> &Platform {

crates/uv-interpreter/src/python_query.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use std::borrow::Cow;
44
use std::env;
5+
use std::ffi::{OsStr, OsString};
56
use std::path::PathBuf;
67

78
use tracing::{debug, instrument};
@@ -58,7 +59,7 @@ pub fn find_requested_python(
5859
}
5960
} else if !request.contains(std::path::MAIN_SEPARATOR) {
6061
// `-p python3.10`; Generally not used on windows because all Python are `python.exe`.
61-
let Some(executable) = Interpreter::find_executable(request)? else {
62+
let Some(executable) = find_executable(request)? else {
6263
return Ok(None);
6364
};
6465
Interpreter::query(&executable, platform.clone(), cache).map(Some)
@@ -198,6 +199,41 @@ fn find_python(
198199
Ok(None)
199200
}
200201

202+
/// Find the Python interpreter in `PATH` matching the given name (e.g., `python3`, respecting
203+
/// `UV_PYTHON_PATH`.
204+
///
205+
/// Returns `Ok(None)` if not found.
206+
fn find_executable<R: AsRef<OsStr> + Into<OsString> + Copy>(
207+
requested: R,
208+
) -> Result<Option<PathBuf>, Error> {
209+
#[allow(non_snake_case)]
210+
let UV_TEST_PYTHON_PATH = env::var_os("UV_TEST_PYTHON_PATH");
211+
212+
#[allow(non_snake_case)]
213+
let PATH = UV_TEST_PYTHON_PATH
214+
.or(env::var_os("PATH"))
215+
.unwrap_or_default();
216+
217+
// We use `which` here instead of joining the paths ourselves because `which` checks for us if the python
218+
// binary is executable and exists. It also has some extra logic that handles inconsistent casing on Windows
219+
// and expands `~`.
220+
for path in env::split_paths(&PATH) {
221+
let paths = match which::which_in_global(requested, Some(&path)) {
222+
Ok(paths) => paths,
223+
Err(which::Error::CannotFindBinaryPath) => continue,
224+
Err(err) => return Err(Error::WhichError(requested.into(), err)),
225+
};
226+
for path in paths {
227+
if cfg!(windows) && windows::is_windows_store_shim(&path) {
228+
continue;
229+
}
230+
return Ok(Some(path));
231+
}
232+
}
233+
234+
Ok(None)
235+
}
236+
201237
#[derive(Debug, Clone)]
202238
enum PythonInstallation {
203239
PyListPath {

0 commit comments

Comments
 (0)