Add `NO_BINARY` and `NO_BINARY_PACKAGE` environment variables (#11399)

<!--
Thank you for contributing to uv! To help us out with reviewing, please
consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->

## Summary

This adds `NO_BINARY` and `NO_BINARY_PACKAGE` environment variables to
the uv CLI, allowing the user to specify packages to build from source
using environment variables. Its not a complete fix for #4291 as it does
not handle the `pip` subcommand.

## Test Plan

This was tested by running `uv sync` with various `UV_NO_BINARY` and
`UV_NO_BINARY_PACKAGE` environment variables set and checking that the
correct set of packages were compiled rather than taken from pre-built
wheels.

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
This commit is contained in:
Alex Lowe 2025-02-10 16:11:46 -05:00 committed by GitHub
parent 768da2091b
commit ac06e1318a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 177 additions and 2 deletions

View File

@ -4770,7 +4770,13 @@ pub struct BuildOptionsArgs {
///
/// The given packages will be built and installed from source. The resolver will still use
/// pre-built wheels to extract package metadata, if available.
#[arg(long, overrides_with("binary"), help_heading = "Build options")]
#[arg(
long,
env = EnvVars::UV_NO_BINARY,
overrides_with("binary"),
value_parser = clap::builder::BoolishValueParser::new(),
help_heading = "Build options"
)]
pub no_binary: bool,
#[arg(
@ -4782,7 +4788,7 @@ pub struct BuildOptionsArgs {
pub binary: bool,
/// Don't install pre-built wheels for a specific package.
#[arg(long, help_heading = "Build options")]
#[arg(long, help_heading = "Build options", env = EnvVars::UV_NO_BINARY_PACKAGE, value_delimiter = ' ')]
pub no_binary_package: Vec<PackageName>,
}

View File

