Ban pre-release versions in uv python upgrade requests (#16160)

This commit is contained in:
Zanie Blue 2025-10-07 15:07:09 -05:00 committed by GitHub
parent 37b3557dab
commit 3a507e69b2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 60 additions and 3 deletions

View file

@ -1945,6 +1945,24 @@ impl PythonRequest {
}
}
/// Check if this request includes a specific prerelease version.
pub fn includes_prerelease(&self) -> bool {
match self {
Self::Default => false,
Self::Any => false,
Self::Version(version_request) => version_request.prerelease().is_some(),
Self::Directory(..) => false,
Self::File(..) => false,
Self::ExecutableName(..) => false,
Self::Implementation(..) => false,
Self::ImplementationVersion(_, version) => version.prerelease().is_some(),
Self::Key(request) => request
.version
.as_ref()
.is_some_and(|request| request.prerelease().is_some()),
}
}
/// Check if a given interpreter satisfies the interpreter request.
pub fn satisfied(&self, interpreter: &Interpreter, cache: &Cache) -> bool {
/// Returns `true` if the two paths refer to the same interpreter executable.
@ -2565,6 +2583,17 @@ impl VersionRequest {
}
}
/// Return the pre-release segment of the request, if any.
pub(crate) fn prerelease(&self) -> Option<&Prerelease> {
match self {
Self::Any | Self::Default | Self::Range(_, _) => None,
Self::Major(_, _) => None,
Self::MajorMinor(_, _, _) => None,
Self::MajorMinorPatch(_, _, _, _) => None,
Self::MajorMinorPrerelease(_, _, prerelease, _) => Some(prerelease),
}
}
/// Check if the request is for a version supported by uv.
///
/// If not, an `Err` is returned with an explanatory message.

View file

@ -285,9 +285,9 @@ pub(crate) async fn install(
.collect::<IndexSet<_>>();
if upgrade
&& requests
.iter()
.any(|request| request.request.includes_patch())
&& requests.iter().any(|request| {
request.request.includes_patch() || request.request.includes_prerelease()
})
{
writeln!(
printer.stderr(),

View file

@ -1216,6 +1216,34 @@ fn python_install_freethreaded() {
");
}
#[test]
fn python_upgrade_not_allowed() {
let context: TestContext = TestContext::new_with_versions(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs();
// Request a patch upgrade
uv_snapshot!(context.filters(), context.python_upgrade().arg("--preview").arg("3.13.0"), @r"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
error: `uv python upgrade` only accepts minor versions
");
// Request a pre-release upgrade
uv_snapshot!(context.filters(), context.python_upgrade().arg("--preview").arg("3.14rc3"), @r"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
error: `uv python upgrade` only accepts minor versions
");
}
// We only support debug builds on Unix
#[cfg(unix)]
#[test]