From e413ac4ce6438ec8a2e613a4d395087017b2b1c5 Mon Sep 17 00:00:00 2001 From: Aria Desires Date: Mon, 16 Jun 2025 17:26:34 -0400 Subject: [PATCH 1/2] WIP extra-build-dependencies --- crates/uv-bench/benches/uv.rs | 4 +- crates/uv-build-frontend/src/lib.rs | 47 ++++++++--- crates/uv-cli/src/options.rs | 2 + crates/uv-dispatch/src/lib.rs | 5 ++ crates/uv-settings/src/combine.rs | 17 +++- crates/uv-settings/src/settings.rs | 38 ++++++++- crates/uv-workspace/src/pyproject.rs | 79 ++++++++++++++++++ crates/uv/src/commands/build_frontend.rs | 5 ++ crates/uv/src/commands/pip/compile.rs | 3 + crates/uv/src/commands/pip/install.rs | 3 + crates/uv/src/commands/pip/sync.rs | 3 + crates/uv/src/commands/project/add.rs | 1 + crates/uv/src/commands/project/lock.rs | 2 + crates/uv/src/commands/project/mod.rs | 8 ++ crates/uv/src/commands/project/sync.rs | 2 + crates/uv/src/commands/project/tree.rs | 1 + crates/uv/src/commands/venv.rs | 4 +- crates/uv/src/lib.rs | 3 + crates/uv/src/settings.rs | 16 +++- crates/uv/tests/it/sync.rs | 100 +++++++++++++++++++++++ docs/reference/settings.md | 84 +++++++++++++++++++ uv.schema.json | 33 ++++++++ 22 files changed, 444 insertions(+), 16 deletions(-) diff --git a/crates/uv-bench/benches/uv.rs b/crates/uv-bench/benches/uv.rs index 9bdd7adb9..4294f9671 100644 --- a/crates/uv-bench/benches/uv.rs +++ b/crates/uv-bench/benches/uv.rs @@ -103,7 +103,7 @@ mod resolver { ResolverEnvironment, ResolverOutput, }; use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy}; - use uv_workspace::WorkspaceCache; + use uv_workspace::{WorkspaceCache, pyproject::ExtraBuildDependencies}; static MARKERS: LazyLock = LazyLock::new(|| { MarkerEnvironment::try_from(MarkerEnvironmentBuilder { @@ -141,6 +141,7 @@ mod resolver { universal: bool, ) -> Result { let build_isolation = BuildIsolation::default(); + let extra_build_dependencies = ExtraBuildDependencies::default(); let build_options = BuildOptions::default(); let concurrency = Concurrency::default(); let config_settings = ConfigSettings::default(); @@ -185,6 +186,7 @@ mod resolver { IndexStrategy::default(), &config_settings, build_isolation, + &extra_build_dependencies, LinkMode::default(), &build_options, &hashes, diff --git a/crates/uv-build-frontend/src/lib.rs b/crates/uv-build-frontend/src/lib.rs index 1c29b2c31..da1921c5c 100644 --- a/crates/uv-build-frontend/src/lib.rs +++ b/crates/uv-build-frontend/src/lib.rs @@ -39,6 +39,7 @@ use uv_static::EnvVars; use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, BuildStack, SourceBuildTrait}; use uv_warnings::warn_user_once; use uv_workspace::WorkspaceCache; +use uv_workspace::pyproject::ExtraBuildDependencies; pub use crate::error::{Error, MissingHeaderCause}; @@ -273,6 +274,7 @@ impl SourceBuild { workspace_cache: &WorkspaceCache, config_settings: ConfigSettings, build_isolation: BuildIsolation<'_>, + extra_build_dependencies: &ExtraBuildDependencies, build_stack: &BuildStack, build_kind: BuildKind, mut environment_variables: FxHashMap, @@ -288,7 +290,6 @@ impl SourceBuild { }; let default_backend: Pep517Backend = DEFAULT_BACKEND.clone(); - // Check if we have a PEP 517 build backend. let (pep517_backend, project) = Self::extract_pep517_backend( &source_tree, @@ -296,6 +297,7 @@ impl SourceBuild { fallback_package_name, locations, source_strategy, + extra_build_dependencies, workspace_cache, &default_backend, ) @@ -470,6 +472,7 @@ impl SourceBuild { package_name: Option<&PackageName>, locations: &IndexLocations, source_strategy: SourceStrategy, + extra_build_dependencies: &ExtraBuildDependencies, workspace_cache: &WorkspaceCache, default_backend: &Pep517Backend, ) -> Result<(Pep517Backend, Option), Box> { @@ -481,17 +484,24 @@ impl SourceBuild { let pyproject_toml: PyProjectToml = PyProjectToml::deserialize(pyproject_toml.into_deserializer()) .map_err(Error::InvalidPyprojectTomlSchema)?; + let name = pyproject_toml + .project + .as_ref() + .map(|project| &project.name) + .or(package_name); + let extra_build_dependencies = name + .as_ref() + .and_then(|name| extra_build_dependencies.get(name).cloned()) + .unwrap_or_default(); + + let backend = if let Some(mut build_system) = pyproject_toml.build_system { + // Apply extra-build-dependencies if there are any + build_system.requires.extend(extra_build_dependencies); - let backend = if let Some(build_system) = pyproject_toml.build_system { // If necessary, lower the requirements. let requirements = match source_strategy { SourceStrategy::Enabled => { - if let Some(name) = pyproject_toml - .project - .as_ref() - .map(|project| &project.name) - .or(package_name) - { + if let Some(name) = name { let build_requires = uv_pypi_types::BuildRequires { name: Some(name.clone()), requires_dist: build_system.requires, @@ -570,7 +580,13 @@ impl SourceBuild { ); } } - default_backend.clone() + let mut backend = default_backend.clone(); + // Apply extra_build_dependencies + // TODO(Gankra): should Sources/Indexes be applied on this path? + backend + .requirements + .extend(extra_build_dependencies.into_iter().map(Requirement::from)); + backend }; Ok((backend, pyproject_toml.project)) } @@ -581,12 +597,21 @@ impl SourceBuild { source_tree.to_path_buf(), ))); } - // If no `pyproject.toml` is present, by default, proceed with a PEP 517 build using // the default backend, to match `build`. `pip` uses `setup.py` directly in this // case, but plans to make PEP 517 builds the default in the future. // See: https://github.com/pypa/pip/issues/9175. - Ok((default_backend.clone(), None)) + let mut backend = default_backend.clone(); + // Apply extra_build_dependencies + // TODO(Gankra): should Sources/Indexes be applied on this path? + let extra_build_dependencies = package_name + .as_ref() + .and_then(|name| extra_build_dependencies.get(name).cloned()) + .unwrap_or_default(); + backend + .requirements + .extend(extra_build_dependencies.into_iter().map(Requirement::from)); + Ok((backend, None)) } Err(err) => Err(Box::new(err.into())), } diff --git a/crates/uv-cli/src/options.rs b/crates/uv-cli/src/options.rs index 656edd43c..3c3dd8ada 100644 --- a/crates/uv-cli/src/options.rs +++ b/crates/uv-cli/src/options.rs @@ -305,6 +305,7 @@ pub fn resolver_options( .map(|config_settings| config_settings.into_iter().collect::()), no_build_isolation: flag(no_build_isolation, build_isolation), no_build_isolation_package: Some(no_build_isolation_package), + extra_build_dependencies: None, exclude_newer, link_mode, no_build: flag(no_build, build), @@ -416,6 +417,7 @@ pub fn resolver_installer_options( } else { Some(no_build_isolation_package) }, + extra_build_dependencies: None, exclude_newer, link_mode, compile_bytecode: flag(compile_bytecode, no_compile_bytecode), diff --git a/crates/uv-dispatch/src/lib.rs b/crates/uv-dispatch/src/lib.rs index 3b0ad5555..a8d9f63d1 100644 --- a/crates/uv-dispatch/src/lib.rs +++ b/crates/uv-dispatch/src/lib.rs @@ -39,6 +39,7 @@ use uv_types::{ InFlight, }; use uv_workspace::WorkspaceCache; +use uv_workspace::pyproject::ExtraBuildDependencies; #[derive(Debug, Error)] pub enum BuildDispatchError { @@ -87,6 +88,7 @@ pub struct BuildDispatch<'a> { shared_state: SharedState, dependency_metadata: &'a DependencyMetadata, build_isolation: BuildIsolation<'a>, + extra_build_dependencies: &'a ExtraBuildDependencies, link_mode: uv_install_wheel::LinkMode, build_options: &'a BuildOptions, config_settings: &'a ConfigSettings, @@ -113,6 +115,7 @@ impl<'a> BuildDispatch<'a> { index_strategy: IndexStrategy, config_settings: &'a ConfigSettings, build_isolation: BuildIsolation<'a>, + extra_build_dependencies: &'a ExtraBuildDependencies, link_mode: uv_install_wheel::LinkMode, build_options: &'a BuildOptions, hasher: &'a HashStrategy, @@ -134,6 +137,7 @@ impl<'a> BuildDispatch<'a> { index_strategy, config_settings, build_isolation, + extra_build_dependencies, link_mode, build_options, hasher, @@ -428,6 +432,7 @@ impl BuildContext for BuildDispatch<'_> { self.workspace_cache(), self.config_settings.clone(), self.build_isolation, + self.extra_build_dependencies, &build_stack, build_kind, self.build_extra_env_vars.clone(), diff --git a/crates/uv-settings/src/combine.rs b/crates/uv-settings/src/combine.rs index 8edbd2a05..9c02b8d07 100644 --- a/crates/uv-settings/src/combine.rs +++ b/crates/uv-settings/src/combine.rs @@ -1,5 +1,5 @@ -use std::num::NonZeroUsize; use std::path::PathBuf; +use std::{collections::BTreeMap, num::NonZeroUsize}; use url::Url; @@ -120,6 +120,21 @@ impl Combine for Option> { } } +impl Combine for Option>> { + /// Combine two maps of vecs by combining their vecs + fn combine(self, other: Option>>) -> Option>> { + match (self, other) { + (Some(mut a), Some(b)) => { + for (key, value) in b { + a.entry(key).or_default().extend(value); + } + Some(a) + } + (a, b) => a.or(b), + } + } +} + impl Combine for Option { /// Combine two maps by merging the map in `self` with the map in `other`, if they're both /// `Some`. diff --git a/crates/uv-settings/src/settings.rs b/crates/uv-settings/src/settings.rs index 2c18fb40a..0bed48f74 100644 --- a/crates/uv-settings/src/settings.rs +++ b/crates/uv-settings/src/settings.rs @@ -20,7 +20,7 @@ use uv_redacted::DisplaySafeUrl; use uv_resolver::{AnnotationStyle, ExcludeNewer, ForkStrategy, PrereleaseMode, ResolutionMode}; use uv_static::EnvVars; use uv_torch::TorchMode; -use uv_workspace::pyproject_mut::AddBoundsKind; +use uv_workspace::{pyproject::ExtraBuildDependencies, pyproject_mut::AddBoundsKind}; /// A `pyproject.toml` with an (optional) `[tool.uv]` section. #[allow(dead_code)] @@ -370,6 +370,7 @@ pub struct ResolverOptions { pub no_binary_package: Option>, pub no_build_isolation: Option, pub no_build_isolation_package: Option>, + pub extra_build_dependencies: Option, pub no_sources: Option, } @@ -610,6 +611,20 @@ pub struct ResolverInstallerOptions { "# )] pub no_build_isolation_package: Option>, + /// Additional build dependencies for dependencies. + /// + /// This is intended for enabling more packages to be built with + /// build-isolation, by adding dependencies that they ambiently + /// assume to exist (`setuptools` and `pip` being common). + #[option( + default = "[]", + value_type = "dict", + example = r#" + [extra-build-dependencies] + pytest = ["setuptools"] + "# + )] + pub extra_build_dependencies: Option, /// Limit candidate packages to those that were uploaded prior to a given point in time. /// /// Accepts a superset of [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339.html) (e.g., @@ -1106,6 +1121,20 @@ pub struct PipOptions { "# )] pub no_build_isolation_package: Option>, + /// Additional build dependencies for dependencies. + /// + /// This is intended for enabling more packages to be built with + /// build-isolation, by adding dependencies that they ambiently + /// assume to exist (`setuptools` and `pip` being common). + #[option( + default = "[]", + value_type = "dict", + example = r#" + [extra-build-dependencies] + pytest = ["setuptools"] + "# + )] + pub extra_build_dependencies: Option, /// Validate the Python environment, to detect packages with missing dependencies and other /// issues. #[option( @@ -1660,6 +1689,7 @@ impl From for ResolverOptions { no_binary_package: value.no_binary_package, no_build_isolation: value.no_build_isolation, no_build_isolation_package: value.no_build_isolation_package, + extra_build_dependencies: value.extra_build_dependencies, no_sources: value.no_sources, } } @@ -1715,6 +1745,7 @@ pub struct ToolOptions { pub config_settings: Option, pub no_build_isolation: Option, pub no_build_isolation_package: Option>, + pub extra_build_dependencies: Option, pub exclude_newer: Option, pub link_mode: Option, pub compile_bytecode: Option, @@ -1742,6 +1773,7 @@ impl From for ToolOptions { config_settings: value.config_settings, no_build_isolation: value.no_build_isolation, no_build_isolation_package: value.no_build_isolation_package, + extra_build_dependencies: value.extra_build_dependencies, exclude_newer: value.exclude_newer, link_mode: value.link_mode, compile_bytecode: value.compile_bytecode, @@ -1771,6 +1803,7 @@ impl From for ResolverInstallerOptions { config_settings: value.config_settings, no_build_isolation: value.no_build_isolation, no_build_isolation_package: value.no_build_isolation_package, + extra_build_dependencies: value.extra_build_dependencies, exclude_newer: value.exclude_newer, link_mode: value.link_mode, compile_bytecode: value.compile_bytecode, @@ -1823,6 +1856,7 @@ pub struct OptionsWire { config_settings: Option, no_build_isolation: Option, no_build_isolation_package: Option>, + extra_build_dependencies: Option, exclude_newer: Option, link_mode: Option, compile_bytecode: Option, @@ -1939,6 +1973,7 @@ impl From for Options { sources, default_groups, dependency_groups, + extra_build_dependencies, dev_dependencies, managed, package, @@ -1978,6 +2013,7 @@ impl From for Options { config_settings, no_build_isolation, no_build_isolation_package, + extra_build_dependencies, exclude_newer, link_mode, compile_bytecode, diff --git a/crates/uv-workspace/src/pyproject.rs b/crates/uv-workspace/src/pyproject.rs index 6499aad5d..25dbcaff4 100644 --- a/crates/uv-workspace/src/pyproject.rs +++ b/crates/uv-workspace/src/pyproject.rs @@ -371,6 +371,21 @@ pub struct ToolUv { )] pub dependency_groups: Option, + /// Additional build dependencies for dependencies. + /// + /// This is intended for enabling more packages to be built with + /// build-isolation, by adding dependencies that they ambiently + /// assume to exist (`setuptools` and `pip` being common). + #[option( + default = "[]", + value_type = "dict", + example = r#" + [tool.uv.extra-build-dependencies] + pytest = ["pip"] + "# + )] + pub extra_build_dependencies: Option, + /// The project's development dependencies. /// /// Development dependencies will be installed by default in `uv run` and `uv sync`, but will @@ -742,6 +757,70 @@ pub struct DependencyGroupSettings { pub requires_python: Option, } +pub type ExtraBuildDependencies = + BTreeMap>>; + +#[derive(Default, Debug, Clone, PartialEq, Eq)] +#[cfg_attr(test, derive(Serialize))] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +pub struct ToolUvExtraBuildDependencies(ExtraBuildDependencies); + +impl ToolUvExtraBuildDependencies { + /// Returns the underlying `BTreeMap` of group names to settings. + pub fn inner(&self) -> &ExtraBuildDependencies { + &self.0 + } + + /// Convert the [`ToolUvExtraBuildDependencies`] into its inner `BTreeMap`. + #[must_use] + pub fn into_inner(self) -> ExtraBuildDependencies { + self.0 + } +} + +/// Ensure that all keys in the TOML table are unique. +impl<'de> serde::de::Deserialize<'de> for ToolUvExtraBuildDependencies { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct DependenciesVisitor; + + impl<'de> serde::de::Visitor<'de> for DependenciesVisitor { + type Value = ToolUvExtraBuildDependencies; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a map with unique keys") + } + + fn visit_map(self, mut access: M) -> Result + where + M: serde::de::MapAccess<'de>, + { + let mut groups = BTreeMap::new(); + while let Some((key, value)) = access + .next_entry::>>()? + { + match groups.entry(key) { + std::collections::btree_map::Entry::Occupied(entry) => { + return Err(serde::de::Error::custom(format!( + "duplicate extra-build-dependencies for `{}`", + entry.key() + ))); + } + std::collections::btree_map::Entry::Vacant(entry) => { + entry.insert(value); + } + } + } + Ok(ToolUvExtraBuildDependencies(groups)) + } + } + + deserializer.deserialize_map(DependenciesVisitor) + } +} + #[derive(Deserialize, OptionsMetadata, Default, Debug, Clone, PartialEq, Eq)] #[cfg_attr(test, derive(Serialize))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] diff --git a/crates/uv/src/commands/build_frontend.rs b/crates/uv/src/commands/build_frontend.rs index dd174ca06..73662fe9c 100644 --- a/crates/uv/src/commands/build_frontend.rs +++ b/crates/uv/src/commands/build_frontend.rs @@ -39,6 +39,7 @@ use uv_requirements::RequirementsSource; use uv_resolver::{ExcludeNewer, FlatIndex}; use uv_settings::PythonInstallMirrors; use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, BuildStack, HashStrategy}; +use uv_workspace::pyproject::ExtraBuildDependencies; use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceCache, WorkspaceError}; use crate::commands::ExitStatus; @@ -209,6 +210,7 @@ async fn build_impl( config_setting, no_build_isolation, no_build_isolation_package, + extra_build_dependencies, exclude_newer, link_mode, upgrade: _, @@ -354,6 +356,7 @@ async fn build_impl( build_constraints, *no_build_isolation, no_build_isolation_package, + extra_build_dependencies, *index_strategy, *keyring_provider, *exclude_newer, @@ -431,6 +434,7 @@ async fn build_package( build_constraints: &[RequirementsSource], no_build_isolation: bool, no_build_isolation_package: &[PackageName], + extra_build_dependencies: &ExtraBuildDependencies, index_strategy: IndexStrategy, keyring_provider: KeyringProviderType, exclude_newer: Option, @@ -586,6 +590,7 @@ async fn build_package( index_strategy, config_setting, build_isolation, + extra_build_dependencies, link_mode, build_options, &hasher, diff --git a/crates/uv/src/commands/pip/compile.rs b/crates/uv/src/commands/pip/compile.rs index 20a60416f..aa5d8c9b3 100644 --- a/crates/uv/src/commands/pip/compile.rs +++ b/crates/uv/src/commands/pip/compile.rs @@ -45,6 +45,7 @@ use uv_torch::{TorchMode, TorchStrategy}; use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy}; use uv_warnings::warn_user; use uv_workspace::WorkspaceCache; +use uv_workspace::pyproject::ExtraBuildDependencies; use crate::commands::pip::loggers::DefaultResolveLogger; use crate::commands::pip::{operations, resolution_environment}; @@ -93,6 +94,7 @@ pub(crate) async fn pip_compile( config_settings: ConfigSettings, no_build_isolation: bool, no_build_isolation_package: Vec, + extra_build_dependencies: &ExtraBuildDependencies, build_options: BuildOptions, mut python_version: Option, python_platform: Option, @@ -478,6 +480,7 @@ pub(crate) async fn pip_compile( index_strategy, &config_settings, build_isolation, + extra_build_dependencies, link_mode, &build_options, &build_hashes, diff --git a/crates/uv/src/commands/pip/install.rs b/crates/uv/src/commands/pip/install.rs index 5fc9a66f4..67faa7387 100644 --- a/crates/uv/src/commands/pip/install.rs +++ b/crates/uv/src/commands/pip/install.rs @@ -39,6 +39,7 @@ use uv_torch::{TorchMode, TorchStrategy}; use uv_types::{BuildIsolation, HashStrategy}; use uv_warnings::warn_user; use uv_workspace::WorkspaceCache; +use uv_workspace::pyproject::ExtraBuildDependencies; use crate::commands::pip::loggers::{DefaultInstallLogger, DefaultResolveLogger, InstallLogger}; use crate::commands::pip::operations::Modifications; @@ -78,6 +79,7 @@ pub(crate) async fn pip_install( config_settings: &ConfigSettings, no_build_isolation: bool, no_build_isolation_package: Vec, + extra_build_dependencies: &ExtraBuildDependencies, build_options: BuildOptions, modifications: Modifications, python_version: Option, @@ -426,6 +428,7 @@ pub(crate) async fn pip_install( index_strategy, config_settings, build_isolation, + extra_build_dependencies, link_mode, &build_options, &build_hasher, diff --git a/crates/uv/src/commands/pip/sync.rs b/crates/uv/src/commands/pip/sync.rs index 35cef5907..44002d6c0 100644 --- a/crates/uv/src/commands/pip/sync.rs +++ b/crates/uv/src/commands/pip/sync.rs @@ -33,6 +33,7 @@ use uv_torch::{TorchMode, TorchStrategy}; use uv_types::{BuildIsolation, HashStrategy}; use uv_warnings::warn_user; use uv_workspace::WorkspaceCache; +use uv_workspace::pyproject::ExtraBuildDependencies; use crate::commands::pip::loggers::{DefaultInstallLogger, DefaultResolveLogger}; use crate::commands::pip::operations::Modifications; @@ -63,6 +64,7 @@ pub(crate) async fn pip_sync( config_settings: &ConfigSettings, no_build_isolation: bool, no_build_isolation_package: Vec, + extra_build_dependencies: &ExtraBuildDependencies, build_options: BuildOptions, python_version: Option, python_platform: Option, @@ -359,6 +361,7 @@ pub(crate) async fn pip_sync( index_strategy, config_settings, build_isolation, + extra_build_dependencies, link_mode, &build_options, &build_hasher, diff --git a/crates/uv/src/commands/project/add.rs b/crates/uv/src/commands/project/add.rs index 8e3c4a03a..e252374f5 100644 --- a/crates/uv/src/commands/project/add.rs +++ b/crates/uv/src/commands/project/add.rs @@ -433,6 +433,7 @@ pub(crate) async fn add( settings.resolver.index_strategy, &settings.resolver.config_setting, build_isolation, + &settings.resolver.extra_build_dependencies, settings.resolver.link_mode, &settings.resolver.build_options, &build_hasher, diff --git a/crates/uv/src/commands/project/lock.rs b/crates/uv/src/commands/project/lock.rs index b57df429b..9615e552c 100644 --- a/crates/uv/src/commands/project/lock.rs +++ b/crates/uv/src/commands/project/lock.rs @@ -416,6 +416,7 @@ async fn do_lock( config_setting, no_build_isolation, no_build_isolation_package, + extra_build_dependencies, exclude_newer, link_mode, upgrade, @@ -666,6 +667,7 @@ async fn do_lock( *index_strategy, config_setting, build_isolation, + extra_build_dependencies, *link_mode, build_options, &build_hasher, diff --git a/crates/uv/src/commands/project/mod.rs b/crates/uv/src/commands/project/mod.rs index 85defd4dd..758a8a0f1 100644 --- a/crates/uv/src/commands/project/mod.rs +++ b/crates/uv/src/commands/project/mod.rs @@ -1587,6 +1587,7 @@ pub(crate) async fn resolve_names( link_mode, no_build_isolation, no_build_isolation_package, + extra_build_dependencies, prerelease: _, resolution: _, sources, @@ -1654,6 +1655,7 @@ pub(crate) async fn resolve_names( *index_strategy, config_setting, build_isolation, + extra_build_dependencies, *link_mode, build_options, &build_hasher, @@ -1744,6 +1746,7 @@ pub(crate) async fn resolve_environment( config_setting, no_build_isolation, no_build_isolation_package, + extra_build_dependencies, exclude_newer, link_mode, upgrade: _, @@ -1868,6 +1871,7 @@ pub(crate) async fn resolve_environment( *index_strategy, config_setting, build_isolation, + extra_build_dependencies, *link_mode, build_options, &build_hasher, @@ -1934,6 +1938,7 @@ pub(crate) async fn sync_environment( config_setting, no_build_isolation, no_build_isolation_package, + extra_build_dependencies, exclude_newer, link_mode, compile_bytecode, @@ -2012,6 +2017,7 @@ pub(crate) async fn sync_environment( index_strategy, config_setting, build_isolation, + extra_build_dependencies, link_mode, build_options, &build_hasher, @@ -2105,6 +2111,7 @@ pub(crate) async fn update_environment( link_mode, no_build_isolation, no_build_isolation_package, + extra_build_dependencies, prerelease, resolution, sources, @@ -2241,6 +2248,7 @@ pub(crate) async fn update_environment( *index_strategy, config_setting, build_isolation, + extra_build_dependencies, *link_mode, build_options, &build_hasher, diff --git a/crates/uv/src/commands/project/sync.rs b/crates/uv/src/commands/project/sync.rs index 940b3a653..1d53dc7de 100644 --- a/crates/uv/src/commands/project/sync.rs +++ b/crates/uv/src/commands/project/sync.rs @@ -598,6 +598,7 @@ pub(super) async fn do_sync( config_setting, no_build_isolation, no_build_isolation_package, + extra_build_dependencies, exclude_newer, link_mode, compile_bytecode, @@ -741,6 +742,7 @@ pub(super) async fn do_sync( index_strategy, config_setting, build_isolation, + extra_build_dependencies, link_mode, build_options, &build_hasher, diff --git a/crates/uv/src/commands/project/tree.rs b/crates/uv/src/commands/project/tree.rs index 9c42a8a86..3cc0ff00b 100644 --- a/crates/uv/src/commands/project/tree.rs +++ b/crates/uv/src/commands/project/tree.rs @@ -199,6 +199,7 @@ pub(crate) async fn tree( config_setting: _, no_build_isolation: _, no_build_isolation_package: _, + extra_build_dependencies: _, exclude_newer: _, link_mode: _, upgrade: _, diff --git a/crates/uv/src/commands/venv.rs b/crates/uv/src/commands/venv.rs index a50c0e155..19e3cddee 100644 --- a/crates/uv/src/commands/venv.rs +++ b/crates/uv/src/commands/venv.rs @@ -30,6 +30,7 @@ use uv_settings::PythonInstallMirrors; use uv_shell::{Shell, shlex_posix, shlex_windows}; use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, BuildStack, HashStrategy}; use uv_warnings::warn_user; +use uv_workspace::pyproject::ExtraBuildDependencies; use uv_workspace::{DiscoveryOptions, VirtualProject, WorkspaceCache, WorkspaceError}; use crate::commands::ExitStatus; @@ -344,7 +345,7 @@ async fn venv_impl( // Do not allow builds let build_options = BuildOptions::new(NoBinary::None, NoBuild::All); - + let extra_build_dependencies = ExtraBuildDependencies::default(); // Prep the build context. let build_dispatch = BuildDispatch::new( &client, @@ -358,6 +359,7 @@ async fn venv_impl( index_strategy, &config_settings, BuildIsolation::Isolated, + &extra_build_dependencies, link_mode, &build_options, &build_hasher, diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs index 51041bcbc..4b44a13fe 100644 --- a/crates/uv/src/lib.rs +++ b/crates/uv/src/lib.rs @@ -519,6 +519,7 @@ async fn run(mut cli: Cli) -> Result { args.settings.config_setting, args.settings.no_build_isolation, args.settings.no_build_isolation_package, + &args.settings.extra_build_dependencies, args.settings.build_options, args.settings.python_version, args.settings.python_platform, @@ -589,6 +590,7 @@ async fn run(mut cli: Cli) -> Result { &args.settings.config_setting, args.settings.no_build_isolation, args.settings.no_build_isolation_package, + &args.settings.extra_build_dependencies, args.settings.build_options, args.settings.python_version, args.settings.python_platform, @@ -740,6 +742,7 @@ async fn run(mut cli: Cli) -> Result { &args.settings.config_setting, args.settings.no_build_isolation, args.settings.no_build_isolation_package, + &args.settings.extra_build_dependencies, args.settings.build_options, args.modifications, args.settings.python_version, diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index f8d44b50c..669b388b2 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -44,7 +44,7 @@ use uv_settings::{ use uv_static::EnvVars; use uv_torch::TorchMode; use uv_warnings::warn_user_once; -use uv_workspace::pyproject::DependencyType; +use uv_workspace::pyproject::{DependencyType, ExtraBuildDependencies}; use uv_workspace::pyproject_mut::AddBoundsKind; use crate::commands::ToolRunCommand; @@ -2600,6 +2600,7 @@ pub(crate) struct InstallerSettingsRef<'a> { pub(crate) config_setting: &'a ConfigSettings, pub(crate) no_build_isolation: bool, pub(crate) no_build_isolation_package: &'a [PackageName], + pub(crate) extra_build_dependencies: &'a ExtraBuildDependencies, pub(crate) exclude_newer: Option, pub(crate) link_mode: LinkMode, pub(crate) compile_bytecode: bool, @@ -2626,6 +2627,7 @@ pub(crate) struct ResolverSettings { pub(crate) link_mode: LinkMode, pub(crate) no_build_isolation: bool, pub(crate) no_build_isolation_package: Vec, + pub(crate) extra_build_dependencies: ExtraBuildDependencies, pub(crate) prerelease: PrereleaseMode, pub(crate) resolution: ResolutionMode, pub(crate) sources: SourceStrategy, @@ -2677,6 +2679,7 @@ impl From for ResolverSettings { config_setting: value.config_settings.unwrap_or_default(), no_build_isolation: value.no_build_isolation.unwrap_or_default(), no_build_isolation_package: value.no_build_isolation_package.unwrap_or_default(), + extra_build_dependencies: value.extra_build_dependencies.unwrap_or_default(), exclude_newer: value.exclude_newer, link_mode: value.link_mode.unwrap_or_default(), sources: SourceStrategy::from_args(value.no_sources.unwrap_or_default()), @@ -2766,6 +2769,7 @@ impl From for ResolverInstallerSettings { link_mode: value.link_mode.unwrap_or_default(), no_build_isolation: value.no_build_isolation.unwrap_or_default(), no_build_isolation_package: value.no_build_isolation_package.unwrap_or_default(), + extra_build_dependencies: value.extra_build_dependencies.unwrap_or_default(), prerelease: value.prerelease.unwrap_or_default(), resolution: value.resolution.unwrap_or_default(), sources: SourceStrategy::from_args(value.no_sources.unwrap_or_default()), @@ -2809,6 +2813,7 @@ pub(crate) struct PipSettings { pub(crate) torch_backend: Option, pub(crate) no_build_isolation: bool, pub(crate) no_build_isolation_package: Vec, + pub(crate) extra_build_dependencies: ExtraBuildDependencies, pub(crate) build_options: BuildOptions, pub(crate) allow_empty_requirements: bool, pub(crate) strict: bool, @@ -2875,6 +2880,7 @@ impl PipSettings { only_binary, no_build_isolation, no_build_isolation_package, + extra_build_dependencies, strict, extra, all_extras, @@ -2931,6 +2937,7 @@ impl PipSettings { config_settings: top_level_config_settings, no_build_isolation: top_level_no_build_isolation, no_build_isolation_package: top_level_no_build_isolation_package, + extra_build_dependencies: top_level_extra_build_dependencies, exclude_newer: top_level_exclude_newer, link_mode: top_level_link_mode, compile_bytecode: top_level_compile_bytecode, @@ -2964,6 +2971,8 @@ impl PipSettings { let no_build_isolation = no_build_isolation.combine(top_level_no_build_isolation); let no_build_isolation_package = no_build_isolation_package.combine(top_level_no_build_isolation_package); + let extra_build_dependencies = + extra_build_dependencies.combine(top_level_extra_build_dependencies); 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); @@ -3059,6 +3068,10 @@ impl PipSettings { .no_build_isolation_package .combine(no_build_isolation_package) .unwrap_or_default(), + extra_build_dependencies: args + .extra_build_dependencies + .combine(extra_build_dependencies) + .unwrap_or_default(), config_setting: args .config_settings .combine(config_settings) @@ -3158,6 +3171,7 @@ impl<'a> From<&'a ResolverInstallerSettings> for InstallerSettingsRef<'a> { config_setting: &settings.resolver.config_setting, no_build_isolation: settings.resolver.no_build_isolation, no_build_isolation_package: &settings.resolver.no_build_isolation_package, + extra_build_dependencies: &settings.resolver.extra_build_dependencies, exclude_newer: settings.resolver.exclude_newer, link_mode: settings.resolver.link_mode, compile_bytecode: settings.compile_bytecode, diff --git a/crates/uv/tests/it/sync.rs b/crates/uv/tests/it/sync.rs index 70d8a9118..d13aa33f3 100644 --- a/crates/uv/tests/it/sync.rs +++ b/crates/uv/tests/it/sync.rs @@ -1298,6 +1298,106 @@ fn sync_build_isolation_extra() -> Result<()> { Ok(()) } +/// Use dedicated extra groups to install dependencies for `--no-build-isolation-package`. +#[test] +fn sync_build_isolation_fail() -> Result<()> { + let context = TestContext::new("3.12").with_filtered_counts(); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str( + r#" + [project] + name = "myproject" + version = "0.1.0" + requires-python = ">=3.12" + dependencies = ["fasttext==0.9.2"] + + [build-system] + requires = ["setuptools >= 40.9.0"] + build-backend = "setuptools.build_meta" + "#, + )?; + let filters = std::iter::once((r"exit code: 1", "exit status: 1")) + .chain(context.filters()) + .collect::>(); + + // Running `uv sync` should fail due to missing build-dependencies + uv_snapshot!(&filters, context.sync(), @r#" + success: false + exit_code: 1 + ----- stdout ----- + + ----- stderr ----- + × Failed to build `fasttext==0.9.2` + ├─▶ The build backend returned an error + ╰─▶ Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1) + + [stderr] + [CACHE_DIR]/builds-v0/[TMP]/python: No module named pip + Traceback (most recent call last): + File "", line 38, in __init__ + ModuleNotFoundError: No module named 'pybind11' + + During handling of the above exception, another exception occurred: + + Traceback (most recent call last): + File "", line 14, in + File "[CACHE_DIR]/builds-v0/[TMP]/build_meta.py", line 325, in get_requires_for_build_wheel + return self._get_build_requires(config_settings, requirements=['wheel']) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "[CACHE_DIR]/builds-v0/[TMP]/build_meta.py", line 295, in _get_build_requires + self.run_setup() + File "[CACHE_DIR]/builds-v0/[TMP]/build_meta.py", line 487, in run_setup + super().run_setup(setup_script=setup_script) + File "[CACHE_DIR]/builds-v0/[TMP]/build_meta.py", line 311, in run_setup + exec(code, locals()) + File "", line 72, in + File "", line 41, in __init__ + RuntimeError: pybind11 install failed. + + hint: This usually indicates a problem with the package or the build environment. + help: `fasttext` (v0.9.2) was included because `myproject` (v0.1.0) depends on `fasttext==0.9.2` + "#); + + // Adding extra-build-dependencies should solve the issue + pyproject_toml.write_str( + r#" + [project] + name = "myproject" + version = "0.1.0" + requires-python = ">=3.12" + dependencies = ["fasttext==0.9.2"] + + [build-system] + requires = ["setuptools >= 40.9.0"] + build-backend = "setuptools.build_meta" + + [tool.uv.extra-build-dependencies] + fasttext = ["setuptools", "wheel", "pybind11"] + "#, + )?; + + uv_snapshot!(&filters, context.sync(), @r" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved [N] packages in [TIME] + Prepared [N] packages in [TIME] + Installed [N] packages in [TIME] + + fasttext==0.9.2 + + myproject==0.1.0 (from file://[TEMP_DIR]/) + + numpy==1.26.4 + + pybind11==2.11.1 + + setuptools==69.2.0 + "); + + // assert!(context.temp_dir.child("uv.lock").exists()); + + Ok(()) +} + /// Avoid using incompatible versions for build dependencies that are also part of the resolved /// environment. This is a very subtle issue, but: when locking, we don't enforce platform /// compatibility. So, if we reuse the resolver state to install, and the install itself has to diff --git a/docs/reference/settings.md b/docs/reference/settings.md index f681690f4..3567fbe0d 100644 --- a/docs/reference/settings.md +++ b/docs/reference/settings.md @@ -202,6 +202,28 @@ environments = ["sys_platform == 'darwin'"] --- +### [`extra-build-dependencies`](#extra-build-dependencies) {: #extra-build-dependencies } + +Additional build dependencies for dependencies. + +This is intended for enabling more packages to be built with +build-isolation, by adding dependencies that they ambiently +assume to exist (`setuptools` and `pip` being common). + +**Default value**: `[]` + +**Type**: `dict` + +**Example usage**: + +```toml title="pyproject.toml" + +[tool.uv.extra-build-dependencies] +pytest = ["pip"] +``` + +--- + ### [`index`](#index) {: #index } The indexes to use when resolving dependencies. @@ -1074,6 +1096,36 @@ behave consistently across timezones. --- +### [`extra-build-dependencies`](#extra-build-dependencies) {: #extra-build-dependencies } + +Additional build dependencies for dependencies. + +This is intended for enabling more packages to be built with +build-isolation, by adding dependencies that they ambiently +assume to exist (`setuptools` and `pip` being common). + +**Default value**: `[]` + +**Type**: `dict` + +**Example usage**: + +=== "pyproject.toml" + + ```toml + [tool.uv] + [extra-build-dependencies] + pytest = ["setuptools"] + ``` +=== "uv.toml" + + ```toml + [extra-build-dependencies] + pytest = ["setuptools"] + ``` + +--- + ### [`extra-index-url`](#extra-index-url) {: #extra-index-url } Extra URLs of package indexes to use, in addition to `--index-url`. @@ -2508,6 +2560,38 @@ Only applies to `pyproject.toml`, `setup.py`, and `setup.cfg` sources. --- +#### [`extra-build-dependencies`](#pip_extra-build-dependencies) {: #pip_extra-build-dependencies } + + +Additional build dependencies for dependencies. + +This is intended for enabling more packages to be built with +build-isolation, by adding dependencies that they ambiently +assume to exist (`setuptools` and `pip` being common). + +**Default value**: `[]` + +**Type**: `dict` + +**Example usage**: + +=== "pyproject.toml" + + ```toml + [tool.uv.pip] + [extra-build-dependencies] + pytest = ["setuptools"] + ``` +=== "uv.toml" + + ```toml + [pip] + [extra-build-dependencies] + pytest = ["setuptools"] + ``` + +--- + #### [`extra-index-url`](#pip_extra-index-url) {: #pip_extra-index-url } diff --git a/uv.schema.json b/uv.schema.json index 33c1ff1f5..e4094b3b4 100644 --- a/uv.schema.json +++ b/uv.schema.json @@ -203,6 +203,17 @@ } ] }, + "extra-build-dependencies": { + "description": "Additional build dependencies for dependencies.\n\nThis is intended for enabling more packages to be built with build-isolation, by adding dependencies that they ambiently assume to exist (`setuptools` and `pip` being common).", + "anyOf": [ + { + "$ref": "#/definitions/ToolUvExtraBuildDependencies" + }, + { + "type": "null" + } + ] + }, "extra-index-url": { "description": "Extra URLs of package indexes to use, in addition to `--index-url`.\n\nAccepts either a repository compliant with [PEP 503](https://peps.python.org/pep-0503/) (the simple repository API), or a local directory laid out in the same format.\n\nAll indexes provided via this flag take priority over the index specified by [`index_url`](#index-url) or [`index`](#index) with `default = true`. When multiple indexes are provided, earlier values take priority.\n\nTo control uv's resolution strategy when multiple indexes are present, see [`index_strategy`](#index-strategy).\n\n(Deprecated: use `index` instead.)", "type": [ @@ -1240,6 +1251,19 @@ "$ref": "#/definitions/ExtraName" } }, + "extra-build-dependencies": { + "description": "Additional build dependencies for dependencies.\n\nThis is intended for enabling more packages to be built with build-isolation, by adding dependencies that they ambiently assume to exist (`setuptools` and `pip` being common).", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/definitions/Requirement" + } + } + }, "extra-index-url": { "description": "Extra URLs of package indexes to use, in addition to `--index-url`.\n\nAccepts either a repository compliant with [PEP 503](https://peps.python.org/pep-0503/) (the simple repository API), or a local directory laid out in the same format.\n\nAll indexes provided via this flag take priority over the index specified by [`index_url`](#index-url). When multiple indexes are provided, earlier values take priority.\n\nTo control uv's resolution strategy when multiple indexes are present, see [`index_strategy`](#index-strategy).", "type": [ @@ -2373,6 +2397,15 @@ "$ref": "#/definitions/DependencyGroupSettings" } }, + "ToolUvExtraBuildDependencies": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/definitions/Requirement" + } + } + }, "ToolUvSources": { "type": "object", "additionalProperties": { From b2caf475a0866a03f8fec70350d9c26c89a80d12 Mon Sep 17 00:00:00 2001 From: Aria Desires Date: Mon, 16 Jun 2025 17:42:25 -0400 Subject: [PATCH 2/2] snapshot regens --- crates/uv-workspace/src/workspace.rs | 6 +++++ crates/uv/tests/it/show_settings.rs | 38 +++++++++++++++++++++++++++- crates/uv/tests/it/sync.rs | 2 +- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/crates/uv-workspace/src/workspace.rs b/crates/uv-workspace/src/workspace.rs index 1349d739c..616e2d1b1 100644 --- a/crates/uv-workspace/src/workspace.rs +++ b/crates/uv-workspace/src/workspace.rs @@ -1868,6 +1868,7 @@ mod tests { "package": null, "default-groups": null, "dependency-groups": null, + "extra-build-dependencies": null, "dev-dependencies": null, "override-dependencies": null, "constraint-dependencies": null, @@ -1964,6 +1965,7 @@ mod tests { "package": null, "default-groups": null, "dependency-groups": null, + "extra-build-dependencies": null, "dev-dependencies": null, "override-dependencies": null, "constraint-dependencies": null, @@ -2175,6 +2177,7 @@ mod tests { "package": null, "default-groups": null, "dependency-groups": null, + "extra-build-dependencies": null, "dev-dependencies": null, "override-dependencies": null, "constraint-dependencies": null, @@ -2283,6 +2286,7 @@ mod tests { "package": null, "default-groups": null, "dependency-groups": null, + "extra-build-dependencies": null, "dev-dependencies": null, "override-dependencies": null, "constraint-dependencies": null, @@ -2404,6 +2408,7 @@ mod tests { "package": null, "default-groups": null, "dependency-groups": null, + "extra-build-dependencies": null, "dev-dependencies": null, "override-dependencies": null, "constraint-dependencies": null, @@ -2499,6 +2504,7 @@ mod tests { "package": null, "default-groups": null, "dependency-groups": null, + "extra-build-dependencies": null, "dev-dependencies": null, "override-dependencies": null, "constraint-dependencies": null, diff --git a/crates/uv/tests/it/show_settings.rs b/crates/uv/tests/it/show_settings.rs index 7635bd523..9489a3f3f 100644 --- a/crates/uv/tests/it/show_settings.rs +++ b/crates/uv/tests/it/show_settings.rs @@ -179,6 +179,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -360,6 +361,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -542,6 +544,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -756,6 +759,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -906,6 +910,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -1099,6 +1104,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -1339,6 +1345,7 @@ fn resolve_index_url() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -1588,6 +1595,7 @@ fn resolve_index_url() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -1794,6 +1802,7 @@ fn resolve_find_links() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -1966,6 +1975,7 @@ fn resolve_top_level() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -2196,6 +2206,7 @@ fn resolve_top_level() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -2409,6 +2420,7 @@ fn resolve_top_level() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -2580,6 +2592,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -2735,6 +2748,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -2890,6 +2904,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -3047,6 +3062,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -3195,6 +3211,7 @@ fn resolve_tool() -> anyhow::Result<()> { config_settings: None, no_build_isolation: None, no_build_isolation_package: None, + extra_build_dependencies: None, exclude_newer: None, link_mode: Some( Clone, @@ -3234,6 +3251,7 @@ fn resolve_tool() -> anyhow::Result<()> { link_mode: Clone, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, prerelease: IfNecessaryOrExplicit, resolution: LowestDirect, sources: Enabled, @@ -3388,6 +3406,7 @@ fn resolve_poetry_toml() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -3604,6 +3623,7 @@ fn resolve_both() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -3910,6 +3930,7 @@ fn resolve_config_file() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -3987,7 +4008,7 @@ fn resolve_config_file() -> anyhow::Result<()> { | 1 | [project] | ^^^^^^^ - unknown field `project`, expected one of `required-version`, `native-tls`, `offline`, `no-cache`, `cache-dir`, `preview`, `python-preference`, `python-downloads`, `concurrent-downloads`, `concurrent-builds`, `concurrent-installs`, `index`, `index-url`, `extra-index-url`, `no-index`, `find-links`, `index-strategy`, `keyring-provider`, `allow-insecure-host`, `resolution`, `prerelease`, `fork-strategy`, `dependency-metadata`, `config-settings`, `no-build-isolation`, `no-build-isolation-package`, `exclude-newer`, `link-mode`, `compile-bytecode`, `no-sources`, `upgrade`, `upgrade-package`, `reinstall`, `reinstall-package`, `no-build`, `no-build-package`, `no-binary`, `no-binary-package`, `python-install-mirror`, `pypy-install-mirror`, `python-downloads-json-url`, `publish-url`, `trusted-publishing`, `check-url`, `add-bounds`, `pip`, `cache-keys`, `override-dependencies`, `constraint-dependencies`, `build-constraint-dependencies`, `environments`, `required-environments`, `conflicts`, `workspace`, `sources`, `managed`, `package`, `default-groups`, `dependency-groups`, `dev-dependencies`, `build-backend` + unknown field `project`, expected one of `required-version`, `native-tls`, `offline`, `no-cache`, `cache-dir`, `preview`, `python-preference`, `python-downloads`, `concurrent-downloads`, `concurrent-builds`, `concurrent-installs`, `index`, `index-url`, `extra-index-url`, `no-index`, `find-links`, `index-strategy`, `keyring-provider`, `allow-insecure-host`, `resolution`, `prerelease`, `fork-strategy`, `dependency-metadata`, `config-settings`, `no-build-isolation`, `no-build-isolation-package`, `extra-build-dependencies`, `exclude-newer`, `link-mode`, `compile-bytecode`, `no-sources`, `upgrade`, `upgrade-package`, `reinstall`, `reinstall-package`, `no-build`, `no-build-package`, `no-binary`, `no-binary-package`, `python-install-mirror`, `pypy-install-mirror`, `python-downloads-json-url`, `publish-url`, `trusted-publishing`, `check-url`, `add-bounds`, `pip`, `cache-keys`, `override-dependencies`, `constraint-dependencies`, `build-constraint-dependencies`, `environments`, `required-environments`, `conflicts`, `workspace`, `sources`, `managed`, `package`, `default-groups`, `dependency-groups`, `dev-dependencies`, `build-backend` " ); @@ -4159,6 +4180,7 @@ fn resolve_skip_empty() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -4317,6 +4339,7 @@ fn resolve_skip_empty() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -4494,6 +4517,7 @@ fn allow_insecure_host() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -4730,6 +4754,7 @@ fn index_priority() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -4945,6 +4970,7 @@ fn index_priority() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -5166,6 +5192,7 @@ fn index_priority() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -5382,6 +5409,7 @@ fn index_priority() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -5605,6 +5633,7 @@ fn index_priority() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -5821,6 +5850,7 @@ fn index_priority() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -5983,6 +6013,7 @@ fn verify_hashes() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -6131,6 +6162,7 @@ fn verify_hashes() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -6277,6 +6309,7 @@ fn verify_hashes() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -6425,6 +6458,7 @@ fn verify_hashes() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -6571,6 +6605,7 @@ fn verify_hashes() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, @@ -6718,6 +6753,7 @@ fn verify_hashes() -> anyhow::Result<()> { torch_backend: None, no_build_isolation: false, no_build_isolation_package: [], + extra_build_dependencies: {}, build_options: BuildOptions { no_binary: None, no_build: None, diff --git a/crates/uv/tests/it/sync.rs b/crates/uv/tests/it/sync.rs index d13aa33f3..2ebd027bf 100644 --- a/crates/uv/tests/it/sync.rs +++ b/crates/uv/tests/it/sync.rs @@ -1393,7 +1393,7 @@ fn sync_build_isolation_fail() -> Result<()> { + setuptools==69.2.0 "); - // assert!(context.temp_dir.child("uv.lock").exists()); + assert!(context.temp_dir.child("uv.lock").exists()); Ok(()) }