From 11115c98703fa7206a83a96f5ad49cf17d2cd3ff Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Wed, 7 May 2025 13:09:56 -0500 Subject: [PATCH] Avoid enumerating sources in errors for path Python requests --- crates/uv-python/src/discovery.rs | 6 +++++ crates/uv/tests/it/common/mod.rs | 13 ++++++++++ crates/uv/tests/it/pip_compile.rs | 2 +- crates/uv/tests/it/python_find.rs | 42 ++++++++++++++++++++++++++++++- 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/crates/uv-python/src/discovery.rs b/crates/uv-python/src/discovery.rs index 6add5eeae2957..379b839a8163b 100644 --- a/crates/uv-python/src/discovery.rs +++ b/crates/uv-python/src/discovery.rs @@ -2646,6 +2646,12 @@ impl fmt::Display for PythonNotFound { PythonRequest::Default | PythonRequest::Any => { write!(f, "No interpreter found in {sources}") } + PythonRequest::File(_) => { + write!(f, "No interpreter found at {}", self.request) + } + PythonRequest::Directory(_) => { + write!(f, "No interpreter found in {}", self.request) + } _ => { write!(f, "No interpreter found for {} in {sources}", self.request) } diff --git a/crates/uv/tests/it/common/mod.rs b/crates/uv/tests/it/common/mod.rs index 6096c4ab95116..93fff441bb9c7 100644 --- a/crates/uv/tests/it/common/mod.rs +++ b/crates/uv/tests/it/common/mod.rs @@ -293,6 +293,19 @@ impl TestContext { self } + /// Adds a filter for platform-specific errors when a file is not executable. + #[inline] + pub fn with_filtered_not_executable(mut self) -> Self { + let pattern = if cfg!(unix) { + r"Permission denied \(os error 13\)" + } else { + r"\%1 is not a valid Win32 application. \(os error 193\)" + }; + self.filters + .push((pattern.to_string(), "[PERMISSION DENIED]".to_string())); + self + } + /// Adds a filter that ignores platform information in a Python installation key. pub fn with_filtered_python_keys(mut self) -> Self { // Filter platform keys diff --git a/crates/uv/tests/it/pip_compile.rs b/crates/uv/tests/it/pip_compile.rs index cc0c95f90ba9d..99f0e61e326fc 100644 --- a/crates/uv/tests/it/pip_compile.rs +++ b/crates/uv/tests/it/pip_compile.rs @@ -17381,7 +17381,7 @@ fn compile_broken_active_venv() -> Result<()> { ----- stdout ----- ----- stderr ----- - × No interpreter found for path `python3.14159` in managed installations or search path + × No interpreter found at path `python3.14159` "); // Simulate a removed Python interpreter diff --git a/crates/uv/tests/it/python_find.rs b/crates/uv/tests/it/python_find.rs index 99611c4188e6b..621385729e0de 100644 --- a/crates/uv/tests/it/python_find.rs +++ b/crates/uv/tests/it/python_find.rs @@ -1,4 +1,4 @@ -use assert_fs::prelude::PathChild; +use assert_fs::prelude::{FileTouch, PathChild}; use assert_fs::{fixture::FileWriteStr, prelude::PathCreateDir}; use indoc::indoc; @@ -977,3 +977,43 @@ fn python_find_show_version() { ----- stderr ----- "); } + +#[test] +fn python_find_path() { + let context: TestContext = TestContext::new_with_versions(&[]).with_filtered_not_executable(); + + context.temp_dir.child("foo").create_dir_all().unwrap(); + context.temp_dir.child("bar").touch().unwrap(); + + // No interpreter in a directory + uv_snapshot!(context.filters(), context.python_find().arg(context.temp_dir.child("foo").as_os_str()), @r" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: No interpreter found in directory `foo` + "); + + // No interpreter at a file + uv_snapshot!(context.filters(), context.python_find().arg(context.temp_dir.child("bar").as_os_str()), @r" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: Failed to inspect Python interpreter from provided path at `bar` + Caused by: Failed to query Python interpreter at `[TEMP_DIR]/bar` + Caused by: [PERMISSION DENIED] + "); + + // No interpreter at a file that does not exist + uv_snapshot!(context.filters(), context.python_find().arg(context.temp_dir.child("foobar").as_os_str()), @r" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: No interpreter found at path `foobar` + "); +}