Prefer stable releases over pre-releases in uv python install (#12194)

e.g., `uv python install 3` should not install the 3.14 alpha

Closes #12184
This commit is contained in:
Zanie Blue 2025-04-21 16:16:07 -05:00 committed by GitHub
parent c55dd0f295
commit 9484e3663c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 116 additions and 9 deletions

View file

@ -2294,9 +2294,9 @@ impl VersionRequest {
match self {
Self::Default => false,
Self::Any => true,
Self::Major(..) => true,
Self::MajorMinor(..) => true,
Self::MajorMinorPatch(..) => true,
Self::Major(..) => false,
Self::MajorMinor(..) => false,
Self::MajorMinorPatch(..) => false,
Self::MajorMinorPrerelease(..) => true,
Self::Range(specifiers, _) => specifiers.iter().any(VersionSpecifier::any_prerelease),
}

View file

@ -485,13 +485,28 @@ pub enum DownloadResult {
impl ManagedPythonDownload {
/// Return the first [`ManagedPythonDownload`] matching a request, if any.
///
/// If there is no stable version matching the request, a compatible pre-release version will
/// be searched for — even if a pre-release was not explicitly requested.
pub fn from_request(
request: &PythonDownloadRequest,
) -> Result<&'static ManagedPythonDownload, Error> {
request
.iter_downloads()?
.next()
.ok_or(Error::NoDownloadFound(request.clone()))
if let Some(download) = request.iter_downloads()?.next() {
return Ok(download);
}
if !request.allows_prereleases() {
if let Some(download) = request
.clone()
.with_prereleases(true)
.iter_downloads()?
.next()
{
return Ok(download);
}
}
Err(Error::NoDownloadFound(request.clone()))
}
/// Iterate over all [`ManagedPythonDownload`]s.

View file

@ -205,10 +205,10 @@ impl TestContext {
self.filters
.push(("python.exe".to_string(), "python".to_string()));
} else {
self.filters
.push((r"python\d".to_string(), "python".to_string()));
self.filters
.push((r"python\d.\d\d".to_string(), "python".to_string()));
self.filters
.push((r"python\d".to_string(), "python".to_string()));
}
self
}
@ -224,6 +224,25 @@ impl TestContext {
self
}
/// Add extra standard filtering for Python installation `bin/` directories, which are not
/// present on Windows but are on Unix. See [`TestContext::with_filtered_virtualenv_bin`] for
/// the virtual environment equivalent.
#[must_use]
pub fn with_filtered_python_install_bin(mut self) -> Self {
if cfg!(unix) {
self.filters.push((
r"[\\/]bin/python".to_string(),
"/[INSTALL-BIN]/python".to_string(),
));
} else {
self.filters.push((
r"[\\/]python".to_string(),
"/[INSTALL-BIN]/python".to_string(),
));
}
self
}
/// Add extra filtering for ` -> <PATH>` symlink display for Python versions in the test
/// context, e.g., for use in `uv python list`.
#[must_use]

View file

@ -1201,3 +1201,76 @@ fn python_install_patch_dylib() {
----- stderr -----
"###);
}
#[test]
fn python_install_314() {
let context: TestContext = TestContext::new_with_versions(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_filtered_python_names()
.with_filtered_python_install_bin();
// Install 3.14
// For now, this provides test coverage of pre-release handling
uv_snapshot!(context.filters(), context.python_install().arg("3.14"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.0a6 in [TIME]
+ cpython-3.14.0a6-[PLATFORM]
");
// Install a specific pre-release
uv_snapshot!(context.filters(), context.python_install().arg("3.14.0a4"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.14.0a4 in [TIME]
+ cpython-3.14.0a4-[PLATFORM]
");
// We should be able to find this version without opt-in, because there is no stable release
// installed
uv_snapshot!(context.filters(), context.python_find().arg("3.14"), @r"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.14.0a6-[PLATFORM]/[INSTALL-BIN]/python
----- stderr -----
");
uv_snapshot!(context.filters(), context.python_find().arg("3"), @r"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.14.0a6-[PLATFORM]/[INSTALL-BIN]/python
----- stderr -----
");
// If we install a stable version, that should be preferred though
uv_snapshot!(context.filters(), context.python_install().arg("3.13"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.13.3 in [TIME]
+ cpython-3.13.3-[PLATFORM]
");
uv_snapshot!(context.filters(), context.python_find().arg("3"), @r"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.13.3-[PLATFORM]/[INSTALL-BIN]/python
----- stderr -----
");
}