diff --git a/crates/uv-resolver/src/pubgrub/dependencies.rs b/crates/uv-resolver/src/pubgrub/dependencies.rs index 441ce4e48..7bb6e083d 100644 --- a/crates/uv-resolver/src/pubgrub/dependencies.rs +++ b/crates/uv-resolver/src/pubgrub/dependencies.rs @@ -121,6 +121,7 @@ impl PubGrubDependencies { // Merge the package. if let Some(package) = merge_package(entry.0, &package)? { + dependencies.remove(&package); dependencies.insert(package, version); } else { dependencies.insert(package, version); diff --git a/crates/uv/tests/pip_compile.rs b/crates/uv/tests/pip_compile.rs index 91be82141..4de554e0c 100644 --- a/crates/uv/tests/pip_compile.rs +++ b/crates/uv/tests/pip_compile.rs @@ -3406,3 +3406,66 @@ fn compile_types_pytz() -> Result<()> { Ok(()) } + +/// Resolve a package from a `requirements.in` file, with a `constraints.txt` file pinning it to +/// a specific URL. +#[test] +fn compile_constraints_compatible_url() -> Result<()> { + let context = TestContext::new("3.12"); + let requirements_in = context.temp_dir.child("requirements.in"); + requirements_in.write_str("anyio>4")?; + + let constraints_txt = context.temp_dir.child("constraints.txt"); + constraints_txt.write_str("anyio @ https://files.pythonhosted.org/packages/bf/cd/d6d9bb1dadf73e7af02d18225cbd2c93f8552e13130484f1c8dcfece292b/anyio-4.2.0-py3-none-any.whl")?; + + uv_snapshot!(context.compile() + .arg("requirements.in") + .arg("--constraint") + .arg("constraints.txt"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + # This file was autogenerated by uv v[VERSION] via the following command: + # uv pip compile --cache-dir [CACHE_DIR] --exclude-newer 2023-11-18T12:00:00Z requirements.in --constraint constraints.txt + anyio @ https://files.pythonhosted.org/packages/bf/cd/d6d9bb1dadf73e7af02d18225cbd2c93f8552e13130484f1c8dcfece292b/anyio-4.2.0-py3-none-any.whl + idna==3.4 + # via anyio + sniffio==1.3.0 + # via anyio + + ----- stderr ----- + Resolved 3 packages in [TIME] + "### + ); + + Ok(()) +} + +/// Resolve a package from a `requirements.in` file, with a `constraints.txt` file pinning it to +/// a specific URL with an incompatible version. +#[test] +fn compile_constraints_incompatible_url() -> Result<()> { + let context = TestContext::new("3.12"); + let requirements_in = context.temp_dir.child("requirements.in"); + requirements_in.write_str("anyio<4")?; + + let constraints_txt = context.temp_dir.child("constraints.txt"); + constraints_txt.write_str("anyio @ https://files.pythonhosted.org/packages/bf/cd/d6d9bb1dadf73e7af02d18225cbd2c93f8552e13130484f1c8dcfece292b/anyio-4.2.0-py3-none-any.whl")?; + + uv_snapshot!(context.compile() + .arg("requirements.in") + .arg("--constraint") + .arg("constraints.txt"), @r###" + success: false + exit_code: 1 + ----- stdout ----- + + ----- stderr ----- + × No solution found when resolving dependencies: + ╰─▶ Because only anyio>=4 is available and you require anyio<4, we can + conclude that the requirements are unsatisfiable. + "### + ); + + Ok(()) +}