From f88be7d1548d9161ad7ac6652ad5cdb26dfed6eb Mon Sep 17 00:00:00 2001 From: konstin Date: Thu, 23 Oct 2025 16:32:29 +0200 Subject: [PATCH 1/4] Don't duplicate exit status Previously: ``` error: Querying Python at `/home/konsti/projects/pdm/.venv/bin/python3` failed with exit status exit status: 1 ``` --- crates/uv-python/src/interpreter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/uv-python/src/interpreter.rs b/crates/uv-python/src/interpreter.rs index bb65e9bf2..80f36dff1 100644 --- a/crates/uv-python/src/interpreter.rs +++ b/crates/uv-python/src/interpreter.rs @@ -794,7 +794,7 @@ impl Display for StatusCodeError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!( f, - "Querying Python at `{}` failed with exit status {}", + "Querying Python at `{}` failed with {}", self.path.display(), self.code )?; From a2b603f8fe6c0fa8867fd5cd3c13083592aa5893 Mon Sep 17 00:00:00 2001 From: konstin Date: Thu, 23 Oct 2025 17:39:16 +0200 Subject: [PATCH 2/4] Show a better hint for broken PBS venvs For some reason, I'm encountering broken PBS venvs again (https://github.com/astral-sh/python-build-standalone/issues/380). Instead of showing the obscure error to the user, we point them to the PBS bug and ask them to run `uv venv`. ``` $ uv sync error: Querying Python at `/tmp/uv/tests/.tmpwXZRTI/temp/.venv/bin/python3` failed with exit status exit status: 1 [stderr] Could not find platform independent libraries Could not find platform dependent libraries Python path configuration: PYTHONHOME = (not set) PYTHONPATH = (not set) program name = '/tmp/uv/tests/.tmpwXZRTI/temp/.venv/bin/python3' isolated = 1 environment = 0 user site = 0 safe_path = 1 import site = 1 is in build tree = 0 stdlib dir = '/install/lib/python3.12' sys._base_executable = '/home/konsti/.local/share/uv/python/cpython-3.12.9-linux-x86_64-gnu/bin/python3.12' sys.base_prefix = '/install' sys.base_exec_prefix = '/install' sys.platlibdir = 'lib' sys.executable = '/tmp/uv/tests/.tmpwXZRTI/temp/.venv/bin/python3' sys.prefix = '/install' sys.exec_prefix = '/install' sys.path = [ '/install/lib/python312.zip', '/install/lib/python3.12', '/install/lib/python3.12/lib-dynload', ] Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding Python runtime state: core initialized ModuleNotFoundError: No module named 'encodings' Current thread 0x000078e48b835740 (most recent call first): ``` ``` $ uv-debug sync error: Can't use Python at `/tmp/uv/tests/.tmpwXZRTI/temp/.venv/bin/python3` Caused by: Python is missing PYTHONHOME. If you are using a managed Python interpreter, this is a known bug (https://github.com/astral-sh/python-build-standalone/issues/380). You can recreate the virtual environment with `uv venv`. ``` --- crates/uv-python/src/interpreter.rs | 49 +++++++++++++++++++--------- crates/uv/tests/it/python_install.rs | 46 ++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 15 deletions(-) diff --git a/crates/uv-python/src/interpreter.rs b/crates/uv-python/src/interpreter.rs index 80f36dff1..2e3f9762c 100644 --- a/crates/uv-python/src/interpreter.rs +++ b/crates/uv-python/src/interpreter.rs @@ -918,6 +918,27 @@ pub enum InterpreterInfoError { }, #[error("Only Pyodide is support for Emscripten Python")] EmscriptenNotPyodide, + #[error("Python is missing PYTHONHOME. If you are using a managed Python interpreter, this is a known bug (https://github.com/astral-sh/python-build-standalone/issues/380). You can recreate the virtual environment with `{}`.", "uv venv".green())] + PythonHomeNotFound, +} + +impl InterpreterInfoError { + /// Check whether the stderr of `python` matches a known pattern. + pub(crate) fn from_query_stderr(stderr: &str) -> Option { + // If the Python version is too old, we may not even be able to invoke the query script + if stderr.contains("Unknown option: -I") { + return Some(Self::UnsupportedPython); + } + + // Until we fixed the PBS bug, inform the user that this is bug on our side and can be fixed + // with `uv venv`. + // https://github.com/astral-sh/python-build-standalone/issues/380 + if stderr.contains("ModuleNotFoundError: No module named 'encodings'") { + return Some(Self::PythonHomeNotFound); + } + + None + } } #[allow(clippy::struct_excessive_bools)] @@ -994,10 +1015,9 @@ impl InterpreterInfo { if !output.status.success() { let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string(); - // If the Python version is too old, we may not even be able to invoke the query script - if stderr.contains("Unknown option: -I") { + if let Some(query_error) = InterpreterInfoError::from_query_stderr(&stderr) { return Err(Error::QueryScript { - err: InterpreterInfoError::UnsupportedPython, + err: query_error, path: interpreter.to_path_buf(), }); } @@ -1014,20 +1034,19 @@ impl InterpreterInfo { serde_json::from_slice(&output.stdout).map_err(|err| { let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string(); - // If the Python version is too old, we may not even be able to invoke the query script - if stderr.contains("Unknown option: -I") { - Error::QueryScript { - err: InterpreterInfoError::UnsupportedPython, + if let Some(query_error) = InterpreterInfoError::from_query_stderr(&stderr) { + return Error::QueryScript { + err: query_error, path: interpreter.to_path_buf(), - } - } else { - Error::UnexpectedResponse(UnexpectedResponseError { - err, - stdout: String::from_utf8_lossy(&output.stdout).trim().to_string(), - stderr, - path: interpreter.to_path_buf(), - }) + }; } + + Error::UnexpectedResponse(UnexpectedResponseError { + err, + stdout: String::from_utf8_lossy(&output.stdout).trim().to_string(), + stderr, + path: interpreter.to_path_buf(), + }) })?; match result { diff --git a/crates/uv/tests/it/python_install.rs b/crates/uv/tests/it/python_install.rs index 98ca7756b..ddb331d91 100644 --- a/crates/uv/tests/it/python_install.rs +++ b/crates/uv/tests/it/python_install.rs @@ -4,6 +4,7 @@ use std::path::PathBuf; use std::{env, path::Path, process::Command}; use crate::common::{TestContext, uv_snapshot}; +use anyhow::Result; use assert_cmd::assert::OutputAssertExt; use assert_fs::{ assert::PathAssert, @@ -3950,3 +3951,48 @@ fn python_install_upgrade_version_file() { hint: The version request came from a `.python-version` file; change the patch version in the file to upgrade instead "); } + +/// Show a fitting error message for +/// . +#[cfg(unix)] +#[test] +fn missing_python_home_error_message() -> Result<()> { + let context = TestContext::new("3.12"); + + // Create a Python project so we can use `uv sync` + context.init().assert().success(); + + // Create a broken venv from a symlink. + let sys_executable = fs_err::canonicalize(context.venv.join("bin").join("python"))?; + fs_err::os::unix::fs::symlink(sys_executable, context.temp_dir.join("python-link"))?; + fs_err::remove_dir_all(context.venv.as_ref())?; + Command::new(context.temp_dir.join("python-link")) + .arg("-m") + .arg("venv") + .arg("--without-pip") + .arg(context.venv.as_ref()) + .assert() + .success(); + + uv_snapshot!(context.filters(), context.pip_list().arg("-p").arg(context.venv.join("bin").join("python")), @r" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: Failed to inspect Python interpreter from provided path at `.venv/bin/python` + Caused by: Can't use Python at `[VENV]/bin/python` + Caused by: Python is missing PYTHONHOME. If you are using a managed Python interpreter, this is a known bug (https://github.com/astral-sh/python-build-standalone/issues/380). You can recreate the virtual environment with `uv venv`. + "); + + // By default, we skip broken interpreters + uv_snapshot!(context.filters(), context.pip_list(), @r" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + "); + + Ok(()) +} From c6c6cd38a44378511e042581c6a5dd463a19aaa7 Mon Sep 17 00:00:00 2001 From: konstin Date: Thu, 23 Oct 2025 17:51:12 +0200 Subject: [PATCH 3/4] Windows clippy --- crates/uv/tests/it/python_install.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/uv/tests/it/python_install.rs b/crates/uv/tests/it/python_install.rs index ddb331d91..58abd6d52 100644 --- a/crates/uv/tests/it/python_install.rs +++ b/crates/uv/tests/it/python_install.rs @@ -4,7 +4,6 @@ use std::path::PathBuf; use std::{env, path::Path, process::Command}; use crate::common::{TestContext, uv_snapshot}; -use anyhow::Result; use assert_cmd::assert::OutputAssertExt; use assert_fs::{ assert::PathAssert, @@ -3956,7 +3955,7 @@ fn python_install_upgrade_version_file() { /// . #[cfg(unix)] #[test] -fn missing_python_home_error_message() -> Result<()> { +fn missing_python_home_error_message() -> anyhow::Result<()> { let context = TestContext::new("3.12"); // Create a Python project so we can use `uv sync` From 2bf2bf78afac3170c03b022e90fc1aa0ad589697 Mon Sep 17 00:00:00 2001 From: konstin Date: Thu, 11 Dec 2025 16:42:23 +0100 Subject: [PATCH 4/4] Wording? --- crates/uv-python/src/interpreter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/uv-python/src/interpreter.rs b/crates/uv-python/src/interpreter.rs index 2e3f9762c..64a8df323 100644 --- a/crates/uv-python/src/interpreter.rs +++ b/crates/uv-python/src/interpreter.rs @@ -918,7 +918,7 @@ pub enum InterpreterInfoError { }, #[error("Only Pyodide is support for Emscripten Python")] EmscriptenNotPyodide, - #[error("Python is missing PYTHONHOME. If you are using a managed Python interpreter, this is a known bug (https://github.com/astral-sh/python-build-standalone/issues/380). You can recreate the virtual environment with `{}`.", "uv venv".green())] + #[error("Python is missing PYTHONHOME. If you are using a managed Python interpreter, this is a bug in older patch versions. Reinstalling the latest patch version and recreating the virtual environment solves this: `{}` and `{}`.", "uv python install --reinstall".green(), "uv venv".green())] PythonHomeNotFound, }