Add --no-build, --no-build-package, and binary variants (#4322)

## Summary

These are now supported on `uv run`, `uv lock`, `uv sync`, and `uv tool
run`.

Closes https://github.com/astral-sh/uv/issues/4297.
This commit is contained in:
Charlie Marsh 2024-06-13 21:05:00 -07:00 committed by GitHub
parent f01ab57518
commit 7d9541d0f4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 700 additions and 434 deletions

View file

@ -594,7 +594,7 @@ fn parse_entry(
end: s.cursor(),
}
})?;
RequirementsTxtStatement::NoBinary(NoBinary::from_arg(specifier))
RequirementsTxtStatement::NoBinary(NoBinary::from_pip_arg(specifier))
} else if s.eat_if("--only-binary") {
let given = parse_value(content, s, |c: char| !['\n', '\r', '#'].contains(&c))?;
let specifier = PackageNameSpecifier::from_str(given).map_err(|err| {
@ -605,7 +605,7 @@ fn parse_entry(
end: s.cursor(),
}
})?;
RequirementsTxtStatement::OnlyBinary(NoBuild::from_arg(specifier))
RequirementsTxtStatement::OnlyBinary(NoBuild::from_pip_arg(specifier))
} else if s.at(char::is_ascii_alphanumeric) || s.at(|char| matches!(char, '.' | '/' | '$')) {
let source = if requirements_txt == Path::new("-") {
None

View file

@ -46,6 +46,14 @@ impl BuildOptions {
}
}
#[must_use]
pub fn combine(self, no_binary: NoBinary, no_build: NoBuild) -> Self {
Self {
no_binary: self.no_binary.combine(no_binary),
no_build: self.no_build.combine(no_build),
}
}
pub fn no_binary_package(&self, package_name: &PackageName) -> bool {
match &self.no_binary {
NoBinary::None => false,
@ -108,7 +116,22 @@ pub enum NoBinary {
impl NoBinary {
/// Determine the binary installation strategy to use for the given arguments.
pub fn from_args(no_binary: Vec<PackageNameSpecifier>) -> Self {
pub fn from_args(no_binary: Option<bool>, no_binary_package: Vec<PackageName>) -> Self {
match no_binary {
Some(true) => Self::All,
Some(false) => Self::None,
None => {
if no_binary_package.is_empty() {
Self::None
} else {
Self::Packages(no_binary_package)
}
}
}
}
/// Determine the binary installation strategy to use for the given arguments from the pip CLI.
pub fn from_pip_args(no_binary: Vec<PackageNameSpecifier>) -> Self {
let combined = PackageNameSpecifiers::from_iter(no_binary.into_iter());
match combined {
PackageNameSpecifiers::All => Self::All,
@ -117,9 +140,9 @@ impl NoBinary {
}
}
/// Determine the binary installation strategy to use for the given argument.
pub fn from_arg(no_binary: PackageNameSpecifier) -> Self {
Self::from_args(vec![no_binary])
/// Determine the binary installation strategy to use for the given argument from the pip CLI.
pub fn from_pip_arg(no_binary: PackageNameSpecifier) -> Self {
Self::from_pip_args(vec![no_binary])
}
/// Combine a set of [`NoBinary`] values.
@ -188,7 +211,22 @@ pub enum NoBuild {
impl NoBuild {
/// Determine the build strategy to use for the given arguments.
pub fn from_args(only_binary: Vec<PackageNameSpecifier>, no_build: bool) -> Self {
pub fn from_args(no_build: Option<bool>, no_build_package: Vec<PackageName>) -> Self {
match no_build {
Some(true) => Self::All,
Some(false) => Self::None,
None => {
if no_build_package.is_empty() {
Self::None
} else {
Self::Packages(no_build_package)
}
}
}
}
/// Determine the build strategy to use for the given arguments from the pip CLI.
pub fn from_pip_args(only_binary: Vec<PackageNameSpecifier>, no_build: bool) -> Self {
if no_build {
Self::All
} else {
@ -201,9 +239,9 @@ impl NoBuild {
}
}
/// Determine the build strategy to use for the given argument.
pub fn from_arg(no_build: PackageNameSpecifier) -> Self {
Self::from_args(vec![no_build], false)
/// Determine the build strategy to use for the given argument from the pip CLI.
pub fn from_pip_arg(no_build: PackageNameSpecifier) -> Self {
Self::from_pip_args(vec![no_build], false)
}
/// Combine a set of [`NoBuild`] values.
@ -310,23 +348,23 @@ mod tests {
#[test]
fn no_build_from_args() -> Result<(), Error> {
assert_eq!(
NoBuild::from_args(vec![PackageNameSpecifier::from_str(":all:")?], false),
NoBuild::from_pip_args(vec![PackageNameSpecifier::from_str(":all:")?], false),
NoBuild::All,
);
assert_eq!(
NoBuild::from_args(vec![PackageNameSpecifier::from_str(":all:")?], true),
NoBuild::from_pip_args(vec![PackageNameSpecifier::from_str(":all:")?], true),
NoBuild::All,
);
assert_eq!(
NoBuild::from_args(vec![PackageNameSpecifier::from_str(":none:")?], true),
NoBuild::from_pip_args(vec![PackageNameSpecifier::from_str(":none:")?], true),
NoBuild::All,
);
assert_eq!(
NoBuild::from_args(vec![PackageNameSpecifier::from_str(":none:")?], false),
NoBuild::from_pip_args(vec![PackageNameSpecifier::from_str(":none:")?], false),
NoBuild::None,
);
assert_eq!(
NoBuild::from_args(
NoBuild::from_pip_args(
vec![
PackageNameSpecifier::from_str("foo")?,
PackageNameSpecifier::from_str("bar")?
@ -339,7 +377,7 @@ mod tests {
]),
);
assert_eq!(
NoBuild::from_args(
NoBuild::from_pip_args(
vec![
PackageNameSpecifier::from_str("test")?,
PackageNameSpecifier::All
@ -349,7 +387,7 @@ mod tests {
NoBuild::All,
);
assert_eq!(
NoBuild::from_args(
NoBuild::from_pip_args(
vec![
PackageNameSpecifier::from_str("foo")?,
PackageNameSpecifier::from_str(":none:")?,

View file

@ -2,6 +2,9 @@ use std::str::FromStr;
use pep508_rs::PackageName;
/// A specifier used for (e.g.) pip's `--no-binary` flag.
///
/// This is a superset of the package name format, allowing for special values `:all:` and `:none:`.
#[derive(Debug, Clone)]
pub enum PackageNameSpecifier {
All,
@ -85,10 +88,9 @@ impl schemars::JsonSchema for PackageNameSpecifier {
}
}
/// Package name specification.
/// A repeated specifier used for (e.g.) pip's `--no-binary` flag.
///
/// Consumes both package names and selection directives for compatibility with pip flags
/// such as `--no-binary`.
/// This is a superset of the package name format, allowing for special values `:all:` and `:none:`.
#[derive(Debug, Clone)]
pub enum PackageNameSpecifiers {
All,

View file

@ -81,6 +81,10 @@ impl Combine for ResolverInstallerOptions {
upgrade_package: self.upgrade_package.combine(other.upgrade_package),
reinstall: self.reinstall.combine(other.reinstall),
reinstall_package: self.reinstall_package.combine(other.reinstall_package),
no_build: self.no_build.combine(other.no_build),
no_build_package: self.no_build_package.combine(other.no_build_package),
no_binary: self.no_binary.combine(other.no_binary),
no_binary_package: self.no_binary_package.combine(other.no_binary_package),
}
}
}

View file

@ -77,6 +77,10 @@ pub struct InstallerOptions {
pub compile_bytecode: Option<bool>,
pub reinstall: Option<bool>,
pub reinstall_package: Option<Vec<PackageName>>,
pub no_build: Option<bool>,
pub no_build_package: Option<Vec<PackageName>>,
pub no_binary: Option<bool>,
pub no_binary_package: Option<Vec<PackageName>>,
}
/// Settings relevant to all resolver operations.
@ -98,6 +102,10 @@ pub struct ResolverOptions {
pub link_mode: Option<LinkMode>,
pub upgrade: Option<bool>,
pub upgrade_package: Option<Vec<PackageName>>,
pub no_build: Option<bool>,
pub no_build_package: Option<Vec<PackageName>>,
pub no_binary: Option<bool>,
pub no_binary_package: Option<Vec<PackageName>>,
}
/// Shared settings, relevant to all operations that must resolve and install dependencies. The
@ -123,6 +131,10 @@ pub struct ResolverInstallerOptions {
pub upgrade_package: Option<Vec<PackageName>>,
pub reinstall: Option<bool>,
pub reinstall_package: Option<Vec<PackageName>>,
pub no_build: Option<bool>,
pub no_build_package: Option<Vec<PackageName>>,
pub no_binary: Option<bool>,
pub no_binary_package: Option<Vec<PackageName>>,
}
/// A `[tool.uv.pip]` section.
@ -180,132 +192,3 @@ pub struct PipOptions {
pub concurrent_builds: Option<NonZeroUsize>,
pub concurrent_installs: Option<NonZeroUsize>,
}
impl Options {
/// Return the `pip` section, with any top-level options merged in. If options are repeated
/// between the top-level and the `pip` section, the `pip` options are preferred.
///
/// For example, prefers `tool.uv.pip.index-url` over `tool.uv.index-url`.
pub fn pip(self) -> PipOptions {
let PipOptions {
python,
system,
break_system_packages,
target,
prefix,
index_url,
extra_index_url,
no_index,
find_links,
index_strategy,
keyring_provider,
no_build,
no_binary,
only_binary,
no_build_isolation,
strict,
extra,
all_extras,
no_deps,
resolution,
prerelease,
output_file,
no_strip_extras,
no_annotate,
no_header,
custom_compile_command,
generate_hashes,
legacy_setup_py,
config_settings,
python_version,
python_platform,
exclude_newer,
no_emit_package,
emit_index_url,
emit_find_links,
emit_marker_expression,
emit_index_annotation,
annotation_style,
link_mode,
compile_bytecode,
require_hashes,
upgrade,
upgrade_package,
reinstall,
reinstall_package,
concurrent_builds,
concurrent_downloads,
concurrent_installs,
} = self.pip.unwrap_or_default();
let ResolverInstallerOptions {
index_url: top_level_index_url,
extra_index_url: top_level_extra_index_url,
no_index: top_level_no_index,
find_links: top_level_find_links,
index_strategy: top_level_index_strategy,
keyring_provider: top_level_keyring_provider,
resolution: top_level_resolution,
prerelease: top_level_prerelease,
config_settings: top_level_config_settings,
exclude_newer: top_level_exclude_newer,
link_mode: top_level_link_mode,
compile_bytecode: top_level_compile_bytecode,
upgrade: top_level_upgrade,
upgrade_package: top_level_upgrade_package,
reinstall: top_level_reinstall,
reinstall_package: top_level_reinstall_package,
} = self.top_level;
PipOptions {
python,
system,
break_system_packages,
target,
prefix,
index_url: index_url.or(top_level_index_url),
extra_index_url: extra_index_url.or(top_level_extra_index_url),
no_index: no_index.or(top_level_no_index),
find_links: find_links.or(top_level_find_links),
index_strategy: index_strategy.or(top_level_index_strategy),
keyring_provider: keyring_provider.or(top_level_keyring_provider),
no_build,
no_binary,
only_binary,
no_build_isolation,
strict,
extra,
all_extras,
no_deps,
resolution: resolution.or(top_level_resolution),
prerelease: prerelease.or(top_level_prerelease),
output_file,
no_strip_extras,
no_annotate,
no_header,
custom_compile_command,
generate_hashes,
legacy_setup_py,
config_settings: config_settings.or(top_level_config_settings),
python_version,
python_platform,
exclude_newer: exclude_newer.or(top_level_exclude_newer),
no_emit_package,
emit_index_url,
emit_find_links,
emit_marker_expression,
emit_index_annotation,
annotation_style,
link_mode: link_mode.or(top_level_link_mode),
compile_bytecode: compile_bytecode.or(top_level_compile_bytecode),
require_hashes,
upgrade: upgrade.or(top_level_upgrade),
upgrade_package: upgrade_package.or(top_level_upgrade_package),
reinstall: reinstall.or(top_level_reinstall),
reinstall_package: reinstall_package.or(top_level_reinstall_package),
concurrent_builds,
concurrent_downloads,
concurrent_installs,
}
}
}

View file

@ -1495,6 +1495,9 @@ pub(crate) struct RunArgs {
#[command(flatten)]
pub(crate) installer: ResolverInstallerArgs,
#[command(flatten)]
pub(crate) build: BuildArgs,
#[command(flatten)]
pub(crate) refresh: RefreshArgs,
@ -1544,6 +1547,9 @@ pub(crate) struct SyncArgs {
#[command(flatten)]
pub(crate) installer: InstallerArgs,
#[command(flatten)]
pub(crate) build: BuildArgs,
#[command(flatten)]
pub(crate) refresh: RefreshArgs,
@ -1568,6 +1574,9 @@ pub(crate) struct LockArgs {
#[command(flatten)]
pub(crate) resolver: ResolverArgs,
#[command(flatten)]
pub(crate) build: BuildArgs,
#[command(flatten)]
pub(crate) refresh: RefreshArgs,
@ -1668,6 +1677,9 @@ pub(crate) struct ToolRunArgs {
#[command(flatten)]
pub(crate) installer: ResolverInstallerArgs,
#[command(flatten)]
pub(crate) build: BuildArgs,
#[command(flatten)]
pub(crate) refresh: RefreshArgs,
@ -1790,6 +1802,39 @@ pub(crate) struct RefreshArgs {
pub(crate) refresh_package: Vec<PackageName>,
}
#[derive(Args)]
#[allow(clippy::struct_excessive_bools)]
pub(crate) struct BuildArgs {
/// Don't build source distributions.
///
/// When enabled, resolving will not run arbitrary code. The cached wheels of already-built
/// source distributions will be reused, but operations that require building distributions will
/// exit with an error.
#[arg(long, overrides_with("build"))]
pub(crate) no_build: bool,
#[arg(long, overrides_with("no_build"), hide = true)]
pub(crate) build: bool,
/// Don't build source distributions for a specific package.
#[arg(long)]
pub(crate) no_build_package: Vec<PackageName>,
/// 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.
#[arg(long, overrides_with("binary"))]
pub(crate) no_binary: bool,
#[arg(long, overrides_with("no_binary"), hide = true)]
pub(crate) binary: bool,
/// Don't install pre-built wheels for a specific package.
#[arg(long)]
pub(crate) no_binary_package: Vec<PackageName>,
}
/// Arguments that are used by commands that need to install (but not resolve) packages.
#[derive(Args)]
#[allow(clippy::struct_excessive_bools)]

View file

@ -22,7 +22,7 @@ use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, Constraints, ExtrasSpecification, IndexStrategy,
NoBinary, NoBuild, Overrides, PreviewMode, SetupPyStrategy, Upgrade,
Overrides, PreviewMode, SetupPyStrategy, Upgrade,
};
use uv_configuration::{KeyringProviderType, TargetTriple};
use uv_dispatch::BuildDispatch;
@ -80,8 +80,7 @@ pub(crate) async fn pip_compile(
config_settings: ConfigSettings,
connectivity: Connectivity,
no_build_isolation: bool,
no_build: NoBuild,
no_binary: NoBinary,
build_options: BuildOptions,
python_version: Option<PythonVersion>,
python_platform: Option<TargetTriple>,
exclude_newer: Option<ExcludeNewer>,
@ -123,8 +122,8 @@ pub(crate) async fn pip_compile(
extra_index_urls,
no_index,
find_links,
no_binary: specified_no_binary,
no_build: specified_no_build,
no_binary,
no_build,
} = RequirementsSpecification::from_sources(
requirements,
constraints,
@ -254,10 +253,8 @@ pub(crate) async fn pip_compile(
let preferences = read_requirements_txt(output_file, &upgrade).await?;
let git = GitResolver::default();
// 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(no_binary, no_build);
// Combine the `--no-binary` and `--no-build` flags from the requirements files.
let build_options = build_options.combine(no_binary, no_build);
// Resolve the flat indexes from `--find-links`.
let flat_index = {

View file

@ -12,8 +12,8 @@ use uv_auth::store_credentials_from_url;
use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, ExtrasSpecification, IndexStrategy, NoBinary,
NoBuild, PreviewMode, Reinstall, SetupPyStrategy, Upgrade,
BuildOptions, Concurrency, ConfigSettings, ExtrasSpecification, IndexStrategy, PreviewMode,
Reinstall, SetupPyStrategy, Upgrade,
};
use uv_configuration::{KeyringProviderType, TargetTriple};
use uv_dispatch::BuildDispatch;
@ -56,8 +56,7 @@ pub(crate) async fn pip_install(
connectivity: Connectivity,
config_settings: &ConfigSettings,
no_build_isolation: bool,
no_build: NoBuild,
no_binary: NoBinary,
build_options: BuildOptions,
python_version: Option<PythonVersion>,
python_platform: Option<TargetTriple>,
strict: bool,
@ -92,8 +91,8 @@ pub(crate) async fn pip_install(
extra_index_urls,
no_index,
find_links,
no_binary: specified_no_binary,
no_build: specified_no_build,
no_binary,
no_build,
extras: _,
} = operations::read_requirements(
requirements,
@ -263,10 +262,8 @@ pub(crate) async fn pip_install(
.platform(interpreter.platform())
.build();
// 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(no_binary, no_build);
// Combine the `--no-binary` and `--no-build` flags from the requirements files.
let build_options = build_options.combine(no_binary, no_build);
// Resolve the flat indexes from `--find-links`.
let flat_index = {

View file

@ -11,8 +11,8 @@ use uv_auth::store_credentials_from_url;
use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, ExtrasSpecification, IndexStrategy, NoBinary,
NoBuild, PreviewMode, Reinstall, SetupPyStrategy, Upgrade,
BuildOptions, Concurrency, ConfigSettings, ExtrasSpecification, IndexStrategy, PreviewMode,
Reinstall, SetupPyStrategy, Upgrade,
};
use uv_configuration::{KeyringProviderType, TargetTriple};
use uv_dispatch::BuildDispatch;
@ -48,8 +48,7 @@ pub(crate) async fn pip_sync(
connectivity: Connectivity,
config_settings: &ConfigSettings,
no_build_isolation: bool,
no_build: NoBuild,
no_binary: NoBinary,
build_options: BuildOptions,
python_version: Option<PythonVersion>,
python_platform: Option<TargetTriple>,
strict: bool,
@ -90,8 +89,8 @@ pub(crate) async fn pip_sync(
extra_index_urls,
no_index,
find_links,
no_binary: specified_no_binary,
no_build: specified_no_build,
no_binary,
no_build,
extras: _,
} = operations::read_requirements(
requirements,
@ -206,10 +205,8 @@ pub(crate) async fn pip_sync(
.platform(interpreter.platform())
.build();
// 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(no_binary, no_build);
// Combine the `--no-binary` and `--no-build` flags from the requirements files.
let build_options = build_options.combine(no_binary, no_build);
// Resolve the flat indexes from `--find-links`.
let flat_index = {

View file

@ -64,6 +64,7 @@ pub(crate) async fn add(
&settings.config_setting,
settings.exclude_newer.as_ref(),
&settings.link_mode,
&settings.build_options,
preview,
connectivity,
concurrency,
@ -93,6 +94,7 @@ pub(crate) async fn add(
&settings.config_setting,
&settings.link_mode,
&settings.compile_bytecode,
&settings.build_options,
preview,
connectivity,
concurrency,

View file

@ -62,6 +62,7 @@ pub(crate) async fn lock(
&settings.config_setting,
settings.exclude_newer.as_ref(),
&settings.link_mode,
&settings.build_options,
preview,
connectivity,
concurrency,
@ -98,6 +99,7 @@ pub(super) async fn do_lock(
config_setting: &ConfigSettings,
exclude_newer: Option<&ExcludeNewer>,
link_mode: &LinkMode,
build_options: &BuildOptions,
preview: PreviewMode,
connectivity: Connectivity,
concurrency: Concurrency,
@ -161,7 +163,6 @@ pub(super) async fn do_lock(
// TODO(charlie): These are all default values. We should consider whether we want to make them
// optional on the downstream APIs.
let build_isolation = BuildIsolation::default();
let build_options = BuildOptions::default();
let extras = ExtrasSpecification::default();
let setup_py = SetupPyStrategy::default();
@ -169,7 +170,7 @@ pub(super) async fn do_lock(
let flat_index = {
let client = FlatIndexClient::new(&client, cache);
let entries = client.fetch(index_locations.flat_index()).await?;
FlatIndex::from_entries(entries, None, &hasher, &build_options)
FlatIndex::from_entries(entries, None, &hasher, build_options)
};
// If an existing lockfile exists, build up a set of preferences.
@ -192,7 +193,7 @@ pub(super) async fn do_lock(
config_setting,
build_isolation,
*link_mode,
&build_options,
build_options,
concurrency,
preview,
);

View file

@ -9,9 +9,7 @@ use distribution_types::Resolution;
use pep440_rs::Version;
use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{
BuildOptions, Concurrency, ExtrasSpecification, PreviewMode, SetupPyStrategy,
};
use uv_configuration::{Concurrency, ExtrasSpecification, PreviewMode, SetupPyStrategy};
use uv_dispatch::BuildDispatch;
use uv_distribution::Workspace;
use uv_fs::Simplified;
@ -280,6 +278,7 @@ pub(crate) async fn update_environment(
compile_bytecode,
upgrade,
reinstall,
build_options,
} = settings;
let client_builder = BaseClientBuilder::new()
@ -348,7 +347,6 @@ pub(crate) async fn update_environment(
// TODO(charlie): These are all default values. We should consider whether we want to make them
// optional on the downstream APIs.
let build_isolation = BuildIsolation::default();
let build_options = BuildOptions::default();
let dev = Vec::default();
let dry_run = false;
let extras = ExtrasSpecification::default();
@ -360,7 +358,7 @@ pub(crate) async fn update_environment(
let flat_index = {
let client = FlatIndexClient::new(&client, cache);
let entries = client.fetch(index_locations.flat_index()).await?;
FlatIndex::from_entries(entries, Some(tags), &hasher, &build_options)
FlatIndex::from_entries(entries, Some(tags), &hasher, build_options)
};
// Create a build dispatch.
@ -377,7 +375,7 @@ pub(crate) async fn update_environment(
config_setting,
build_isolation,
*link_mode,
&build_options,
build_options,
concurrency,
preview,
);
@ -436,7 +434,7 @@ pub(crate) async fn update_environment(
config_setting,
build_isolation,
*link_mode,
&build_options,
build_options,
concurrency,
preview,
)
@ -448,7 +446,7 @@ pub(crate) async fn update_environment(
site_packages,
pip::operations::Modifications::Sufficient,
reinstall,
&build_options,
build_options,
*link_mode,
*compile_bytecode,
index_locations,

View file

@ -66,6 +66,7 @@ pub(crate) async fn remove(
&settings.config_setting,
settings.exclude_newer.as_ref(),
&settings.link_mode,
&settings.build_options,
preview,
connectivity,
concurrency,
@ -95,6 +96,7 @@ pub(crate) async fn remove(
&settings.config_setting,
&settings.link_mode,
&settings.compile_bytecode,
&settings.build_options,
preview,
connectivity,
concurrency,

View file

@ -75,6 +75,7 @@ pub(crate) async fn run(
&settings.config_setting,
settings.exclude_newer.as_ref(),
&settings.link_mode,
&settings.build_options,
preview,
connectivity,
concurrency,
@ -97,6 +98,7 @@ pub(crate) async fn run(
&settings.config_setting,
&settings.link_mode,
&settings.compile_bytecode,
&settings.build_options,
preview,
connectivity,
concurrency,

View file

@ -72,6 +72,7 @@ pub(crate) async fn sync(
&settings.config_setting,
&settings.link_mode,
&settings.compile_bytecode,
&settings.build_options,
preview,
connectivity,
concurrency,
@ -100,6 +101,7 @@ pub(super) async fn do_sync(
config_setting: &ConfigSettings,
link_mode: &LinkMode,
compile_bytecode: &bool,
build_options: &BuildOptions,
preview: PreviewMode,
connectivity: Connectivity,
concurrency: Concurrency,
@ -150,7 +152,6 @@ pub(super) async fn do_sync(
// TODO(charlie): These are all default values. We should consider whether we want to make them
// optional on the downstream APIs.
let build_isolation = BuildIsolation::default();
let build_options = BuildOptions::default();
let dry_run = false;
let hasher = HashStrategy::default();
let setup_py = SetupPyStrategy::default();
@ -159,7 +160,7 @@ pub(super) async fn do_sync(
let flat_index = {
let client = FlatIndexClient::new(&client, cache);
let entries = client.fetch(index_locations.flat_index()).await?;
FlatIndex::from_entries(entries, Some(tags), &hasher, &build_options)
FlatIndex::from_entries(entries, Some(tags), &hasher, build_options)
};
// Create a build dispatch.
@ -176,7 +177,7 @@ pub(super) async fn do_sync(
config_setting,
build_isolation,
*link_mode,
&build_options,
build_options,
concurrency,
preview,
);
@ -189,7 +190,7 @@ pub(super) async fn do_sync(
site_packages,
Modifications::Sufficient,
reinstall,
&build_options,
build_options,
*link_mode,
*compile_bytecode,
index_locations,

View file

@ -272,8 +272,7 @@ async fn run() -> Result<ExitStatus> {
args.settings.config_setting,
globals.connectivity,
args.settings.no_build_isolation,
args.settings.no_build,
args.settings.no_binary,
args.settings.build_options,
args.settings.python_version,
args.settings.python_platform,
args.settings.exclude_newer,
@ -332,8 +331,7 @@ async fn run() -> Result<ExitStatus> {
globals.connectivity,
&args.settings.config_setting,
args.settings.no_build_isolation,
args.settings.no_build,
args.settings.no_binary,
args.settings.build_options,
args.settings.python_version,
args.settings.python_platform,
args.settings.strict,
@ -411,8 +409,7 @@ async fn run() -> Result<ExitStatus> {
globals.connectivity,
&args.settings.config_setting,
args.settings.no_build_isolation,
args.settings.no_build,
args.settings.no_binary,
args.settings.build_options,
args.settings.python_version,
args.settings.python_platform,
args.settings.strict,

View file

@ -12,8 +12,9 @@ use pypi_types::Requirement;
use uv_cache::{CacheArgs, Refresh};
use uv_client::Connectivity;
use uv_configuration::{
Concurrency, ConfigSettings, ExtrasSpecification, IndexStrategy, KeyringProviderType, NoBinary,
NoBuild, PreviewMode, Reinstall, SetupPyStrategy, TargetTriple, Upgrade,
BuildOptions, Concurrency, ConfigSettings, ExtrasSpecification, IndexStrategy,
KeyringProviderType, NoBinary, NoBuild, PreviewMode, Reinstall, SetupPyStrategy, TargetTriple,
Upgrade,
};
use uv_normalize::PackageName;
use uv_resolver::{AnnotationStyle, DependencyMode, ExcludeNewer, PreReleaseMode, ResolutionMode};
@ -24,10 +25,10 @@ use uv_settings::{
use uv_toolchain::{Prefix, PythonVersion, Target};
use crate::cli::{
AddArgs, ColorChoice, GlobalArgs, IndexArgs, InstallerArgs, LockArgs, Maybe, PipCheckArgs,
PipCompileArgs, PipFreezeArgs, PipInstallArgs, PipListArgs, PipShowArgs, PipSyncArgs,
PipUninstallArgs, RefreshArgs, RemoveArgs, ResolverArgs, ResolverInstallerArgs, RunArgs,
SyncArgs, ToolRunArgs, ToolchainInstallArgs, ToolchainListArgs, VenvArgs,
AddArgs, BuildArgs, ColorChoice, GlobalArgs, IndexArgs, InstallerArgs, LockArgs, Maybe,
PipCheckArgs, PipCompileArgs, PipFreezeArgs, PipInstallArgs, PipListArgs, PipShowArgs,
PipSyncArgs, PipUninstallArgs, RefreshArgs, RemoveArgs, ResolverArgs, ResolverInstallerArgs,
RunArgs, SyncArgs, ToolRunArgs, ToolchainInstallArgs, ToolchainListArgs, VenvArgs,
};
use crate::commands::ListFormat;
@ -142,6 +143,7 @@ impl RunSettings {
args,
with,
installer,
build,
refresh,
python,
package,
@ -160,7 +162,7 @@ impl RunSettings {
package,
refresh: Refresh::from(refresh),
settings: ResolverInstallerSettings::combine(
ResolverInstallerOptions::from(installer),
resolver_installer_options(installer, build),
filesystem,
),
}
@ -190,6 +192,7 @@ impl ToolRunSettings {
from,
with,
installer,
build,
refresh,
python,
} = args;
@ -202,7 +205,7 @@ impl ToolRunSettings {
python,
refresh: Refresh::from(refresh),
settings: ResolverInstallerSettings::combine(
ResolverInstallerOptions::from(installer),
resolver_installer_options(installer, build),
filesystem,
),
}
@ -292,6 +295,7 @@ impl SyncSettings {
dev,
no_dev,
installer,
build,
refresh,
python,
} = args;
@ -304,7 +308,7 @@ impl SyncSettings {
dev: flag(dev, no_dev).unwrap_or(true),
python,
refresh: Refresh::from(refresh),
settings: InstallerSettings::combine(InstallerOptions::from(installer), filesystem),
settings: InstallerSettings::combine(installer_options(installer, build), filesystem),
}
}
}
@ -324,6 +328,7 @@ impl LockSettings {
pub(crate) fn resolve(args: LockArgs, filesystem: Option<FilesystemOptions>) -> Self {
let LockArgs {
resolver,
build,
refresh,
python,
} = args;
@ -331,7 +336,7 @@ impl LockSettings {
Self {
python,
refresh: Refresh::from(refresh),
settings: ResolverSettings::combine(ResolverOptions::from(resolver), filesystem),
settings: ResolverSettings::combine(resolver_options(resolver, build), filesystem),
}
}
}
@ -955,6 +960,7 @@ pub(crate) struct InstallerSettings {
pub(crate) link_mode: LinkMode,
pub(crate) compile_bytecode: bool,
pub(crate) reinstall: Reinstall,
pub(crate) build_options: BuildOptions,
}
impl InstallerSettings {
@ -977,6 +983,10 @@ impl InstallerSettings {
upgrade_package: _,
reinstall,
reinstall_package,
no_build,
no_build_package,
no_binary,
no_binary_package,
} = filesystem
.map(FilesystemOptions::into_options)
.map(|options| options.top_level)
@ -1009,11 +1019,25 @@ impl InstallerSettings {
.combine(compile_bytecode)
.unwrap_or_default(),
reinstall: Reinstall::from_args(
args.reinstall.or(reinstall),
args.reinstall.combine(reinstall),
args.reinstall_package
.or(reinstall_package)
.combine(reinstall_package)
.unwrap_or_default(),
),
build_options: BuildOptions::new(
NoBinary::from_args(
args.no_binary.combine(no_binary),
args.no_binary_package
.combine(no_binary_package)
.unwrap_or_default(),
),
NoBuild::from_args(
args.no_build.combine(no_build),
args.no_build_package
.combine(no_build_package)
.unwrap_or_default(),
),
),
}
}
}
@ -1034,6 +1058,7 @@ pub(crate) struct ResolverSettings {
pub(crate) exclude_newer: Option<ExcludeNewer>,
pub(crate) link_mode: LinkMode,
pub(crate) upgrade: Upgrade,
pub(crate) build_options: BuildOptions,
}
impl ResolverSettings {
@ -1056,6 +1081,10 @@ impl ResolverSettings {
upgrade_package,
reinstall: _,
reinstall_package: _,
no_build,
no_build_package,
no_binary,
no_binary_package,
} = filesystem
.map(FilesystemOptions::into_options)
.map(|options| options.top_level)
@ -1087,8 +1116,24 @@ impl ResolverSettings {
exclude_newer: args.exclude_newer.combine(exclude_newer),
link_mode: args.link_mode.combine(link_mode).unwrap_or_default(),
upgrade: Upgrade::from_args(
args.upgrade.or(upgrade),
args.upgrade_package.or(upgrade_package).unwrap_or_default(),
args.upgrade.combine(upgrade),
args.upgrade_package
.combine(upgrade_package)
.unwrap_or_default(),
),
build_options: BuildOptions::new(
NoBinary::from_args(
args.no_binary.combine(no_binary),
args.no_binary_package
.combine(no_binary_package)
.unwrap_or_default(),
),
NoBuild::from_args(
args.no_build.combine(no_build),
args.no_build_package
.combine(no_build_package)
.unwrap_or_default(),
),
),
}
}
@ -1113,6 +1158,7 @@ pub(crate) struct ResolverInstallerSettings {
pub(crate) compile_bytecode: bool,
pub(crate) upgrade: Upgrade,
pub(crate) reinstall: Reinstall,
pub(crate) build_options: BuildOptions,
}
impl ResolverInstallerSettings {
@ -1138,6 +1184,10 @@ impl ResolverInstallerSettings {
upgrade_package,
reinstall,
reinstall_package,
no_build,
no_build_package,
no_binary,
no_binary_package,
} = filesystem
.map(FilesystemOptions::into_options)
.map(|options| options.top_level)
@ -1173,15 +1223,31 @@ impl ResolverInstallerSettings {
.combine(compile_bytecode)
.unwrap_or_default(),
upgrade: Upgrade::from_args(
args.upgrade.or(upgrade),
args.upgrade_package.or(upgrade_package).unwrap_or_default(),
args.upgrade.combine(upgrade),
args.upgrade_package
.combine(upgrade_package)
.unwrap_or_default(),
),
reinstall: Reinstall::from_args(
args.reinstall.or(reinstall),
args.reinstall.combine(reinstall),
args.reinstall_package
.or(reinstall_package)
.combine(reinstall_package)
.unwrap_or_default(),
),
build_options: BuildOptions::new(
NoBinary::from_args(
args.no_binary.combine(no_binary),
args.no_binary_package
.combine(no_binary_package)
.unwrap_or_default(),
),
NoBuild::from_args(
args.no_build.combine(no_build),
args.no_build_package
.combine(no_build_package)
.unwrap_or_default(),
),
),
}
}
}
@ -1202,9 +1268,8 @@ pub(crate) struct PipSettings {
pub(crate) prefix: Option<Prefix>,
pub(crate) index_strategy: IndexStrategy,
pub(crate) keyring_provider: KeyringProviderType,
pub(crate) no_binary: NoBinary,
pub(crate) no_build: NoBuild,
pub(crate) no_build_isolation: bool,
pub(crate) build_options: BuildOptions,
pub(crate) strict: bool,
pub(crate) dependency_mode: DependencyMode,
pub(crate) resolution: ResolutionMode,
@ -1237,6 +1302,10 @@ pub(crate) struct PipSettings {
impl PipSettings {
/// Resolve the [`PipSettings`] from the CLI and filesystem configuration.
pub(crate) fn combine(args: PipOptions, filesystem: Option<FilesystemOptions>) -> Self {
let Options { top_level, pip, .. } = filesystem
.map(FilesystemOptions::into_options)
.unwrap_or_default();
let PipOptions {
python,
system,
@ -1286,10 +1355,51 @@ impl PipSettings {
concurrent_builds,
concurrent_downloads,
concurrent_installs,
} = filesystem
.map(FilesystemOptions::into_options)
.map(Options::pip)
.unwrap_or_default();
} = pip.unwrap_or_default();
let ResolverInstallerOptions {
index_url: top_level_index_url,
extra_index_url: top_level_extra_index_url,
no_index: top_level_no_index,
find_links: top_level_find_links,
index_strategy: top_level_index_strategy,
keyring_provider: top_level_keyring_provider,
resolution: top_level_resolution,
prerelease: top_level_prerelease,
config_settings: top_level_config_settings,
exclude_newer: top_level_exclude_newer,
link_mode: top_level_link_mode,
compile_bytecode: top_level_compile_bytecode,
upgrade: top_level_upgrade,
upgrade_package: top_level_upgrade_package,
reinstall: top_level_reinstall,
reinstall_package: top_level_reinstall_package,
no_build: top_level_no_build,
no_build_package: top_level_no_build_package,
no_binary: top_level_no_binary,
no_binary_package: top_level_no_binary_package,
} = top_level;
// Merge the top-level options (`tool.uv`) with the pip-specific options (`tool.uv.pip`),
// preferring the latter.
//
// For example, prefer `tool.uv.pip.index-url` over `tool.uv.index-url`.
let index_url = index_url.combine(top_level_index_url);
let extra_index_url = extra_index_url.combine(top_level_extra_index_url);
let no_index = no_index.combine(top_level_no_index);
let find_links = find_links.combine(top_level_find_links);
let index_strategy = index_strategy.combine(top_level_index_strategy);
let keyring_provider = keyring_provider.combine(top_level_keyring_provider);
let resolution = resolution.combine(top_level_resolution);
let prerelease = prerelease.combine(top_level_prerelease);
let config_settings = config_settings.combine(top_level_config_settings);
let exclude_newer = exclude_newer.combine(top_level_exclude_newer);
let link_mode = link_mode.combine(top_level_link_mode);
let compile_bytecode = compile_bytecode.combine(top_level_compile_bytecode);
let upgrade = upgrade.combine(top_level_upgrade);
let upgrade_package = upgrade_package.combine(top_level_upgrade_package);
let reinstall = reinstall.combine(top_level_reinstall);
let reinstall_package = reinstall_package.combine(top_level_reinstall_package);
Self {
index_locations: IndexLocations::new(
@ -1348,10 +1458,6 @@ impl PipSettings {
.no_build_isolation
.combine(no_build_isolation)
.unwrap_or_default(),
no_build: NoBuild::from_args(
args.only_binary.combine(only_binary).unwrap_or_default(),
args.no_build.combine(no_build).unwrap_or_default(),
),
config_setting: args
.config_settings
.combine(config_settings)
@ -1392,20 +1498,21 @@ impl PipSettings {
.unwrap_or_default(),
target: args.target.combine(target).map(Target::from),
prefix: args.prefix.combine(prefix).map(Prefix::from),
no_binary: NoBinary::from_args(args.no_binary.combine(no_binary).unwrap_or_default()),
compile_bytecode: args
.compile_bytecode
.combine(compile_bytecode)
.unwrap_or_default(),
strict: args.strict.combine(strict).unwrap_or_default(),
upgrade: Upgrade::from_args(
args.upgrade.or(upgrade),
args.upgrade_package.or(upgrade_package).unwrap_or_default(),
args.upgrade.combine(upgrade),
args.upgrade_package
.combine(upgrade_package)
.unwrap_or_default(),
),
reinstall: Reinstall::from_args(
args.reinstall.or(reinstall),
args.reinstall.combine(reinstall),
args.reinstall_package
.or(reinstall_package)
.combine(reinstall_package)
.unwrap_or_default(),
),
concurrency: Concurrency {
@ -1425,6 +1532,21 @@ impl PipSettings {
.map(NonZeroUsize::get)
.unwrap_or_else(Concurrency::threads),
},
build_options: BuildOptions::new(
NoBinary::from_pip_args(args.no_binary.combine(no_binary).unwrap_or_default())
.combine(NoBinary::from_args(
top_level_no_binary,
top_level_no_binary_package.unwrap_or_default(),
)),
NoBuild::from_pip_args(
args.only_binary.combine(only_binary).unwrap_or_default(),
args.no_build.combine(no_build).unwrap_or_default(),
)
.combine(NoBuild::from_args(
top_level_no_build,
top_level_no_build_package.unwrap_or_default(),
)),
),
}
}
}
@ -1507,15 +1629,6 @@ impl From<ResolverArgs> for PipOptions {
} = args;
Self {
index_url: index_args.index_url.and_then(Maybe::into_option),
extra_index_url: index_args.extra_index_url.map(|extra_index_urls| {
extra_index_urls
.into_iter()
.filter_map(Maybe::into_option)
.collect()
}),
no_index: Some(index_args.no_index),
find_links: index_args.find_links,
upgrade: flag(upgrade, no_upgrade),
upgrade_package: Some(upgrade_package),
index_strategy,
@ -1530,7 +1643,7 @@ impl From<ResolverArgs> for PipOptions {
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
exclude_newer,
link_mode,
..PipOptions::default()
..PipOptions::from(index_args)
}
}
}
@ -1551,15 +1664,6 @@ impl From<InstallerArgs> for PipOptions {
} = args;
Self {
index_url: index_args.index_url.and_then(Maybe::into_option),
extra_index_url: index_args.extra_index_url.map(|extra_index_urls| {
extra_index_urls
.into_iter()
.filter_map(Maybe::into_option)
.collect()
}),
no_index: Some(index_args.no_index),
find_links: index_args.find_links,
reinstall: flag(reinstall, no_reinstall),
reinstall_package: Some(reinstall_package),
index_strategy,
@ -1568,7 +1672,7 @@ impl From<InstallerArgs> for PipOptions {
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
link_mode,
compile_bytecode: flag(compile_bytecode, no_compile_bytecode),
..PipOptions::default()
..PipOptions::from(index_args)
}
}
}
@ -1596,151 +1700,6 @@ impl From<ResolverInstallerArgs> for PipOptions {
} = args;
Self {
index_url: index_args.index_url.and_then(Maybe::into_option),
extra_index_url: index_args.extra_index_url.map(|extra_index_urls| {
extra_index_urls
.into_iter()
.filter_map(Maybe::into_option)
.collect()
}),
no_index: Some(index_args.no_index),
find_links: index_args.find_links,
upgrade: flag(upgrade, no_upgrade),
upgrade_package: Some(upgrade_package),
reinstall: flag(reinstall, no_reinstall),
reinstall_package: Some(reinstall_package),
index_strategy,
keyring_provider,
resolution,
prerelease: if pre {
Some(PreReleaseMode::Allow)
} else {
prerelease
},
config_settings: config_setting
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
exclude_newer,
link_mode,
compile_bytecode: flag(compile_bytecode, no_compile_bytecode),
..PipOptions::default()
}
}
}
impl From<InstallerArgs> for InstallerOptions {
fn from(args: InstallerArgs) -> Self {
let InstallerArgs {
index_args,
reinstall,
no_reinstall,
reinstall_package,
index_strategy,
keyring_provider,
config_setting,
link_mode,
compile_bytecode,
no_compile_bytecode,
} = args;
Self {
index_url: index_args.index_url.and_then(Maybe::into_option),
extra_index_url: index_args.extra_index_url.map(|extra_index_urls| {
extra_index_urls
.into_iter()
.filter_map(Maybe::into_option)
.collect()
}),
no_index: Some(index_args.no_index),
find_links: index_args.find_links,
reinstall: flag(reinstall, no_reinstall),
reinstall_package: Some(reinstall_package),
index_strategy,
keyring_provider,
config_settings: config_setting
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
link_mode,
compile_bytecode: flag(compile_bytecode, no_compile_bytecode),
}
}
}
impl From<ResolverArgs> for ResolverOptions {
fn from(args: ResolverArgs) -> Self {
let ResolverArgs {
index_args,
upgrade,
no_upgrade,
upgrade_package,
index_strategy,
keyring_provider,
resolution,
prerelease,
pre,
config_setting,
exclude_newer,
link_mode,
} = args;
Self {
index_url: index_args.index_url.and_then(Maybe::into_option),
extra_index_url: index_args.extra_index_url.map(|extra_index_urls| {
extra_index_urls
.into_iter()
.filter_map(Maybe::into_option)
.collect()
}),
no_index: Some(index_args.no_index),
find_links: index_args.find_links,
upgrade: flag(upgrade, no_upgrade),
upgrade_package: Some(upgrade_package),
index_strategy,
keyring_provider,
resolution,
prerelease: if pre {
Some(PreReleaseMode::Allow)
} else {
prerelease
},
config_settings: config_setting
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
exclude_newer,
link_mode,
}
}
}
impl From<ResolverInstallerArgs> for ResolverInstallerOptions {
fn from(args: ResolverInstallerArgs) -> Self {
let ResolverInstallerArgs {
index_args,
upgrade,
no_upgrade,
upgrade_package,
reinstall,
no_reinstall,
reinstall_package,
index_strategy,
keyring_provider,
resolution,
prerelease,
pre,
config_setting,
exclude_newer,
link_mode,
compile_bytecode,
no_compile_bytecode,
} = args;
Self {
index_url: index_args.index_url.and_then(Maybe::into_option),
extra_index_url: index_args.extra_index_url.map(|extra_index_urls| {
extra_index_urls
.into_iter()
.filter_map(Maybe::into_option)
.collect()
}),
no_index: Some(index_args.no_index),
find_links: index_args.find_links,
upgrade: flag(upgrade, no_upgrade),
upgrade_package: Some(upgrade_package),
reinstall: flag(reinstall, no_reinstall),
@ -1758,6 +1717,7 @@ impl From<ResolverInstallerArgs> for ResolverInstallerOptions {
exclude_newer,
link_mode,
compile_bytecode: flag(compile_bytecode, no_compile_bytecode),
..PipOptions::from(index_args)
}
}
}
@ -1779,9 +1739,195 @@ impl From<IndexArgs> for PipOptions {
.filter_map(Maybe::into_option)
.collect()
}),
no_index: Some(no_index),
no_index: if no_index { Some(true) } else { None },
find_links,
..PipOptions::default()
}
}
}
/// Construct the [`InstallerOptions`] from the [`InstallerArgs`] and [`BuildArgs`].
fn installer_options(installer_args: InstallerArgs, build_args: BuildArgs) -> InstallerOptions {
let InstallerArgs {
index_args,
reinstall,
no_reinstall,
reinstall_package,
index_strategy,
keyring_provider,
config_setting,
link_mode,
compile_bytecode,
no_compile_bytecode,
} = installer_args;
let BuildArgs {
no_build,
build,
no_build_package,
no_binary,
binary,
no_binary_package,
} = build_args;
InstallerOptions {
index_url: index_args.index_url.and_then(Maybe::into_option),
extra_index_url: index_args.extra_index_url.map(|extra_index_urls| {
extra_index_urls
.into_iter()
.filter_map(Maybe::into_option)
.collect()
}),
no_index: if index_args.no_index {
Some(true)
} else {
None
},
find_links: index_args.find_links,
reinstall: flag(reinstall, no_reinstall),
reinstall_package: Some(reinstall_package),
index_strategy,
keyring_provider,
config_settings: config_setting
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
link_mode,
compile_bytecode: flag(compile_bytecode, no_compile_bytecode),
no_build: flag(no_build, build),
no_build_package: Some(no_build_package),
no_binary: flag(no_binary, binary),
no_binary_package: Some(no_binary_package),
}
}
/// Construct the [`ResolverOptions`] from the [`ResolverArgs`] and [`BuildArgs`].
fn resolver_options(resolver_args: ResolverArgs, build_args: BuildArgs) -> ResolverOptions {
let ResolverArgs {
index_args,
upgrade,
no_upgrade,
upgrade_package,
index_strategy,
keyring_provider,
resolution,
prerelease,
pre,
config_setting,
exclude_newer,
link_mode,
} = resolver_args;
let BuildArgs {
no_build,
build,
no_build_package,
no_binary,
binary,
no_binary_package,
} = build_args;
ResolverOptions {
index_url: index_args.index_url.and_then(Maybe::into_option),
extra_index_url: index_args.extra_index_url.map(|extra_index_urls| {
extra_index_urls
.into_iter()
.filter_map(Maybe::into_option)
.collect()
}),
no_index: if index_args.no_index {
Some(true)
} else {
None
},
find_links: index_args.find_links,
upgrade: flag(upgrade, no_upgrade),
upgrade_package: Some(upgrade_package),
index_strategy,
keyring_provider,
resolution,
prerelease: if pre {
Some(PreReleaseMode::Allow)
} else {
prerelease
},
config_settings: config_setting
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
exclude_newer,
link_mode,
no_build: flag(no_build, build),
no_build_package: Some(no_build_package),
no_binary: flag(no_binary, binary),
no_binary_package: Some(no_binary_package),
}
}
/// Construct the [`ResolverInstallerOptions`] from the [`ResolverInstallerArgs`] and [`BuildArgs`].
fn resolver_installer_options(
resolver_installer_args: ResolverInstallerArgs,
build_args: BuildArgs,
) -> ResolverInstallerOptions {
let ResolverInstallerArgs {
index_args,
upgrade,
no_upgrade,
upgrade_package,
reinstall,
no_reinstall,
reinstall_package,
index_strategy,
keyring_provider,
resolution,
prerelease,
pre,
config_setting,
exclude_newer,
link_mode,
compile_bytecode,
no_compile_bytecode,
} = resolver_installer_args;
let BuildArgs {
no_build,
build,
no_build_package,
no_binary,
binary,
no_binary_package,
} = build_args;
ResolverInstallerOptions {
index_url: index_args.index_url.and_then(Maybe::into_option),
extra_index_url: index_args.extra_index_url.map(|extra_index_urls| {
extra_index_urls
.into_iter()
.filter_map(Maybe::into_option)
.collect()
}),
no_index: if index_args.no_index {
Some(true)
} else {
None
},
find_links: index_args.find_links,
upgrade: flag(upgrade, no_upgrade),
upgrade_package: Some(upgrade_package),
reinstall: flag(reinstall, no_reinstall),
reinstall_package: Some(reinstall_package),
index_strategy,
keyring_provider,
resolution,
prerelease: if pre {
Some(PreReleaseMode::Allow)
} else {
prerelease
},
config_settings: config_setting
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
exclude_newer,
link_mode,
compile_bytecode: flag(compile_bytecode, no_compile_bytecode),
no_build: flag(no_build, build),
no_build_package: Some(no_build_package),
no_binary: flag(no_binary, binary),
no_binary_package: Some(no_binary_package),
}
}

View file

@ -117,9 +117,11 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
prefix: None,
index_strategy: FirstIndex,
keyring_provider: Disabled,
no_build_isolation: false,
build_options: BuildOptions {
no_binary: None,
no_build: None,
no_build_isolation: false,
},
strict: false,
dependency_mode: Transitive,
resolution: LowestDirect,
@ -241,9 +243,11 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
prefix: None,
index_strategy: FirstIndex,
keyring_provider: Disabled,
no_build_isolation: false,
build_options: BuildOptions {
no_binary: None,
no_build: None,
no_build_isolation: false,
},
strict: false,
dependency_mode: Transitive,
resolution: Highest,
@ -366,9 +370,11 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
prefix: None,
index_strategy: FirstIndex,
keyring_provider: Disabled,
no_build_isolation: false,
build_options: BuildOptions {
no_binary: None,
no_build: None,
no_build_isolation: false,
},
strict: false,
dependency_mode: Transitive,
resolution: Highest,
@ -523,9 +529,11 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
prefix: None,
index_strategy: FirstIndex,
keyring_provider: Disabled,
no_build_isolation: false,
build_options: BuildOptions {
no_binary: None,
no_build: None,
no_build_isolation: false,
},
strict: false,
dependency_mode: Transitive,
resolution: LowestDirect,
@ -626,9 +634,11 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
prefix: None,
index_strategy: FirstIndex,
keyring_provider: Disabled,
no_build_isolation: false,
build_options: BuildOptions {
no_binary: None,
no_build: None,
no_build_isolation: false,
},
strict: false,
dependency_mode: Transitive,
resolution: Highest,
@ -761,9 +771,11 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
prefix: None,
index_strategy: FirstIndex,
keyring_provider: Disabled,
no_build_isolation: false,
build_options: BuildOptions {
no_binary: None,
no_build: None,
no_build_isolation: false,
},
strict: false,
dependency_mode: Transitive,
resolution: LowestDirect,
@ -933,9 +945,11 @@ fn resolve_index_url() -> anyhow::Result<()> {
prefix: None,
index_strategy: FirstIndex,
keyring_provider: Disabled,
no_build_isolation: false,
build_options: BuildOptions {
no_binary: None,
no_build: None,
no_build_isolation: false,
},
strict: false,
dependency_mode: Transitive,
resolution: Highest,
@ -1104,9 +1118,11 @@ fn resolve_index_url() -> anyhow::Result<()> {
prefix: None,
index_strategy: FirstIndex,
keyring_provider: Disabled,
no_build_isolation: false,
build_options: BuildOptions {
no_binary: None,
no_build: None,
no_build_isolation: false,
},
strict: false,
dependency_mode: Transitive,
resolution: Highest,
@ -1238,7 +1254,7 @@ fn resolve_find_links() -> anyhow::Result<()> {
},
),
],
no_index: false,
no_index: true,
},
python: None,
system: false,
@ -1248,9 +1264,11 @@ fn resolve_find_links() -> anyhow::Result<()> {
prefix: None,
index_strategy: FirstIndex,
keyring_provider: Disabled,
no_build_isolation: false,
build_options: BuildOptions {
no_binary: None,
no_build: None,
no_build_isolation: false,
},
strict: false,
dependency_mode: Transitive,
resolution: Highest,
@ -1373,9 +1391,11 @@ fn resolve_top_level() -> anyhow::Result<()> {
prefix: None,
index_strategy: FirstIndex,
keyring_provider: Disabled,
no_build_isolation: false,
build_options: BuildOptions {
no_binary: None,
no_build: None,
no_build_isolation: false,
},
strict: false,
dependency_mode: Transitive,
resolution: LowestDirect,
@ -1421,7 +1441,7 @@ fn resolve_top_level() -> anyhow::Result<()> {
);
// Write out to both the top-level (`tool.uv`) and the pip section (`tool.uv.pip`). The
// `tool.uv.pip` section should take precedence.
// `tool.uv.pip` section should take precedence when combining.
pyproject.write_str(indoc::indoc! {r#"
[project]
name = "example"
@ -1429,9 +1449,11 @@ fn resolve_top_level() -> anyhow::Result<()> {
[tool.uv]
resolution = "lowest-direct"
extra-index-url = ["https://test.pypi.org/simple"]
[tool.uv.pip]
resolution = "highest"
extra-index-url = ["https://download.pytorch.org/whl"]
"#})?;
let requirements_in = context.temp_dir.child("requirements.in");
@ -1477,7 +1499,52 @@ fn resolve_top_level() -> anyhow::Result<()> {
settings: PipSettings {
index_locations: IndexLocations {
index: None,
extra_index: [],
extra_index: [
Url(
VerbatimUrl {
url: Url {
scheme: "https",
cannot_be_a_base: false,
username: "",
password: None,
host: Some(
Domain(
"download.pytorch.org",
),
),
port: None,
path: "/whl",
query: None,
fragment: None,
},
given: Some(
"https://download.pytorch.org/whl",
),
},
),
Url(
VerbatimUrl {
url: Url {
scheme: "https",
cannot_be_a_base: false,
username: "",
password: None,
host: Some(
Domain(
"test.pypi.org",
),
),
port: None,
path: "/simple",
query: None,
fragment: None,
},
given: Some(
"https://test.pypi.org/simple",
),
},
),
],
flat_index: [],
no_index: false,
},
@ -1489,9 +1556,11 @@ fn resolve_top_level() -> anyhow::Result<()> {
prefix: None,
index_strategy: FirstIndex,
keyring_provider: Disabled,
no_build_isolation: false,
build_options: BuildOptions {
no_binary: None,
no_build: None,
no_build_isolation: false,
},
strict: false,
dependency_mode: Transitive,
resolution: Highest,
@ -1578,7 +1647,52 @@ fn resolve_top_level() -> anyhow::Result<()> {
settings: PipSettings {
index_locations: IndexLocations {
index: None,
extra_index: [],
extra_index: [
Url(
VerbatimUrl {
url: Url {
scheme: "https",
cannot_be_a_base: false,
username: "",
password: None,
host: Some(
Domain(
"download.pytorch.org",
),
),
port: None,
path: "/whl",
query: None,
fragment: None,
},
given: Some(
"https://download.pytorch.org/whl",
),
},
),
Url(
VerbatimUrl {
url: Url {
scheme: "https",
cannot_be_a_base: false,
username: "",
password: None,
host: Some(
Domain(
"test.pypi.org",
),
),
port: None,
path: "/simple",
query: None,
fragment: None,
},
given: Some(
"https://test.pypi.org/simple",
),
},
),
],
flat_index: [],
no_index: false,
},
@ -1590,9 +1704,11 @@ fn resolve_top_level() -> anyhow::Result<()> {
prefix: None,
index_strategy: FirstIndex,
keyring_provider: Disabled,
no_build_isolation: false,
build_options: BuildOptions {
no_binary: None,
no_build: None,
no_build_isolation: false,
},
strict: false,
dependency_mode: Transitive,
resolution: LowestDirect,
@ -1715,9 +1831,11 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
prefix: None,
index_strategy: FirstIndex,
keyring_provider: Disabled,
no_build_isolation: false,
build_options: BuildOptions {
no_binary: None,
no_build: None,
no_build_isolation: false,
},
strict: false,
dependency_mode: Transitive,
resolution: LowestDirect,
@ -1823,9 +1941,11 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
prefix: None,
index_strategy: FirstIndex,
keyring_provider: Disabled,
no_build_isolation: false,
build_options: BuildOptions {
no_binary: None,
no_build: None,
no_build_isolation: false,
},
strict: false,
dependency_mode: Transitive,
resolution: LowestDirect,
@ -1931,9 +2051,11 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
prefix: None,
index_strategy: FirstIndex,
keyring_provider: Disabled,
no_build_isolation: false,
build_options: BuildOptions {
no_binary: None,
no_build: None,
no_build_isolation: false,
},
strict: false,
dependency_mode: Transitive,
resolution: Highest,
@ -2041,9 +2163,11 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
prefix: None,
index_strategy: FirstIndex,
keyring_provider: Disabled,
no_build_isolation: false,
build_options: BuildOptions {
no_binary: None,
no_build: None,
no_build_isolation: false,
},
strict: false,
dependency_mode: Transitive,
resolution: LowestDirect,

30
uv.schema.json generated
View file

@ -110,6 +110,36 @@
"null"
]
},
"no-binary": {
"type": [
"boolean",
"null"
]
},
"no-binary-package": {
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/PackageName"
}
},
"no-build": {
"type": [
"boolean",
"null"
]
},
"no-build-package": {
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/PackageName"
}
},
"no-cache": {
"type": [
"boolean",