@ -142,6 +142,15 @@ impl EnvVars {
/// will compile Python source files to bytecode after installation.
pub const UV_COMPILE_BYTECODE: &'static str = "UV_COMPILE_BYTECODE";
/// Equivalent to the `--no-binary` command-line argument. If set, uv will install
/// all packages from source. The resolver will still use pre-built wheels to
/// extract package metadata, if available.
pub const UV_NO_BINARY: &'static str = "UV_NO_BINARY";
/// Equivalent to the `--no-binary-package` command line argument. If set, uv will
/// not use pre-built wheels for the given space-delimited list of packages.
pub const UV_NO_BINARY_PACKAGE: &'static str = "UV_NO_BINARY_PACKAGE";
/// Equivalent to the `--publish-url` command-line argument. The URL of the upload
/// endpoint of the index to use with `uv publish`.
pub const UV_PUBLISH_URL: &'static str = "UV_PUBLISH_URL";

View File

@ -2279,6 +2279,83 @@ fn install_no_binary_overrides_only_binary_all() {
context.assert_command("import anyio").success();
}
/// Disable binaries with an environment variable
/// TODO(zanieb): This is not yet implemented
#[test]
fn install_no_binary_env() {
let context = TestContext::new("3.12");
let mut command = context.pip_install();
command.arg("anyio").env("UV_NO_BINARY", "1");
uv_snapshot!(
command,
@r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 3 packages in [TIME]
Prepared 3 packages in [TIME]
Installed 3 packages in [TIME]
+ anyio==4.3.0
+ idna==3.6
+ sniffio==1.3.1
"###
);
let mut command = context.pip_install();
command
.arg("anyio")
.arg("--reinstall")
.env("UV_NO_BINARY", "anyio");
uv_snapshot!(
command,
@r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 3 packages in [TIME]
Prepared 3 packages in [TIME]
Uninstalled 3 packages in [TIME]
Installed 3 packages in [TIME]
~ anyio==4.3.0
~ idna==3.6
~ sniffio==1.3.1
"###
);
context.assert_command("import anyio").success();
let mut command = context.pip_install();
command
.arg("anyio")
.arg("--reinstall")
.arg("idna")
.env("UV_NO_BINARY_PACKAGE", "idna");
uv_snapshot!(
command,
@r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 3 packages in [TIME]
Prepared 3 packages in [TIME]
Uninstalled 3 packages in [TIME]
Installed 3 packages in [TIME]
~ anyio==4.3.0
~ idna==3.6
~ sniffio==1.3.1
"###
);
context.assert_command("import idna").success();
}
/// Overlapping usage of `--no-binary` and `--only-binary`
#[test]
fn install_only_binary_overrides_no_binary_all() {

View File

@ -3963,6 +3963,56 @@ fn no_binary() -> Result<()> {
assert!(context.temp_dir.child("uv.lock").exists());
uv_snapshot!(context.filters(), context.sync().arg("--reinstall").arg("--no-binary"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 2 packages in [TIME]
Prepared 1 package in [TIME]
Uninstalled 1 package in [TIME]
Installed 1 package in [TIME]
~ iniconfig==2.0.0
"###);
uv_snapshot!(context.filters(), context.sync().arg("--reinstall").env("UV_NO_BINARY_PACKAGE", "iniconfig"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 2 packages in [TIME]
Prepared 1 package in [TIME]
Uninstalled 1 package in [TIME]
Installed 1 package in [TIME]
~ iniconfig==2.0.0
"###);
uv_snapshot!(context.filters(), context.sync().arg("--reinstall").env("UV_NO_BINARY", "1"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 2 packages in [TIME]
Prepared 1 package in [TIME]
Uninstalled 1 package in [TIME]
Installed 1 package in [TIME]
~ iniconfig==2.0.0
"###);
uv_snapshot!(context.filters(), context.sync().arg("--reinstall").env("UV_NO_BINARY", "iniconfig"), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: invalid value 'iniconfig' for '--no-binary': value was not a boolean
For more information, try '--help'.
"###);
Ok(())
}

View File

@ -178,6 +178,17 @@ Equivalent to the `--locked` command-line argument. If set, uv will assert that
Equivalent to the `--native-tls` command-line argument. If set to `true`, uv will
use the system's trust store instead of the bundled `webpki-roots` crate.
### `UV_NO_BINARY`
Equivalent to the `--no-binary` command-line argument. If set, uv will install
all packages from source. The resolver will still use pre-built wheels to
extract package metadata, if available.
### `UV_NO_BINARY_PACKAGE`
Equivalent to the `--no-binary-package` command line argument. If set, uv will
not use pre-built wheels for the given space-delimited list of packages.
### `UV_NO_BUILD_ISOLATION`
Equivalent to the `--no-build-isolation` command-line argument. If set, uv will

View File

@ -299,8 +299,10 @@ uv run [OPTIONS] [COMMAND]
<p>The given packages will be built and installed from source. The resolver will still use pre-built wheels to extract package metadata, if available.</p>
<p>May also be set with the <code>UV_NO_BINARY</code> environment variable.</p>
</dd><dt><code>--no-binary-package</code> <i>no-binary-package</i></dt><dd><p>Don&#8217;t install pre-built wheels for a specific package</p>
<p>May also be set with the <code>UV_NO_BINARY_PACKAGE</code> environment variable.</p>
</dd><dt><code>--no-build</code></dt><dd><p>Don&#8217;t build source distributions.</p>
<p>When enabled, resolving will not run arbitrary Python code. The cached wheels of already-built source distributions will be reused, but operations that require building distributions will exit with an error.</p>
@ -958,8 +960,10 @@ uv add [OPTIONS] <PACKAGES|--requirements <REQUIREMENTS>>
<p>The given packages will be built and installed from source. The resolver will still use pre-built wheels to extract package metadata, if available.</p>
<p>May also be set with the <code>UV_NO_BINARY</code> environment variable.</p>
</dd><dt><code>--no-binary-package</code> <i>no-binary-package</i></dt><dd><p>Don&#8217;t install pre-built wheels for a specific package</p>
<p>May also be set with the <code>UV_NO_BINARY_PACKAGE</code> environment variable.</p>
</dd><dt><code>--no-build</code></dt><dd><p>Don&#8217;t build source distributions.</p>
<p>When enabled, resolving will not run arbitrary Python code. The cached wheels of already-built source distributions will be reused, but operations that require building distributions will exit with an error.</p>
@ -1319,8 +1323,10 @@ uv remove [OPTIONS] <PACKAGES>...
<p>The given packages will be built and installed from source. The resolver will still use pre-built wheels to extract package metadata, if available.</p>
<p>May also be set with the <code>UV_NO_BINARY</code> environment variable.</p>
</dd><dt><code>--no-binary-package</code> <i>no-binary-package</i></dt><dd><p>Don&#8217;t install pre-built wheels for a specific package</p>
<p>May also be set with the <code>UV_NO_BINARY_PACKAGE</code> environment variable.</p>
</dd><dt><code>--no-build</code></dt><dd><p>Don&#8217;t build source distributions.</p>
<p>When enabled, resolving will not run arbitrary Python code. The cached wheels of already-built source distributions will be reused, but operations that require building distributions will exit with an error.</p>
@ -1692,8 +1698,10 @@ uv sync [OPTIONS]
<p>The given packages will be built and installed from source. The resolver will still use pre-built wheels to extract package metadata, if available.</p>
<p>May also be set with the <code>UV_NO_BINARY</code> environment variable.</p>
</dd><dt><code>--no-binary-package</code> <i>no-binary-package</i></dt><dd><p>Don&#8217;t install pre-built wheels for a specific package</p>
<p>May also be set with the <code>UV_NO_BINARY_PACKAGE</code> environment variable.</p>
</dd><dt><code>--no-build</code></dt><dd><p>Don&#8217;t build source distributions.</p>
<p>When enabled, resolving will not run arbitrary Python code. The cached wheels of already-built source distributions will be reused, but operations that require building distributions will exit with an error.</p>
@ -2059,8 +2067,10 @@ uv lock [OPTIONS]
<p>The given packages will be built and installed from source. The resolver will still use pre-built wheels to extract package metadata, if available.</p>
<p>May also be set with the <code>UV_NO_BINARY</code> environment variable.</p>
</dd><dt><code>--no-binary-package</code> <i>no-binary-package</i></dt><dd><p>Don&#8217;t install pre-built wheels for a specific package</p>
<p>May also be set with the <code>UV_NO_BINARY_PACKAGE</code> environment variable.</p>
</dd><dt><code>--no-build</code></dt><dd><p>Don&#8217;t build source distributions.</p>
<p>When enabled, resolving will not run arbitrary Python code. The cached wheels of already-built source distributions will be reused, but operations that require building distributions will exit with an error.</p>
@ -2404,8 +2414,10 @@ uv export [OPTIONS]
<p>The given packages will be built and installed from source. The resolver will still use pre-built wheels to extract package metadata, if available.</p>
<p>May also be set with the <code>UV_NO_BINARY</code> environment variable.</p>
</dd><dt><code>--no-binary-package</code> <i>no-binary-package</i></dt><dd><p>Don&#8217;t install pre-built wheels for a specific package</p>
<p>May also be set with the <code>UV_NO_BINARY_PACKAGE</code> environment variable.</p>
</dd><dt><code>--no-build</code></dt><dd><p>Don&#8217;t build source distributions.</p>
<p>When enabled, resolving will not run arbitrary Python code. The cached wheels of already-built source distributions will be reused, but operations that require building distributions will exit with an error.</p>
@ -2782,8 +2794,10 @@ uv tree [OPTIONS]
<p>The given packages will be built and installed from source. The resolver will still use pre-built wheels to extract package metadata, if available.</p>
<p>May also be set with the <code>UV_NO_BINARY</code> environment variable.</p>
</dd><dt><code>--no-binary-package</code> <i>no-binary-package</i></dt><dd><p>Don&#8217;t install pre-built wheels for a specific package</p>
<p>May also be set with the <code>UV_NO_BINARY_PACKAGE</code> environment variable.</p>
</dd><dt><code>--no-build</code></dt><dd><p>Don&#8217;t build source distributions.</p>
<p>When enabled, resolving will not run arbitrary Python code. The cached wheels of already-built source distributions will be reused, but operations that require building distributions will exit with an error.</p>
@ -3255,8 +3269,10 @@ uv tool run [OPTIONS] [COMMAND]
<p>The given packages will be built and installed from source. The resolver will still use pre-built wheels to extract package metadata, if available.</p>
<p>May also be set with the <code>UV_NO_BINARY</code> environment variable.</p>
</dd><dt><code>--no-binary-package</code> <i>no-binary-package</i></dt><dd><p>Don&#8217;t install pre-built wheels for a specific package</p>
<p>May also be set with the <code>UV_NO_BINARY_PACKAGE</code> environment variable.</p>
</dd><dt><code>--no-build</code></dt><dd><p>Don&#8217;t build source distributions.</p>
<p>When enabled, resolving will not run arbitrary Python code. The cached wheels of already-built source distributions will be reused, but operations that require building distributions will exit with an error.</p>
@ -3584,8 +3600,10 @@ uv tool install [OPTIONS] <PACKAGE>
<p>The given packages will be built and installed from source. The resolver will still use pre-built wheels to extract package metadata, if available.</p>
<p>May also be set with the <code>UV_NO_BINARY</code> environment variable.</p>
</dd><dt><code>--no-binary-package</code> <i>no-binary-package</i></dt><dd><p>Don&#8217;t install pre-built wheels for a specific package</p>
<p>May also be set with the <code>UV_NO_BINARY_PACKAGE</code> environment variable.</p>
</dd><dt><code>--no-build</code></dt><dd><p>Don&#8217;t build source distributions.</p>
<p>When enabled, resolving will not run arbitrary Python code. The cached wheels of already-built source distributions will be reused, but operations that require building distributions will exit with an error.</p>
@ -3907,8 +3925,10 @@ uv tool upgrade [OPTIONS] <NAME>...
<p>The given packages will be built and installed from source. The resolver will still use pre-built wheels to extract package metadata, if available.</p>
<p>May also be set with the <code>UV_NO_BINARY</code> environment variable.</p>
</dd><dt><code>--no-binary-package</code> <i>no-binary-package</i></dt><dd><p>Don&#8217;t install pre-built wheels for a specific package</p>
<p>May also be set with the <code>UV_NO_BINARY_PACKAGE</code> environment variable.</p>
</dd><dt><code>--no-build</code></dt><dd><p>Don&#8217;t build source distributions.</p>
<p>When enabled, resolving will not run arbitrary Python code. The cached wheels of already-built source distributions will be reused, but operations that require building distributions will exit with an error.</p>
@ -8349,8 +8369,10 @@ uv build [OPTIONS] [SRC]
<p>The given packages will be built and installed from source. The resolver will still use pre-built wheels to extract package metadata, if available.</p>
<p>May also be set with the <code>UV_NO_BINARY</code> environment variable.</p>
</dd><dt><code>--no-binary-package</code> <i>no-binary-package</i></dt><dd><p>Don&#8217;t install pre-built wheels for a specific package</p>
<p>May also be set with the <code>UV_NO_BINARY_PACKAGE</code> environment variable.</p>
</dd><dt><code>--no-build</code></dt><dd><p>Don&#8217;t build source distributions.</p>
<p>When enabled, resolving will not run arbitrary Python code. The cached wheels of already-built source distributions will be reused, but operations that require building distributions will exit with an error.</p>