diff --git a/crates/uv-resolver/src/pubgrub/dependencies.rs b/crates/uv-resolver/src/pubgrub/dependencies.rs index 3faa01821..accf922e1 100644 --- a/crates/uv-resolver/src/pubgrub/dependencies.rs +++ b/crates/uv-resolver/src/pubgrub/dependencies.rs @@ -183,9 +183,9 @@ impl From for Vec<(PubGrubPackage, Range)> { /// A PubGrub-compatible package and version range. #[derive(Debug, Clone)] -struct PubGrubRequirement { - package: PubGrubPackage, - version: Range, +pub(crate) struct PubGrubRequirement { + pub(crate) package: PubGrubPackage, + pub(crate) version: Range, } impl PubGrubRequirement { diff --git a/crates/uv-resolver/src/pubgrub/mod.rs b/crates/uv-resolver/src/pubgrub/mod.rs index 3d37c5174..1176297cc 100644 --- a/crates/uv-resolver/src/pubgrub/mod.rs +++ b/crates/uv-resolver/src/pubgrub/mod.rs @@ -1,4 +1,4 @@ -pub(crate) use crate::pubgrub::dependencies::PubGrubDependencies; +pub(crate) use crate::pubgrub::dependencies::{PubGrubDependencies, PubGrubRequirement}; pub(crate) use crate::pubgrub::distribution::PubGrubDistribution; pub(crate) use crate::pubgrub::package::{PubGrubPackage, PubGrubPython}; pub(crate) use crate::pubgrub::priority::{PubGrubPriorities, PubGrubPriority}; diff --git a/crates/uv-resolver/src/resolver/mod.rs b/crates/uv-resolver/src/resolver/mod.rs index 268008ecb..18de8f479 100644 --- a/crates/uv-resolver/src/resolver/mod.rs +++ b/crates/uv-resolver/src/resolver/mod.rs @@ -43,7 +43,7 @@ use crate::pins::FilePins; use crate::preferences::Preferences; use crate::pubgrub::{ PubGrubDependencies, PubGrubDistribution, PubGrubPackage, PubGrubPriorities, PubGrubPython, - PubGrubSpecifier, + PubGrubRequirement, PubGrubSpecifier, }; use crate::python_requirement::PythonRequirement; use crate::resolution::ResolutionGraph; @@ -931,6 +931,19 @@ impl<'a, Provider: ResolverProvider, InstalledPackages: InstalledPackagesProvide Range::singleton(metadata.version.clone()), ); } + + // Add any constraints. + for constraint in self.constraints.get(&metadata.name).into_iter().flatten() { + if constraint.evaluate_markers(self.markers, &[]) { + let PubGrubRequirement { package, version } = + PubGrubRequirement::from_constraint( + constraint, + &self.urls, + &self.locals, + )?; + dependencies.push(package, version); + } + } } Ok(Dependencies::Available(dependencies.into())) diff --git a/crates/uv/tests/pip_install.rs b/crates/uv/tests/pip_install.rs index d395d3013..93c65d53c 100644 --- a/crates/uv/tests/pip_install.rs +++ b/crates/uv/tests/pip_install.rs @@ -957,6 +957,89 @@ fn install_editable_no_binary() { ); } +#[test] +fn install_editable_compatible_constraint() -> Result<()> { + let context = TestContext::new("3.12"); + + let constraints_txt = context.temp_dir.child("constraints.txt"); + constraints_txt.write_str("black==0.1.0")?; + + // Install the editable package with a compatible constraint. + uv_snapshot!(context.filters(), context.install() + .arg("-e") + .arg(context.workspace_root.join("scripts/packages/black_editable")) + .arg("--constraint") + .arg("constraints.txt"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Built 1 editable in [TIME] + Resolved 1 package in [TIME] + Installed 1 package in [TIME] + + black==0.1.0 (from file://[WORKSPACE]/scripts/packages/black_editable) + "### + ); + + Ok(()) +} + +#[test] +fn install_editable_incompatible_constraint_version() -> Result<()> { + let context = TestContext::new("3.12"); + + let constraints_txt = context.temp_dir.child("constraints.txt"); + constraints_txt.write_str("black>0.1.0")?; + + // Install the editable package with an incompatible constraint. + uv_snapshot!(context.filters(), context.install() + .arg("-e") + .arg(context.workspace_root.join("scripts/packages/black_editable")) + .arg("--constraint") + .arg("constraints.txt"), @r###" + success: false + exit_code: 1 + ----- stdout ----- + + ----- stderr ----- + Built 1 editable in [TIME] + × No solution found when resolving dependencies: + ╰─▶ Because you require black==0.1.0 and black>0.1.0, we can conclude that the requirements are unsatisfiable. + "### + ); + + Ok(()) +} + +#[test] +fn install_editable_incompatible_constraint_url() -> Result<()> { + let context = TestContext::new("3.12"); + + let constraints_txt = context.temp_dir.child("constraints.txt"); + constraints_txt.write_str("black @ https://files.pythonhosted.org/packages/0f/89/294c9a6b6c75a08da55e9d05321d0707e9418735e3062b12ef0f54c33474/black-24.4.2-py3-none-any.whl")?; + + // Install the editable package with an incompatible constraint. + uv_snapshot!(context.filters(), context.install() + .arg("-e") + .arg(context.workspace_root.join("scripts/packages/black_editable")) + .arg("--constraint") + .arg("constraints.txt"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + Built 1 editable in [TIME] + error: Requirements contain conflicting URLs for package `black`: + - [WORKSPACE]/scripts/packages/black_editable + - https://files.pythonhosted.org/packages/0f/89/294c9a6b6c75a08da55e9d05321d0707e9418735e3062b12ef0f54c33474/black-24.4.2-py3-none-any.whl + "### + ); + + Ok(()) +} + /// Install a source distribution that uses the `flit` build system, along with `flit` /// at the top-level, along with `--reinstall` to force a re-download after resolution, to ensure /// that the `flit` install and the source distribution build don't conflict.