Improve error message when requested Python version is unsupported (#7269)

Follows test cases in #7265 and validation removal in
https://github.com/astral-sh/uv/pull/7264

It turns out we don't have good error messages for these as-is.
This commit is contained in:
Zanie Blue 2024-09-10 14:01:36 -05:00 committed by GitHub
parent 948071b2f2
commit 0dc1f5db21
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 134 additions and 56 deletions

View file

@ -776,19 +776,24 @@ pub fn find_python_installations<'a>(
.map(FindPythonResult::Ok)
})
}),
PythonRequest::Version(version) => Box::new({
debug!("Searching for {request} in {preference}");
python_interpreters(Some(version), None, environments, preference, cache)
.filter(|result| match result {
Err(_) => true,
Ok((_source, interpreter)) => version.matches_interpreter(interpreter),
})
.map(|result| {
result
.map(PythonInstallation::from_tuple)
.map(FindPythonResult::Ok)
})
}),
PythonRequest::Version(version) => {
if let Err(err) = version.check_supported() {
return Box::new(std::iter::once(Err(Error::InvalidVersionRequest(err))));
};
Box::new({
debug!("Searching for {request} in {preference}");
python_interpreters(Some(version), None, environments, preference, cache)
.filter(|result| match result {
Err(_) => true,
Ok((_source, interpreter)) => version.matches_interpreter(interpreter),
})
.map(|result| {
result
.map(PythonInstallation::from_tuple)
.map(FindPythonResult::Ok)
})
})
}
PythonRequest::Implementation(implementation) => Box::new({
debug!("Searching for a {request} interpreter in {preference}");
python_interpreters(None, Some(implementation), environments, preference, cache)
@ -804,49 +809,61 @@ pub fn find_python_installations<'a>(
.map(FindPythonResult::Ok)
})
}),
PythonRequest::ImplementationVersion(implementation, version) => Box::new({
debug!("Searching for {request} in {preference}");
python_interpreters(
Some(version),
Some(implementation),
environments,
preference,
cache,
)
.filter(|result| match result {
Err(_) => true,
Ok((_source, interpreter)) => {
version.matches_interpreter(interpreter)
&& interpreter
.implementation_name()
.eq_ignore_ascii_case(implementation.into())
}
PythonRequest::ImplementationVersion(implementation, version) => {
if let Err(err) = version.check_supported() {
return Box::new(std::iter::once(Err(Error::InvalidVersionRequest(err))));
};
Box::new({
debug!("Searching for {request} in {preference}");
python_interpreters(
Some(version),
Some(implementation),
environments,
preference,
cache,
)
.filter(|result| match result {
Err(_) => true,
Ok((_source, interpreter)) => {
version.matches_interpreter(interpreter)
&& interpreter
.implementation_name()
.eq_ignore_ascii_case(implementation.into())
}
})
.map(|result| {
result
.map(PythonInstallation::from_tuple)
.map(FindPythonResult::Ok)
})
})
.map(|result| {
result
.map(PythonInstallation::from_tuple)
.map(FindPythonResult::Ok)
}
PythonRequest::Key(request) => {
if let Some(version) = request.version() {
if let Err(err) = version.check_supported() {
return Box::new(std::iter::once(Err(Error::InvalidVersionRequest(err))));
};
};
Box::new({
debug!("Searching for {request} in {preference}");
python_interpreters(
request.version(),
request.implementation(),
environments,
preference,
cache,
)
.filter(|result| match result {
Err(_) => true,
Ok((_source, interpreter)) => request.satisfied_by_interpreter(interpreter),
})
.map(|result| {
result
.map(PythonInstallation::from_tuple)
.map(FindPythonResult::Ok)
})
})
}),
PythonRequest::Key(request) => Box::new({
debug!("Searching for {request} in {preference}");
python_interpreters(
request.version(),
request.implementation(),
environments,
preference,
cache,
)
.filter(|result| match result {
Err(_) => true,
Ok((_source, interpreter)) => request.satisfied_by_interpreter(interpreter),
})
.map(|result| {
result
.map(PythonInstallation::from_tuple)
.map(FindPythonResult::Ok)
})
}),
}
}
}
@ -1446,6 +1463,37 @@ impl VersionRequest {
.flatten()
}
pub(crate) fn check_supported(&self) -> Result<(), String> {
match self {
Self::Any => (),
Self::Major(major) => {
if *major < 3 {
return Err(format!(
"Python <3 is not supported but {major} was requested."
));
}
}
Self::MajorMinor(major, minor) => {
if (*major, *minor) < (3, 7) {
return Err(format!(
"Python <3.7 is not supported but {major}.{minor} was requested."
));
}
}
Self::MajorMinorPatch(major, minor, patch) => {
if (*major, *minor) < (3, 7) {
return Err(format!(
"Python <3.7 is not supported but {major}.{minor}.{patch} was requested."
));
}
}
// TODO(zanieb): We could do some checking here to see if the range can be satisfied
Self::Range(_) => (),
}
Ok(())
}
/// Check if a interpreter matches the requested Python version.
pub(crate) fn matches_interpreter(&self, interpreter: &Interpreter) -> bool {
match self {