mirror of https://github.com/astral-sh/uv
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 <prefix> Could not find platform dependent libraries <exec_prefix> 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): <no Python frame> ``` ``` $ 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`. ```
This commit is contained in:
parent
f88be7d154
commit
a2b603f8fe
|
|
@ -918,6 +918,27 @@ pub enum InterpreterInfoError {
|
||||||
},
|
},
|
||||||
#[error("Only Pyodide is support for Emscripten Python")]
|
#[error("Only Pyodide is support for Emscripten Python")]
|
||||||
EmscriptenNotPyodide,
|
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<Self> {
|
||||||
|
// 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)]
|
#[allow(clippy::struct_excessive_bools)]
|
||||||
|
|
@ -994,10 +1015,9 @@ impl InterpreterInfo {
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
|
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 let Some(query_error) = InterpreterInfoError::from_query_stderr(&stderr) {
|
||||||
if stderr.contains("Unknown option: -I") {
|
|
||||||
return Err(Error::QueryScript {
|
return Err(Error::QueryScript {
|
||||||
err: InterpreterInfoError::UnsupportedPython,
|
err: query_error,
|
||||||
path: interpreter.to_path_buf(),
|
path: interpreter.to_path_buf(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -1014,20 +1034,19 @@ impl InterpreterInfo {
|
||||||
serde_json::from_slice(&output.stdout).map_err(|err| {
|
serde_json::from_slice(&output.stdout).map_err(|err| {
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
|
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 let Some(query_error) = InterpreterInfoError::from_query_stderr(&stderr) {
|
||||||
if stderr.contains("Unknown option: -I") {
|
return Error::QueryScript {
|
||||||
Error::QueryScript {
|
err: query_error,
|
||||||
err: InterpreterInfoError::UnsupportedPython,
|
|
||||||
path: interpreter.to_path_buf(),
|
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 {
|
match result {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use std::path::PathBuf;
|
||||||
use std::{env, path::Path, process::Command};
|
use std::{env, path::Path, process::Command};
|
||||||
|
|
||||||
use crate::common::{TestContext, uv_snapshot};
|
use crate::common::{TestContext, uv_snapshot};
|
||||||
|
use anyhow::Result;
|
||||||
use assert_cmd::assert::OutputAssertExt;
|
use assert_cmd::assert::OutputAssertExt;
|
||||||
use assert_fs::{
|
use assert_fs::{
|
||||||
assert::PathAssert,
|
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
|
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
|
||||||
|
/// <https://github.com/astral-sh/python-build-standalone/issues/380>.
|
||||||
|
#[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(())
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue