Respect extra build requires when reading from wheel cache (#15030)

## Summary

We weren't including these in the cache key when constructing the
install plan. We likely still read them from the cache later, but we may
have reported the wrong number of prepares, etc.
This commit is contained in:
Charlie Marsh 2025-08-02 15:26:02 -04:00 committed by GitHub
parent 368b7b1e12
commit 3a7aeff86f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 58 additions and 15 deletions

1
Cargo.lock generated
View File

@ -5450,6 +5450,7 @@ dependencies = [
"uv-static",
"uv-types",
"uv-warnings",
"uv-workspace",
"walkdir",
]

View File

@ -311,6 +311,7 @@ impl BuildContext for BuildDispatch<'_> {
self.index_locations,
self.config_settings,
self.config_settings_package,
self.extra_build_dependencies(),
self.cache(),
venv,
tags,
@ -460,7 +461,7 @@ impl BuildContext for BuildDispatch<'_> {
self.workspace_cache(),
config_settings,
self.build_isolation,
&self.extra_build_requires.extra_build_dependencies,
self.extra_build_dependencies(),
&build_stack,
build_kind,
self.build_extra_env_vars.clone(),

View File

@ -1,4 +1,5 @@
use std::borrow::Cow;
use uv_cache::{Cache, CacheBucket, CacheShard, WheelCache};
use uv_cache_info::CacheInfo;
use uv_cache_key::cache_digest;
@ -9,6 +10,7 @@ use uv_distribution_types::{
use uv_normalize::PackageName;
use uv_platform_tags::Tags;
use uv_types::HashStrategy;
use uv_workspace::pyproject::ExtraBuildDependencies;
use crate::Error;
use crate::index::cached_wheel::CachedWheel;
@ -22,6 +24,7 @@ pub struct BuiltWheelIndex<'a> {
hasher: &'a HashStrategy,
config_settings: &'a ConfigSettings,
config_settings_package: &'a PackageConfigSettings,
extra_build_dependencies: &'a ExtraBuildDependencies,
}
impl<'a> BuiltWheelIndex<'a> {
@ -32,6 +35,7 @@ impl<'a> BuiltWheelIndex<'a> {
hasher: &'a HashStrategy,
config_settings: &'a ConfigSettings,
config_settings_package: &'a PackageConfigSettings,
extra_build_dependencies: &'a ExtraBuildDependencies,
) -> Self {
Self {
cache,
@ -39,6 +43,7 @@ impl<'a> BuiltWheelIndex<'a> {
hasher,
config_settings,
config_settings_package,
extra_build_dependencies,
}
}
@ -69,10 +74,11 @@ impl<'a> BuiltWheelIndex<'a> {
// If there are build settings, we need to scope to a cache shard.
let config_settings = self.config_settings_for(&source_dist.name);
let cache_shard = if config_settings.is_empty() {
let extra_build_deps = self.extra_build_dependencies_for(&source_dist.name);
let cache_shard = if config_settings.is_empty() && extra_build_deps.is_empty() {
cache_shard
} else {
cache_shard.shard(cache_digest(&config_settings))
cache_shard.shard(cache_digest(&(&config_settings, extra_build_deps)))
};
Ok(self.find(&cache_shard))
@ -107,10 +113,11 @@ impl<'a> BuiltWheelIndex<'a> {
// If there are build settings, we need to scope to a cache shard.
let config_settings = self.config_settings_for(&source_dist.name);
let cache_shard = if config_settings.is_empty() {
let extra_build_deps = self.extra_build_dependencies_for(&source_dist.name);
let cache_shard = if config_settings.is_empty() && extra_build_deps.is_empty() {
cache_shard
} else {
cache_shard.shard(cache_digest(&config_settings))
cache_shard.shard(cache_digest(&(&config_settings, extra_build_deps)))
};
Ok(self
@ -156,10 +163,11 @@ impl<'a> BuiltWheelIndex<'a> {
// If there are build settings, we need to scope to a cache shard.
let config_settings = self.config_settings_for(&source_dist.name);
let cache_shard = if config_settings.is_empty() {
let extra_build_deps = self.extra_build_dependencies_for(&source_dist.name);
let cache_shard = if config_settings.is_empty() && extra_build_deps.is_empty() {
cache_shard
} else {
cache_shard.shard(cache_digest(&config_settings))
cache_shard.shard(cache_digest(&(&config_settings, extra_build_deps)))
};
Ok(self
@ -183,10 +191,11 @@ impl<'a> BuiltWheelIndex<'a> {
// If there are build settings, we need to scope to a cache shard.
let config_settings = self.config_settings_for(&source_dist.name);
let cache_shard = if config_settings.is_empty() {
let extra_build_deps = self.extra_build_dependencies_for(&source_dist.name);
let cache_shard = if config_settings.is_empty() && extra_build_deps.is_empty() {
cache_shard
} else {
cache_shard.shard(cache_digest(&config_settings))
cache_shard.shard(cache_digest(&(&config_settings, extra_build_deps)))
};
self.find(&cache_shard)
@ -257,4 +266,15 @@ impl<'a> BuiltWheelIndex<'a> {
Cow::Borrowed(self.config_settings)
}
}
/// Determine the extra build dependencies for the given package name.
fn extra_build_dependencies_for(
&self,
name: &PackageName,
) -> &[uv_pep508::Requirement<uv_pypi_types::VerbatimParsedUrl>] {
self.extra_build_dependencies
.get(name)
.map(Vec::as_slice)
.unwrap_or(&[])
}
}

View File

@ -413,7 +413,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
self.build_context
.extra_build_dependencies()
.get(name)
.map(|v| v.as_slice())
.map(Vec::as_slice)
})
.unwrap_or(&[])
}

View File

@ -35,6 +35,7 @@ uv-redacted = { workspace = true }
uv-static = { workspace = true }
uv-types = { workspace = true }
uv-warnings = { workspace = true }
uv-workspace = { workspace = true }
anyhow = { workspace = true }
async-channel = { workspace = true }

View File

@ -1,5 +1,6 @@
use anyhow::{Result, bail};
use std::sync::Arc;
use anyhow::{Result, bail};
use tracing::{debug, warn};
use uv_cache::{Cache, CacheBucket, WheelCache};
@ -17,6 +18,7 @@ use uv_platform_tags::Tags;
use uv_pypi_types::VerbatimParsedUrl;
use uv_python::PythonEnvironment;
use uv_types::HashStrategy;
use uv_workspace::pyproject::ExtraBuildDependencies;
use crate::SitePackages;
use crate::satisfies::RequirementSatisfaction;
@ -53,6 +55,7 @@ impl<'a> Planner<'a> {
index_locations: &IndexLocations,
config_settings: &ConfigSettings,
config_settings_package: &PackageConfigSettings,
extra_build_dependencies: &ExtraBuildDependencies,
cache: &Cache,
venv: &PythonEnvironment,
tags: &Tags,
@ -66,6 +69,7 @@ impl<'a> Planner<'a> {
hasher,
config_settings,
config_settings_package,
extra_build_dependencies,
);
let mut cached = vec![];

View File

@ -19,6 +19,7 @@ use uv_git::GitResolver;
use uv_pep508::PackageName;
use uv_python::{Interpreter, PythonEnvironment};
use uv_workspace::WorkspaceCache;
use uv_workspace::pyproject::ExtraBuildDependencies;
use crate::BuildArena;
@ -104,7 +105,7 @@ pub trait BuildContext {
fn workspace_cache(&self) -> &WorkspaceCache;
/// Get the extra build dependencies.
fn extra_build_dependencies(&self) -> &uv_workspace::pyproject::ExtraBuildDependencies;
fn extra_build_dependencies(&self) -> &ExtraBuildDependencies;
/// Resolve the given requirements into a ready-to-install set of package versions.
fn resolve<'a>(

View File

@ -1,12 +1,13 @@
//! Common operations shared across the `pip` API and subcommands.
use anyhow::{Context, anyhow};
use itertools::Itertools;
use owo_colors::OwoColorize;
use std::collections::{BTreeMap, BTreeSet, HashSet};
use std::fmt::Write;
use std::path::PathBuf;
use std::sync::Arc;
use anyhow::{Context, anyhow};
use itertools::Itertools;
use owo_colors::OwoColorize;
use tracing::debug;
use uv_cache::Cache;
@ -468,6 +469,7 @@ pub(crate) async fn install(
index_urls,
config_settings,
config_settings_package,
build_dispatch.extra_build_dependencies(),
cache,
venv,
tags,

View File

@ -1662,6 +1662,19 @@ fn sync_extra_build_dependencies() -> Result<()> {
+ child==0.1.0 (from file://[TEMP_DIR]/child)
");
context.venv().arg("--clear").assert().success();
uv_snapshot!(context.filters(), context.sync(), @r"
success: true
exit_code: 0
----- 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.
Resolved [N] packages in [TIME]
Installed [N] packages in [TIME]
+ child==0.1.0 (from file://[TEMP_DIR]/child)
");
// Adding `extra-build-dependencies` with the wrong name should fail the build
// (the cache is invalidated when extra build dependencies change)
pyproject_toml.write_str(indoc! {r#"