Allow system environments during project environment validity check (#7585)

This commit is contained in:
Zanie Blue 2024-09-20 12:28:17 -05:00 committed by GitHub
parent 8259600ca6
commit 9164999f23
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 108 additions and 33 deletions

View file

@ -37,7 +37,12 @@ pub struct EnvironmentNotFound {
#[derive(Clone, Debug, Error)]
pub struct InvalidEnvironment {
path: PathBuf,
reason: String,
pub kind: InvalidEnvironmentKind,
}
#[derive(Debug, Clone)]
pub enum InvalidEnvironmentKind {
NotDirectory,
MissingExecutable(PathBuf),
}
impl From<PythonNotFound> for EnvironmentNotFound {
@ -110,11 +115,22 @@ impl std::fmt::Display for InvalidEnvironment {
f,
"Invalid environment at `{}`: {}",
self.path.user_display(),
self.reason
self.kind
)
}
}
impl std::fmt::Display for InvalidEnvironmentKind {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::NotDirectory => write!(f, "expected directory but found a file"),
Self::MissingExecutable(path) => {
write!(f, "missing Python executable at `{}`", path.user_display())
}
}
}
}
impl PythonEnvironment {
/// Find a [`PythonEnvironment`] matching the given request and preference.
///
@ -139,6 +155,8 @@ impl PythonEnvironment {
}
/// Create a [`PythonEnvironment`] from the virtual environment at the given root.
///
/// 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,
@ -154,20 +172,24 @@ impl PythonEnvironment {
if venv.is_file() {
return Err(InvalidEnvironment {
path: venv,
reason: "expected directory but found a file".to_string(),
kind: InvalidEnvironmentKind::NotDirectory,
}
.into());
}
if !venv.join("pyvenv.cfg").is_file() {
let executable = virtualenv_python_executable(&venv);
// 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 !(executable.is_symlink() || executable.is_file()) {
return Err(InvalidEnvironment {
path: venv,
reason: "missing a `pyvenv.cfg` marker".to_string(),
kind: InvalidEnvironmentKind::MissingExecutable(executable.clone()),
}
.into());
}
};
let executable = virtualenv_python_executable(venv);
let interpreter = Interpreter::query(executable, cache)?;
Ok(Self(Arc::new(PythonEnvironmentShared {