diff --git a/crates/uv-distribution-types/src/build_requires.rs b/crates/uv-distribution-types/src/build_requires.rs index 4e97e7a60..18d885f8e 100644 --- a/crates/uv-distribution-types/src/build_requires.rs +++ b/crates/uv-distribution-types/src/build_requires.rs @@ -13,6 +13,14 @@ pub enum ExtraBuildRequiresError { "`{0}` was declared as an extra build dependency with `match-runtime = true`, but was not found in the resolution" )] NotFound(PackageName), + #[error( + "Dependencies marked with `match-runtime = true` cannot include version specifiers, but found: `{0}{1}`" + )] + VersionSpecifiersNotAllowed(PackageName, Box), + #[error( + "Dependencies marked with `match-runtime = true` cannot include URL constraints, but found: `{0}{1}`" + )] + UrlNotAllowed(PackageName, Box), } /// Lowered extra build dependencies with source resolution applied. @@ -83,6 +91,26 @@ impl ExtraBuildRequires { requirement, match_runtime: true, } => { + // Reject requirements with `match-runtime = true` that include any form + // of constraint. + if let RequirementSource::Registry { specifier, .. } = + &requirement.source + { + if !specifier.is_empty() { + return Err( + ExtraBuildRequiresError::VersionSpecifiersNotAllowed( + requirement.name.clone(), + Box::new(requirement.source.clone()), + ), + ); + } + } else { + return Err(ExtraBuildRequiresError::VersionSpecifiersNotAllowed( + requirement.name.clone(), + Box::new(requirement.source.clone()), + )); + } + let dist = resolution .distributions() .find(|dist| dist.name() == &requirement.name) diff --git a/crates/uv-settings/src/settings.rs b/crates/uv-settings/src/settings.rs index 285b77cf7..a66f3c7ca 100644 --- a/crates/uv-settings/src/settings.rs +++ b/crates/uv-settings/src/settings.rs @@ -785,9 +785,8 @@ pub struct ResolverInstallerSchema { default = "[]", value_type = "dict", example = r#" - [extra-build-dependencies] - pytest = ["setuptools"] - "# + extra-build-dependencies = { pytest = ["setuptools"] } + "# )] pub extra_build_dependencies: Option, /// Extra environment variables to set when building certain packages. @@ -798,8 +797,7 @@ pub struct ResolverInstallerSchema { default = r#"{}"#, value_type = r#"dict[str, dict[str, str]]"#, example = r#" - [tool.uv.extra-build-variables] - flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } + extra-build-variables = { flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } } "# )] pub extra_build_variables: Option, @@ -1284,8 +1282,7 @@ pub struct PipOptions { default = "[]", value_type = "dict", example = r#" - [extra-build-dependencies] - pytest = ["setuptools"] + extra-build-dependencies = { pytest = ["setuptools"] } "# )] pub extra_build_dependencies: Option, @@ -1297,8 +1294,7 @@ pub struct PipOptions { default = r#"{}"#, value_type = r#"dict[str, dict[str, str]]"#, example = r#" - [extra-build-variables] - flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } + extra-build-variables = { flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } } "# )] pub extra_build_variables: Option, diff --git a/crates/uv-workspace/src/pyproject.rs b/crates/uv-workspace/src/pyproject.rs index 82714e465..e73cc764b 100644 --- a/crates/uv-workspace/src/pyproject.rs +++ b/crates/uv-workspace/src/pyproject.rs @@ -22,14 +22,14 @@ use serde::{Deserialize, Deserializer, Serialize}; use thiserror::Error; use uv_build_backend::BuildBackendSettings; -use uv_distribution_types::{ExtraBuildVariables, Index, IndexName, RequirementSource}; +use uv_distribution_types::{Index, IndexName, RequirementSource}; use uv_fs::{PortablePathBuf, relative_to}; use uv_git_types::GitReference; use uv_macros::OptionsMetadata; use uv_normalize::{DefaultGroups, ExtraName, GroupName, PackageName}; use uv_options_metadata::{OptionSet, OptionsMetadata, Visit}; use uv_pep440::{Version, VersionSpecifiers}; -use uv_pep508::{MarkerTree, VersionOrUrl}; +use uv_pep508::MarkerTree; use uv_pypi_types::{ Conflicts, DependencyGroups, SchemaConflicts, SupportedEnvironments, VerbatimParsedUrl, }; @@ -428,35 +428,6 @@ pub struct ToolUv { )] pub dependency_groups: Option, - /// Additional build dependencies for packages. - /// - /// This allows extending the PEP 517 build environment for the project's dependencies with - /// additional packages. This is useful for packages that assume the presence of packages, like, - /// `pip`, and do not declare them as build dependencies. - #[option( - default = "[]", - value_type = "dict", - example = r#" - [tool.uv.extra-build-dependencies] - pytest = ["pip"] - "# - )] - pub extra_build_dependencies: Option, - - /// Extra environment variables to set when building certain packages. - /// - /// Environment variables will be added to the environment when building the - /// specified packages. - #[option( - default = r#"{}"#, - value_type = r#"dict[str, dict[str, str]]"#, - example = r#" - [tool.uv.extra-build-variables] - flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } - "# - )] - pub extra_build_variables: Option, - /// The project's development dependencies. /// /// Development dependencies will be installed by default in `uv run` and `uv sync`, but will @@ -785,7 +756,7 @@ pub enum ExtraBuildDependencyWire { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde( deny_unknown_fields, - try_from = "ExtraBuildDependencyWire", + from = "ExtraBuildDependencyWire", into = "ExtraBuildDependencyWire" )] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] @@ -800,38 +771,19 @@ impl From for uv_pep508::Requirement { } } -#[derive(Error, Debug)] -pub enum ExtraBuildDependencyError { - #[error("Dependencies marked with `match-runtime = true` cannot include version specifiers")] - VersionSpecifiersNotAllowed, - #[error("Dependencies marked with `match-runtime = true` cannot include URL constraints")] - UrlNotAllowed, -} - -impl TryFrom for ExtraBuildDependency { - type Error = ExtraBuildDependencyError; - - fn try_from(wire: ExtraBuildDependencyWire) -> Result { +impl From for ExtraBuildDependency { + fn from(wire: ExtraBuildDependencyWire) -> Self { match wire { - ExtraBuildDependencyWire::Unannotated(requirement) => Ok(Self { + ExtraBuildDependencyWire::Unannotated(requirement) => Self { requirement, match_runtime: false, - }), + }, ExtraBuildDependencyWire::Annotated { requirement, match_runtime, - } => match requirement.version_or_url { - // If `match-runtime = true`, reject additional constraints. - Some(VersionOrUrl::VersionSpecifier(..)) if match_runtime => { - Err(ExtraBuildDependencyError::VersionSpecifiersNotAllowed) - } - Some(VersionOrUrl::Url(..)) if match_runtime => { - Err(ExtraBuildDependencyError::UrlNotAllowed) - } - _ => Ok(Self { - requirement, - match_runtime, - }), + } => Self { + requirement, + match_runtime, }, } } diff --git a/crates/uv-workspace/src/workspace.rs b/crates/uv-workspace/src/workspace.rs index 62aa9ca1c..d277dc7c8 100644 --- a/crates/uv-workspace/src/workspace.rs +++ b/crates/uv-workspace/src/workspace.rs @@ -1970,8 +1970,6 @@ mod tests { "package": null, "default-groups": null, "dependency-groups": null, - "extra-build-dependencies": null, - "extra-build-variables": null, "dev-dependencies": null, "override-dependencies": null, "constraint-dependencies": null, @@ -2072,8 +2070,6 @@ mod tests { "package": null, "default-groups": null, "dependency-groups": null, - "extra-build-dependencies": null, - "extra-build-variables": null, "dev-dependencies": null, "override-dependencies": null, "constraint-dependencies": null, @@ -2287,8 +2283,6 @@ mod tests { "package": null, "default-groups": null, "dependency-groups": null, - "extra-build-dependencies": null, - "extra-build-variables": null, "dev-dependencies": null, "override-dependencies": null, "constraint-dependencies": null, @@ -2398,8 +2392,6 @@ mod tests { "package": null, "default-groups": null, "dependency-groups": null, - "extra-build-dependencies": null, - "extra-build-variables": null, "dev-dependencies": null, "override-dependencies": null, "constraint-dependencies": null, @@ -2522,8 +2514,6 @@ mod tests { "package": null, "default-groups": null, "dependency-groups": null, - "extra-build-dependencies": null, - "extra-build-variables": null, "dev-dependencies": null, "override-dependencies": null, "constraint-dependencies": null, @@ -2620,8 +2610,6 @@ mod tests { "package": null, "default-groups": null, "dependency-groups": null, - "extra-build-dependencies": null, - "extra-build-variables": null, "dev-dependencies": null, "override-dependencies": null, "constraint-dependencies": null, diff --git a/crates/uv/tests/it/sync.rs b/crates/uv/tests/it/sync.rs index ee057713a..a3de53e30 100644 --- a/crates/uv/tests/it/sync.rs +++ b/crates/uv/tests/it/sync.rs @@ -13175,26 +13175,16 @@ fn sync_build_dependencies_respect_locked_versions() -> Result<()> { child = [{ requirement = "anyio>4", match-runtime = true }] "#})?; - uv_snapshot!(context.filters(), context.sync(), @r#" + uv_snapshot!(context.filters(), context.sync(), @r" success: false exit_code: 2 ----- stdout ----- ----- stderr ----- - warning: Failed to parse `pyproject.toml` during settings discovery: - TOML parse error at line 11, column 9 - | - 11 | child = [{ requirement = "anyio>4", match-runtime = true }] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Dependencies marked with `match-runtime = true` cannot include version specifiers - - error: Failed to parse: `pyproject.toml` - Caused by: TOML parse error at line 11, column 9 - | - 11 | child = [{ requirement = "anyio>4", match-runtime = true }] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Dependencies marked with `match-runtime = true` cannot include version specifiers - "#); + warning: The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features extra-build-dependencies` to disable this warning. + Resolved [N] packages in [TIME] + error: Dependencies marked with `match-runtime = true` cannot include version specifiers, but found: `anyio>4` + "); Ok(()) } diff --git a/docs/reference/settings.md b/docs/reference/settings.md index c91137b9b..73ad03805 100644 --- a/docs/reference/settings.md +++ b/docs/reference/settings.md @@ -202,49 +202,6 @@ environments = ["sys_platform == 'darwin'"] --- -### [`extra-build-dependencies`](#extra-build-dependencies) {: #extra-build-dependencies } - -Additional build dependencies for packages. - -This allows extending the PEP 517 build environment for the project's dependencies with -additional packages. This is useful for packages that assume the presence of packages, like, -`pip`, and do not declare them as build dependencies. - -**Default value**: `[]` - -**Type**: `dict` - -**Example usage**: - -```toml title="pyproject.toml" - -[tool.uv.extra-build-dependencies] -pytest = ["pip"] -``` - ---- - -### [`extra-build-variables`](#extra-build-variables) {: #extra-build-variables } - -Extra environment variables to set when building certain packages. - -Environment variables will be added to the environment when building the -specified packages. - -**Default value**: `{}` - -**Type**: `dict[str, dict[str, str]]` - -**Example usage**: - -```toml title="pyproject.toml" - -[tool.uv.extra-build-variables] -flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } -``` - ---- - ### [`index`](#index) {: #index } The indexes to use when resolving dependencies. @@ -1188,14 +1145,12 @@ additional packages. This is useful for packages that assume the presence of pac ```toml [tool.uv] - [extra-build-dependencies] - pytest = ["setuptools"] + extra-build-dependencies = { pytest = ["setuptools"] } ``` === "uv.toml" ```toml - [extra-build-dependencies] - pytest = ["setuptools"] + extra-build-dependencies = { pytest = ["setuptools"] } ``` --- @@ -1216,14 +1171,13 @@ specified packages. === "pyproject.toml" ```toml - [tool.uv.extra-build-variables] - flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } + [tool.uv] + extra-build-variables = { flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } } ``` === "uv.toml" ```toml - [tool.uv.extra-build-variables] - flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } + extra-build-variables = { flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } } ``` --- @@ -2741,15 +2695,13 @@ additional packages. This is useful for packages that assume the presence of pac ```toml [tool.uv.pip] - [extra-build-dependencies] - pytest = ["setuptools"] + extra-build-dependencies = { pytest = ["setuptools"] } ``` === "uv.toml" ```toml [pip] - [extra-build-dependencies] - pytest = ["setuptools"] + extra-build-dependencies = { pytest = ["setuptools"] } ``` --- @@ -2772,15 +2724,13 @@ specified packages. ```toml [tool.uv.pip] - [extra-build-variables] - flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } + extra-build-variables = { flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } } ``` === "uv.toml" ```toml [pip] - [extra-build-variables] - flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } + extra-build-variables = { flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } } ``` --- diff --git a/uv.schema.json b/uv.schema.json index 6deddd4be..4781a6a9a 100644 --- a/uv.schema.json +++ b/uv.schema.json @@ -226,7 +226,7 @@ ] }, "extra-build-dependencies": { - "description": "Additional build dependencies for packages.\n\nThis allows extending the PEP 517 build environment for the project's dependencies with\nadditional packages. This is useful for packages that assume the presence of packages, like,\n`pip`, and do not declare them as build dependencies.", + "description": "Additional build dependencies for packages.\n\nThis allows extending the PEP 517 build environment for the project's dependencies with\nadditional packages. This is useful for packages that assume the presence of packages like\n`pip`, and do not declare them as build dependencies.", "anyOf": [ { "$ref": "#/definitions/ExtraBuildDependencies"