Allow `--no-binary` with `uv pip compile` (#4301)

## Summary

This i still a draft, but it gets some of the work started on issue
#4064 , which requests --no-binary functionality similar to `uv pip
install` to exist on `uv pip compile`.

So far this has moved the command line shape from install and cloned it
over to compile. The actual functionality of respecting --no-binary
<package> and generating the resulting line in requirements.txt I could
use a hand with.

My understanding is we want to create a requirements.in file such as:

```
yt
```

Then when running `cargo run -- pip compile --no-binary yt
requirements.in`
we want the file to have this line in it:

```
yt==4.3.1 --no-binary yt
```

## Test Plan

Existing unit tests continue to pass.
No new unit tests have been created yet.
The new command line options do show up when testing with `cargo run --
pip compile -h`

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
This commit is contained in:
Brian Mego 2024-06-13 08:59:03 -05:00 committed by GitHub
parent 5d1305aa6b
commit cd461f1243
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 69 additions and 4 deletions

View File

@ -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<Vec<PackageNameSpecifier>>,
/// 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

View File

@ -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<PythonVersion>,
python_platform: Option<TargetTriple>,
exclude_newer: Option<ExcludeNewer>,
@ -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 = {

View File

@ -241,6 +241,7 @@ async fn run() -> Result<ExitStatus> {
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,

View File

@ -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,

View File

@ -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(())
}