From fff3a7d8f99e575e9ddebea67b7712bb7907ff28 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 24 Jul 2024 15:23:14 -0400 Subject: [PATCH] Always accept already-installed pre-releases (#5419) ## Summary If a pre-release is already installed, we should allow it to be used even if it doesn't match the strategy. Closes https://github.com/astral-sh/uv/issues/5418. --- crates/uv-resolver/src/candidate_selector.rs | 24 ++++------- crates/uv/tests/pip_install.rs | 43 ++++++++++++++++++++ 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/crates/uv-resolver/src/candidate_selector.rs b/crates/uv-resolver/src/candidate_selector.rs index 061148bae..87ef4af81 100644 --- a/crates/uv-resolver/src/candidate_selector.rs +++ b/crates/uv-resolver/src/candidate_selector.rs @@ -120,14 +120,6 @@ impl CandidateSelector { break 'preference; } - // Respect the pre-release strategy for this fork. - if version.any_prerelease() - && self.prerelease_strategy.allows(package_name, markers) - != AllowPreRelease::Yes - { - break 'preference; - } - // Check for a locally installed distribution that matches the preferred version if !exclusions.contains(package_name) { let installed_dists = installed_packages.get_packages(package_name); @@ -155,6 +147,14 @@ impl CandidateSelector { } } + // Respect the pre-release strategy for this fork. + if version.any_prerelease() + && self.prerelease_strategy.allows(package_name, markers) + != AllowPreRelease::Yes + { + break 'preference; + } + // Check for a remote distribution that matches the preferred version if let Some(file) = version_maps .iter() @@ -183,14 +183,6 @@ impl CandidateSelector { return None; } - // Respect the pre-release strategy for this fork. - if version.any_prerelease() - && self.prerelease_strategy.allows(package_name, markers) - != AllowPreRelease::Yes - { - return None; - } - debug!("Found installed version of {dist} that satisfies {range}"); return Some(Candidate { name: package_name, diff --git a/crates/uv/tests/pip_install.rs b/crates/uv/tests/pip_install.rs index 79a5695eb..9cc690b78 100644 --- a/crates/uv/tests/pip_install.rs +++ b/crates/uv/tests/pip_install.rs @@ -6105,3 +6105,46 @@ fn local_index_fallback() -> Result<()> { Ok(()) } + +#[test] +fn accept_existing_prerelease() -> Result<()> { + let context = TestContext::new("3.12").with_filtered_counts(); + let requirements_txt = context.temp_dir.child("requirements.txt"); + requirements_txt.write_str("Flask==2.0.0rc1")?; + + // Install a pre-release version of `flask`. + uv_snapshot!(context.filters(), context.pip_install().arg("Flask==2.0.0rc1"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved [N] packages in [TIME] + Prepared [N] packages in [TIME] + Installed [N] packages in [TIME] + + click==8.1.7 + + flask==2.0.0rc1 + + itsdangerous==2.1.2 + + jinja2==3.1.3 + + markupsafe==2.1.5 + + werkzeug==3.0.1 + "### + ); + + // Install `flask-login`, without enabling pre-releases. The existing version of `flask` should + // still be accepted. + uv_snapshot!(context.filters(), context.pip_install().arg("flask-login==0.6.0"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved [N] packages in [TIME] + Prepared [N] packages in [TIME] + Installed [N] packages in [TIME] + + flask-login==0.6.0 + "### + ); + + Ok(()) +}