Refactor toolchain discovery to use `satisfies_system_python` explicitly (#4310)

Splitting out the refactor from
https://github.com/astral-sh/uv/pull/4309
This commit is contained in:
Zanie Blue 2024-06-13 13:44:53 -04:00 committed by GitHub
parent b07c132ede
commit 572551c108
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 62 additions and 56 deletions

View File

@ -357,17 +357,12 @@ fn python_executables_from_search_path<'a>(
fn python_interpreters<'a>(
version: Option<&'a VersionRequest>,
implementation: Option<&'a ImplementationName>,
system: SystemPython,
sources: &ToolchainSources,
cache: &'a Cache,
) -> impl Iterator<Item = Result<(ToolchainSource, Interpreter), Error>> + 'a {
// TODO(zanieb): Move filtering to callers
filter_by_system_python(
python_interpreters_from_executables(
python_executables(version, implementation, sources),
cache,
),
system,
python_interpreters_from_executables(
python_executables(version, implementation, sources),
cache,
)
}
@ -393,56 +388,63 @@ fn python_interpreters_from_executables<'a>(
})
}
fn filter_by_system_python<'a>(
interpreters: impl Iterator<Item = Result<(ToolchainSource, Interpreter), Error>> + 'a,
/// Returns true if a interpreter matches the system Python policy.
fn satisfies_system_python(
source: ToolchainSource,
interpreter: &Interpreter,
system: SystemPython,
) -> impl Iterator<Item = Result<(ToolchainSource, Interpreter), Error>> + 'a {
interpreters.filter(move |result| match result {
// Filter the returned interpreters to conform to the system request
Ok((source, interpreter)) => match (
system,
// Conda environments are not conformant virtual environments but we should not treat them as system interpreters
interpreter.is_virtualenv() || matches!(source, ToolchainSource::CondaPrefix),
) {
(SystemPython::Allowed, _) => true,
(SystemPython::Explicit, false) => {
if matches!(
source,
ToolchainSource::ProvidedPath | ToolchainSource::ParentInterpreter
) {
debug!(
"Allowing system Python interpreter at `{}`",
interpreter.sys_executable().display()
);
true
} else {
debug!(
"Ignoring Python interpreter at `{}`: system interpreter not explicit",
interpreter.sys_executable().display()
);
false
}
}
(SystemPython::Explicit, true) => true,
(SystemPython::Disallowed, false) => {
) -> bool {
match (
system,
// Conda environments are not conformant virtual environments but we should not treat them as system interpreters
interpreter.is_virtualenv() || matches!(source, ToolchainSource::CondaPrefix),
) {
(SystemPython::Allowed, _) => true,
(SystemPython::Explicit, false) => {
if matches!(
source,
ToolchainSource::ProvidedPath | ToolchainSource::ParentInterpreter
) {
debug!(
"Ignoring Python interpreter at `{}`: system interpreter not allowed",
"Allowing system Python interpreter at `{}`",
interpreter.sys_executable().display()
);
true
} else {
debug!(
"Ignoring Python interpreter at `{}`: system interpreter not explicit",
interpreter.sys_executable().display()
);
false
}
(SystemPython::Disallowed, true) => true,
(SystemPython::Required, true) => {
debug!(
"Ignoring Python interpreter at `{}`: system interpreter required",
interpreter.sys_executable().display()
);
false
}
(SystemPython::Required, false) => true,
},
// Do not drop any errors
Err(_) => true,
}
(SystemPython::Explicit, true) => true,
(SystemPython::Disallowed, false) => {
debug!(
"Ignoring Python interpreter at `{}`: system interpreter not allowed",
interpreter.sys_executable().display()
);
false
}
(SystemPython::Disallowed, true) => true,
(SystemPython::Required, true) => {
debug!(
"Ignoring Python interpreter at `{}`: system interpreter required",
interpreter.sys_executable().display()
);
false
}
(SystemPython::Required, false) => true,
}
}
/// Utility for applying [`satisfies_system_python`] to a result type.
fn result_satisfies_system_python(
result: &Result<(ToolchainSource, Interpreter), Error>,
system: SystemPython,
) -> bool {
result.as_ref().ok().map_or(true, |(source, interpreter)| {
satisfies_system_python(*source, interpreter, system)
})
}
@ -566,12 +568,14 @@ pub fn find_toolchains<'a>(
}
ToolchainRequest::Any => Box::new({
debug!("Searching for Python interpreter in {sources}");
python_interpreters(None, None, system, sources, cache)
python_interpreters(None, None, sources, cache)
.filter(move |result| result_satisfies_system_python(result, system))
.map(|result| result.map(Toolchain::from_tuple).map(ToolchainResult::Ok))
}),
ToolchainRequest::Version(version) => Box::new({
debug!("Searching for {request} in {sources}");
python_interpreters(Some(version), None, system, sources, cache)
python_interpreters(Some(version), None, sources, cache)
.filter(move |result| result_satisfies_system_python(result, system))
.filter(|result| match result {
Err(_) => true,
Ok((_source, interpreter)) => version.matches_interpreter(interpreter),
@ -580,7 +584,8 @@ pub fn find_toolchains<'a>(
}),
ToolchainRequest::Implementation(implementation) => Box::new({
debug!("Searching for a {request} interpreter in {sources}");
python_interpreters(None, Some(implementation), system, sources, cache)
python_interpreters(None, Some(implementation), sources, cache)
.filter(move |result| result_satisfies_system_python(result, system))
.filter(|result| match result {
Err(_) => true,
Ok((_source, interpreter)) => {
@ -591,7 +596,8 @@ pub fn find_toolchains<'a>(
}),
ToolchainRequest::ImplementationVersion(implementation, version) => Box::new({
debug!("Searching for {request} in {sources}");
python_interpreters(Some(version), Some(implementation), system, sources, cache)
python_interpreters(Some(version), Some(implementation), sources, cache)
.filter(move |result| result_satisfies_system_python(result, system))
.filter(|result| match result {
Err(_) => true,
Ok((_source, interpreter)) => {