mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-01 17:42:19 +00:00
Avoid resolving symbolic links when querying Python interpreters (#11083)
Closes https://github.com/astral-sh/uv/issues/11048 This brings the `PythonEnvironment::from_root` behavior in-line with the rest of uv Python discovery behavior (and in-line with pip). It's not clear why we were canonicalizing the path in the first place here.
This commit is contained in:
parent
586bab32b9
commit
d281f49103
3 changed files with 105 additions and 12 deletions
|
@ -4,6 +4,7 @@ use std::env;
|
|||
use std::fmt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
use tracing::debug;
|
||||
use uv_cache::Cache;
|
||||
use uv_cache_key::cache_digest;
|
||||
use uv_fs::{LockedFile, Simplified};
|
||||
|
@ -161,9 +162,13 @@ impl PythonEnvironment {
|
|||
///
|
||||
/// N.B. This function also works for system Python environments and users depend on this.
|
||||
pub fn from_root(root: impl AsRef<Path>, cache: &Cache) -> Result<Self, Error> {
|
||||
let venv = match fs_err::canonicalize(root.as_ref()) {
|
||||
Ok(venv) => venv,
|
||||
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
|
||||
debug!(
|
||||
"Checking for Python environment at `{}`",
|
||||
root.as_ref().user_display()
|
||||
);
|
||||
match root.as_ref().try_exists() {
|
||||
Ok(true) => {}
|
||||
Ok(false) => {
|
||||
return Err(Error::MissingEnvironment(EnvironmentNotFound {
|
||||
preference: EnvironmentPreference::Any,
|
||||
request: PythonRequest::Directory(root.as_ref().to_owned()),
|
||||
|
@ -172,30 +177,35 @@ impl PythonEnvironment {
|
|||
Err(err) => return Err(Error::Discovery(err.into())),
|
||||
};
|
||||
|
||||
if venv.is_file() {
|
||||
if root.as_ref().is_file() {
|
||||
return Err(InvalidEnvironment {
|
||||
path: venv,
|
||||
path: root.as_ref().to_path_buf(),
|
||||
kind: InvalidEnvironmentKind::NotDirectory,
|
||||
}
|
||||
.into());
|
||||
}
|
||||
|
||||
if venv.read_dir().is_ok_and(|mut dir| dir.next().is_none()) {
|
||||
if root
|
||||
.as_ref()
|
||||
.read_dir()
|
||||
.is_ok_and(|mut dir| dir.next().is_none())
|
||||
{
|
||||
return Err(InvalidEnvironment {
|
||||
path: venv,
|
||||
path: root.as_ref().to_path_buf(),
|
||||
kind: InvalidEnvironmentKind::Empty,
|
||||
}
|
||||
.into());
|
||||
}
|
||||
|
||||
let executable = virtualenv_python_executable(&venv);
|
||||
// Note we do not canonicalize the root path or the executable path, this is important
|
||||
// because the path the interpreter is invoked at can determine the value of
|
||||
// `sys.executable`.
|
||||
let executable = virtualenv_python_executable(&root);
|
||||
|
||||
// Check if the executable exists before querying so we can provide a more specific error
|
||||
// Note we intentionally don't require a resolved link to exist here, we're just trying to
|
||||
// tell if this _looks_ like a Python environment.
|
||||
// If we can't find an executable, exit before querying to provide a better error.
|
||||
if !(executable.is_symlink() || executable.is_file()) {
|
||||
return Err(InvalidEnvironment {
|
||||
path: venv,
|
||||
path: root.as_ref().to_path_buf(),
|
||||
kind: InvalidEnvironmentKind::MissingExecutable(executable.clone()),
|
||||
}
|
||||
.into());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue