mirror of https://github.com/astral-sh/uv
Merge branch 'zb/extra-build-dependencies' into zb/flash-attn
This commit is contained in:
commit
1c52d9ad35
|
|
@ -5538,6 +5538,7 @@ dependencies = [
|
|||
"tracing-test",
|
||||
"unicode-width 0.2.1",
|
||||
"url",
|
||||
"uv-cache-key",
|
||||
"uv-fs",
|
||||
"uv-normalize",
|
||||
"uv-pep440",
|
||||
|
|
|
|||
|
|
@ -141,6 +141,9 @@ mod resolver {
|
|||
universal: bool,
|
||||
) -> Result<ResolverOutput> {
|
||||
let build_isolation = BuildIsolation::default();
|
||||
let extra_build_requires = uv_distribution::ExtraBuildRequires {
|
||||
extra_build_dependencies: uv_workspace::pyproject::ExtraBuildDependencies::default(),
|
||||
};
|
||||
let build_options = BuildOptions::default();
|
||||
let concurrency = Concurrency::default();
|
||||
let config_settings = ConfigSettings::default();
|
||||
|
|
@ -187,6 +190,7 @@ mod resolver {
|
|||
&config_settings,
|
||||
&config_settings_package,
|
||||
build_isolation,
|
||||
&extra_build_requires,
|
||||
LinkMode::default(),
|
||||
&build_options,
|
||||
&hashes,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
mod error;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::OsString;
|
||||
use std::fmt::Formatter;
|
||||
use std::fmt::Write;
|
||||
|
|
@ -42,6 +43,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};
|
||||
|
||||
|
|
@ -281,6 +283,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<OsString, OsString>,
|
||||
|
|
@ -297,7 +300,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,
|
||||
|
|
@ -322,6 +324,14 @@ impl SourceBuild {
|
|||
.or(fallback_package_version)
|
||||
.cloned();
|
||||
|
||||
let extra_build_dependencies = package_name
|
||||
.as_ref()
|
||||
.and_then(|name| extra_build_dependencies.get(name).cloned())
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(Requirement::from)
|
||||
.collect();
|
||||
|
||||
// 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()) {
|
||||
venv.clone()
|
||||
|
|
@ -349,10 +359,13 @@ impl SourceBuild {
|
|||
source_build_context,
|
||||
&default_backend,
|
||||
&pep517_backend,
|
||||
extra_build_dependencies,
|
||||
build_stack,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// TODO(zanieb): We'll report `build-system.requires` here but it may include
|
||||
// `extra-build-dependencies`
|
||||
build_context
|
||||
.install(&resolved_requirements, &venv, build_stack)
|
||||
.await
|
||||
|
|
@ -471,10 +484,13 @@ impl SourceBuild {
|
|||
source_build_context: SourceBuildContext,
|
||||
default_backend: &Pep517Backend,
|
||||
pep517_backend: &Pep517Backend,
|
||||
extra_build_dependencies: Vec<Requirement>,
|
||||
build_stack: &BuildStack,
|
||||
) -> Result<Resolution, Error> {
|
||||
Ok(
|
||||
if pep517_backend.requirements == default_backend.requirements {
|
||||
if pep517_backend.requirements == default_backend.requirements
|
||||
&& extra_build_dependencies.is_empty()
|
||||
{
|
||||
let mut resolution = source_build_context.default_resolution.lock().await;
|
||||
if let Some(resolved_requirements) = &*resolution {
|
||||
resolved_requirements.clone()
|
||||
|
|
@ -489,8 +505,21 @@ impl SourceBuild {
|
|||
resolved_requirements
|
||||
}
|
||||
} else {
|
||||
// TODO(zanieb): It's unclear if we actually want to solve these together. We might
|
||||
// want to perform a separate solve to allow conflicts?
|
||||
let requirements = if extra_build_dependencies.is_empty() {
|
||||
Cow::Borrowed(&pep517_backend.requirements)
|
||||
} else {
|
||||
// If there are extra build dependencies, we need to resolve them together with
|
||||
// the backend requirements.
|
||||
let mut requirements = pep517_backend.requirements.clone();
|
||||
requirements.extend(extra_build_dependencies);
|
||||
Cow::Owned(requirements)
|
||||
};
|
||||
// TODO(zanieb): We'll report `build-system.requires` here but it may include
|
||||
// `extra-build-dependencies`
|
||||
build_context
|
||||
.resolve(&pep517_backend.requirements, build_stack)
|
||||
.resolve(&requirements, build_stack)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
Error::RequirementsResolve("`build-system.requires`", err.into())
|
||||
|
|
@ -604,6 +633,7 @@ impl SourceBuild {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
default_backend.clone()
|
||||
};
|
||||
Ok((backend, pyproject_toml.project))
|
||||
|
|
|
|||
|
|
@ -347,6 +347,7 @@ pub fn resolver_options(
|
|||
}),
|
||||
no_build_isolation: flag(no_build_isolation, 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, "build"),
|
||||
|
|
@ -465,6 +466,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, "compile-bytecode"),
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ bitflags::bitflags! {
|
|||
const PYLOCK = 1 << 3;
|
||||
const ADD_BOUNDS = 1 << 4;
|
||||
const PREFER_LOCKED_BUILDS = 1 << 5;
|
||||
const EXTRA_BUILD_DEPENDENCIES = 1 << 6;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -30,6 +31,7 @@ impl PreviewFeatures {
|
|||
Self::PYLOCK => "pylock",
|
||||
Self::ADD_BOUNDS => "add-bounds",
|
||||
Self::PREFER_LOCKED_BUILDS => "prefer-locked-builds",
|
||||
Self::EXTRA_BUILD_DEPENDENCIES => "extra-build-dependencies",
|
||||
_ => panic!("`flag_as_str` can only be used for exactly one feature flag"),
|
||||
}
|
||||
}
|
||||
|
|
@ -73,6 +75,7 @@ impl FromStr for PreviewFeatures {
|
|||
"pylock" => Self::PYLOCK,
|
||||
"add-bounds" => Self::ADD_BOUNDS,
|
||||
"prefer-locked-builds" => Self::PREFER_LOCKED_BUILDS,
|
||||
"extra-build-dependencies" => Self::EXTRA_BUILD_DEPENDENCIES,
|
||||
_ => {
|
||||
warn_user_once!("Unknown preview feature: `{part}`");
|
||||
continue;
|
||||
|
|
@ -239,6 +242,10 @@ mod tests {
|
|||
PreviewFeatures::PREFER_LOCKED_BUILDS.flag_as_str(),
|
||||
"prefer-locked-builds"
|
||||
);
|
||||
assert_eq!(
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES.flag_as_str(),
|
||||
"extra-build-dependencies"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ use uv_configuration::{
|
|||
};
|
||||
use uv_configuration::{BuildOutput, Concurrency};
|
||||
use uv_distribution::DistributionDatabase;
|
||||
use uv_distribution::ExtraBuildRequires;
|
||||
use uv_distribution_filename::DistFilename;
|
||||
use uv_distribution_types::{
|
||||
CachedDist, DependencyMetadata, Identifier, IndexCapabilities, IndexLocations,
|
||||
|
|
@ -88,6 +89,7 @@ pub struct BuildDispatch<'a> {
|
|||
shared_state: SharedState,
|
||||
dependency_metadata: &'a DependencyMetadata,
|
||||
build_isolation: BuildIsolation<'a>,
|
||||
extra_build_requires: &'a ExtraBuildRequires,
|
||||
link_mode: uv_install_wheel::LinkMode,
|
||||
build_options: &'a BuildOptions,
|
||||
config_settings: &'a ConfigSettings,
|
||||
|
|
@ -117,6 +119,7 @@ impl<'a> BuildDispatch<'a> {
|
|||
config_settings: &'a ConfigSettings,
|
||||
config_settings_package: &'a PackageConfigSettings,
|
||||
build_isolation: BuildIsolation<'a>,
|
||||
extra_build_requires: &'a ExtraBuildRequires,
|
||||
link_mode: uv_install_wheel::LinkMode,
|
||||
build_options: &'a BuildOptions,
|
||||
hasher: &'a HashStrategy,
|
||||
|
|
@ -140,6 +143,7 @@ impl<'a> BuildDispatch<'a> {
|
|||
config_settings,
|
||||
config_settings_package,
|
||||
build_isolation,
|
||||
extra_build_requires,
|
||||
link_mode,
|
||||
build_options,
|
||||
hasher,
|
||||
|
|
@ -222,6 +226,10 @@ impl BuildContext for BuildDispatch<'_> {
|
|||
&self.workspace_cache
|
||||
}
|
||||
|
||||
fn extra_build_dependencies(&self) -> &uv_workspace::pyproject::ExtraBuildDependencies {
|
||||
&self.extra_build_requires.extra_build_dependencies
|
||||
}
|
||||
|
||||
async fn resolve<'data>(
|
||||
&'data self,
|
||||
requirements: &'data [Requirement],
|
||||
|
|
@ -457,6 +465,7 @@ impl BuildContext for BuildDispatch<'_> {
|
|||
self.workspace_cache(),
|
||||
config_settings,
|
||||
self.build_isolation,
|
||||
&self.extra_build_requires.extra_build_dependencies,
|
||||
&build_stack,
|
||||
build_kind,
|
||||
self.build_extra_env_vars.clone(),
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ pub use download::LocalWheel;
|
|||
pub use error::Error;
|
||||
pub use index::{BuiltWheelIndex, RegistryWheelIndex};
|
||||
pub use metadata::{
|
||||
ArchiveMetadata, BuildRequires, FlatRequiresDist, LoweredRequirement, LoweringError, Metadata,
|
||||
MetadataError, RequiresDist, SourcedDependencyGroups,
|
||||
ArchiveMetadata, BuildRequires, ExtraBuildRequires, FlatRequiresDist, LoweredRequirement,
|
||||
LoweringError, Metadata, MetadataError, RequiresDist, SourcedDependencyGroups,
|
||||
};
|
||||
pub use reporter::Reporter;
|
||||
pub use source::prune;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ use std::path::Path;
|
|||
use uv_configuration::SourceStrategy;
|
||||
use uv_distribution_types::{IndexLocations, Requirement};
|
||||
use uv_normalize::PackageName;
|
||||
use uv_workspace::pyproject::ToolUvSources;
|
||||
use uv_pypi_types::VerbatimParsedUrl;
|
||||
use uv_workspace::pyproject::{ExtraBuildDependencies, ToolUvSources};
|
||||
use uv_workspace::{
|
||||
DiscoveryOptions, MemberDiscovery, ProjectWorkspace, Workspace, WorkspaceCache,
|
||||
};
|
||||
|
|
@ -203,3 +204,93 @@ impl BuildRequires {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Lowered extra build dependencies with source resolution applied.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ExtraBuildRequires {
|
||||
pub extra_build_dependencies: ExtraBuildDependencies,
|
||||
}
|
||||
|
||||
impl ExtraBuildRequires {
|
||||
/// Lower extra build dependencies from a workspace, applying source resolution.
|
||||
pub fn from_workspace(
|
||||
extra_build_dependencies: ExtraBuildDependencies,
|
||||
workspace: &Workspace,
|
||||
index_locations: &IndexLocations,
|
||||
source_strategy: SourceStrategy,
|
||||
) -> Result<Self, MetadataError> {
|
||||
match source_strategy {
|
||||
SourceStrategy::Enabled => {
|
||||
// Collect project sources and indexes
|
||||
let project_indexes = workspace
|
||||
.pyproject_toml()
|
||||
.tool
|
||||
.as_ref()
|
||||
.and_then(|tool| tool.uv.as_ref())
|
||||
.and_then(|uv| uv.index.as_deref())
|
||||
.unwrap_or(&[]);
|
||||
|
||||
let empty_sources = BTreeMap::default();
|
||||
let project_sources = workspace
|
||||
.pyproject_toml()
|
||||
.tool
|
||||
.as_ref()
|
||||
.and_then(|tool| tool.uv.as_ref())
|
||||
.and_then(|uv| uv.sources.as_ref())
|
||||
.map(ToolUvSources::inner)
|
||||
.unwrap_or(&empty_sources);
|
||||
|
||||
// Lower each package's extra build dependencies
|
||||
let mut result = ExtraBuildDependencies::default();
|
||||
for (package_name, requirements) in extra_build_dependencies {
|
||||
let lowered: Vec<uv_pep508::Requirement<VerbatimParsedUrl>> = requirements
|
||||
.into_iter()
|
||||
.flat_map(|requirement| {
|
||||
let requirement_name = requirement.name.clone();
|
||||
let extra = requirement.marker.top_level_extra_name();
|
||||
let group = None;
|
||||
LoweredRequirement::from_requirement(
|
||||
requirement,
|
||||
None,
|
||||
workspace.install_path(),
|
||||
project_sources,
|
||||
project_indexes,
|
||||
extra.as_deref(),
|
||||
group,
|
||||
index_locations,
|
||||
workspace,
|
||||
None,
|
||||
)
|
||||
.map(
|
||||
move |requirement| match requirement {
|
||||
Ok(requirement) => Ok(requirement.into_inner().into()),
|
||||
Err(err) => Err(MetadataError::LoweringError(
|
||||
requirement_name.clone(),
|
||||
Box::new(err),
|
||||
)),
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
result.insert(package_name, lowered);
|
||||
}
|
||||
Ok(Self {
|
||||
extra_build_dependencies: result,
|
||||
})
|
||||
}
|
||||
SourceStrategy::Disabled => {
|
||||
// Without source resolution, just return the dependencies as-is
|
||||
Ok(Self {
|
||||
extra_build_dependencies,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create from pre-lowered dependencies (for non-workspace contexts).
|
||||
pub fn from_lowered(extra_build_dependencies: ExtraBuildDependencies) -> Self {
|
||||
Self {
|
||||
extra_build_dependencies,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use uv_pypi_types::{HashDigests, ResolutionMetadata};
|
|||
use uv_workspace::dependency_groups::DependencyGroupError;
|
||||
use uv_workspace::{WorkspaceCache, WorkspaceError};
|
||||
|
||||
pub use crate::metadata::build_requires::BuildRequires;
|
||||
pub use crate::metadata::build_requires::{BuildRequires, ExtraBuildRequires};
|
||||
pub use crate::metadata::dependency_groups::SourcedDependencyGroups;
|
||||
pub use crate::metadata::lowering::LoweredRequirement;
|
||||
pub use crate::metadata::lowering::LoweringError;
|
||||
|
|
|
|||
|
|
@ -404,6 +404,20 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Determine the extra build dependencies for the given package name.
|
||||
fn extra_build_dependencies_for(
|
||||
&self,
|
||||
name: Option<&PackageName>,
|
||||
) -> &[uv_pep508::Requirement<uv_pypi_types::VerbatimParsedUrl>] {
|
||||
name.and_then(|name| {
|
||||
self.build_context
|
||||
.extra_build_dependencies()
|
||||
.get(name)
|
||||
.map(|v| v.as_slice())
|
||||
})
|
||||
.unwrap_or(&[])
|
||||
}
|
||||
|
||||
/// Build a source distribution from a remote URL.
|
||||
async fn url<'data>(
|
||||
&self,
|
||||
|
|
@ -438,12 +452,13 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
let cache_shard = cache_shard.shard(revision.id());
|
||||
let source_dist_entry = cache_shard.entry(SOURCE);
|
||||
|
||||
// If there are build settings, we need to scope to a cache shard.
|
||||
// If there are build settings or extra build dependencies, we need to scope to a cache shard.
|
||||
let config_settings = self.config_settings_for(source.name());
|
||||
let cache_shard = if config_settings.is_empty() {
|
||||
let extra_build_deps = self.extra_build_dependencies_for(source.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)))
|
||||
};
|
||||
|
||||
// If the cache contains a compatible wheel, return it.
|
||||
|
|
@ -614,12 +629,13 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
// If there are build settings, we need to scope to a cache shard.
|
||||
// If there are build settings or extra build dependencies, we need to scope to a cache shard.
|
||||
let config_settings = self.config_settings_for(source.name());
|
||||
let cache_shard = if config_settings.is_empty() {
|
||||
let extra_build_deps = self.extra_build_dependencies_for(source.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)))
|
||||
};
|
||||
|
||||
// Otherwise, we either need to build the metadata.
|
||||
|
|
@ -827,12 +843,13 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
let cache_shard = cache_shard.shard(revision.id());
|
||||
let source_entry = cache_shard.entry(SOURCE);
|
||||
|
||||
// If there are build settings, we need to scope to a cache shard.
|
||||
// If there are build settings or extra build dependencies, we need to scope to a cache shard.
|
||||
let config_settings = self.config_settings_for(source.name());
|
||||
let cache_shard = if config_settings.is_empty() {
|
||||
let extra_build_deps = self.extra_build_dependencies_for(source.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)))
|
||||
};
|
||||
|
||||
// If the cache contains a compatible wheel, return it.
|
||||
|
|
@ -989,12 +1006,13 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
});
|
||||
}
|
||||
|
||||
// If there are build settings, we need to scope to a cache shard.
|
||||
// If there are build settings or extra build dependencies, we need to scope to a cache shard.
|
||||
let config_settings = self.config_settings_for(source.name());
|
||||
let cache_shard = if config_settings.is_empty() {
|
||||
let extra_build_deps = self.extra_build_dependencies_for(source.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)))
|
||||
};
|
||||
|
||||
// Otherwise, we need to build a wheel.
|
||||
|
|
@ -1131,12 +1149,13 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
// freshness, since entries have to be fresher than the revision itself.
|
||||
let cache_shard = cache_shard.shard(revision.id());
|
||||
|
||||
// If there are build settings, we need to scope to a cache shard.
|
||||
// If there are build settings or extra build dependencies, we need to scope to a cache shard.
|
||||
let config_settings = self.config_settings_for(source.name());
|
||||
let cache_shard = if config_settings.is_empty() {
|
||||
let extra_build_deps = self.extra_build_dependencies_for(source.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)))
|
||||
};
|
||||
|
||||
// If the cache contains a compatible wheel, return it.
|
||||
|
|
@ -1319,12 +1338,13 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
));
|
||||
}
|
||||
|
||||
// If there are build settings, we need to scope to a cache shard.
|
||||
// If there are build settings or extra build dependencies, we need to scope to a cache shard.
|
||||
let config_settings = self.config_settings_for(source.name());
|
||||
let cache_shard = if config_settings.is_empty() {
|
||||
let extra_build_deps = self.extra_build_dependencies_for(source.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)))
|
||||
};
|
||||
|
||||
// Otherwise, we need to build a wheel.
|
||||
|
|
@ -1524,12 +1544,13 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
// Acquire the advisory lock.
|
||||
let _lock = cache_shard.lock().await.map_err(Error::CacheWrite)?;
|
||||
|
||||
// If there are build settings, we need to scope to a cache shard.
|
||||
// If there are build settings or extra build dependencies, we need to scope to a cache shard.
|
||||
let config_settings = self.config_settings_for(source.name());
|
||||
let cache_shard = if config_settings.is_empty() {
|
||||
let extra_build_deps = self.extra_build_dependencies_for(source.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)))
|
||||
};
|
||||
|
||||
// If the cache contains a compatible wheel, return it.
|
||||
|
|
@ -1827,12 +1848,13 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
));
|
||||
}
|
||||
|
||||
// If there are build settings, we need to scope to a cache shard.
|
||||
// If there are build settings or extra build dependencies, we need to scope to a cache shard.
|
||||
let config_settings = self.config_settings_for(source.name());
|
||||
let cache_shard = if config_settings.is_empty() {
|
||||
let extra_build_deps = self.extra_build_dependencies_for(source.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)))
|
||||
};
|
||||
|
||||
// Otherwise, we need to build a wheel.
|
||||
|
|
|
|||
|
|
@ -114,6 +114,24 @@ impl Operator {
|
|||
pub fn is_star(self) -> bool {
|
||||
matches!(self, Self::EqualStar | Self::NotEqualStar)
|
||||
}
|
||||
|
||||
/// Returns the string representation of this operator.
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Equal => "==",
|
||||
// Beware, this doesn't print the star
|
||||
Self::EqualStar => "==",
|
||||
#[allow(deprecated)]
|
||||
Self::ExactEqual => "===",
|
||||
Self::NotEqual => "!=",
|
||||
Self::NotEqualStar => "!=",
|
||||
Self::TildeEqual => "~=",
|
||||
Self::LessThan => "<",
|
||||
Self::LessThanEqual => "<=",
|
||||
Self::GreaterThan => ">",
|
||||
Self::GreaterThanEqual => ">=",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Operator {
|
||||
|
|
@ -150,21 +168,7 @@ impl FromStr for Operator {
|
|||
impl std::fmt::Display for Operator {
|
||||
/// Note the `EqualStar` is also `==`.
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let operator = match self {
|
||||
Self::Equal => "==",
|
||||
// Beware, this doesn't print the star
|
||||
Self::EqualStar => "==",
|
||||
#[allow(deprecated)]
|
||||
Self::ExactEqual => "===",
|
||||
Self::NotEqual => "!=",
|
||||
Self::NotEqualStar => "!=",
|
||||
Self::TildeEqual => "~=",
|
||||
Self::LessThan => "<",
|
||||
Self::LessThanEqual => "<=",
|
||||
Self::GreaterThan => ">",
|
||||
Self::GreaterThanEqual => ">=",
|
||||
};
|
||||
|
||||
let operator = self.as_str();
|
||||
write!(f, "{operator}")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,11 @@ impl VersionSpecifiers {
|
|||
Self(Box::new([]))
|
||||
}
|
||||
|
||||
/// The number of specifiers.
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
/// Whether all specifiers match the given version.
|
||||
pub fn contains(&self, version: &Version) -> bool {
|
||||
self.iter().all(|specifier| specifier.contains(version))
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ doctest = false
|
|||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
uv-cache-key = { workspace = true }
|
||||
uv-fs = { workspace = true }
|
||||
uv-normalize = { workspace = true }
|
||||
uv-pep440 = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ use std::str::FromStr;
|
|||
use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
|
||||
use thiserror::Error;
|
||||
use url::Url;
|
||||
use uv_cache_key::{CacheKey, CacheKeyHasher};
|
||||
|
||||
use cursor::Cursor;
|
||||
pub use marker::{
|
||||
|
|
@ -251,6 +252,52 @@ impl<T: Pep508Url> Serialize for Requirement<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Pep508Url> CacheKey for Requirement<T>
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
fn cache_key(&self, state: &mut CacheKeyHasher) {
|
||||
self.name.as_str().cache_key(state);
|
||||
|
||||
self.extras.len().cache_key(state);
|
||||
for extra in &self.extras {
|
||||
extra.as_str().cache_key(state);
|
||||
}
|
||||
|
||||
// TODO(zanieb): We inline cache key handling for the child types here, but we could
|
||||
// move the implementations to the children. The intent here was to limit the scope of
|
||||
// types exposing the `CacheKey` trait for now.
|
||||
if let Some(version_or_url) = &self.version_or_url {
|
||||
1u8.cache_key(state);
|
||||
match version_or_url {
|
||||
VersionOrUrl::VersionSpecifier(spec) => {
|
||||
0u8.cache_key(state);
|
||||
spec.len().cache_key(state);
|
||||
for specifier in spec.iter() {
|
||||
specifier.operator().as_str().cache_key(state);
|
||||
specifier.version().to_string().cache_key(state);
|
||||
}
|
||||
}
|
||||
VersionOrUrl::Url(url) => {
|
||||
1u8.cache_key(state);
|
||||
url.to_string().cache_key(state);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
0u8.cache_key(state);
|
||||
}
|
||||
|
||||
if let Some(marker) = self.marker.contents() {
|
||||
1u8.cache_key(state);
|
||||
marker.to_string().cache_key(state);
|
||||
} else {
|
||||
0u8.cache_key(state);
|
||||
}
|
||||
|
||||
// `origin` is intentionally omitted
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Pep508Url> Requirement<T> {
|
||||
/// Returns whether the markers apply for the given environment
|
||||
pub fn evaluate_markers(&self, env: &MarkerEnvironment, extras: &[ExtraName]) -> bool {
|
||||
|
|
|
|||
|
|
@ -381,6 +381,8 @@ pub struct ToolUv {
|
|||
pub override_dependencies: Option<Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>,
|
||||
pub constraint_dependencies: Option<Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>,
|
||||
pub build_constraint_dependencies: Option<Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>,
|
||||
pub extra_build_dependencies:
|
||||
Option<BTreeMap<PackageName, Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>>,
|
||||
pub sources: Option<BTreeMap<PackageName, Sources>>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use std::num::NonZeroUsize;
|
||||
use std::path::PathBuf;
|
||||
use std::{collections::BTreeMap, num::NonZeroUsize};
|
||||
|
||||
use url::Url;
|
||||
|
||||
|
|
@ -121,6 +121,21 @@ impl<T> Combine for Option<Vec<T>> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<K: Ord, T> Combine for Option<BTreeMap<K, Vec<T>>> {
|
||||
/// Combine two maps of vecs by combining their vecs
|
||||
fn combine(self, other: Option<BTreeMap<K, Vec<T>>>) -> Option<BTreeMap<K, Vec<T>>> {
|
||||
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<ConfigSettings> {
|
||||
/// Combine two maps by merging the map in `self` with the map in `other`, if they're both
|
||||
/// `Some`.
|
||||
|
|
|
|||
|
|
@ -317,6 +317,7 @@ fn warn_uv_toml_masked_fields(options: &Options) {
|
|||
config_settings_package,
|
||||
no_build_isolation,
|
||||
no_build_isolation_package,
|
||||
extra_build_dependencies,
|
||||
exclude_newer,
|
||||
link_mode,
|
||||
compile_bytecode,
|
||||
|
|
@ -445,6 +446,9 @@ fn warn_uv_toml_masked_fields(options: &Options) {
|
|||
if no_build_isolation_package.is_some() {
|
||||
masked_fields.push("no-build-isolation-package");
|
||||
}
|
||||
if extra_build_dependencies.is_some() {
|
||||
masked_fields.push("extra-build-dependencies");
|
||||
}
|
||||
if exclude_newer.is_some() {
|
||||
masked_fields.push("exclude-newer");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,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)]
|
||||
|
|
@ -373,6 +373,7 @@ pub struct ResolverOptions {
|
|||
pub no_binary_package: Option<Vec<PackageName>>,
|
||||
pub no_build_isolation: Option<bool>,
|
||||
pub no_build_isolation_package: Option<Vec<PackageName>>,
|
||||
pub extra_build_dependencies: Option<ExtraBuildDependencies>,
|
||||
pub no_sources: Option<bool>,
|
||||
pub build_dependency_strategy: Option<BuildDependencyStrategy>,
|
||||
}
|
||||
|
|
@ -643,6 +644,20 @@ pub struct ResolverInstallerOptions {
|
|||
"#
|
||||
)]
|
||||
pub no_build_isolation_package: Option<Vec<PackageName>>,
|
||||
/// 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#"
|
||||
[extra-build-dependencies]
|
||||
pytest = ["setuptools"]
|
||||
"#
|
||||
)]
|
||||
pub extra_build_dependencies: Option<ExtraBuildDependencies>,
|
||||
/// 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.,
|
||||
|
|
@ -1139,6 +1154,20 @@ pub struct PipOptions {
|
|||
"#
|
||||
)]
|
||||
pub no_build_isolation_package: Option<Vec<PackageName>>,
|
||||
/// 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#"
|
||||
[extra-build-dependencies]
|
||||
pytest = ["setuptools"]
|
||||
"#
|
||||
)]
|
||||
pub extra_build_dependencies: Option<ExtraBuildDependencies>,
|
||||
/// Validate the Python environment, to detect packages with missing dependencies and other
|
||||
/// issues.
|
||||
#[option(
|
||||
|
|
@ -1704,6 +1733,7 @@ impl From<ResolverInstallerOptions> 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,
|
||||
build_dependency_strategy: value.build_dependency_strategy,
|
||||
}
|
||||
|
|
@ -1761,6 +1791,7 @@ pub struct ToolOptions {
|
|||
pub config_settings_package: Option<PackageConfigSettings>,
|
||||
pub no_build_isolation: Option<bool>,
|
||||
pub no_build_isolation_package: Option<Vec<PackageName>>,
|
||||
pub extra_build_dependencies: Option<ExtraBuildDependencies>,
|
||||
pub exclude_newer: Option<ExcludeNewer>,
|
||||
pub link_mode: Option<LinkMode>,
|
||||
pub compile_bytecode: Option<bool>,
|
||||
|
|
@ -1789,6 +1820,7 @@ impl From<ResolverInstallerOptions> for ToolOptions {
|
|||
config_settings_package: value.config_settings_package,
|
||||
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,
|
||||
|
|
@ -1819,6 +1851,7 @@ impl From<ToolOptions> for ResolverInstallerOptions {
|
|||
config_settings_package: value.config_settings_package,
|
||||
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,
|
||||
|
|
@ -1873,6 +1906,7 @@ pub struct OptionsWire {
|
|||
config_settings_package: Option<PackageConfigSettings>,
|
||||
no_build_isolation: Option<bool>,
|
||||
no_build_isolation_package: Option<Vec<PackageName>>,
|
||||
extra_build_dependencies: Option<ExtraBuildDependencies>,
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
link_mode: Option<LinkMode>,
|
||||
compile_bytecode: Option<bool>,
|
||||
|
|
@ -1992,6 +2026,7 @@ impl From<OptionsWire> for Options {
|
|||
sources,
|
||||
default_groups,
|
||||
dependency_groups,
|
||||
extra_build_dependencies,
|
||||
dev_dependencies,
|
||||
managed,
|
||||
package,
|
||||
|
|
@ -2033,6 +2068,7 @@ impl From<OptionsWire> for Options {
|
|||
config_settings_package,
|
||||
no_build_isolation,
|
||||
no_build_isolation_package,
|
||||
extra_build_dependencies,
|
||||
exclude_newer,
|
||||
link_mode,
|
||||
compile_bytecode,
|
||||
|
|
|
|||
|
|
@ -101,6 +101,9 @@ pub trait BuildContext {
|
|||
/// Workspace discovery caching.
|
||||
fn workspace_cache(&self) -> &WorkspaceCache;
|
||||
|
||||
/// Get the extra build dependencies.
|
||||
fn extra_build_dependencies(&self) -> &uv_workspace::pyproject::ExtraBuildDependencies;
|
||||
|
||||
/// Resolve the given requirements into a ready-to-install set of package versions.
|
||||
fn resolve<'a>(
|
||||
&'a self,
|
||||
|
|
|
|||
|
|
@ -378,6 +378,21 @@ pub struct ToolUv {
|
|||
)]
|
||||
pub dependency_groups: Option<ToolUvDependencyGroups>,
|
||||
|
||||
/// 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<ToolUvExtraBuildDependencies>,
|
||||
|
||||
/// The project's development dependencies.
|
||||
///
|
||||
/// Development dependencies will be installed by default in `uv run` and `uv sync`, but will
|
||||
|
|
@ -749,6 +764,70 @@ pub struct DependencyGroupSettings {
|
|||
pub requires_python: Option<VersionSpecifiers>,
|
||||
}
|
||||
|
||||
pub type ExtraBuildDependencies =
|
||||
BTreeMap<PackageName, Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>;
|
||||
|
||||
#[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<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
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<M>(self, mut access: M) -> Result<Self::Value, M::Error>
|
||||
where
|
||||
M: serde::de::MapAccess<'de>,
|
||||
{
|
||||
let mut groups = BTreeMap::new();
|
||||
while let Some((key, value)) = access
|
||||
.next_entry::<PackageName, Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>()?
|
||||
{
|
||||
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))]
|
||||
|
|
|
|||
|
|
@ -1970,6 +1970,7 @@ mod tests {
|
|||
"package": null,
|
||||
"default-groups": null,
|
||||
"dependency-groups": null,
|
||||
"extra-build-dependencies": null,
|
||||
"dev-dependencies": null,
|
||||
"override-dependencies": null,
|
||||
"constraint-dependencies": null,
|
||||
|
|
@ -2070,6 +2071,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 +2285,7 @@ mod tests {
|
|||
"package": null,
|
||||
"default-groups": null,
|
||||
"dependency-groups": null,
|
||||
"extra-build-dependencies": null,
|
||||
"dev-dependencies": null,
|
||||
"override-dependencies": null,
|
||||
"constraint-dependencies": null,
|
||||
|
|
@ -2392,6 +2395,7 @@ mod tests {
|
|||
"package": null,
|
||||
"default-groups": null,
|
||||
"dependency-groups": null,
|
||||
"extra-build-dependencies": null,
|
||||
"dev-dependencies": null,
|
||||
"override-dependencies": null,
|
||||
"constraint-dependencies": null,
|
||||
|
|
@ -2514,6 +2518,7 @@ mod tests {
|
|||
"package": null,
|
||||
"default-groups": null,
|
||||
"dependency-groups": null,
|
||||
"extra-build-dependencies": null,
|
||||
"dev-dependencies": null,
|
||||
"override-dependencies": null,
|
||||
"constraint-dependencies": null,
|
||||
|
|
@ -2610,6 +2615,7 @@ mod tests {
|
|||
"package": null,
|
||||
"default-groups": null,
|
||||
"dependency-groups": null,
|
||||
"extra-build-dependencies": null,
|
||||
"dev-dependencies": null,
|
||||
"override-dependencies": null,
|
||||
"constraint-dependencies": null,
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ use uv_requirements::RequirementsSource;
|
|||
use uv_resolver::{ExcludeNewer, FlatIndex, Preferences};
|
||||
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;
|
||||
|
|
@ -200,6 +201,7 @@ async fn build_impl(
|
|||
config_settings_package,
|
||||
no_build_isolation,
|
||||
no_build_isolation_package,
|
||||
extra_build_dependencies,
|
||||
exclude_newer,
|
||||
link_mode,
|
||||
upgrade: _,
|
||||
|
|
@ -347,6 +349,7 @@ async fn build_impl(
|
|||
build_constraints,
|
||||
*no_build_isolation,
|
||||
no_build_isolation_package,
|
||||
extra_build_dependencies,
|
||||
*index_strategy,
|
||||
*keyring_provider,
|
||||
*exclude_newer,
|
||||
|
|
@ -425,6 +428,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<ExcludeNewer>,
|
||||
|
|
@ -561,6 +565,8 @@ async fn build_package(
|
|||
let workspace_cache = WorkspaceCache::default();
|
||||
|
||||
// Create a build dispatch.
|
||||
let extra_build_requires =
|
||||
uv_distribution::ExtraBuildRequires::from_lowered(extra_build_dependencies.clone());
|
||||
let build_dispatch = BuildDispatch::new(
|
||||
&client,
|
||||
cache,
|
||||
|
|
@ -574,6 +580,7 @@ async fn build_package(
|
|||
config_setting,
|
||||
config_settings_package,
|
||||
build_isolation,
|
||||
&extra_build_requires,
|
||||
link_mode,
|
||||
build_options,
|
||||
&hasher,
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ use uv_cache::Cache;
|
|||
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
||||
use uv_configuration::{
|
||||
BuildOptions, Concurrency, ConfigSettings, Constraints, ExportFormat, ExtrasSpecification,
|
||||
IndexStrategy, NoBinary, NoBuild, PackageConfigSettings, Preview, Reinstall, SourceStrategy,
|
||||
Upgrade,
|
||||
IndexStrategy, NoBinary, NoBuild, PackageConfigSettings, Preview, PreviewFeatures, Reinstall,
|
||||
SourceStrategy, Upgrade,
|
||||
};
|
||||
use uv_configuration::{KeyringProviderType, TargetTriple};
|
||||
use uv_dispatch::{BuildDispatch, SharedState};
|
||||
|
|
@ -44,8 +44,9 @@ use uv_resolver::{
|
|||
};
|
||||
use uv_torch::{TorchMode, TorchStrategy};
|
||||
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy};
|
||||
use uv_warnings::warn_user;
|
||||
use uv_warnings::{warn_user, warn_user_once};
|
||||
use uv_workspace::WorkspaceCache;
|
||||
use uv_workspace::pyproject::ExtraBuildDependencies;
|
||||
|
||||
use crate::commands::pip::loggers::DefaultResolveLogger;
|
||||
use crate::commands::pip::{operations, resolution_environment};
|
||||
|
|
@ -95,6 +96,7 @@ pub(crate) async fn pip_compile(
|
|||
config_settings_package: PackageConfigSettings,
|
||||
no_build_isolation: bool,
|
||||
no_build_isolation_package: Vec<PackageName>,
|
||||
extra_build_dependencies: &ExtraBuildDependencies,
|
||||
build_options: BuildOptions,
|
||||
mut python_version: Option<PythonVersion>,
|
||||
python_platform: Option<TargetTriple>,
|
||||
|
|
@ -112,6 +114,15 @@ pub(crate) async fn pip_compile(
|
|||
printer: Printer,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
if !preview.is_enabled(PreviewFeatures::EXTRA_BUILD_DEPENDENCIES)
|
||||
&& !extra_build_dependencies.is_empty()
|
||||
{
|
||||
warn_user_once!(
|
||||
"The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES
|
||||
);
|
||||
}
|
||||
|
||||
// If the user provides a `pyproject.toml` or other TOML file as the output file, raise an
|
||||
// error.
|
||||
if output_file
|
||||
|
|
@ -469,6 +480,8 @@ pub(crate) async fn pip_compile(
|
|||
.map(|constraint| constraint.requirement.clone()),
|
||||
);
|
||||
|
||||
let extra_build_requires =
|
||||
uv_distribution::ExtraBuildRequires::from_lowered(extra_build_dependencies.clone());
|
||||
let build_dispatch = BuildDispatch::new(
|
||||
&client,
|
||||
&cache,
|
||||
|
|
@ -482,6 +495,7 @@ pub(crate) async fn pip_compile(
|
|||
&config_settings,
|
||||
&config_settings_package,
|
||||
build_isolation,
|
||||
&extra_build_requires,
|
||||
link_mode,
|
||||
&build_options,
|
||||
&build_hashes,
|
||||
|
|
|
|||
|
|
@ -36,8 +36,9 @@ use uv_resolver::{
|
|||
};
|
||||
use uv_torch::{TorchMode, TorchStrategy};
|
||||
use uv_types::{BuildIsolation, HashStrategy};
|
||||
use uv_warnings::warn_user;
|
||||
use uv_warnings::{warn_user, warn_user_once};
|
||||
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_package: &PackageConfigSettings,
|
||||
no_build_isolation: bool,
|
||||
no_build_isolation_package: Vec<PackageName>,
|
||||
extra_build_dependencies: &ExtraBuildDependencies,
|
||||
build_options: BuildOptions,
|
||||
modifications: Modifications,
|
||||
python_version: Option<PythonVersion>,
|
||||
|
|
@ -99,6 +101,15 @@ pub(crate) async fn pip_install(
|
|||
) -> anyhow::Result<ExitStatus> {
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
if !preview.is_enabled(PreviewFeatures::EXTRA_BUILD_DEPENDENCIES)
|
||||
&& !extra_build_dependencies.is_empty()
|
||||
{
|
||||
warn_user_once!(
|
||||
"The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES
|
||||
);
|
||||
}
|
||||
|
||||
let client_builder = BaseClientBuilder::new()
|
||||
.retries_from_env()?
|
||||
.connectivity(network_settings.connectivity)
|
||||
|
|
@ -413,6 +424,8 @@ pub(crate) async fn pip_install(
|
|||
let state = SharedState::default();
|
||||
|
||||
// Create a build dispatch.
|
||||
let extra_build_requires =
|
||||
uv_distribution::ExtraBuildRequires::from_lowered(extra_build_dependencies.clone());
|
||||
let build_dispatch = BuildDispatch::new(
|
||||
&client,
|
||||
&cache,
|
||||
|
|
@ -426,6 +439,7 @@ pub(crate) async fn pip_install(
|
|||
config_settings,
|
||||
config_settings_package,
|
||||
build_isolation,
|
||||
&extra_build_requires,
|
||||
link_mode,
|
||||
&build_options,
|
||||
&build_hasher,
|
||||
|
|
|
|||
|
|
@ -32,8 +32,9 @@ use uv_resolver::{
|
|||
};
|
||||
use uv_torch::{TorchMode, TorchStrategy};
|
||||
use uv_types::{BuildIsolation, HashStrategy};
|
||||
use uv_warnings::warn_user;
|
||||
use uv_warnings::{warn_user, warn_user_once};
|
||||
use uv_workspace::WorkspaceCache;
|
||||
use uv_workspace::pyproject::ExtraBuildDependencies;
|
||||
|
||||
use crate::commands::pip::loggers::{DefaultInstallLogger, DefaultResolveLogger};
|
||||
use crate::commands::pip::operations::Modifications;
|
||||
|
|
@ -67,6 +68,7 @@ pub(crate) async fn pip_sync(
|
|||
config_settings_package: &PackageConfigSettings,
|
||||
no_build_isolation: bool,
|
||||
no_build_isolation_package: Vec<PackageName>,
|
||||
extra_build_dependencies: &ExtraBuildDependencies,
|
||||
build_options: BuildOptions,
|
||||
python_version: Option<PythonVersion>,
|
||||
python_platform: Option<TargetTriple>,
|
||||
|
|
@ -85,6 +87,15 @@ pub(crate) async fn pip_sync(
|
|||
printer: Printer,
|
||||
preview: Preview,
|
||||
) -> Result<ExitStatus> {
|
||||
if !preview.is_enabled(PreviewFeatures::EXTRA_BUILD_DEPENDENCIES)
|
||||
&& !extra_build_dependencies.is_empty()
|
||||
{
|
||||
warn_user_once!(
|
||||
"The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES
|
||||
);
|
||||
}
|
||||
|
||||
let client_builder = BaseClientBuilder::new()
|
||||
.retries_from_env()?
|
||||
.connectivity(network_settings.connectivity)
|
||||
|
|
@ -348,6 +359,8 @@ pub(crate) async fn pip_sync(
|
|||
let state = SharedState::default();
|
||||
|
||||
// Create a build dispatch.
|
||||
let extra_build_requires =
|
||||
uv_distribution::ExtraBuildRequires::from_lowered(extra_build_dependencies.clone());
|
||||
let build_dispatch = BuildDispatch::new(
|
||||
&client,
|
||||
&cache,
|
||||
|
|
@ -361,6 +374,7 @@ pub(crate) async fn pip_sync(
|
|||
config_settings,
|
||||
config_settings_package,
|
||||
build_isolation,
|
||||
&extra_build_requires,
|
||||
link_mode,
|
||||
&build_options,
|
||||
&build_hasher,
|
||||
|
|
|
|||
|
|
@ -104,6 +104,15 @@ pub(crate) async fn add(
|
|||
);
|
||||
}
|
||||
|
||||
if !preview.is_enabled(PreviewFeatures::EXTRA_BUILD_DEPENDENCIES)
|
||||
&& !settings.resolver.extra_build_dependencies.is_empty()
|
||||
{
|
||||
warn_user_once!(
|
||||
"The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES
|
||||
);
|
||||
}
|
||||
|
||||
for source in &requirements {
|
||||
match source {
|
||||
RequirementsSource::PyprojectToml(_) => {
|
||||
|
|
@ -457,6 +466,18 @@ pub(crate) async fn add(
|
|||
};
|
||||
|
||||
// Create a build dispatch.
|
||||
let extra_build_requires = if let AddTarget::Project(project, _) = &target {
|
||||
uv_distribution::ExtraBuildRequires::from_workspace(
|
||||
settings.resolver.extra_build_dependencies.clone(),
|
||||
project.workspace(),
|
||||
&settings.resolver.index_locations,
|
||||
settings.resolver.sources,
|
||||
)?
|
||||
} else {
|
||||
uv_distribution::ExtraBuildRequires::from_lowered(
|
||||
settings.resolver.extra_build_dependencies.clone(),
|
||||
)
|
||||
};
|
||||
let build_dispatch = BuildDispatch::new(
|
||||
&client,
|
||||
cache,
|
||||
|
|
@ -470,6 +491,7 @@ pub(crate) async fn add(
|
|||
&settings.resolver.config_setting,
|
||||
&settings.resolver.config_settings_package,
|
||||
build_isolation,
|
||||
&extra_build_requires,
|
||||
settings.resolver.link_mode,
|
||||
&settings.resolver.build_options,
|
||||
&build_hasher,
|
||||
|
|
@ -1312,6 +1334,7 @@ impl PythonTarget {
|
|||
|
||||
/// Represents the destination where dependencies are added, either to a project or a script.
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub(super) enum AddTarget {
|
||||
/// A PEP 723 script, with inline metadata.
|
||||
Script(Pep723Script, Box<Interpreter>),
|
||||
|
|
@ -1420,6 +1443,7 @@ impl AddTarget {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
enum AddTargetSnapshot {
|
||||
Script(Pep723Script, Option<Vec<u8>>),
|
||||
Project(VirtualProject, Option<Vec<u8>>),
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ use crate::printer::Printer;
|
|||
use crate::settings::{NetworkSettings, ResolverSettings};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
enum ExportTarget {
|
||||
/// A PEP 723 script, with inline metadata.
|
||||
Script(Pep723Script),
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ use crate::commands::pip::loggers::{DefaultResolveLogger, ResolveLogger, Summary
|
|||
use crate::commands::project::lock_target::LockTarget;
|
||||
use crate::commands::project::{
|
||||
ProjectError, ProjectInterpreter, ScriptInterpreter, UniversalState,
|
||||
init_script_python_requirement,
|
||||
init_script_python_requirement, script_specification,
|
||||
};
|
||||
use crate::commands::reporters::{PythonDownloadReporter, ResolverReporter};
|
||||
use crate::commands::{ExitStatus, ScriptPath, diagnostics, pip};
|
||||
|
|
@ -435,6 +435,7 @@ async fn do_lock(
|
|||
config_settings_package,
|
||||
no_build_isolation,
|
||||
no_build_isolation_package,
|
||||
extra_build_dependencies,
|
||||
exclude_newer,
|
||||
link_mode,
|
||||
upgrade,
|
||||
|
|
@ -453,6 +454,15 @@ async fn do_lock(
|
|||
);
|
||||
}
|
||||
|
||||
if !preview.is_enabled(PreviewFeatures::EXTRA_BUILD_DEPENDENCIES)
|
||||
&& !extra_build_dependencies.is_empty()
|
||||
{
|
||||
warn_user_once!(
|
||||
"The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES
|
||||
);
|
||||
}
|
||||
|
||||
// Collect the requirements, etc.
|
||||
let members = target.members();
|
||||
let packages = target.packages();
|
||||
|
|
@ -695,6 +705,24 @@ async fn do_lock(
|
|||
};
|
||||
|
||||
// Create a build dispatch.
|
||||
let extra_build_requires = match &target {
|
||||
LockTarget::Workspace(workspace) => uv_distribution::ExtraBuildRequires::from_workspace(
|
||||
extra_build_dependencies.clone(),
|
||||
workspace,
|
||||
index_locations,
|
||||
*sources,
|
||||
)?,
|
||||
LockTarget::Script(script) => {
|
||||
// Try to get extra build dependencies from the script metadata
|
||||
script_specification(Pep723ItemRef::Script(script), settings)?
|
||||
.map(|spec| spec.extra_build_requires)
|
||||
.unwrap_or_else(|| {
|
||||
uv_distribution::ExtraBuildRequires::from_lowered(
|
||||
extra_build_dependencies.clone(),
|
||||
)
|
||||
})
|
||||
}
|
||||
};
|
||||
let build_dispatch = BuildDispatch::new(
|
||||
&client,
|
||||
cache,
|
||||
|
|
@ -708,6 +736,7 @@ async fn do_lock(
|
|||
config_setting,
|
||||
config_settings_package,
|
||||
build_isolation,
|
||||
&extra_build_requires,
|
||||
*link_mode,
|
||||
build_options,
|
||||
&build_hasher,
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy};
|
|||
use uv_virtualenv::remove_virtualenv;
|
||||
use uv_warnings::{warn_user, warn_user_once};
|
||||
use uv_workspace::dependency_groups::DependencyGroupError;
|
||||
use uv_workspace::pyproject::ExtraBuildDependencies;
|
||||
use uv_workspace::pyproject::PyProjectToml;
|
||||
use uv_workspace::{RequiresPythonSources, Workspace, WorkspaceCache};
|
||||
|
||||
|
|
@ -1692,6 +1693,7 @@ pub(crate) async fn resolve_names(
|
|||
link_mode,
|
||||
no_build_isolation,
|
||||
no_build_isolation_package,
|
||||
extra_build_dependencies,
|
||||
prerelease: _,
|
||||
resolution: _,
|
||||
sources,
|
||||
|
|
@ -1741,6 +1743,8 @@ pub(crate) async fn resolve_names(
|
|||
let build_hasher = HashStrategy::default();
|
||||
|
||||
// Create a build dispatch.
|
||||
let extra_build_requires =
|
||||
uv_distribution::ExtraBuildRequires::from_lowered(extra_build_dependencies.clone());
|
||||
let build_dispatch = BuildDispatch::new(
|
||||
&client,
|
||||
cache,
|
||||
|
|
@ -1754,6 +1758,7 @@ pub(crate) async fn resolve_names(
|
|||
config_setting,
|
||||
config_settings_package,
|
||||
build_isolation,
|
||||
&extra_build_requires,
|
||||
*link_mode,
|
||||
build_options,
|
||||
&build_hasher,
|
||||
|
|
@ -1847,6 +1852,7 @@ pub(crate) async fn resolve_environment(
|
|||
config_settings_package,
|
||||
no_build_isolation,
|
||||
no_build_isolation_package,
|
||||
extra_build_dependencies,
|
||||
exclude_newer,
|
||||
link_mode,
|
||||
upgrade: _,
|
||||
|
|
@ -1951,6 +1957,8 @@ pub(crate) async fn resolve_environment(
|
|||
let workspace_cache = WorkspaceCache::default();
|
||||
|
||||
// Create a build dispatch.
|
||||
let extra_build_requires =
|
||||
uv_distribution::ExtraBuildRequires::from_lowered(extra_build_dependencies.clone());
|
||||
let resolve_dispatch = BuildDispatch::new(
|
||||
&client,
|
||||
cache,
|
||||
|
|
@ -1964,6 +1972,7 @@ pub(crate) async fn resolve_environment(
|
|||
config_setting,
|
||||
config_settings_package,
|
||||
build_isolation,
|
||||
&extra_build_requires,
|
||||
*link_mode,
|
||||
build_options,
|
||||
&build_hasher,
|
||||
|
|
@ -2032,6 +2041,7 @@ pub(crate) async fn sync_environment(
|
|||
config_settings_package,
|
||||
no_build_isolation,
|
||||
no_build_isolation_package,
|
||||
extra_build_dependencies,
|
||||
exclude_newer,
|
||||
link_mode,
|
||||
compile_bytecode,
|
||||
|
|
@ -2091,6 +2101,8 @@ pub(crate) async fn sync_environment(
|
|||
};
|
||||
|
||||
// Create a build dispatch.
|
||||
let extra_build_requires =
|
||||
uv_distribution::ExtraBuildRequires::from_lowered(extra_build_dependencies.clone());
|
||||
let build_dispatch = BuildDispatch::new(
|
||||
&client,
|
||||
cache,
|
||||
|
|
@ -2104,6 +2116,7 @@ pub(crate) async fn sync_environment(
|
|||
config_setting,
|
||||
config_settings_package,
|
||||
build_isolation,
|
||||
&extra_build_requires,
|
||||
link_mode,
|
||||
build_options,
|
||||
&build_hasher,
|
||||
|
|
@ -2148,6 +2161,15 @@ pub(crate) async fn sync_environment(
|
|||
Ok(venv)
|
||||
}
|
||||
|
||||
/// A script specification that includes both requirements and extra build dependencies.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ScriptSpecification {
|
||||
/// The requirements specification for the script.
|
||||
pub(crate) requirements: RequirementsSpecification,
|
||||
/// The extra build dependencies for the script.
|
||||
pub(crate) extra_build_requires: uv_distribution::ExtraBuildRequires,
|
||||
}
|
||||
|
||||
/// The result of updating a [`PythonEnvironment`] to satisfy a set of [`RequirementsSource`]s.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct EnvironmentUpdate {
|
||||
|
|
@ -2170,6 +2192,7 @@ pub(crate) async fn update_environment(
|
|||
spec: RequirementsSpecification,
|
||||
modifications: Modifications,
|
||||
build_constraints: Constraints,
|
||||
extra_build_requires: uv_distribution::ExtraBuildRequires,
|
||||
settings: &ResolverInstallerSettings,
|
||||
network_settings: &NetworkSettings,
|
||||
state: &SharedState,
|
||||
|
|
@ -2200,6 +2223,7 @@ pub(crate) async fn update_environment(
|
|||
link_mode,
|
||||
no_build_isolation,
|
||||
no_build_isolation_package,
|
||||
extra_build_dependencies: _,
|
||||
prerelease,
|
||||
resolution,
|
||||
sources,
|
||||
|
|
@ -2330,6 +2354,7 @@ pub(crate) async fn update_environment(
|
|||
config_setting,
|
||||
config_settings_package,
|
||||
build_isolation,
|
||||
&extra_build_requires,
|
||||
*link_mode,
|
||||
build_options,
|
||||
&build_hasher,
|
||||
|
|
@ -2535,12 +2560,12 @@ pub(crate) fn detect_conflicts(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Determine the [`RequirementsSpecification`] for a script.
|
||||
/// Determine the [`ScriptSpecification`] for a script.
|
||||
#[allow(clippy::result_large_err)]
|
||||
pub(crate) fn script_specification(
|
||||
script: Pep723ItemRef<'_>,
|
||||
settings: &ResolverSettings,
|
||||
) -> Result<Option<RequirementsSpecification>, ProjectError> {
|
||||
) -> Result<Option<ScriptSpecification>, ProjectError> {
|
||||
let Some(dependencies) = script.metadata().dependencies.as_ref() else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
|
@ -2635,11 +2660,47 @@ pub(crate) fn script_specification(
|
|||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
Ok(Some(RequirementsSpecification::from_overrides(
|
||||
requirements,
|
||||
constraints,
|
||||
overrides,
|
||||
)))
|
||||
// Collect any `tool.uv.extra-build-dependencies` from the script.
|
||||
let empty = BTreeMap::default();
|
||||
let script_extra_build_dependencies = script
|
||||
.metadata()
|
||||
.tool
|
||||
.as_ref()
|
||||
.and_then(|tool| tool.uv.as_ref())
|
||||
.and_then(|uv| uv.extra_build_dependencies.as_ref())
|
||||
.unwrap_or(&empty);
|
||||
|
||||
// Lower the extra build dependencies
|
||||
let mut extra_build_dependencies = ExtraBuildDependencies::default();
|
||||
for (name, requirements) in script_extra_build_dependencies {
|
||||
let lowered_requirements: Vec<_> = requirements
|
||||
.iter()
|
||||
.cloned()
|
||||
.flat_map(|requirement| {
|
||||
LoweredRequirement::from_non_workspace_requirement(
|
||||
requirement,
|
||||
script_dir.as_ref(),
|
||||
script_sources,
|
||||
script_indexes,
|
||||
&settings.index_locations,
|
||||
)
|
||||
.map_ok(|req| req.into_inner().into())
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
extra_build_dependencies.insert(name.clone(), lowered_requirements);
|
||||
}
|
||||
|
||||
let extra_build_requires =
|
||||
uv_distribution::ExtraBuildRequires::from_lowered(extra_build_dependencies);
|
||||
|
||||
Ok(Some(ScriptSpecification {
|
||||
requirements: RequirementsSpecification::from_overrides(
|
||||
requirements,
|
||||
constraints,
|
||||
overrides,
|
||||
),
|
||||
extra_build_requires,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Warn if the user provides (e.g.) an `--index-url` in a requirements file.
|
||||
|
|
|
|||
|
|
@ -386,6 +386,7 @@ pub(crate) async fn remove(
|
|||
|
||||
/// Represents the destination where dependencies are added, either to a project or a script.
|
||||
#[derive(Debug)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
enum RemoveTarget {
|
||||
/// A PEP 723 script, with inline metadata.
|
||||
Project(VirtualProject),
|
||||
|
|
|
|||
|
|
@ -358,7 +358,9 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
|
|||
}
|
||||
|
||||
// Install the script requirements, if necessary. Otherwise, use an isolated environment.
|
||||
if let Some(spec) = script_specification((&script).into(), &settings.resolver)? {
|
||||
if let Some(script_spec) = script_specification((&script).into(), &settings.resolver)? {
|
||||
let spec = script_spec.requirements;
|
||||
let script_extra_build_requires = script_spec.extra_build_requires;
|
||||
let environment = ScriptEnvironment::get_or_init(
|
||||
(&script).into(),
|
||||
python.as_deref().map(PythonRequest::parse),
|
||||
|
|
@ -407,6 +409,7 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
|
|||
spec,
|
||||
modifications,
|
||||
build_constraints.unwrap_or_default(),
|
||||
script_extra_build_requires,
|
||||
&settings,
|
||||
&network_settings,
|
||||
&sync_state,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use uv_configuration::{
|
|||
BuildDependencyStrategy, Concurrency, Constraints, DependencyGroups,
|
||||
DependencyGroupsWithDefaults, DryRun, EditableMode, ExtrasSpecification,
|
||||
ExtrasSpecificationWithDefaults, HashCheckingMode, InstallOptions, Preview, PreviewFeatures,
|
||||
TargetTriple,
|
||||
TargetTriple, Upgrade,
|
||||
};
|
||||
use uv_dispatch::BuildDispatch;
|
||||
use uv_distribution_types::{
|
||||
|
|
@ -27,12 +27,13 @@ use uv_normalize::{DefaultExtras, DefaultGroups, PackageName};
|
|||
use uv_pep508::{MarkerTree, VersionOrUrl};
|
||||
use uv_pypi_types::{ParsedArchiveUrl, ParsedGitUrl, ParsedUrl};
|
||||
use uv_python::{PythonDownloads, PythonEnvironment, PythonPreference, PythonRequest};
|
||||
use uv_resolver::{FlatIndex, Installable, Lock, Preference, Preferences, ResolverEnvironment};
|
||||
use uv_requirements::RequirementsSpecification;
|
||||
use uv_resolver::{FlatIndex, ForkStrategy, Installable, Lock, Preference, Preferences, PrereleaseMode, ResolutionMode, ResolverEnvironment};
|
||||
use uv_scripts::{Pep723ItemRef, Pep723Script};
|
||||
use uv_settings::PythonInstallMirrors;
|
||||
use uv_types::{BuildIsolation, HashStrategy};
|
||||
use uv_warnings::{warn_user, warn_user_once};
|
||||
use uv_workspace::pyproject::Source;
|
||||
use uv_workspace::pyproject::{ExtraBuildDependencies, Source};
|
||||
use uv_workspace::{DiscoveryOptions, MemberDiscovery, VirtualProject, Workspace, WorkspaceCache};
|
||||
|
||||
use crate::commands::pip::loggers::{DefaultInstallLogger, DefaultResolveLogger, InstallLogger};
|
||||
|
|
@ -48,7 +49,9 @@ use crate::commands::project::{
|
|||
};
|
||||
use crate::commands::{ExitStatus, diagnostics};
|
||||
use crate::printer::Printer;
|
||||
use crate::settings::{InstallerSettingsRef, NetworkSettings, ResolverInstallerSettings};
|
||||
use crate::settings::{
|
||||
InstallerSettingsRef, NetworkSettings, ResolverInstallerSettings, ResolverSettings,
|
||||
};
|
||||
|
||||
/// Sync the project environment.
|
||||
#[allow(clippy::fn_params_excessive_bools)]
|
||||
|
|
@ -223,8 +226,18 @@ pub(crate) async fn sync(
|
|||
}
|
||||
|
||||
// Parse the requirements from the script.
|
||||
let spec = script_specification(Pep723ItemRef::Script(script), &settings.resolver)?
|
||||
.unwrap_or_default();
|
||||
let script_spec =
|
||||
script_specification(Pep723ItemRef::Script(script), &settings.resolver)?;
|
||||
let (spec, script_extra_build_requires) = if let Some(script_spec) = script_spec {
|
||||
(script_spec.requirements, script_spec.extra_build_requires)
|
||||
} else {
|
||||
(
|
||||
RequirementsSpecification::default(),
|
||||
uv_distribution::ExtraBuildRequires::from_lowered(
|
||||
ExtraBuildDependencies::default(),
|
||||
),
|
||||
)
|
||||
};
|
||||
|
||||
// Parse the build constraints from the script.
|
||||
let build_constraints = script
|
||||
|
|
@ -249,6 +262,7 @@ pub(crate) async fn sync(
|
|||
spec,
|
||||
modifications,
|
||||
build_constraints.unwrap_or_default(),
|
||||
script_extra_build_requires,
|
||||
&settings,
|
||||
&network_settings,
|
||||
&PlatformState::default(),
|
||||
|
|
@ -495,6 +509,7 @@ fn identify_installation_target<'a>(
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
enum SyncTarget {
|
||||
/// Sync a project environment.
|
||||
Project(VirtualProject),
|
||||
|
|
@ -579,6 +594,7 @@ pub(super) async fn do_sync(
|
|||
config_settings_package,
|
||||
no_build_isolation,
|
||||
no_build_isolation_package,
|
||||
extra_build_dependencies,
|
||||
exclude_newer,
|
||||
link_mode,
|
||||
compile_bytecode,
|
||||
|
|
@ -588,6 +604,57 @@ pub(super) async fn do_sync(
|
|||
build_dependency_strategy,
|
||||
} = settings;
|
||||
|
||||
if !preview.is_enabled(PreviewFeatures::EXTRA_BUILD_DEPENDENCIES)
|
||||
&& !extra_build_dependencies.is_empty()
|
||||
{
|
||||
warn_user_once!(
|
||||
"The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES
|
||||
);
|
||||
}
|
||||
|
||||
// Lower the extra build dependencies with source resolution
|
||||
let extra_build_requires = match &target {
|
||||
InstallTarget::Workspace { workspace, .. }
|
||||
| InstallTarget::Project { workspace, .. }
|
||||
| InstallTarget::NonProjectWorkspace { workspace, .. } => {
|
||||
uv_distribution::ExtraBuildRequires::from_workspace(
|
||||
extra_build_dependencies.clone(),
|
||||
workspace,
|
||||
index_locations,
|
||||
sources,
|
||||
)?
|
||||
}
|
||||
InstallTarget::Script { script, .. } => {
|
||||
// Try to get extra build dependencies from the script metadata
|
||||
let resolver_settings = ResolverSettings {
|
||||
build_options: build_options.clone(),
|
||||
config_setting: config_setting.clone(),
|
||||
config_settings_package: config_settings_package.clone(),
|
||||
dependency_metadata: dependency_metadata.clone(),
|
||||
exclude_newer,
|
||||
fork_strategy: ForkStrategy::default(),
|
||||
index_locations: index_locations.clone(),
|
||||
index_strategy,
|
||||
keyring_provider,
|
||||
link_mode,
|
||||
no_build_isolation,
|
||||
no_build_isolation_package: no_build_isolation_package.to_vec(),
|
||||
extra_build_dependencies: extra_build_dependencies.clone(),
|
||||
prerelease: PrereleaseMode::default(),
|
||||
resolution: ResolutionMode::default(),
|
||||
sources,
|
||||
upgrade: Upgrade::default(),
|
||||
build_dependency_strategy: *build_dependency_strategy,
|
||||
};
|
||||
script_specification(Pep723ItemRef::Script(script), &resolver_settings)?
|
||||
.map(|spec| spec.extra_build_requires)
|
||||
.unwrap_or_else(|| uv_distribution::ExtraBuildRequires {
|
||||
extra_build_dependencies: ExtraBuildDependencies::default(),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let client_builder = BaseClientBuilder::new()
|
||||
.retries_from_env()?
|
||||
.connectivity(network_settings.connectivity)
|
||||
|
|
@ -739,6 +806,7 @@ pub(super) async fn do_sync(
|
|||
config_setting,
|
||||
config_settings_package,
|
||||
build_isolation,
|
||||
&extra_build_requires,
|
||||
link_mode,
|
||||
build_options,
|
||||
&build_hasher,
|
||||
|
|
|
|||
|
|
@ -203,6 +203,7 @@ pub(crate) async fn tree(
|
|||
config_settings_package: _,
|
||||
no_build_isolation: _,
|
||||
no_build_isolation_package: _,
|
||||
extra_build_dependencies: _,
|
||||
exclude_newer: _,
|
||||
link_mode: _,
|
||||
upgrade: _,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use uv_requirements::{RequirementsSource, RequirementsSpecification};
|
|||
use uv_settings::{PythonInstallMirrors, ResolverInstallerOptions, ToolOptions};
|
||||
use uv_tool::InstalledTools;
|
||||
use uv_warnings::warn_user;
|
||||
use uv_workspace::WorkspaceCache;
|
||||
use uv_workspace::{WorkspaceCache, pyproject::ExtraBuildDependencies};
|
||||
|
||||
use crate::commands::ExitStatus;
|
||||
use crate::commands::pip::loggers::{DefaultInstallLogger, DefaultResolveLogger};
|
||||
|
|
@ -439,6 +439,7 @@ pub(crate) async fn install(
|
|||
spec,
|
||||
Modifications::Exact,
|
||||
Constraints::from_requirements(build_constraints.iter().cloned()),
|
||||
uv_distribution::ExtraBuildRequires::from_lowered(ExtraBuildDependencies::default()),
|
||||
&settings,
|
||||
&network_settings,
|
||||
&state,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use uv_requirements::RequirementsSpecification;
|
|||
use uv_settings::{Combine, PythonInstallMirrors, ResolverInstallerOptions, ToolOptions};
|
||||
use uv_tool::InstalledTools;
|
||||
use uv_warnings::write_error_chain;
|
||||
use uv_workspace::WorkspaceCache;
|
||||
use uv_workspace::{WorkspaceCache, pyproject::ExtraBuildDependencies};
|
||||
|
||||
use crate::commands::pip::loggers::{
|
||||
DefaultInstallLogger, SummaryResolveLogger, UpgradeInstallLogger,
|
||||
|
|
@ -337,6 +337,7 @@ async fn upgrade_tool(
|
|||
spec,
|
||||
Modifications::Exact,
|
||||
build_constraints,
|
||||
uv_distribution::ExtraBuildRequires::from_lowered(ExtraBuildDependencies::default()),
|
||||
&settings,
|
||||
network_settings,
|
||||
&state,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ use uv_shell::{Shell, shlex_posix, shlex_windows};
|
|||
use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, BuildStack, HashStrategy};
|
||||
use uv_virtualenv::OnExisting;
|
||||
use uv_warnings::warn_user;
|
||||
use uv_workspace::pyproject::ExtraBuildDependencies;
|
||||
use uv_workspace::{DiscoveryOptions, VirtualProject, WorkspaceCache, WorkspaceError};
|
||||
|
||||
use crate::commands::ExitStatus;
|
||||
|
|
@ -266,7 +267,8 @@ pub(crate) async fn venv(
|
|||
|
||||
// Do not allow builds
|
||||
let build_options = BuildOptions::new(NoBinary::None, NoBuild::All);
|
||||
|
||||
let extra_build_requires =
|
||||
uv_distribution::ExtraBuildRequires::from_lowered(ExtraBuildDependencies::default());
|
||||
// Prep the build context.
|
||||
let build_dispatch = BuildDispatch::new(
|
||||
&client,
|
||||
|
|
@ -281,6 +283,7 @@ pub(crate) async fn venv(
|
|||
&config_settings,
|
||||
&config_settings_package,
|
||||
BuildIsolation::Isolated,
|
||||
&extra_build_requires,
|
||||
link_mode,
|
||||
&build_options,
|
||||
&build_hasher,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ use uv_cli::{
|
|||
ProjectCommand, PythonCommand, PythonNamespace, SelfCommand, SelfNamespace, ToolCommand,
|
||||
ToolNamespace, TopLevelArgs, compat::CompatArgs,
|
||||
};
|
||||
use uv_configuration::min_stack_size;
|
||||
use uv_configuration::{PreviewFeatures, min_stack_size};
|
||||
use uv_fs::{CWD, Simplified};
|
||||
#[cfg(feature = "self-update")]
|
||||
use uv_pep440::release_specifiers_to_ranges;
|
||||
|
|
@ -443,6 +443,16 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
|||
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||
let args = PipCompileSettings::resolve(args, filesystem);
|
||||
show_settings!(args);
|
||||
if !args.settings.extra_build_dependencies.is_empty()
|
||||
&& !globals
|
||||
.preview
|
||||
.is_enabled(PreviewFeatures::EXTRA_BUILD_DEPENDENCIES)
|
||||
{
|
||||
warn_user_once!(
|
||||
"The `extra-build-dependencies` setting is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES
|
||||
);
|
||||
}
|
||||
|
||||
// Initialize the cache.
|
||||
let cache = cache.init()?.with_refresh(
|
||||
|
|
@ -516,6 +526,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
|||
args.settings.config_settings_package,
|
||||
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,
|
||||
|
|
@ -543,6 +554,16 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
|||
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||
let args = PipSyncSettings::resolve(args, filesystem);
|
||||
show_settings!(args);
|
||||
if !args.settings.extra_build_dependencies.is_empty()
|
||||
&& !globals
|
||||
.preview
|
||||
.is_enabled(PreviewFeatures::EXTRA_BUILD_DEPENDENCIES)
|
||||
{
|
||||
warn_user_once!(
|
||||
"The `extra-build-dependencies` setting is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES
|
||||
);
|
||||
}
|
||||
|
||||
// Initialize the cache.
|
||||
let cache = cache.init()?.with_refresh(
|
||||
|
|
@ -593,6 +614,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
|||
&args.settings.config_settings_package,
|
||||
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,
|
||||
|
|
@ -621,6 +643,16 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
|||
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||
let mut args = PipInstallSettings::resolve(args, filesystem);
|
||||
show_settings!(args);
|
||||
if !args.settings.extra_build_dependencies.is_empty()
|
||||
&& !globals
|
||||
.preview
|
||||
.is_enabled(PreviewFeatures::EXTRA_BUILD_DEPENDENCIES)
|
||||
{
|
||||
warn_user_once!(
|
||||
"The `extra-build-dependencies` setting is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
|
||||
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES
|
||||
);
|
||||
}
|
||||
|
||||
let mut requirements = Vec::with_capacity(
|
||||
args.package.len() + args.editables.len() + args.requirements.len(),
|
||||
|
|
@ -735,6 +767,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
|||
&args.settings.config_settings_package,
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -2708,6 +2708,7 @@ pub(crate) struct InstallerSettingsRef<'a> {
|
|||
pub(crate) config_settings_package: &'a PackageConfigSettings,
|
||||
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<ExcludeNewer>,
|
||||
pub(crate) link_mode: LinkMode,
|
||||
pub(crate) compile_bytecode: bool,
|
||||
|
|
@ -2735,6 +2736,7 @@ pub(crate) struct ResolverSettings {
|
|||
pub(crate) link_mode: LinkMode,
|
||||
pub(crate) no_build_isolation: bool,
|
||||
pub(crate) no_build_isolation_package: Vec<PackageName>,
|
||||
pub(crate) extra_build_dependencies: ExtraBuildDependencies,
|
||||
pub(crate) prerelease: PrereleaseMode,
|
||||
pub(crate) resolution: ResolutionMode,
|
||||
pub(crate) sources: SourceStrategy,
|
||||
|
|
@ -2788,6 +2790,7 @@ impl From<ResolverOptions> for ResolverSettings {
|
|||
config_settings_package: value.config_settings_package.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()),
|
||||
|
|
@ -2878,6 +2881,7 @@ impl From<ResolverInstallerOptions> 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()),
|
||||
|
|
@ -2921,6 +2925,7 @@ pub(crate) struct PipSettings {
|
|||
pub(crate) torch_backend: Option<TorchMode>,
|
||||
pub(crate) no_build_isolation: bool,
|
||||
pub(crate) no_build_isolation_package: Vec<PackageName>,
|
||||
pub(crate) extra_build_dependencies: ExtraBuildDependencies,
|
||||
pub(crate) build_options: BuildOptions,
|
||||
pub(crate) allow_empty_requirements: bool,
|
||||
pub(crate) strict: bool,
|
||||
|
|
@ -2988,6 +2993,7 @@ impl PipSettings {
|
|||
only_binary,
|
||||
no_build_isolation,
|
||||
no_build_isolation_package,
|
||||
extra_build_dependencies,
|
||||
strict,
|
||||
extra,
|
||||
all_extras,
|
||||
|
|
@ -3046,6 +3052,7 @@ impl PipSettings {
|
|||
config_settings_package: top_level_config_settings_package,
|
||||
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,
|
||||
|
|
@ -3082,6 +3089,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);
|
||||
|
|
@ -3177,6 +3186,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)
|
||||
|
|
@ -3281,6 +3294,7 @@ impl<'a> From<&'a ResolverInstallerSettings> for InstallerSettingsRef<'a> {
|
|||
config_settings_package: &settings.resolver.config_settings_package,
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -3920,16 +3920,17 @@ fn config_settings_registry() {
|
|||
.arg("iniconfig")
|
||||
.arg("--no-binary")
|
||||
.arg("iniconfig")
|
||||
.arg("-C=global-option=build_ext"), @r###"
|
||||
.arg("-C=global-option=build_ext"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 1 package in [TIME]
|
||||
Prepared 1 package in [TIME]
|
||||
Installed 1 package in [TIME]
|
||||
+ iniconfig==2.0.0
|
||||
"###
|
||||
"
|
||||
);
|
||||
|
||||
// Uninstall the package.
|
||||
|
|
|
|||
|
|
@ -184,6 +184,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,
|
||||
|
|
@ -373,6 +374,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,
|
||||
|
|
@ -563,6 +565,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,
|
||||
|
|
@ -785,6 +788,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,
|
||||
|
|
@ -942,6 +946,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,
|
||||
|
|
@ -1143,6 +1148,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,
|
||||
|
|
@ -1392,6 +1398,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,
|
||||
|
|
@ -1651,6 +1658,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,
|
||||
|
|
@ -1865,6 +1873,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,
|
||||
|
|
@ -2044,6 +2053,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,
|
||||
|
|
@ -2283,6 +2293,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,
|
||||
|
|
@ -2505,6 +2516,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,
|
||||
|
|
@ -2683,6 +2695,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,
|
||||
|
|
@ -2845,6 +2858,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,
|
||||
|
|
@ -3007,6 +3021,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,
|
||||
|
|
@ -3171,6 +3186,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,
|
||||
|
|
@ -3327,6 +3343,7 @@ fn resolve_tool() -> anyhow::Result<()> {
|
|||
config_settings_package: None,
|
||||
no_build_isolation: None,
|
||||
no_build_isolation_package: None,
|
||||
extra_build_dependencies: None,
|
||||
exclude_newer: None,
|
||||
link_mode: Some(
|
||||
Clone,
|
||||
|
|
@ -3369,6 +3386,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,
|
||||
|
|
@ -3527,6 +3545,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,
|
||||
|
|
@ -3757,6 +3776,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,
|
||||
|
|
@ -3991,6 +4011,7 @@ fn resolve_both_special_fields() -> 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,
|
||||
|
|
@ -4304,6 +4325,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,
|
||||
|
|
@ -4384,7 +4406,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`, `config-settings-package`, `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`, `config-settings-package`, `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`
|
||||
"
|
||||
);
|
||||
|
||||
|
|
@ -4559,6 +4581,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,
|
||||
|
|
@ -4724,6 +4747,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,
|
||||
|
|
@ -4908,6 +4932,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,
|
||||
|
|
@ -5153,6 +5178,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,
|
||||
|
|
@ -5377,6 +5403,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,
|
||||
|
|
@ -5607,6 +5634,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,
|
||||
|
|
@ -5832,6 +5860,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,
|
||||
|
|
@ -6064,6 +6093,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,
|
||||
|
|
@ -6289,6 +6319,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,
|
||||
|
|
@ -6458,6 +6489,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,
|
||||
|
|
@ -6613,6 +6645,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,
|
||||
|
|
@ -6766,6 +6799,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,
|
||||
|
|
@ -6921,6 +6955,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,
|
||||
|
|
@ -7074,6 +7109,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,
|
||||
|
|
@ -7228,6 +7264,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,
|
||||
|
|
@ -7320,7 +7357,7 @@ fn preview_features() {
|
|||
show_settings: true,
|
||||
preview: Preview {
|
||||
flags: PreviewFeatures(
|
||||
PYTHON_INSTALL_DEFAULT | PYTHON_UPGRADE | JSON_OUTPUT | PYLOCK | ADD_BOUNDS,
|
||||
PYTHON_INSTALL_DEFAULT | PYTHON_UPGRADE | JSON_OUTPUT | PYLOCK | ADD_BOUNDS | EXTRA_BUILD_DEPENDENCIES,
|
||||
),
|
||||
},
|
||||
python_preference: Managed,
|
||||
|
|
@ -7386,6 +7423,7 @@ fn preview_features() {
|
|||
link_mode: Clone,
|
||||
no_build_isolation: false,
|
||||
no_build_isolation_package: [],
|
||||
extra_build_dependencies: {},
|
||||
prerelease: IfNecessaryOrExplicit,
|
||||
resolution: Highest,
|
||||
sources: Enabled,
|
||||
|
|
@ -7488,6 +7526,7 @@ fn preview_features() {
|
|||
link_mode: Clone,
|
||||
no_build_isolation: false,
|
||||
no_build_isolation_package: [],
|
||||
extra_build_dependencies: {},
|
||||
prerelease: IfNecessaryOrExplicit,
|
||||
resolution: Highest,
|
||||
sources: Enabled,
|
||||
|
|
@ -7524,7 +7563,7 @@ fn preview_features() {
|
|||
show_settings: true,
|
||||
preview: Preview {
|
||||
flags: PreviewFeatures(
|
||||
PYTHON_INSTALL_DEFAULT | PYTHON_UPGRADE | JSON_OUTPUT | PYLOCK | ADD_BOUNDS,
|
||||
PYTHON_INSTALL_DEFAULT | PYTHON_UPGRADE | JSON_OUTPUT | PYLOCK | ADD_BOUNDS | EXTRA_BUILD_DEPENDENCIES,
|
||||
),
|
||||
},
|
||||
python_preference: Managed,
|
||||
|
|
@ -7590,6 +7629,7 @@ fn preview_features() {
|
|||
link_mode: Clone,
|
||||
no_build_isolation: false,
|
||||
no_build_isolation_package: [],
|
||||
extra_build_dependencies: {},
|
||||
prerelease: IfNecessaryOrExplicit,
|
||||
resolution: Highest,
|
||||
sources: Enabled,
|
||||
|
|
@ -7692,6 +7732,7 @@ fn preview_features() {
|
|||
link_mode: Clone,
|
||||
no_build_isolation: false,
|
||||
no_build_isolation_package: [],
|
||||
extra_build_dependencies: {},
|
||||
prerelease: IfNecessaryOrExplicit,
|
||||
resolution: Highest,
|
||||
sources: Enabled,
|
||||
|
|
@ -7794,6 +7835,7 @@ fn preview_features() {
|
|||
link_mode: Clone,
|
||||
no_build_isolation: false,
|
||||
no_build_isolation_package: [],
|
||||
extra_build_dependencies: {},
|
||||
prerelease: IfNecessaryOrExplicit,
|
||||
resolution: Highest,
|
||||
sources: Enabled,
|
||||
|
|
@ -7898,6 +7940,7 @@ fn preview_features() {
|
|||
link_mode: Clone,
|
||||
no_build_isolation: false,
|
||||
no_build_isolation_package: [],
|
||||
extra_build_dependencies: {},
|
||||
prerelease: IfNecessaryOrExplicit,
|
||||
resolution: Highest,
|
||||
sources: Enabled,
|
||||
|
|
|
|||
|
|
@ -1567,6 +1567,401 @@ fn sync_build_isolation_extra() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_extra_build_dependencies() -> Result<()> {
|
||||
let context = TestContext::new("3.12").with_filtered_counts();
|
||||
|
||||
// Write a test package that arbitrarily requires `anyio` at build time
|
||||
let child = context.temp_dir.child("child");
|
||||
child.create_dir_all()?;
|
||||
let child_pyproject_toml = child.child("pyproject.toml");
|
||||
child_pyproject_toml.write_str(indoc! {r#"
|
||||
[project]
|
||||
name = "child"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.9"
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
backend-path = ["."]
|
||||
build-backend = "build_backend"
|
||||
"#})?;
|
||||
let build_backend = child.child("build_backend.py");
|
||||
build_backend.write_str(indoc! {r#"
|
||||
import sys
|
||||
|
||||
from hatchling.build import *
|
||||
|
||||
try:
|
||||
import anyio
|
||||
except ModuleNotFoundError:
|
||||
print("Missing `anyio` module", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
"#})?;
|
||||
child.child("src/child/__init__.py").touch()?;
|
||||
|
||||
let parent = &context.temp_dir;
|
||||
let pyproject_toml = parent.child("pyproject.toml");
|
||||
pyproject_toml.write_str(indoc! {r#"
|
||||
[project]
|
||||
name = "parent"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.9"
|
||||
dependencies = ["child"]
|
||||
|
||||
[tool.uv.sources]
|
||||
child = { path = "child" }
|
||||
"#})?;
|
||||
|
||||
context.venv().arg("--clear").assert().success();
|
||||
// Running `uv sync` should fail due to missing build-dependencies
|
||||
uv_snapshot!(context.filters(), context.sync(), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved [N] packages in [TIME]
|
||||
× Failed to build `child @ file://[TEMP_DIR]/child`
|
||||
├─▶ The build backend returned an error
|
||||
╰─▶ Call to `build_backend.build_wheel` failed (exit status: 1)
|
||||
|
||||
[stderr]
|
||||
Missing `anyio` module
|
||||
|
||||
hint: This usually indicates a problem with the package or the build environment.
|
||||
help: `child` was included because `parent` (v0.1.0) depends on `child`
|
||||
");
|
||||
|
||||
// Adding `extra-build-dependencies` should solve the issue
|
||||
pyproject_toml.write_str(indoc! {r#"
|
||||
[project]
|
||||
name = "parent"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.9"
|
||||
dependencies = ["child"]
|
||||
|
||||
[tool.uv.sources]
|
||||
child = { path = "child" }
|
||||
|
||||
[tool.uv.extra-build-dependencies]
|
||||
child = ["anyio"]
|
||||
"#})?;
|
||||
|
||||
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]
|
||||
Prepared [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#"
|
||||
[project]
|
||||
name = "parent"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.9"
|
||||
dependencies = ["child"]
|
||||
|
||||
[tool.uv.sources]
|
||||
child = { path = "child" }
|
||||
|
||||
[tool.uv.extra-build-dependencies]
|
||||
wrong_name = ["anyio"]
|
||||
"#})?;
|
||||
|
||||
context.venv().arg("--clear").assert().success();
|
||||
uv_snapshot!(context.filters(), context.sync(), @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.
|
||||
Resolved [N] packages in [TIME]
|
||||
× Failed to build `child @ file://[TEMP_DIR]/child`
|
||||
├─▶ The build backend returned an error
|
||||
╰─▶ Call to `build_backend.build_wheel` failed (exit status: 1)
|
||||
|
||||
[stderr]
|
||||
Missing `anyio` module
|
||||
|
||||
hint: This usually indicates a problem with the package or the build environment.
|
||||
help: `child` was included because `parent` (v0.1.0) depends on `child`
|
||||
");
|
||||
|
||||
// Write a test package that arbitrarily bans `anyio` at build time
|
||||
let bad_child = context.temp_dir.child("bad_child");
|
||||
bad_child.create_dir_all()?;
|
||||
let bad_child_pyproject_toml = bad_child.child("pyproject.toml");
|
||||
bad_child_pyproject_toml.write_str(indoc! {r#"
|
||||
[project]
|
||||
name = "bad_child"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.9"
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
backend-path = ["."]
|
||||
build-backend = "build_backend"
|
||||
"#})?;
|
||||
let build_backend = bad_child.child("build_backend.py");
|
||||
build_backend.write_str(indoc! {r#"
|
||||
import sys
|
||||
|
||||
from hatchling.build import *
|
||||
|
||||
try:
|
||||
import anyio
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
else:
|
||||
print("Found `anyio` module", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
"#})?;
|
||||
bad_child.child("src/bad_child/__init__.py").touch()?;
|
||||
|
||||
// Depend on `bad_child` too
|
||||
pyproject_toml.write_str(indoc! {r#"
|
||||
[project]
|
||||
name = "parent"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.9"
|
||||
dependencies = ["child", "bad_child"]
|
||||
|
||||
[tool.uv.sources]
|
||||
child = { path = "child" }
|
||||
bad_child = { path = "bad_child" }
|
||||
|
||||
[tool.uv.extra-build-dependencies]
|
||||
child = ["anyio"]
|
||||
bad_child = ["anyio"]
|
||||
"#})?;
|
||||
|
||||
// Confirm that `bad_child` fails if anyio is provided
|
||||
context.venv().arg("--clear").assert().success();
|
||||
uv_snapshot!(context.filters(), context.sync(), @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.
|
||||
Resolved [N] packages in [TIME]
|
||||
× Failed to build `bad-child @ file://[TEMP_DIR]/bad_child`
|
||||
├─▶ The build backend returned an error
|
||||
╰─▶ Call to `build_backend.build_wheel` failed (exit status: 1)
|
||||
|
||||
[stderr]
|
||||
Found `anyio` module
|
||||
|
||||
hint: This usually indicates a problem with the package or the build environment.
|
||||
help: `bad-child` was included because `parent` (v0.1.0) depends on `bad-child`
|
||||
");
|
||||
|
||||
// But `anyio` is not provided to `bad_child` if scoped to `child`
|
||||
pyproject_toml.write_str(indoc! {r#"
|
||||
[project]
|
||||
name = "parent"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.9"
|
||||
dependencies = ["child", "bad_child"]
|
||||
|
||||
[tool.uv.sources]
|
||||
child = { path = "child" }
|
||||
bad_child = { path = "bad_child" }
|
||||
|
||||
[tool.uv.extra-build-dependencies]
|
||||
child = ["anyio"]
|
||||
"#})?;
|
||||
|
||||
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]
|
||||
Prepared [N] packages in [TIME]
|
||||
Installed [N] packages in [TIME]
|
||||
+ bad-child==0.1.0 (from file://[TEMP_DIR]/bad_child)
|
||||
+ child==0.1.0 (from file://[TEMP_DIR]/child)
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_extra_build_dependencies_sources() -> Result<()> {
|
||||
let context = TestContext::new("3.12").with_filtered_counts();
|
||||
|
||||
let anyio_local = context.workspace_root.join("scripts/packages/anyio_local");
|
||||
|
||||
// Write a test package that arbitrarily requires `anyio` at a specific _path_ at build time
|
||||
let child = context.temp_dir.child("child");
|
||||
child.create_dir_all()?;
|
||||
let child_pyproject_toml = child.child("pyproject.toml");
|
||||
child_pyproject_toml.write_str(indoc! {r#"
|
||||
[project]
|
||||
name = "child"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.9"
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
backend-path = ["."]
|
||||
build-backend = "build_backend"
|
||||
"#})?;
|
||||
let build_backend = child.child("build_backend.py");
|
||||
build_backend.write_str(&formatdoc! {r#"
|
||||
import sys
|
||||
|
||||
from hatchling.build import *
|
||||
|
||||
try:
|
||||
import anyio
|
||||
except ModuleNotFoundError:
|
||||
print("Missing `anyio` module", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Check that we got the local version of anyio by checking for the marker
|
||||
if not hasattr(anyio, 'LOCAL_ANYIO_MARKER'):
|
||||
print("Found system anyio instead of local anyio", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
"#})?;
|
||||
child.child("src/child/__init__.py").touch()?;
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(&formatdoc! {r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["child"]
|
||||
|
||||
[tool.uv.sources]
|
||||
anyio = {{ path = "{anyio_local}" }}
|
||||
child = {{ path = "child" }}
|
||||
|
||||
[tool.uv.extra-build-dependencies]
|
||||
child = ["anyio"]
|
||||
"#,
|
||||
anyio_local = anyio_local.portable_display(),
|
||||
})?;
|
||||
|
||||
// Running `uv sync` should succeed, as `anyio` is provided as a source
|
||||
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]
|
||||
Prepared [N] packages in [TIME]
|
||||
Installed [N] packages in [TIME]
|
||||
+ child==0.1.0 (from file://[TEMP_DIR]/child)
|
||||
");
|
||||
|
||||
// TODO(zanieb): We want to test with `--no-sources` too but unfortunately that's not easy
|
||||
// because it'll disable the `child` path source too!
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_extra_build_dependencies_sources_from_child() -> Result<()> {
|
||||
let context = TestContext::new("3.12").with_filtered_counts();
|
||||
|
||||
let anyio_local = context.workspace_root.join("scripts/packages/anyio_local");
|
||||
|
||||
// Write a test package that arbitrarily requires `anyio` at a specific _path_ at build time
|
||||
let child = context.temp_dir.child("child");
|
||||
child.create_dir_all()?;
|
||||
let child_pyproject_toml = child.child("pyproject.toml");
|
||||
child_pyproject_toml.write_str(&formatdoc! {r#"
|
||||
[project]
|
||||
name = "child"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.9"
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
backend-path = ["."]
|
||||
build-backend = "build_backend"
|
||||
|
||||
[tool.uv.sources]
|
||||
anyio = {{ path = "{}" }}
|
||||
"#, anyio_local.portable_display()
|
||||
})?;
|
||||
let build_backend = child.child("build_backend.py");
|
||||
build_backend.write_str(&formatdoc! {r#"
|
||||
import sys
|
||||
|
||||
from hatchling.build import *
|
||||
|
||||
try:
|
||||
import anyio
|
||||
except ModuleNotFoundError:
|
||||
print("Missing `anyio` module", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Check that we got the local version of anyio by checking for the marker
|
||||
if not hasattr(anyio, 'LOCAL_ANYIO_MARKER'):
|
||||
print("Found system anyio instead of local anyio", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
"#})?;
|
||||
child.child("src/child/__init__.py").touch()?;
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(indoc! {r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["child"]
|
||||
|
||||
[tool.uv.sources]
|
||||
child = { path = "child" }
|
||||
|
||||
[tool.uv.extra-build-dependencies]
|
||||
child = ["anyio"]
|
||||
"#,
|
||||
})?;
|
||||
|
||||
// Running `uv sync` should fail due to the unapplied source
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--reinstall").arg("--refresh"), @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.
|
||||
Resolved [N] packages in [TIME]
|
||||
× Failed to build `child @ file://[TEMP_DIR]/child`
|
||||
├─▶ The build backend returned an error
|
||||
╰─▶ Call to `build_backend.build_wheel` failed (exit status: 1)
|
||||
|
||||
[stderr]
|
||||
Found system anyio instead of local anyio
|
||||
|
||||
hint: This usually indicates a problem with the package or the build environment.
|
||||
help: `child` was included because `project` (v0.1.0) depends on `child`
|
||||
");
|
||||
|
||||
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
|
||||
|
|
@ -4198,6 +4593,187 @@ fn no_install_project_no_build() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_extra_build_dependencies_script() -> Result<()> {
|
||||
let context = TestContext::new("3.12").with_filtered_counts();
|
||||
|
||||
// Write a test package that arbitrarily requires `anyio` at build time
|
||||
let child = context.temp_dir.child("child");
|
||||
child.create_dir_all()?;
|
||||
let child_pyproject_toml = child.child("pyproject.toml");
|
||||
child_pyproject_toml.write_str(indoc! {r#"
|
||||
[project]
|
||||
name = "child"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.9"
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
backend-path = ["."]
|
||||
build-backend = "build_backend"
|
||||
"#})?;
|
||||
let build_backend = child.child("build_backend.py");
|
||||
build_backend.write_str(indoc! {r#"
|
||||
import sys
|
||||
from hatchling.build import *
|
||||
try:
|
||||
import anyio
|
||||
except ModuleNotFoundError:
|
||||
print("Missing `anyio` module", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
"#})?;
|
||||
child.child("src/child/__init__.py").touch()?;
|
||||
|
||||
// Create a script that depends on the child package
|
||||
let script = context.temp_dir.child("script.py");
|
||||
script.write_str(indoc! {r#"
|
||||
# /// script
|
||||
# requires-python = ">=3.12"
|
||||
# dependencies = ["child"]
|
||||
#
|
||||
# [tool.uv.sources]
|
||||
# child = { path = "child" }
|
||||
# ///
|
||||
"#})?;
|
||||
|
||||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain(vec![(
|
||||
r"environments-v2/script-[a-z0-9]+",
|
||||
"environments-v2/script-[HASH]",
|
||||
)])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Running `uv sync` should fail due to missing build-dependencies
|
||||
uv_snapshot!(filters, context.sync().arg("--script").arg("script.py"), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Creating script environment at: [CACHE_DIR]/environments-v2/script-[HASH]
|
||||
Resolved [N] packages in [TIME]
|
||||
× Failed to build `child @ file://[TEMP_DIR]/child`
|
||||
├─▶ The build backend returned an error
|
||||
╰─▶ Call to `build_backend.build_wheel` failed (exit status: 1)
|
||||
|
||||
[stderr]
|
||||
Missing `anyio` module
|
||||
|
||||
hint: This usually indicates a problem with the package or the build environment.
|
||||
");
|
||||
|
||||
// Add extra build dependencies to the script
|
||||
script.write_str(indoc! {r#"
|
||||
# /// script
|
||||
# requires-python = ">=3.12"
|
||||
# dependencies = ["child"]
|
||||
#
|
||||
# [tool.uv.sources]
|
||||
# child = { path = "child" }
|
||||
#
|
||||
# [tool.uv.extra-build-dependencies]
|
||||
# child = ["anyio"]
|
||||
# ///
|
||||
"#})?;
|
||||
|
||||
// Running `uv sync` should now succeed due to extra build-dependencies
|
||||
context.venv().arg("--clear").assert().success();
|
||||
uv_snapshot!(filters, context.sync().arg("--script").arg("script.py"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using script environment at: [CACHE_DIR]/environments-v2/script-[HASH]
|
||||
Resolved [N] packages in [TIME]
|
||||
Prepared [N] packages in [TIME]
|
||||
Installed [N] packages in [TIME]
|
||||
+ child==0.1.0 (from file://[TEMP_DIR]/child)
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_extra_build_dependencies_script_sources() -> Result<()> {
|
||||
let context = TestContext::new("3.12").with_filtered_counts();
|
||||
let anyio_local = context.workspace_root.join("scripts/packages/anyio_local");
|
||||
|
||||
// Write a test package that arbitrarily requires `anyio` at a specific _path_ at build time
|
||||
let child = context.temp_dir.child("child");
|
||||
child.create_dir_all()?;
|
||||
let child_pyproject_toml = child.child("pyproject.toml");
|
||||
child_pyproject_toml.write_str(indoc! {r#"
|
||||
[project]
|
||||
name = "child"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.9"
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
backend-path = ["."]
|
||||
build-backend = "build_backend"
|
||||
"#})?;
|
||||
let build_backend = child.child("build_backend.py");
|
||||
build_backend.write_str(&formatdoc! {r#"
|
||||
import sys
|
||||
from hatchling.build import *
|
||||
try:
|
||||
import anyio
|
||||
except ModuleNotFoundError:
|
||||
print("Missing `anyio` module", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Check that we got the local version of anyio by checking for the marker
|
||||
if not hasattr(anyio, 'LOCAL_ANYIO_MARKER'):
|
||||
print("Found system anyio instead of local anyio", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
"#})?;
|
||||
child.child("src/child/__init__.py").touch()?;
|
||||
|
||||
// Create a script that depends on the child package
|
||||
let script = context.temp_dir.child("script.py");
|
||||
script.write_str(&formatdoc! {r#"
|
||||
# /// script
|
||||
# requires-python = ">=3.12"
|
||||
# dependencies = ["child"]
|
||||
#
|
||||
# [tool.uv.sources]
|
||||
# anyio = {{ path = "{}" }}
|
||||
# child = {{ path = "child" }}
|
||||
#
|
||||
# [tool.uv.extra-build-dependencies]
|
||||
# child = ["anyio"]
|
||||
# ///
|
||||
"#, anyio_local.portable_display()
|
||||
})?;
|
||||
|
||||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain(vec![(
|
||||
r"environments-v2/script-[a-z0-9]+",
|
||||
"environments-v2/script-[HASH]",
|
||||
)])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Running `uv sync` should succeed with the sources applied
|
||||
uv_snapshot!(filters, context.sync().arg("--script").arg("script.py"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Creating script environment at: [CACHE_DIR]/environments-v2/script-[HASH]
|
||||
Resolved [N] packages in [TIME]
|
||||
Prepared [N] packages in [TIME]
|
||||
Installed [N] packages in [TIME]
|
||||
+ child==0.1.0 (from file://[TEMP_DIR]/child)
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn virtual_no_build() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
|
|
|||
|
|
@ -202,6 +202,28 @@ 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"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### [`index`](#index) {: #index }
|
||||
|
||||
The indexes to use when resolving dependencies.
|
||||
|
|
@ -1135,6 +1157,36 @@ behave consistently across timezones.
|
|||
|
||||
---
|
||||
|
||||
### [`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**:
|
||||
|
||||
=== "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`.
|
||||
|
|
@ -2596,6 +2648,38 @@ Only applies to `pyproject.toml`, `setup.py`, and `setup.cfg` sources.
|
|||
|
||||
---
|
||||
|
||||
#### [`extra-build-dependencies`](#pip_extra-build-dependencies) {: #pip_extra-build-dependencies }
|
||||
<span id="extra-build-dependencies"></span>
|
||||
|
||||
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**:
|
||||
|
||||
=== "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 }
|
||||
<span id="extra-index-url"></span>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
# This is a local dummy anyio package
|
||||
LOCAL_ANYIO_MARKER = True
|
||||
|
|
@ -225,6 +225,17 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"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.",
|
||||
"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/)\n(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\n[`index_url`](#index-url) or [`index`](#index) with `default = true`. When multiple indexes\nare provided, earlier values take priority.\n\nTo control uv's resolution strategy when multiple indexes are present, see\n[`index_strategy`](#index-strategy).\n\n(Deprecated: use `index` instead.)",
|
||||
"type": [
|
||||
|
|
@ -1312,6 +1323,19 @@
|
|||
"$ref": "#/definitions/ExtraName"
|
||||
}
|
||||
},
|
||||
"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.",
|
||||
"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/)\n(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\n[`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\n[`index_strategy`](#index-strategy).",
|
||||
"type": [
|
||||
|
|
@ -2341,6 +2365,15 @@
|
|||
"$ref": "#/definitions/DependencyGroupSettings"
|
||||
}
|
||||
},
|
||||
"ToolUvExtraBuildDependencies": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Requirement"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ToolUvSources": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
|
|
|
|||
Loading…
Reference in New Issue