Make uv pip compile attempt to download a specified --python-version if it can. (#17249)

## Summary

Addresses #16709. Now specifying a simple version with `--python` or
specifying a version using `--python-version` will result in the
specified version getting downloaded with a fallback to the previous
behaviour if the download fails for some transient reason or if
downloads are disabled.

The behaviour of how `--python` gets treated as `--python-version`, if a
"simple version" is specified, is kept. This means that `--python 3.7`
turns into a soft requirement. This seems at odds with how other similar
parts of UV work, but there seem to be quite a few tests which test for
this specific behaviour and I think this is best saved for a separate
issue.

## Test Plan

I added a test case which would previously fall back to the default
interpreter and warn about it.

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
This commit is contained in:
Tomasz Kramkowski
2026-01-16 14:01:56 +00:00
committed by GitHub
parent 8a02f6352a
commit f7d1215a98
6 changed files with 420 additions and 70 deletions
+32 -7
View File
@@ -73,19 +73,44 @@ impl PythonInstallation {
Ok(installation)
}
/// Find an installed [`PythonInstallation`] that satisfies a requested version, if the request cannot
/// be satisfied, fallback to the best available Python installation.
pub fn find_best(
/// Find or download a [`PythonInstallation`] that satisfies a requested version, if the request
/// cannot be satisfied, fallback to the best available Python installation.
pub async fn find_best(
request: &PythonRequest,
environments: EnvironmentPreference,
preference: PythonPreference,
download_list: &ManagedPythonDownloadList,
python_downloads: PythonDownloads,
client_builder: &BaseClientBuilder<'_>,
cache: &Cache,
reporter: Option<&dyn Reporter>,
python_install_mirror: Option<&str>,
pypy_install_mirror: Option<&str>,
python_downloads_json_url: Option<&str>,
preview: Preview,
) -> Result<Self, Error> {
let installation =
find_best_python_installation(request, environments, preference, cache, preview)??;
installation.warn_if_outdated_prerelease(request, download_list);
let retry_policy = client_builder.retry_policy();
let client = client_builder.clone().retries(0).build();
let download_list =
ManagedPythonDownloadList::new(&client, python_downloads_json_url).await?;
let downloads_enabled = preference.allows_managed()
&& python_downloads.is_automatic()
&& client_builder.connectivity.is_online();
let installation = find_best_python_installation(
request,
environments,
preference,
downloads_enabled,
&download_list,
&client,
&retry_policy,
cache,
reporter,
python_install_mirror,
pypy_install_mirror,
preview,
)
.await?;
installation.warn_if_outdated_prerelease(request, &download_list);
Ok(installation)
}