mirror of https://github.com/astral-sh/uv
parent
38f1d1adb0
commit
88acedafb9
|
|
@ -97,6 +97,10 @@ pub enum Error {
|
|||
UnmatchedRuntime(PackageName, PackageName),
|
||||
#[error("Build requires for `{0}` missing for metadata declared in `pyproject.toml`")]
|
||||
MissingBuildRequirementForMetadata(PackageName),
|
||||
#[error(
|
||||
"Build requirement `{0}` was declared with `match-runtime = true`, but there is no runtime environment to match against"
|
||||
)]
|
||||
UnmatchedRuntimeMetadata(PackageName),
|
||||
}
|
||||
|
||||
impl IsBuildBackendError for Error {
|
||||
|
|
@ -114,6 +118,7 @@ impl IsBuildBackendError for Error {
|
|||
| Self::NoSourceDistBuilds
|
||||
| Self::CyclicBuildDependency(_)
|
||||
| Self::UnmatchedRuntime(_, _)
|
||||
| Self::UnmatchedRuntimeMetadata(_)
|
||||
| Self::MissingBuildRequirementForMetadata(_) => false,
|
||||
Self::CommandFailed(_, _)
|
||||
| Self::BuildBackend(_)
|
||||
|
|
|
|||
|
|
@ -404,6 +404,7 @@ impl SourceBuild {
|
|||
};
|
||||
|
||||
let resolved_requirements = Self::get_resolved_requirements(
|
||||
build_kind,
|
||||
build_context,
|
||||
source_build_context,
|
||||
&DEFAULT_BACKEND,
|
||||
|
|
@ -528,10 +529,25 @@ impl SourceBuild {
|
|||
}
|
||||
|
||||
fn apply_build_metadata<'a>(
|
||||
build_kind: BuildKind,
|
||||
metadata: &BTreeMap<PackageName, BuildDependencyMetadata>,
|
||||
build_requires: impl Iterator<Item = &'a Requirement>,
|
||||
top_level_resolution: &Resolution,
|
||||
build_context: &impl BuildContext,
|
||||
) -> Result<Vec<Requirement>, Box<Error>> {
|
||||
let top_level_resolution = build_context.top_level_resolution();
|
||||
if top_level_resolution.is_none() {
|
||||
for (package, metadata) in metadata {
|
||||
if let Some(true) = metadata.match_runtime {
|
||||
if !matches!(build_kind, BuildKind::Sdist) {
|
||||
return Err(Box::new(Error::UnmatchedRuntimeMetadata(package.clone())));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Nothing needs runtime matching, carry on
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
// SAFETY: check above guarantees that top_level_resolution is Some
|
||||
let top_level_resolution = top_level_resolution.unwrap();
|
||||
let dists = top_level_resolution.distributions();
|
||||
let dists_by_name = dists
|
||||
.filter_map(|dist| metadata.get(dist.name()).map(|_| (dist.name(), dist)))
|
||||
|
|
@ -578,6 +594,7 @@ impl SourceBuild {
|
|||
}
|
||||
|
||||
async fn get_resolved_requirements(
|
||||
build_kind: BuildKind,
|
||||
build_context: &impl BuildContext,
|
||||
source_build_context: SourceBuildContext,
|
||||
default_backend: &Pep517Backend,
|
||||
|
|
@ -622,16 +639,15 @@ impl SourceBuild {
|
|||
};
|
||||
|
||||
if let Some(build_dep_metadata) = build_dep_metadata {
|
||||
if let Some(resolution) = build_context.top_level_resolution() {
|
||||
let mut reqs_with_metadata = Self::apply_build_metadata(
|
||||
&build_dep_metadata.0,
|
||||
requirements.iter(),
|
||||
resolution,
|
||||
)
|
||||
.map_err(|err| *err)?;
|
||||
reqs_with_metadata.extend(requirements.into_owned().into_iter());
|
||||
requirements = Cow::Owned(reqs_with_metadata);
|
||||
}
|
||||
let mut reqs_with_metadata = Self::apply_build_metadata(
|
||||
build_kind,
|
||||
&build_dep_metadata.0,
|
||||
requirements.iter(),
|
||||
build_context,
|
||||
)
|
||||
.map_err(|err| *err)?;
|
||||
reqs_with_metadata.extend(requirements.into_owned().into_iter());
|
||||
requirements = Cow::Owned(reqs_with_metadata);
|
||||
}
|
||||
|
||||
build_context
|
||||
|
|
|
|||
|
|
@ -2084,3 +2084,56 @@ fn venv_included_in_sdist() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Runtime matching causes building a wheel to fail
|
||||
#[test]
|
||||
fn runtime_matching() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
let project = context.temp_dir.child("project");
|
||||
project
|
||||
.child("src")
|
||||
.child("project")
|
||||
.child("__init__.py")
|
||||
.touch()?;
|
||||
project.child("README").touch()?;
|
||||
let pyproject_toml = project.child("pyproject.toml");
|
||||
pyproject_toml.write_str(indoc! {r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
|
||||
[tool.uv.build-dependencies-metadata.hatchling]
|
||||
match-runtime = true
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
"#})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.build().current_dir(&project), @r"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Building source distribution...
|
||||
Building wheel from source distribution...
|
||||
× Failed to build `[TEMP_DIR]/project`
|
||||
╰─▶ Build requirement `hatchling` was declared with `match-runtime = true`, but there is no runtime environment to match against
|
||||
");
|
||||
|
||||
// But building a sdist is fine
|
||||
uv_snapshot!(context.filters(), context.build().arg("--sdist").current_dir(&project), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Building source distribution...
|
||||
Successfully built dist/project-0.1.0.tar.gz
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,26 @@ build-constraint-dependencies = ["setuptools==60.0.0"]
|
|||
|
||||
---
|
||||
|
||||
### [`build-dependencies-metadata`](#build-dependencies-metadata) {: #build-dependencies-metadata }
|
||||
|
||||
Metadata for build dependencies.
|
||||
|
||||
This allows specifying metadata for build dependencies, such as runtime matching.
|
||||
|
||||
**Default value**: `None`
|
||||
|
||||
**Type**: `dict`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
[tool.uv]
|
||||
[build-dependencies-metadata.package1]
|
||||
match-runtime = true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [`conflicts`](#conflicts) {: #conflicts }
|
||||
|
||||
Declare collections of extras or dependency groups that are conflicting
|
||||
|
|
|
|||
|
|
@ -46,6 +46,17 @@
|
|||
"type": "string"
|
||||
}
|
||||
},
|
||||
"build-dependencies-metadata": {
|
||||
"description": "Metadata for build dependencies.\n\nThis allows specifying metadata for build dependencies, such as runtime matching.",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/BuildDependenciesMetadata"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cache-dir": {
|
||||
"description": "Path to the cache directory.\n\nDefaults to `$XDG_CACHE_HOME/uv` or `$HOME/.cache/uv` on Linux and macOS, and\n`%LOCALAPPDATA%\\uv\\cache` on Windows.",
|
||||
"type": [
|
||||
|
|
@ -759,6 +770,23 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"BuildDependenciesMetadata": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/BuildDependencyMetadata"
|
||||
}
|
||||
},
|
||||
"BuildDependencyMetadata": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"match_runtime": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"CacheKey": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue