mirror of https://github.com/astral-sh/uv
Reject `match-runtime = true` for dynamic packages (#15292)
## Summary If `match-runtime = true`, but we can't resolve a package's metadata statically, then we can't _know_ what the runtime version of the package will be -- because we can't resolve without building it. This PR makes that footgun clearer by raising an error. Closes https://github.com/astral-sh/uv/issues/15264.
This commit is contained in:
parent
7eb076aaef
commit
627c062cab
|
|
@ -91,6 +91,10 @@ pub enum Error {
|
|||
NoSourceDistBuilds,
|
||||
#[error("Cyclic build dependency detected for `{0}`")]
|
||||
CyclicBuildDependency(PackageName),
|
||||
#[error(
|
||||
"Extra build requirement `{0}` was declared with `match-runtime = true`, but `{1}` does not declare static metadata, making runtime-matching impossible"
|
||||
)]
|
||||
UnmatchedRuntime(PackageName, PackageName),
|
||||
}
|
||||
|
||||
impl IsBuildBackendError for Error {
|
||||
|
|
@ -106,7 +110,8 @@ impl IsBuildBackendError for Error {
|
|||
| Self::Virtualenv(_)
|
||||
| Self::NoSourceDistBuild(_)
|
||||
| Self::NoSourceDistBuilds
|
||||
| Self::CyclicBuildDependency(_) => false,
|
||||
| Self::CyclicBuildDependency(_)
|
||||
| Self::UnmatchedRuntime(_, _) => false,
|
||||
Self::CommandFailed(_, _)
|
||||
| Self::BuildBackend(_)
|
||||
| Self::MissingHeader(_)
|
||||
|
|
|
|||
|
|
@ -34,7 +34,8 @@ use uv_configuration::Preview;
|
|||
use uv_configuration::{BuildKind, BuildOutput, SourceStrategy};
|
||||
use uv_distribution::BuildRequires;
|
||||
use uv_distribution_types::{
|
||||
ConfigSettings, ExtraBuildRequires, IndexLocations, Requirement, Resolution,
|
||||
ConfigSettings, ExtraBuildRequirement, ExtraBuildRequires, IndexLocations, Requirement,
|
||||
Resolution,
|
||||
};
|
||||
use uv_fs::LockedFile;
|
||||
use uv_fs::{PythonExt, Simplified};
|
||||
|
|
@ -326,13 +327,28 @@ impl SourceBuild {
|
|||
.or(fallback_package_version)
|
||||
.cloned();
|
||||
|
||||
let extra_build_dependencies: Vec<Requirement> = package_name
|
||||
let extra_build_dependencies = package_name
|
||||
.as_ref()
|
||||
.and_then(|name| extra_build_requires.get(name).cloned())
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(Requirement::from)
|
||||
.collect();
|
||||
.map(|requirement| {
|
||||
match requirement {
|
||||
ExtraBuildRequirement {
|
||||
requirement,
|
||||
match_runtime: true,
|
||||
} if requirement.source.is_empty() => {
|
||||
Err(Error::UnmatchedRuntime(
|
||||
requirement.name.clone(),
|
||||
// SAFETY: if `package_name` is `None`, the iterator is empty.
|
||||
package_name.clone().unwrap(),
|
||||
))
|
||||
}
|
||||
requirement => Ok(requirement),
|
||||
}
|
||||
})
|
||||
.map_ok(Requirement::from)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
// Create a virtual environment, or install into the shared environment if requested.
|
||||
let venv = if let Some(venv) = build_isolation.shared_environment(package_name.as_ref()) {
|
||||
|
|
|
|||
|
|
@ -480,7 +480,7 @@ impl BuildContext for BuildDispatch<'_> {
|
|||
self.workspace_cache(),
|
||||
config_settings,
|
||||
self.build_isolation,
|
||||
self.extra_build_requires(),
|
||||
self.extra_build_requires,
|
||||
&build_stack,
|
||||
build_kind,
|
||||
environment_variables,
|
||||
|
|
|
|||
|
|
@ -13089,3 +13089,36 @@ fn sync_extra_build_variables() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reject_unmatched_runtime() -> Result<()> {
|
||||
let context = TestContext::new("3.12").with_exclude_newer("2025-01-01T00:00Z");
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["source-distribution", "iniconfig"]
|
||||
|
||||
[tool.uv.extra-build-dependencies]
|
||||
source-distribution = [{ requirement = "iniconfig", match-runtime = true }]
|
||||
"#,
|
||||
)?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
warning: The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features extra-build-dependencies` to disable this warning.
|
||||
× Failed to download and build `source-distribution==0.0.3`
|
||||
╰─▶ Extra build requirement `iniconfig` was declared with `match-runtime = true`, but `source-distribution` does not declare static metadata, making runtime-matching impossible
|
||||
help: `source-distribution` (v0.0.3) was included because `foo` (v0.1.0) depends on `source-distribution`
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue