Skip to content

Commit

Permalink
Improve error message when requested Python version is unsupported
Browse files Browse the repository at this point in the history
  • Loading branch information
zanieb committed Sep 10, 2024
1 parent 948071b commit e41d9ff
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 54 deletions.
152 changes: 100 additions & 52 deletions crates/uv-python/src/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -776,77 +776,94 @@ 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)
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)
.filter(|result| match result {
Err(_) => true,
Ok((_source, interpreter)) => version.matches_interpreter(interpreter),
Ok((_source, interpreter)) => interpreter
.implementation_name()
.eq_ignore_ascii_case(implementation.into()),
})
.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)
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)) => interpreter
.implementation_name()
.eq_ignore_ascii_case(implementation.into()),
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)
})
}),
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())
}
})
.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)
}
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)
})
})
}),
}
}
}

Expand Down Expand Up @@ -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 {
Expand Down
34 changes: 32 additions & 2 deletions crates/uv/tests/python_find.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,17 @@ fn python_find_unsupported_version() {
----- stdout -----
----- stderr -----
error: No interpreter found for Python 3.6 in virtual environments or system path
error: Invalid version request: Python <3.7 is not supported but 3.6 was requested.
"###);

// Request a low version with a patch
uv_snapshot!(context.filters(), context.python_find().arg("3.6.9"), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: Invalid version request: Python <3.7 is not supported but 3.6.9 was requested.
"###);

// Request a really low version
Expand All @@ -413,7 +423,17 @@ fn python_find_unsupported_version() {
----- stdout -----
----- stderr -----
error: No interpreter found for Python 2.6 in virtual environments or system path
error: Invalid version request: Python <3.7 is not supported but 2.6 was requested.
"###);

// Request a really low version with a patch
uv_snapshot!(context.filters(), context.python_find().arg("2.6.8"), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: Invalid version request: Python <3.7 is not supported but 2.6.8 was requested.
"###);

// Request a future version
Expand All @@ -425,4 +445,14 @@ fn python_find_unsupported_version() {
----- stderr -----
error: No interpreter found for Python 4.2 in virtual environments or system path
"###);

// Request a low version with a range
uv_snapshot!(context.filters(), context.python_find().arg("<3.0"), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: No interpreter found for Python <3.0 in virtual environments or system path
"###);
}

0 comments on commit e41d9ff

Please sign in to comment.