diff --git a/crates/uv/src/cli.rs b/crates/uv/src/cli.rs index 52b26bca515d..047d897c0861 100644 --- a/crates/uv/src/cli.rs +++ b/crates/uv/src/cli.rs @@ -532,17 +532,33 @@ pub(crate) struct PipCompileArgs { /// exit with an error. /// /// Alias for `--only-binary :all:`. - #[arg(long, conflicts_with = "only_binary", overrides_with = "build")] + #[arg( + long, + conflicts_with = "no_binary", + conflicts_with = "only_binary", + overrides_with("build") + )] pub(crate) no_build: bool, #[arg( long, + conflicts_with = "no_binary", conflicts_with = "only_binary", overrides_with("no_build"), hide = true )] pub(crate) build: bool, + /// Don't install pre-built wheels. + /// + /// The given packages will be installed from a source distribution. The resolver + /// will still use pre-built wheels for metadata. + /// + /// Multiple packages may be provided. Disable binaries for all packages with `:all:`. + /// Clear previously specified packages with `:none:`. + #[arg(long, conflicts_with = "no_build")] + pub(crate) no_binary: Option>, + /// Only use pre-built wheels; don't build source distributions. /// /// When enabled, resolving will not run code from the given packages. The cached wheels of already-built diff --git a/crates/uv/src/commands/pip/compile.rs b/crates/uv/src/commands/pip/compile.rs index ec4722c91424..a8d56da048bc 100644 --- a/crates/uv/src/commands/pip/compile.rs +++ b/crates/uv/src/commands/pip/compile.rs @@ -81,6 +81,7 @@ pub(crate) async fn pip_compile( connectivity: Connectivity, no_build_isolation: bool, no_build: NoBuild, + no_binary: NoBinary, python_version: Option, python_platform: Option, exclude_newer: Option, @@ -122,7 +123,7 @@ pub(crate) async fn pip_compile( extra_index_urls, no_index, find_links, - no_binary: _, + no_binary: specified_no_binary, no_build: specified_no_build, } = RequirementsSpecification::from_sources( requirements, @@ -253,9 +254,10 @@ pub(crate) async fn pip_compile( let preferences = read_requirements_txt(output_file, &upgrade).await?; let git = GitResolver::default(); - // Combine the `--no-build` flags. + // Combine the `--no-binary` and `--no-build` flags. + let no_binary = no_binary.combine(specified_no_binary); let no_build = no_build.combine(specified_no_build); - let build_options = BuildOptions::new(NoBinary::default(), no_build); + let build_options = BuildOptions::new(no_binary, no_build); // Resolve the flat indexes from `--find-links`. let flat_index = { diff --git a/crates/uv/src/main.rs b/crates/uv/src/main.rs index fbfefa0b9779..ce4987e1b721 100644 --- a/crates/uv/src/main.rs +++ b/crates/uv/src/main.rs @@ -241,6 +241,7 @@ async fn run() -> Result { globals.connectivity, args.pip.no_build_isolation, args.pip.no_build, + args.pip.no_binary, args.pip.python_version, args.pip.python_platform, args.pip.exclude_newer, diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index 01c542e1b486..d55d70dd679c 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -441,6 +441,7 @@ impl PipCompileSettings { build_isolation, no_build, build, + no_binary, only_binary, config_setting, python_version, @@ -499,6 +500,7 @@ impl PipCompileSettings { index_strategy, keyring_provider, no_build: flag(no_build, build), + no_binary, only_binary, no_build_isolation: flag(no_build_isolation, build_isolation), extra, diff --git a/crates/uv/tests/pip_compile.rs b/crates/uv/tests/pip_compile.rs index 195609531cee..343e70f24739 100644 --- a/crates/uv/tests/pip_compile.rs +++ b/crates/uv/tests/pip_compile.rs @@ -9764,3 +9764,47 @@ fn file_url() -> Result<()> { Ok(()) } + +/// Allow `--no-binary` to override `--only-binary`, to allow select source distributions. +#[test] +fn no_binary_only_binary() -> Result<()> { + let context = TestContext::new("3.12"); + let requirements_in = context.temp_dir.child("requirements.in"); + requirements_in.write_str("source-distribution")?; + + uv_snapshot!(context.compile_without_exclude_newer() + .arg("requirements.in") + .arg("--only-binary") + .arg(":all:"), @r###" + success: false + exit_code: 1 + ----- stdout ----- + + ----- stderr ----- + × No solution found when resolving dependencies: + ╰─▶ Because only source-distribution==0.0.1 is available and source-distribution==0.0.1 has no usable wheels and building from source is disabled, we can conclude that all versions of source-distribution cannot be used. + And because you require source-distribution, we can conclude that the requirements are unsatisfiable. + "### + ); + + uv_snapshot!(context.compile_without_exclude_newer() + .arg("requirements.in") + .arg("--only-binary") + .arg(":all:") + .arg("--no-binary") + .arg("source-distribution"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + # This file was autogenerated by uv via the following command: + # uv pip compile --cache-dir [CACHE_DIR] requirements.in --only-binary :all: --no-binary source-distribution + source-distribution==0.0.1 + # via -r requirements.in + + ----- stderr ----- + Resolved 1 package in [TIME] + "### + ); + + Ok(()) +}