Ignore pre-release Python versions when a patch version is requested (#16210)

I think this is ostensively breaking, though I think the impact would be
small given this will go out in 0.9.1 and should only affect people
using pre-release Python versions.

When `3.14.0` is requested (opposed to `3.14`), we treat this as a
request for a final / stable version and ignore pre-releases.

I think this is a fairly clean way to allow users to explicitly request
the stable version.

Closes https://github.com/astral-sh/uv/issues/16175
Follows #16208
This commit is contained in:
Zanie Blue 2025-10-09 11:39:26 -05:00
parent fb7d5361b0
commit 84d6a913ac
2 changed files with 53 additions and 0 deletions

View file

@ -2690,6 +2690,9 @@ impl VersionRequest {
interpreter.python_minor(),
interpreter.python_patch(),
) == (*major, *minor, *patch)
// When a patch version is included, we treat it as a request for a stable
// release
&& interpreter.python_version().pre().is_none()
&& variant.matches_interpreter(interpreter)
}
Self::Range(specifiers, variant) => {
@ -2814,6 +2817,9 @@ impl VersionRequest {
}
Self::MajorMinorPatch(self_major, self_minor, self_patch, _) => {
(*self_major, *self_minor, *self_patch) == (major, minor, patch)
// When a patch version is included, we treat it as a request for a stable
// release
&& prerelease.is_none()
}
Self::Range(specifiers, _) => specifiers.contains(
&Version::new([u64::from(major), u64::from(minor), u64::from(patch)])

View file

@ -1433,3 +1433,50 @@ fn python_find_prerelease_version_specifiers() {
----- stderr -----
");
}
#[test]
fn python_find_prerelease_with_patch_request() {
let context: TestContext = TestContext::new_with_versions(&[])
.with_filtered_python_keys()
.with_filtered_python_sources()
.with_managed_python_dirs()
.with_python_download_cache()
.with_filtered_python_install_bin()
.with_filtered_python_names()
.with_filtered_exe_suffix();
// Install 3.14.0rc3
context.python_install().arg("3.14.0rc3").assert().success();
// When no `.0` patch version is included, we'll allow selection of a pre-release
uv_snapshot!(context.filters(), context.python_find().arg("3.14"), @r"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.14.0rc3-[PLATFORM]/[INSTALL-BIN]/[PYTHON]
----- stderr -----
");
// When `.0` is explicitly included, we will require a stable release
uv_snapshot!(context.filters(), context.python_find().arg("3.14.0"), @r"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: No interpreter found for Python 3.14.0 in [PYTHON SOURCES]
");
// Install 3.14.0 stable
context.python_install().arg("3.14.0").assert().success();
uv_snapshot!(context.filters(), context.python_find().arg("3.14.0"), @r"
success: true
exit_code: 0
----- stdout -----
[TEMP_DIR]/managed/cpython-3.14.0-[PLATFORM]/[INSTALL-BIN]/[PYTHON]
----- stderr -----
");
}