mirror of https://github.com/astral-sh/uv
Add `extra-build-dependencies` (#14735)
Replaces https://github.com/astral-sh/uv/pull/14092 Adds `tool.uv.extra-build-dependencies = {package = [dependency, ...]}` which extends `build-system.requires` during package builds. These are lowered via workspace sources, are applied to transitive dependencies, and are included in the wheel cache shard hash. There are some features we need to follow-up on, but are out of scope here: - Preferring locked versions for build dependencies - Settings for requiring locked versions for build depencies There are some quality of life follow-ups we should also do: - Warn on `extra-build-dependencies` that do not apply to any packages - Add test cases and improve error messaging when the `extra-build-dependencies` resolve fails ------- There ~are~ were a few open decisions to be made here 1. Should we resolve these dependencies alongside the `build-system.requires` dependencies? Or should we resolve separately? (I think the latter is more powerful? because you can override things? but it opens the door to breaking your build) 2. Should we install these dependencies into the same environment? Or should we layer it on top as we do elsewhere? (I think it's fine to install into the same environment) 3. Should we respect sources defined in the parent project? (I think yes, but then we need to lower the dependencies earlier — I don't think that's a big deal, but it's not implemented) 4. Should we respect sources defined in the child project? (I think no, this gets really complicated and seems weird to allow) 5. Should we apply this to transitive dependencies? (I think so) --------- Co-authored-by: Aria Desires <aria.desires@gmail.com> Co-authored-by: konstin <konstin@mailbox.org>
This commit is contained in:
parent
17f0c91896
commit
6856a27711
|
|
@ -5516,6 +5516,7 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
"unicode-width 0.2.1",
|
"unicode-width 0.2.1",
|
||||||
"unscanny",
|
"unscanny",
|
||||||
|
"uv-cache-key",
|
||||||
"version-ranges",
|
"version-ranges",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -5539,6 +5540,7 @@ dependencies = [
|
||||||
"tracing-test",
|
"tracing-test",
|
||||||
"unicode-width 0.2.1",
|
"unicode-width 0.2.1",
|
||||||
"url",
|
"url",
|
||||||
|
"uv-cache-key",
|
||||||
"uv-fs",
|
"uv-fs",
|
||||||
"uv-normalize",
|
"uv-normalize",
|
||||||
"uv-pep440",
|
"uv-pep440",
|
||||||
|
|
@ -5864,6 +5866,8 @@ dependencies = [
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"toml",
|
"toml",
|
||||||
"url",
|
"url",
|
||||||
|
"uv-configuration",
|
||||||
|
"uv-distribution-types",
|
||||||
"uv-pep440",
|
"uv-pep440",
|
||||||
"uv-pep508",
|
"uv-pep508",
|
||||||
"uv-pypi-types",
|
"uv-pypi-types",
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,7 @@ mod resolver {
|
||||||
universal: bool,
|
universal: bool,
|
||||||
) -> Result<ResolverOutput> {
|
) -> Result<ResolverOutput> {
|
||||||
let build_isolation = BuildIsolation::default();
|
let build_isolation = BuildIsolation::default();
|
||||||
|
let extra_build_requires = uv_distribution::ExtraBuildRequires::default();
|
||||||
let build_options = BuildOptions::default();
|
let build_options = BuildOptions::default();
|
||||||
let concurrency = Concurrency::default();
|
let concurrency = Concurrency::default();
|
||||||
let config_settings = ConfigSettings::default();
|
let config_settings = ConfigSettings::default();
|
||||||
|
|
@ -189,6 +190,7 @@ mod resolver {
|
||||||
&config_settings,
|
&config_settings,
|
||||||
&config_settings_package,
|
&config_settings_package,
|
||||||
build_isolation,
|
build_isolation,
|
||||||
|
&extra_build_requires,
|
||||||
LinkMode::default(),
|
LinkMode::default(),
|
||||||
&build_options,
|
&build_options,
|
||||||
&hashes,
|
&hashes,
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::fmt::Formatter;
|
use std::fmt::Formatter;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
@ -42,6 +43,7 @@ use uv_static::EnvVars;
|
||||||
use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, BuildStack, SourceBuildTrait};
|
use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, BuildStack, SourceBuildTrait};
|
||||||
use uv_warnings::warn_user_once;
|
use uv_warnings::warn_user_once;
|
||||||
use uv_workspace::WorkspaceCache;
|
use uv_workspace::WorkspaceCache;
|
||||||
|
use uv_workspace::pyproject::ExtraBuildDependencies;
|
||||||
|
|
||||||
pub use crate::error::{Error, MissingHeaderCause};
|
pub use crate::error::{Error, MissingHeaderCause};
|
||||||
|
|
||||||
|
|
@ -281,6 +283,7 @@ impl SourceBuild {
|
||||||
workspace_cache: &WorkspaceCache,
|
workspace_cache: &WorkspaceCache,
|
||||||
config_settings: ConfigSettings,
|
config_settings: ConfigSettings,
|
||||||
build_isolation: BuildIsolation<'_>,
|
build_isolation: BuildIsolation<'_>,
|
||||||
|
extra_build_dependencies: &ExtraBuildDependencies,
|
||||||
build_stack: &BuildStack,
|
build_stack: &BuildStack,
|
||||||
build_kind: BuildKind,
|
build_kind: BuildKind,
|
||||||
mut environment_variables: FxHashMap<OsString, OsString>,
|
mut environment_variables: FxHashMap<OsString, OsString>,
|
||||||
|
|
@ -297,7 +300,6 @@ impl SourceBuild {
|
||||||
};
|
};
|
||||||
|
|
||||||
let default_backend: Pep517Backend = DEFAULT_BACKEND.clone();
|
let default_backend: Pep517Backend = DEFAULT_BACKEND.clone();
|
||||||
|
|
||||||
// Check if we have a PEP 517 build backend.
|
// Check if we have a PEP 517 build backend.
|
||||||
let (pep517_backend, project) = Self::extract_pep517_backend(
|
let (pep517_backend, project) = Self::extract_pep517_backend(
|
||||||
&source_tree,
|
&source_tree,
|
||||||
|
|
@ -322,6 +324,14 @@ impl SourceBuild {
|
||||||
.or(fallback_package_version)
|
.or(fallback_package_version)
|
||||||
.cloned();
|
.cloned();
|
||||||
|
|
||||||
|
let extra_build_dependencies: Vec<Requirement> = 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.
|
// 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()) {
|
let venv = if let Some(venv) = build_isolation.shared_environment(package_name.as_ref()) {
|
||||||
venv.clone()
|
venv.clone()
|
||||||
|
|
@ -344,11 +354,18 @@ impl SourceBuild {
|
||||||
if build_isolation.is_isolated(package_name.as_ref()) {
|
if build_isolation.is_isolated(package_name.as_ref()) {
|
||||||
debug!("Resolving build requirements");
|
debug!("Resolving build requirements");
|
||||||
|
|
||||||
|
let dependency_sources = if extra_build_dependencies.is_empty() {
|
||||||
|
"`build-system.requires`"
|
||||||
|
} else {
|
||||||
|
"`build-system.requires` and `extra-build-dependencies`"
|
||||||
|
};
|
||||||
|
|
||||||
let resolved_requirements = Self::get_resolved_requirements(
|
let resolved_requirements = Self::get_resolved_requirements(
|
||||||
build_context,
|
build_context,
|
||||||
source_build_context,
|
source_build_context,
|
||||||
&default_backend,
|
&default_backend,
|
||||||
&pep517_backend,
|
&pep517_backend,
|
||||||
|
extra_build_dependencies,
|
||||||
build_stack,
|
build_stack,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
@ -356,7 +373,7 @@ impl SourceBuild {
|
||||||
build_context
|
build_context
|
||||||
.install(&resolved_requirements, &venv, build_stack)
|
.install(&resolved_requirements, &venv, build_stack)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| Error::RequirementsInstall("`build-system.requires`", err.into()))?;
|
.map_err(|err| Error::RequirementsInstall(dependency_sources, err.into()))?;
|
||||||
} else {
|
} else {
|
||||||
debug!("Proceeding without build isolation");
|
debug!("Proceeding without build isolation");
|
||||||
}
|
}
|
||||||
|
|
@ -471,10 +488,13 @@ impl SourceBuild {
|
||||||
source_build_context: SourceBuildContext,
|
source_build_context: SourceBuildContext,
|
||||||
default_backend: &Pep517Backend,
|
default_backend: &Pep517Backend,
|
||||||
pep517_backend: &Pep517Backend,
|
pep517_backend: &Pep517Backend,
|
||||||
|
extra_build_dependencies: Vec<Requirement>,
|
||||||
build_stack: &BuildStack,
|
build_stack: &BuildStack,
|
||||||
) -> Result<Resolution, Error> {
|
) -> Result<Resolution, Error> {
|
||||||
Ok(
|
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;
|
let mut resolution = source_build_context.default_resolution.lock().await;
|
||||||
if let Some(resolved_requirements) = &*resolution {
|
if let Some(resolved_requirements) = &*resolution {
|
||||||
resolved_requirements.clone()
|
resolved_requirements.clone()
|
||||||
|
|
@ -489,12 +509,25 @@ impl SourceBuild {
|
||||||
resolved_requirements
|
resolved_requirements
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
let (requirements, dependency_sources) = if extra_build_dependencies.is_empty() {
|
||||||
|
(
|
||||||
|
Cow::Borrowed(&pep517_backend.requirements),
|
||||||
|
"`build-system.requires`",
|
||||||
|
)
|
||||||
|
} 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),
|
||||||
|
"`build-system.requires` and `extra-build-dependencies`",
|
||||||
|
)
|
||||||
|
};
|
||||||
build_context
|
build_context
|
||||||
.resolve(&pep517_backend.requirements, build_stack)
|
.resolve(&requirements, build_stack)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| {
|
.map_err(|err| Error::RequirementsResolve(dependency_sources, err.into()))?
|
||||||
Error::RequirementsResolve("`build-system.requires`", err.into())
|
|
||||||
})?
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -604,6 +637,7 @@ impl SourceBuild {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
default_backend.clone()
|
default_backend.clone()
|
||||||
};
|
};
|
||||||
Ok((backend, pyproject_toml.project))
|
Ok((backend, pyproject_toml.project))
|
||||||
|
|
|
||||||
|
|
@ -354,6 +354,7 @@ pub fn resolver_options(
|
||||||
}),
|
}),
|
||||||
no_build_isolation: flag(no_build_isolation, build_isolation, "build-isolation"),
|
no_build_isolation: flag(no_build_isolation, build_isolation, "build-isolation"),
|
||||||
no_build_isolation_package: Some(no_build_isolation_package),
|
no_build_isolation_package: Some(no_build_isolation_package),
|
||||||
|
extra_build_dependencies: None,
|
||||||
exclude_newer: ExcludeNewer::from_args(
|
exclude_newer: ExcludeNewer::from_args(
|
||||||
exclude_newer,
|
exclude_newer,
|
||||||
exclude_newer_package.unwrap_or_default(),
|
exclude_newer_package.unwrap_or_default(),
|
||||||
|
|
@ -475,6 +476,7 @@ pub fn resolver_installer_options(
|
||||||
} else {
|
} else {
|
||||||
Some(no_build_isolation_package)
|
Some(no_build_isolation_package)
|
||||||
},
|
},
|
||||||
|
extra_build_dependencies: None,
|
||||||
exclude_newer,
|
exclude_newer,
|
||||||
exclude_newer_package: exclude_newer_package.map(ExcludeNewerPackage::from_iter),
|
exclude_newer_package: exclude_newer_package.map(ExcludeNewerPackage::from_iter),
|
||||||
link_mode,
|
link_mode,
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ bitflags::bitflags! {
|
||||||
const JSON_OUTPUT = 1 << 2;
|
const JSON_OUTPUT = 1 << 2;
|
||||||
const PYLOCK = 1 << 3;
|
const PYLOCK = 1 << 3;
|
||||||
const ADD_BOUNDS = 1 << 4;
|
const ADD_BOUNDS = 1 << 4;
|
||||||
|
const EXTRA_BUILD_DEPENDENCIES = 1 << 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -28,6 +29,7 @@ impl PreviewFeatures {
|
||||||
Self::JSON_OUTPUT => "json-output",
|
Self::JSON_OUTPUT => "json-output",
|
||||||
Self::PYLOCK => "pylock",
|
Self::PYLOCK => "pylock",
|
||||||
Self::ADD_BOUNDS => "add-bounds",
|
Self::ADD_BOUNDS => "add-bounds",
|
||||||
|
Self::EXTRA_BUILD_DEPENDENCIES => "extra-build-dependencies",
|
||||||
_ => panic!("`flag_as_str` can only be used for exactly one feature flag"),
|
_ => panic!("`flag_as_str` can only be used for exactly one feature flag"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -70,6 +72,7 @@ impl FromStr for PreviewFeatures {
|
||||||
"json-output" => Self::JSON_OUTPUT,
|
"json-output" => Self::JSON_OUTPUT,
|
||||||
"pylock" => Self::PYLOCK,
|
"pylock" => Self::PYLOCK,
|
||||||
"add-bounds" => Self::ADD_BOUNDS,
|
"add-bounds" => Self::ADD_BOUNDS,
|
||||||
|
"extra-build-dependencies" => Self::EXTRA_BUILD_DEPENDENCIES,
|
||||||
_ => {
|
_ => {
|
||||||
warn_user_once!("Unknown preview feature: `{part}`");
|
warn_user_once!("Unknown preview feature: `{part}`");
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -232,6 +235,10 @@ mod tests {
|
||||||
assert_eq!(PreviewFeatures::JSON_OUTPUT.flag_as_str(), "json-output");
|
assert_eq!(PreviewFeatures::JSON_OUTPUT.flag_as_str(), "json-output");
|
||||||
assert_eq!(PreviewFeatures::PYLOCK.flag_as_str(), "pylock");
|
assert_eq!(PreviewFeatures::PYLOCK.flag_as_str(), "pylock");
|
||||||
assert_eq!(PreviewFeatures::ADD_BOUNDS.flag_as_str(), "add-bounds");
|
assert_eq!(PreviewFeatures::ADD_BOUNDS.flag_as_str(), "add-bounds");
|
||||||
|
assert_eq!(
|
||||||
|
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES.flag_as_str(),
|
||||||
|
"extra-build-dependencies"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ use uv_configuration::{
|
||||||
};
|
};
|
||||||
use uv_configuration::{BuildOutput, Concurrency};
|
use uv_configuration::{BuildOutput, Concurrency};
|
||||||
use uv_distribution::DistributionDatabase;
|
use uv_distribution::DistributionDatabase;
|
||||||
|
use uv_distribution::ExtraBuildRequires;
|
||||||
use uv_distribution_filename::DistFilename;
|
use uv_distribution_filename::DistFilename;
|
||||||
use uv_distribution_types::{
|
use uv_distribution_types::{
|
||||||
CachedDist, DependencyMetadata, Identifier, IndexCapabilities, IndexLocations,
|
CachedDist, DependencyMetadata, Identifier, IndexCapabilities, IndexLocations,
|
||||||
|
|
@ -88,6 +89,7 @@ pub struct BuildDispatch<'a> {
|
||||||
shared_state: SharedState,
|
shared_state: SharedState,
|
||||||
dependency_metadata: &'a DependencyMetadata,
|
dependency_metadata: &'a DependencyMetadata,
|
||||||
build_isolation: BuildIsolation<'a>,
|
build_isolation: BuildIsolation<'a>,
|
||||||
|
extra_build_requires: &'a ExtraBuildRequires,
|
||||||
link_mode: uv_install_wheel::LinkMode,
|
link_mode: uv_install_wheel::LinkMode,
|
||||||
build_options: &'a BuildOptions,
|
build_options: &'a BuildOptions,
|
||||||
config_settings: &'a ConfigSettings,
|
config_settings: &'a ConfigSettings,
|
||||||
|
|
@ -116,6 +118,7 @@ impl<'a> BuildDispatch<'a> {
|
||||||
config_settings: &'a ConfigSettings,
|
config_settings: &'a ConfigSettings,
|
||||||
config_settings_package: &'a PackageConfigSettings,
|
config_settings_package: &'a PackageConfigSettings,
|
||||||
build_isolation: BuildIsolation<'a>,
|
build_isolation: BuildIsolation<'a>,
|
||||||
|
extra_build_requires: &'a ExtraBuildRequires,
|
||||||
link_mode: uv_install_wheel::LinkMode,
|
link_mode: uv_install_wheel::LinkMode,
|
||||||
build_options: &'a BuildOptions,
|
build_options: &'a BuildOptions,
|
||||||
hasher: &'a HashStrategy,
|
hasher: &'a HashStrategy,
|
||||||
|
|
@ -138,6 +141,7 @@ impl<'a> BuildDispatch<'a> {
|
||||||
config_settings,
|
config_settings,
|
||||||
config_settings_package,
|
config_settings_package,
|
||||||
build_isolation,
|
build_isolation,
|
||||||
|
extra_build_requires,
|
||||||
link_mode,
|
link_mode,
|
||||||
build_options,
|
build_options,
|
||||||
hasher,
|
hasher,
|
||||||
|
|
@ -219,6 +223,10 @@ impl BuildContext for BuildDispatch<'_> {
|
||||||
&self.workspace_cache
|
&self.workspace_cache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn extra_build_dependencies(&self) -> &uv_workspace::pyproject::ExtraBuildDependencies {
|
||||||
|
&self.extra_build_requires.extra_build_dependencies
|
||||||
|
}
|
||||||
|
|
||||||
async fn resolve<'data>(
|
async fn resolve<'data>(
|
||||||
&'data self,
|
&'data self,
|
||||||
requirements: &'data [Requirement],
|
requirements: &'data [Requirement],
|
||||||
|
|
@ -452,6 +460,7 @@ impl BuildContext for BuildDispatch<'_> {
|
||||||
self.workspace_cache(),
|
self.workspace_cache(),
|
||||||
config_settings,
|
config_settings,
|
||||||
self.build_isolation,
|
self.build_isolation,
|
||||||
|
&self.extra_build_requires.extra_build_dependencies,
|
||||||
&build_stack,
|
&build_stack,
|
||||||
build_kind,
|
build_kind,
|
||||||
self.build_extra_env_vars.clone(),
|
self.build_extra_env_vars.clone(),
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ pub use download::LocalWheel;
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
pub use index::{BuiltWheelIndex, RegistryWheelIndex};
|
pub use index::{BuiltWheelIndex, RegistryWheelIndex};
|
||||||
pub use metadata::{
|
pub use metadata::{
|
||||||
ArchiveMetadata, BuildRequires, FlatRequiresDist, LoweredRequirement, LoweringError, Metadata,
|
ArchiveMetadata, BuildRequires, ExtraBuildRequires, FlatRequiresDist, LoweredRequirement,
|
||||||
MetadataError, RequiresDist, SourcedDependencyGroups,
|
LoweringError, Metadata, MetadataError, RequiresDist, SourcedDependencyGroups,
|
||||||
};
|
};
|
||||||
pub use reporter::Reporter;
|
pub use reporter::Reporter;
|
||||||
pub use source::prune;
|
pub use source::prune;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ use std::path::Path;
|
||||||
use uv_configuration::SourceStrategy;
|
use uv_configuration::SourceStrategy;
|
||||||
use uv_distribution_types::{IndexLocations, Requirement};
|
use uv_distribution_types::{IndexLocations, Requirement};
|
||||||
use uv_normalize::PackageName;
|
use uv_normalize::PackageName;
|
||||||
use uv_workspace::pyproject::ToolUvSources;
|
use uv_pypi_types::VerbatimParsedUrl;
|
||||||
|
use uv_workspace::pyproject::{ExtraBuildDependencies, ToolUvSources};
|
||||||
use uv_workspace::{
|
use uv_workspace::{
|
||||||
DiscoveryOptions, MemberDiscovery, ProjectWorkspace, Workspace, WorkspaceCache,
|
DiscoveryOptions, MemberDiscovery, ProjectWorkspace, Workspace, WorkspaceCache,
|
||||||
};
|
};
|
||||||
|
|
@ -203,3 +204,93 @@ impl BuildRequires {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Lowered extra build dependencies with source resolution applied.
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
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::dependency_groups::DependencyGroupError;
|
||||||
use uv_workspace::{WorkspaceCache, WorkspaceError};
|
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::dependency_groups::SourcedDependencyGroups;
|
||||||
pub use crate::metadata::lowering::LoweredRequirement;
|
pub use crate::metadata::lowering::LoweredRequirement;
|
||||||
pub use crate::metadata::lowering::LoweringError;
|
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.
|
/// Build a source distribution from a remote URL.
|
||||||
async fn url<'data>(
|
async fn url<'data>(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -438,12 +452,13 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
let cache_shard = cache_shard.shard(revision.id());
|
let cache_shard = cache_shard.shard(revision.id());
|
||||||
let source_dist_entry = cache_shard.entry(SOURCE);
|
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 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
|
cache_shard
|
||||||
} else {
|
} 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.
|
// 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 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
|
cache_shard
|
||||||
} else {
|
} 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.
|
// 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 cache_shard = cache_shard.shard(revision.id());
|
||||||
let source_entry = cache_shard.entry(SOURCE);
|
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 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
|
cache_shard
|
||||||
} else {
|
} 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.
|
// 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 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
|
cache_shard
|
||||||
} else {
|
} 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.
|
// 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.
|
// freshness, since entries have to be fresher than the revision itself.
|
||||||
let cache_shard = cache_shard.shard(revision.id());
|
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 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
|
cache_shard
|
||||||
} else {
|
} 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.
|
// 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 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
|
cache_shard
|
||||||
} else {
|
} 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.
|
// Otherwise, we need to build a wheel.
|
||||||
|
|
@ -1524,12 +1544,13 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
// Acquire the advisory lock.
|
// Acquire the advisory lock.
|
||||||
let _lock = cache_shard.lock().await.map_err(Error::CacheWrite)?;
|
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 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
|
cache_shard
|
||||||
} else {
|
} 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.
|
// 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 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
|
cache_shard
|
||||||
} else {
|
} 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.
|
// Otherwise, we need to build a wheel.
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ serde = { workspace = true, features = ["derive"] }
|
||||||
tracing = { workspace = true, optional = true }
|
tracing = { workspace = true, optional = true }
|
||||||
unicode-width = { workspace = true }
|
unicode-width = { workspace = true }
|
||||||
unscanny = { workspace = true }
|
unscanny = { workspace = true }
|
||||||
|
uv-cache-key = { workspace = true }
|
||||||
# Adds conversions from [`VersionSpecifiers`] to [`version_ranges::Ranges`]
|
# Adds conversions from [`VersionSpecifiers`] to [`version_ranges::Ranges`]
|
||||||
version-ranges = { workspace = true, optional = true }
|
version-ranges = { workspace = true, optional = true }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ use std::{
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
use uv_cache_key::{CacheKey, CacheKeyHasher};
|
||||||
|
|
||||||
/// One of `~=` `==` `!=` `<=` `>=` `<` `>` `===`
|
/// One of `~=` `==` `!=` `<=` `>=` `<` `>` `===`
|
||||||
#[derive(Eq, Ord, PartialEq, PartialOrd, Debug, Hash, Clone, Copy)]
|
#[derive(Eq, Ord, PartialEq, PartialOrd, Debug, Hash, Clone, Copy)]
|
||||||
|
|
@ -114,6 +115,24 @@ impl Operator {
|
||||||
pub fn is_star(self) -> bool {
|
pub fn is_star(self) -> bool {
|
||||||
matches!(self, Self::EqualStar | Self::NotEqualStar)
|
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 {
|
impl FromStr for Operator {
|
||||||
|
|
@ -150,21 +169,7 @@ impl FromStr for Operator {
|
||||||
impl std::fmt::Display for Operator {
|
impl std::fmt::Display for Operator {
|
||||||
/// Note the `EqualStar` is also `==`.
|
/// Note the `EqualStar` is also `==`.
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let operator = match self {
|
let operator = self.as_str();
|
||||||
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 => ">=",
|
|
||||||
};
|
|
||||||
|
|
||||||
write!(f, "{operator}")
|
write!(f, "{operator}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -930,6 +935,46 @@ impl Hash for Version {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CacheKey for Version {
|
||||||
|
fn cache_key(&self, state: &mut CacheKeyHasher) {
|
||||||
|
self.epoch().cache_key(state);
|
||||||
|
|
||||||
|
let release = self.release();
|
||||||
|
release.len().cache_key(state);
|
||||||
|
for segment in release.iter() {
|
||||||
|
segment.cache_key(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(pre) = self.pre() {
|
||||||
|
1u8.cache_key(state);
|
||||||
|
match pre.kind {
|
||||||
|
PrereleaseKind::Alpha => 0u8.cache_key(state),
|
||||||
|
PrereleaseKind::Beta => 1u8.cache_key(state),
|
||||||
|
PrereleaseKind::Rc => 2u8.cache_key(state),
|
||||||
|
}
|
||||||
|
pre.number.cache_key(state);
|
||||||
|
} else {
|
||||||
|
0u8.cache_key(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(post) = self.post() {
|
||||||
|
1u8.cache_key(state);
|
||||||
|
post.cache_key(state);
|
||||||
|
} else {
|
||||||
|
0u8.cache_key(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(dev) = self.dev() {
|
||||||
|
1u8.cache_key(state);
|
||||||
|
dev.cache_key(state);
|
||||||
|
} else {
|
||||||
|
0u8.cache_key(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.local().cache_key(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialOrd<Self> for Version {
|
impl PartialOrd<Self> for Version {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
|
@ -1711,6 +1756,23 @@ impl std::fmt::Display for LocalVersionSlice<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CacheKey for LocalVersionSlice<'_> {
|
||||||
|
fn cache_key(&self, state: &mut CacheKeyHasher) {
|
||||||
|
match self {
|
||||||
|
LocalVersionSlice::Segments(segments) => {
|
||||||
|
0u8.cache_key(state);
|
||||||
|
segments.len().cache_key(state);
|
||||||
|
for segment in *segments {
|
||||||
|
segment.cache_key(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LocalVersionSlice::Max => {
|
||||||
|
1u8.cache_key(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialOrd for LocalVersionSlice<'_> {
|
impl PartialOrd for LocalVersionSlice<'_> {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
Some(self.cmp(other))
|
Some(self.cmp(other))
|
||||||
|
|
@ -1777,6 +1839,21 @@ impl std::fmt::Display for LocalSegment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CacheKey for LocalSegment {
|
||||||
|
fn cache_key(&self, state: &mut CacheKeyHasher) {
|
||||||
|
match self {
|
||||||
|
Self::String(string) => {
|
||||||
|
0u8.cache_key(state);
|
||||||
|
string.cache_key(state);
|
||||||
|
}
|
||||||
|
Self::Number(number) => {
|
||||||
|
1u8.cache_key(state);
|
||||||
|
number.cache_key(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialOrd for LocalSegment {
|
impl PartialOrd for LocalSegment {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
Some(self.cmp(other))
|
Some(self.cmp(other))
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,11 @@ impl VersionSpecifiers {
|
||||||
Self(Box::new([]))
|
Self(Box::new([]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The number of specifiers.
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.0.len()
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether all specifiers match the given version.
|
/// Whether all specifiers match the given version.
|
||||||
pub fn contains(&self, version: &Version) -> bool {
|
pub fn contains(&self, version: &Version) -> bool {
|
||||||
self.iter().all(|specifier| specifier.contains(version))
|
self.iter().all(|specifier| specifier.contains(version))
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ doctest = false
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
uv-cache-key = { workspace = true }
|
||||||
uv-fs = { workspace = true }
|
uv-fs = { workspace = true }
|
||||||
uv-normalize = { workspace = true }
|
uv-normalize = { workspace = true }
|
||||||
uv-pep440 = { workspace = true }
|
uv-pep440 = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ use std::str::FromStr;
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
use uv_cache_key::{CacheKey, CacheKeyHasher};
|
||||||
|
|
||||||
use cursor::Cursor;
|
use cursor::Cursor;
|
||||||
pub use marker::{
|
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().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> {
|
impl<T: Pep508Url> Requirement<T> {
|
||||||
/// Returns whether the markers apply for the given environment
|
/// Returns whether the markers apply for the given environment
|
||||||
pub fn evaluate_markers(&self, env: &MarkerEnvironment, extras: &[ExtraName]) -> bool {
|
pub fn evaluate_markers(&self, env: &MarkerEnvironment, extras: &[ExtraName]) -> bool {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ doctest = false
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
uv-configuration = { workspace = true }
|
||||||
|
uv-distribution-types = { workspace = true }
|
||||||
uv-pep440 = { workspace = true }
|
uv-pep440 = { workspace = true }
|
||||||
uv-pep508 = { workspace = true }
|
uv-pep508 = { workspace = true }
|
||||||
uv-pypi-types = { workspace = true }
|
uv-pypi-types = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ use serde::Deserialize;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
use uv_configuration::SourceStrategy;
|
||||||
use uv_pep440::VersionSpecifiers;
|
use uv_pep440::VersionSpecifiers;
|
||||||
use uv_pep508::PackageName;
|
use uv_pep508::PackageName;
|
||||||
use uv_pypi_types::VerbatimParsedUrl;
|
use uv_pypi_types::VerbatimParsedUrl;
|
||||||
|
|
@ -96,6 +97,46 @@ impl Pep723ItemRef<'_> {
|
||||||
Self::Remote(..) => None,
|
Self::Remote(..) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determine the working directory for the script.
|
||||||
|
pub fn directory(&self) -> Result<PathBuf, io::Error> {
|
||||||
|
match self {
|
||||||
|
Self::Script(script) => Ok(std::path::absolute(&script.path)?
|
||||||
|
.parent()
|
||||||
|
.expect("script path has no parent")
|
||||||
|
.to_owned()),
|
||||||
|
Self::Stdin(..) | Self::Remote(..) => std::env::current_dir(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Collect any `tool.uv.index` from the script.
|
||||||
|
pub fn indexes(&self, source_strategy: SourceStrategy) -> &[uv_distribution_types::Index] {
|
||||||
|
match source_strategy {
|
||||||
|
SourceStrategy::Enabled => self
|
||||||
|
.metadata()
|
||||||
|
.tool
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|tool| tool.uv.as_ref())
|
||||||
|
.and_then(|uv| uv.top_level.index.as_deref())
|
||||||
|
.unwrap_or(&[]),
|
||||||
|
SourceStrategy::Disabled => &[],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Collect any `tool.uv.sources` from the script.
|
||||||
|
pub fn sources(&self, source_strategy: SourceStrategy) -> &BTreeMap<PackageName, Sources> {
|
||||||
|
static EMPTY: BTreeMap<PackageName, Sources> = BTreeMap::new();
|
||||||
|
match source_strategy {
|
||||||
|
SourceStrategy::Enabled => self
|
||||||
|
.metadata()
|
||||||
|
.tool
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|tool| tool.uv.as_ref())
|
||||||
|
.and_then(|uv| uv.sources.as_ref())
|
||||||
|
.unwrap_or(&EMPTY),
|
||||||
|
SourceStrategy::Disabled => &EMPTY,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'item> From<&'item Pep723Item> for Pep723ItemRef<'item> {
|
impl<'item> From<&'item Pep723Item> for Pep723ItemRef<'item> {
|
||||||
|
|
@ -108,6 +149,12 @@ impl<'item> From<&'item Pep723Item> for Pep723ItemRef<'item> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'item> From<&'item Pep723Script> for Pep723ItemRef<'item> {
|
||||||
|
fn from(script: &'item Pep723Script) -> Self {
|
||||||
|
Self::Script(script)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A PEP 723 script, including its [`Pep723Metadata`].
|
/// A PEP 723 script, including its [`Pep723Metadata`].
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Pep723Script {
|
pub struct Pep723Script {
|
||||||
|
|
@ -381,6 +428,8 @@ pub struct ToolUv {
|
||||||
pub override_dependencies: Option<Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>,
|
pub override_dependencies: Option<Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>,
|
||||||
pub constraint_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 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>>,
|
pub sources: Option<BTreeMap<PackageName, Sources>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use std::num::NonZeroUsize;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::{collections::BTreeMap, num::NonZeroUsize};
|
||||||
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
|
@ -17,6 +17,7 @@ use uv_resolver::{
|
||||||
PrereleaseMode, ResolutionMode,
|
PrereleaseMode, ResolutionMode,
|
||||||
};
|
};
|
||||||
use uv_torch::TorchMode;
|
use uv_torch::TorchMode;
|
||||||
|
use uv_workspace::pyproject::ExtraBuildDependencies;
|
||||||
use uv_workspace::pyproject_mut::AddBoundsKind;
|
use uv_workspace::pyproject_mut::AddBoundsKind;
|
||||||
|
|
||||||
use crate::{FilesystemOptions, Options, PipOptions};
|
use crate::{FilesystemOptions, Options, PipOptions};
|
||||||
|
|
@ -124,6 +125,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<ExcludeNewerPackage> {
|
impl Combine for Option<ExcludeNewerPackage> {
|
||||||
/// Combine two [`ExcludeNewerPackage`] instances by merging them, with the values in `self` taking precedence.
|
/// Combine two [`ExcludeNewerPackage`] instances by merging them, with the values in `self` taking precedence.
|
||||||
fn combine(self, other: Option<ExcludeNewerPackage>) -> Option<ExcludeNewerPackage> {
|
fn combine(self, other: Option<ExcludeNewerPackage>) -> Option<ExcludeNewerPackage> {
|
||||||
|
|
@ -192,3 +208,30 @@ impl Combine for ExcludeNewer {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Combine for ExtraBuildDependencies {
|
||||||
|
fn combine(mut self, other: Self) -> Self {
|
||||||
|
for (key, value) in other {
|
||||||
|
match self.entry(key) {
|
||||||
|
std::collections::btree_map::Entry::Occupied(mut entry) => {
|
||||||
|
// Combine the vecs, with self taking precedence
|
||||||
|
let existing = entry.get_mut();
|
||||||
|
existing.extend(value);
|
||||||
|
}
|
||||||
|
std::collections::btree_map::Entry::Vacant(entry) => {
|
||||||
|
entry.insert(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Combine for Option<ExtraBuildDependencies> {
|
||||||
|
fn combine(self, other: Option<ExtraBuildDependencies>) -> Option<ExtraBuildDependencies> {
|
||||||
|
match (self, other) {
|
||||||
|
(Some(a), Some(b)) => Some(a.combine(b)),
|
||||||
|
(a, b) => a.or(b),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -317,6 +317,7 @@ fn warn_uv_toml_masked_fields(options: &Options) {
|
||||||
config_settings_package,
|
config_settings_package,
|
||||||
no_build_isolation,
|
no_build_isolation,
|
||||||
no_build_isolation_package,
|
no_build_isolation_package,
|
||||||
|
extra_build_dependencies,
|
||||||
exclude_newer,
|
exclude_newer,
|
||||||
exclude_newer_package,
|
exclude_newer_package,
|
||||||
link_mode,
|
link_mode,
|
||||||
|
|
@ -445,6 +446,9 @@ fn warn_uv_toml_masked_fields(options: &Options) {
|
||||||
if no_build_isolation_package.is_some() {
|
if no_build_isolation_package.is_some() {
|
||||||
masked_fields.push("no-build-isolation-package");
|
masked_fields.push("no-build-isolation-package");
|
||||||
}
|
}
|
||||||
|
if extra_build_dependencies.is_some() {
|
||||||
|
masked_fields.push("extra-build-dependencies");
|
||||||
|
}
|
||||||
if exclude_newer.is_some() {
|
if exclude_newer.is_some() {
|
||||||
masked_fields.push("exclude-newer");
|
masked_fields.push("exclude-newer");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ use uv_resolver::{
|
||||||
};
|
};
|
||||||
use uv_static::EnvVars;
|
use uv_static::EnvVars;
|
||||||
use uv_torch::TorchMode;
|
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.
|
/// A `pyproject.toml` with an (optional) `[tool.uv]` section.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
@ -376,6 +376,7 @@ pub struct ResolverOptions {
|
||||||
pub no_binary_package: Option<Vec<PackageName>>,
|
pub no_binary_package: Option<Vec<PackageName>>,
|
||||||
pub no_build_isolation: Option<bool>,
|
pub no_build_isolation: Option<bool>,
|
||||||
pub no_build_isolation_package: Option<Vec<PackageName>>,
|
pub no_build_isolation_package: Option<Vec<PackageName>>,
|
||||||
|
pub extra_build_dependencies: Option<ExtraBuildDependencies>,
|
||||||
pub no_sources: Option<bool>,
|
pub no_sources: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -628,6 +629,20 @@ pub struct ResolverInstallerOptions {
|
||||||
"#
|
"#
|
||||||
)]
|
)]
|
||||||
pub no_build_isolation_package: Option<Vec<PackageName>>,
|
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.
|
/// 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.,
|
/// Accepts a superset of [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339.html) (e.g.,
|
||||||
|
|
@ -1135,6 +1150,20 @@ pub struct PipOptions {
|
||||||
"#
|
"#
|
||||||
)]
|
)]
|
||||||
pub no_build_isolation_package: Option<Vec<PackageName>>,
|
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
|
/// Validate the Python environment, to detect packages with missing dependencies and other
|
||||||
/// issues.
|
/// issues.
|
||||||
#[option(
|
#[option(
|
||||||
|
|
@ -1719,6 +1748,7 @@ impl From<ResolverInstallerOptions> for ResolverOptions {
|
||||||
no_binary_package: value.no_binary_package,
|
no_binary_package: value.no_binary_package,
|
||||||
no_build_isolation: value.no_build_isolation,
|
no_build_isolation: value.no_build_isolation,
|
||||||
no_build_isolation_package: value.no_build_isolation_package,
|
no_build_isolation_package: value.no_build_isolation_package,
|
||||||
|
extra_build_dependencies: value.extra_build_dependencies,
|
||||||
no_sources: value.no_sources,
|
no_sources: value.no_sources,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1784,6 +1814,7 @@ pub struct ToolOptions {
|
||||||
pub config_settings_package: Option<PackageConfigSettings>,
|
pub config_settings_package: Option<PackageConfigSettings>,
|
||||||
pub no_build_isolation: Option<bool>,
|
pub no_build_isolation: Option<bool>,
|
||||||
pub no_build_isolation_package: Option<Vec<PackageName>>,
|
pub no_build_isolation_package: Option<Vec<PackageName>>,
|
||||||
|
pub extra_build_dependencies: Option<ExtraBuildDependencies>,
|
||||||
pub exclude_newer: Option<ExcludeNewerTimestamp>,
|
pub exclude_newer: Option<ExcludeNewerTimestamp>,
|
||||||
pub exclude_newer_package: Option<ExcludeNewerPackage>,
|
pub exclude_newer_package: Option<ExcludeNewerPackage>,
|
||||||
pub link_mode: Option<LinkMode>,
|
pub link_mode: Option<LinkMode>,
|
||||||
|
|
@ -1813,6 +1844,7 @@ impl From<ResolverInstallerOptions> for ToolOptions {
|
||||||
config_settings_package: value.config_settings_package,
|
config_settings_package: value.config_settings_package,
|
||||||
no_build_isolation: value.no_build_isolation,
|
no_build_isolation: value.no_build_isolation,
|
||||||
no_build_isolation_package: value.no_build_isolation_package,
|
no_build_isolation_package: value.no_build_isolation_package,
|
||||||
|
extra_build_dependencies: value.extra_build_dependencies,
|
||||||
exclude_newer: value.exclude_newer,
|
exclude_newer: value.exclude_newer,
|
||||||
exclude_newer_package: value.exclude_newer_package,
|
exclude_newer_package: value.exclude_newer_package,
|
||||||
link_mode: value.link_mode,
|
link_mode: value.link_mode,
|
||||||
|
|
@ -1844,6 +1876,7 @@ impl From<ToolOptions> for ResolverInstallerOptions {
|
||||||
config_settings_package: value.config_settings_package,
|
config_settings_package: value.config_settings_package,
|
||||||
no_build_isolation: value.no_build_isolation,
|
no_build_isolation: value.no_build_isolation,
|
||||||
no_build_isolation_package: value.no_build_isolation_package,
|
no_build_isolation_package: value.no_build_isolation_package,
|
||||||
|
extra_build_dependencies: value.extra_build_dependencies,
|
||||||
exclude_newer: value.exclude_newer,
|
exclude_newer: value.exclude_newer,
|
||||||
exclude_newer_package: value.exclude_newer_package,
|
exclude_newer_package: value.exclude_newer_package,
|
||||||
link_mode: value.link_mode,
|
link_mode: value.link_mode,
|
||||||
|
|
@ -1898,6 +1931,7 @@ pub struct OptionsWire {
|
||||||
config_settings_package: Option<PackageConfigSettings>,
|
config_settings_package: Option<PackageConfigSettings>,
|
||||||
no_build_isolation: Option<bool>,
|
no_build_isolation: Option<bool>,
|
||||||
no_build_isolation_package: Option<Vec<PackageName>>,
|
no_build_isolation_package: Option<Vec<PackageName>>,
|
||||||
|
extra_build_dependencies: Option<ExtraBuildDependencies>,
|
||||||
exclude_newer: Option<ExcludeNewerTimestamp>,
|
exclude_newer: Option<ExcludeNewerTimestamp>,
|
||||||
exclude_newer_package: Option<ExcludeNewerPackage>,
|
exclude_newer_package: Option<ExcludeNewerPackage>,
|
||||||
link_mode: Option<LinkMode>,
|
link_mode: Option<LinkMode>,
|
||||||
|
|
@ -2017,6 +2051,7 @@ impl From<OptionsWire> for Options {
|
||||||
sources,
|
sources,
|
||||||
default_groups,
|
default_groups,
|
||||||
dependency_groups,
|
dependency_groups,
|
||||||
|
extra_build_dependencies,
|
||||||
dev_dependencies,
|
dev_dependencies,
|
||||||
managed,
|
managed,
|
||||||
package,
|
package,
|
||||||
|
|
@ -2057,6 +2092,7 @@ impl From<OptionsWire> for Options {
|
||||||
config_settings_package,
|
config_settings_package,
|
||||||
no_build_isolation,
|
no_build_isolation,
|
||||||
no_build_isolation_package,
|
no_build_isolation_package,
|
||||||
|
extra_build_dependencies,
|
||||||
exclude_newer,
|
exclude_newer,
|
||||||
exclude_newer_package,
|
exclude_newer_package,
|
||||||
link_mode,
|
link_mode,
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,9 @@ pub trait BuildContext {
|
||||||
/// Workspace discovery caching.
|
/// Workspace discovery caching.
|
||||||
fn workspace_cache(&self) -> &WorkspaceCache;
|
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.
|
/// Resolve the given requirements into a ready-to-install set of package versions.
|
||||||
fn resolve<'a>(
|
fn resolve<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,55 @@ pub enum PyprojectTomlError {
|
||||||
MissingVersion,
|
MissingVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper function to deserialize a map while ensuring all keys are unique.
|
||||||
|
fn deserialize_unique_map<'de, D, K, V, F>(
|
||||||
|
deserializer: D,
|
||||||
|
error_msg: F,
|
||||||
|
) -> Result<BTreeMap<K, V>, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
K: Deserialize<'de> + Ord + std::fmt::Display,
|
||||||
|
V: Deserialize<'de>,
|
||||||
|
F: FnOnce(&K) -> String,
|
||||||
|
{
|
||||||
|
struct Visitor<K, V, F>(F, std::marker::PhantomData<(K, V)>);
|
||||||
|
|
||||||
|
impl<'de, K, V, F> serde::de::Visitor<'de> for Visitor<K, V, F>
|
||||||
|
where
|
||||||
|
K: Deserialize<'de> + Ord + std::fmt::Display,
|
||||||
|
V: Deserialize<'de>,
|
||||||
|
F: FnOnce(&K) -> String,
|
||||||
|
{
|
||||||
|
type Value = BTreeMap<K, V>;
|
||||||
|
|
||||||
|
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>,
|
||||||
|
{
|
||||||
|
use std::collections::btree_map::Entry;
|
||||||
|
|
||||||
|
let mut map = BTreeMap::new();
|
||||||
|
while let Some((key, value)) = access.next_entry::<K, V>()? {
|
||||||
|
match map.entry(key) {
|
||||||
|
Entry::Occupied(entry) => {
|
||||||
|
return Err(serde::de::Error::custom((self.0)(entry.key())));
|
||||||
|
}
|
||||||
|
Entry::Vacant(entry) => {
|
||||||
|
entry.insert(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(map)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_map(Visitor(error_msg, std::marker::PhantomData))
|
||||||
|
}
|
||||||
|
|
||||||
/// A `pyproject.toml` as specified in PEP 517.
|
/// A `pyproject.toml` as specified in PEP 517.
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
#[cfg_attr(test, derive(Serialize))]
|
#[cfg_attr(test, derive(Serialize))]
|
||||||
|
|
@ -378,6 +427,21 @@ pub struct ToolUv {
|
||||||
)]
|
)]
|
||||||
pub dependency_groups: Option<ToolUvDependencyGroups>,
|
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<ExtraBuildDependencies>,
|
||||||
|
|
||||||
/// The project's development dependencies.
|
/// The project's development dependencies.
|
||||||
///
|
///
|
||||||
/// Development dependencies will be installed by default in `uv run` and `uv sync`, but will
|
/// Development dependencies will be installed by default in `uv run` and `uv sync`, but will
|
||||||
|
|
@ -643,38 +707,10 @@ impl<'de> serde::de::Deserialize<'de> for ToolUvSources {
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
struct SourcesVisitor;
|
deserialize_unique_map(deserializer, |key: &PackageName| {
|
||||||
|
format!("duplicate sources for package `{key}`")
|
||||||
impl<'de> serde::de::Visitor<'de> for SourcesVisitor {
|
})
|
||||||
type Value = ToolUvSources;
|
.map(ToolUvSources)
|
||||||
|
|
||||||
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 sources = BTreeMap::new();
|
|
||||||
while let Some((key, value)) = access.next_entry::<PackageName, Sources>()? {
|
|
||||||
match sources.entry(key) {
|
|
||||||
std::collections::btree_map::Entry::Occupied(entry) => {
|
|
||||||
return Err(serde::de::Error::custom(format!(
|
|
||||||
"duplicate sources for package `{}`",
|
|
||||||
entry.key()
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
std::collections::btree_map::Entry::Vacant(entry) => {
|
|
||||||
entry.insert(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(ToolUvSources(sources))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deserializer.deserialize_map(SourcesVisitor)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -702,40 +738,10 @@ impl<'de> serde::de::Deserialize<'de> for ToolUvDependencyGroups {
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
struct SourcesVisitor;
|
deserialize_unique_map(deserializer, |key: &GroupName| {
|
||||||
|
format!("duplicate settings for dependency group `{key}`")
|
||||||
impl<'de> serde::de::Visitor<'de> for SourcesVisitor {
|
})
|
||||||
type Value = ToolUvDependencyGroups;
|
.map(ToolUvDependencyGroups)
|
||||||
|
|
||||||
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::<GroupName, DependencyGroupSettings>()?
|
|
||||||
{
|
|
||||||
match groups.entry(key) {
|
|
||||||
std::collections::btree_map::Entry::Occupied(entry) => {
|
|
||||||
return Err(serde::de::Error::custom(format!(
|
|
||||||
"duplicate settings for dependency group `{}`",
|
|
||||||
entry.key()
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
std::collections::btree_map::Entry::Vacant(entry) => {
|
|
||||||
entry.insert(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(ToolUvDependencyGroups(groups))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deserializer.deserialize_map(SourcesVisitor)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -749,6 +755,51 @@ pub struct DependencyGroupSettings {
|
||||||
pub requires_python: Option<VersionSpecifiers>,
|
pub requires_python: Option<VersionSpecifiers>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize)]
|
||||||
|
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||||
|
pub struct ExtraBuildDependencies(
|
||||||
|
BTreeMap<PackageName, Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>,
|
||||||
|
);
|
||||||
|
|
||||||
|
impl std::ops::Deref for ExtraBuildDependencies {
|
||||||
|
type Target = BTreeMap<PackageName, Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::DerefMut for ExtraBuildDependencies {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoIterator for ExtraBuildDependencies {
|
||||||
|
type Item = (PackageName, Vec<uv_pep508::Requirement<VerbatimParsedUrl>>);
|
||||||
|
type IntoIter = std::collections::btree_map::IntoIter<
|
||||||
|
PackageName,
|
||||||
|
Vec<uv_pep508::Requirement<VerbatimParsedUrl>>,
|
||||||
|
>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.0.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ensure that all keys in the TOML table are unique.
|
||||||
|
impl<'de> serde::de::Deserialize<'de> for ExtraBuildDependencies {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserialize_unique_map(deserializer, |key: &PackageName| {
|
||||||
|
format!("duplicate extra-build-dependencies for `{key}`")
|
||||||
|
})
|
||||||
|
.map(ExtraBuildDependencies)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, OptionsMetadata, Default, Debug, Clone, PartialEq, Eq)]
|
#[derive(Deserialize, OptionsMetadata, Default, Debug, Clone, PartialEq, Eq)]
|
||||||
#[cfg_attr(test, derive(Serialize))]
|
#[cfg_attr(test, derive(Serialize))]
|
||||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||||
|
|
|
||||||
|
|
@ -1970,6 +1970,7 @@ mod tests {
|
||||||
"package": null,
|
"package": null,
|
||||||
"default-groups": null,
|
"default-groups": null,
|
||||||
"dependency-groups": null,
|
"dependency-groups": null,
|
||||||
|
"extra-build-dependencies": null,
|
||||||
"dev-dependencies": null,
|
"dev-dependencies": null,
|
||||||
"override-dependencies": null,
|
"override-dependencies": null,
|
||||||
"constraint-dependencies": null,
|
"constraint-dependencies": null,
|
||||||
|
|
@ -2070,6 +2071,7 @@ mod tests {
|
||||||
"package": null,
|
"package": null,
|
||||||
"default-groups": null,
|
"default-groups": null,
|
||||||
"dependency-groups": null,
|
"dependency-groups": null,
|
||||||
|
"extra-build-dependencies": null,
|
||||||
"dev-dependencies": null,
|
"dev-dependencies": null,
|
||||||
"override-dependencies": null,
|
"override-dependencies": null,
|
||||||
"constraint-dependencies": null,
|
"constraint-dependencies": null,
|
||||||
|
|
@ -2283,6 +2285,7 @@ mod tests {
|
||||||
"package": null,
|
"package": null,
|
||||||
"default-groups": null,
|
"default-groups": null,
|
||||||
"dependency-groups": null,
|
"dependency-groups": null,
|
||||||
|
"extra-build-dependencies": null,
|
||||||
"dev-dependencies": null,
|
"dev-dependencies": null,
|
||||||
"override-dependencies": null,
|
"override-dependencies": null,
|
||||||
"constraint-dependencies": null,
|
"constraint-dependencies": null,
|
||||||
|
|
@ -2392,6 +2395,7 @@ mod tests {
|
||||||
"package": null,
|
"package": null,
|
||||||
"default-groups": null,
|
"default-groups": null,
|
||||||
"dependency-groups": null,
|
"dependency-groups": null,
|
||||||
|
"extra-build-dependencies": null,
|
||||||
"dev-dependencies": null,
|
"dev-dependencies": null,
|
||||||
"override-dependencies": null,
|
"override-dependencies": null,
|
||||||
"constraint-dependencies": null,
|
"constraint-dependencies": null,
|
||||||
|
|
@ -2514,6 +2518,7 @@ mod tests {
|
||||||
"package": null,
|
"package": null,
|
||||||
"default-groups": null,
|
"default-groups": null,
|
||||||
"dependency-groups": null,
|
"dependency-groups": null,
|
||||||
|
"extra-build-dependencies": null,
|
||||||
"dev-dependencies": null,
|
"dev-dependencies": null,
|
||||||
"override-dependencies": null,
|
"override-dependencies": null,
|
||||||
"constraint-dependencies": null,
|
"constraint-dependencies": null,
|
||||||
|
|
@ -2610,6 +2615,7 @@ mod tests {
|
||||||
"package": null,
|
"package": null,
|
||||||
"default-groups": null,
|
"default-groups": null,
|
||||||
"dependency-groups": null,
|
"dependency-groups": null,
|
||||||
|
"extra-build-dependencies": null,
|
||||||
"dev-dependencies": null,
|
"dev-dependencies": null,
|
||||||
"override-dependencies": null,
|
"override-dependencies": null,
|
||||||
"constraint-dependencies": null,
|
"constraint-dependencies": null,
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ use uv_requirements::RequirementsSource;
|
||||||
use uv_resolver::{ExcludeNewer, FlatIndex};
|
use uv_resolver::{ExcludeNewer, FlatIndex};
|
||||||
use uv_settings::PythonInstallMirrors;
|
use uv_settings::PythonInstallMirrors;
|
||||||
use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, BuildStack, HashStrategy};
|
use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, BuildStack, HashStrategy};
|
||||||
|
use uv_workspace::pyproject::ExtraBuildDependencies;
|
||||||
use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceCache, WorkspaceError};
|
use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceCache, WorkspaceError};
|
||||||
|
|
||||||
use crate::commands::ExitStatus;
|
use crate::commands::ExitStatus;
|
||||||
|
|
@ -200,6 +201,7 @@ async fn build_impl(
|
||||||
config_settings_package,
|
config_settings_package,
|
||||||
no_build_isolation,
|
no_build_isolation,
|
||||||
no_build_isolation_package,
|
no_build_isolation_package,
|
||||||
|
extra_build_dependencies,
|
||||||
exclude_newer,
|
exclude_newer,
|
||||||
link_mode,
|
link_mode,
|
||||||
upgrade: _,
|
upgrade: _,
|
||||||
|
|
@ -346,6 +348,7 @@ async fn build_impl(
|
||||||
build_constraints,
|
build_constraints,
|
||||||
*no_build_isolation,
|
*no_build_isolation,
|
||||||
no_build_isolation_package,
|
no_build_isolation_package,
|
||||||
|
extra_build_dependencies,
|
||||||
*index_strategy,
|
*index_strategy,
|
||||||
*keyring_provider,
|
*keyring_provider,
|
||||||
exclude_newer.clone(),
|
exclude_newer.clone(),
|
||||||
|
|
@ -424,6 +427,7 @@ async fn build_package(
|
||||||
build_constraints: &[RequirementsSource],
|
build_constraints: &[RequirementsSource],
|
||||||
no_build_isolation: bool,
|
no_build_isolation: bool,
|
||||||
no_build_isolation_package: &[PackageName],
|
no_build_isolation_package: &[PackageName],
|
||||||
|
extra_build_dependencies: &ExtraBuildDependencies,
|
||||||
index_strategy: IndexStrategy,
|
index_strategy: IndexStrategy,
|
||||||
keyring_provider: KeyringProviderType,
|
keyring_provider: KeyringProviderType,
|
||||||
exclude_newer: ExcludeNewer,
|
exclude_newer: ExcludeNewer,
|
||||||
|
|
@ -560,6 +564,8 @@ async fn build_package(
|
||||||
let workspace_cache = WorkspaceCache::default();
|
let workspace_cache = WorkspaceCache::default();
|
||||||
|
|
||||||
// Create a build dispatch.
|
// Create a build dispatch.
|
||||||
|
let extra_build_requires =
|
||||||
|
uv_distribution::ExtraBuildRequires::from_lowered(extra_build_dependencies.clone());
|
||||||
let build_dispatch = BuildDispatch::new(
|
let build_dispatch = BuildDispatch::new(
|
||||||
&client,
|
&client,
|
||||||
cache,
|
cache,
|
||||||
|
|
@ -573,6 +579,7 @@ async fn build_package(
|
||||||
config_setting,
|
config_setting,
|
||||||
config_settings_package,
|
config_settings_package,
|
||||||
build_isolation,
|
build_isolation,
|
||||||
|
&extra_build_requires,
|
||||||
link_mode,
|
link_mode,
|
||||||
build_options,
|
build_options,
|
||||||
&hasher,
|
&hasher,
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ use uv_cache::Cache;
|
||||||
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
||||||
use uv_configuration::{
|
use uv_configuration::{
|
||||||
BuildOptions, Concurrency, ConfigSettings, Constraints, ExportFormat, ExtrasSpecification,
|
BuildOptions, Concurrency, ConfigSettings, Constraints, ExportFormat, ExtrasSpecification,
|
||||||
IndexStrategy, NoBinary, NoBuild, PackageConfigSettings, Preview, Reinstall, SourceStrategy,
|
IndexStrategy, NoBinary, NoBuild, PackageConfigSettings, Preview, PreviewFeatures, Reinstall,
|
||||||
Upgrade,
|
SourceStrategy, Upgrade,
|
||||||
};
|
};
|
||||||
use uv_configuration::{KeyringProviderType, TargetTriple};
|
use uv_configuration::{KeyringProviderType, TargetTriple};
|
||||||
use uv_dispatch::{BuildDispatch, SharedState};
|
use uv_dispatch::{BuildDispatch, SharedState};
|
||||||
|
|
@ -44,8 +44,9 @@ use uv_resolver::{
|
||||||
};
|
};
|
||||||
use uv_torch::{TorchMode, TorchStrategy};
|
use uv_torch::{TorchMode, TorchStrategy};
|
||||||
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy};
|
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::WorkspaceCache;
|
||||||
|
use uv_workspace::pyproject::ExtraBuildDependencies;
|
||||||
|
|
||||||
use crate::commands::pip::loggers::DefaultResolveLogger;
|
use crate::commands::pip::loggers::DefaultResolveLogger;
|
||||||
use crate::commands::pip::{operations, resolution_environment};
|
use crate::commands::pip::{operations, resolution_environment};
|
||||||
|
|
@ -95,6 +96,7 @@ pub(crate) async fn pip_compile(
|
||||||
config_settings_package: PackageConfigSettings,
|
config_settings_package: PackageConfigSettings,
|
||||||
no_build_isolation: bool,
|
no_build_isolation: bool,
|
||||||
no_build_isolation_package: Vec<PackageName>,
|
no_build_isolation_package: Vec<PackageName>,
|
||||||
|
extra_build_dependencies: &ExtraBuildDependencies,
|
||||||
build_options: BuildOptions,
|
build_options: BuildOptions,
|
||||||
mut python_version: Option<PythonVersion>,
|
mut python_version: Option<PythonVersion>,
|
||||||
python_platform: Option<TargetTriple>,
|
python_platform: Option<TargetTriple>,
|
||||||
|
|
@ -112,6 +114,15 @@ pub(crate) async fn pip_compile(
|
||||||
printer: Printer,
|
printer: Printer,
|
||||||
preview: Preview,
|
preview: Preview,
|
||||||
) -> Result<ExitStatus> {
|
) -> 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
|
// If the user provides a `pyproject.toml` or other TOML file as the output file, raise an
|
||||||
// error.
|
// error.
|
||||||
if output_file
|
if output_file
|
||||||
|
|
@ -469,6 +480,8 @@ pub(crate) async fn pip_compile(
|
||||||
.map(|constraint| constraint.requirement.clone()),
|
.map(|constraint| constraint.requirement.clone()),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let extra_build_requires =
|
||||||
|
uv_distribution::ExtraBuildRequires::from_lowered(extra_build_dependencies.clone());
|
||||||
let build_dispatch = BuildDispatch::new(
|
let build_dispatch = BuildDispatch::new(
|
||||||
&client,
|
&client,
|
||||||
&cache,
|
&cache,
|
||||||
|
|
@ -482,6 +495,7 @@ pub(crate) async fn pip_compile(
|
||||||
&config_settings,
|
&config_settings,
|
||||||
&config_settings_package,
|
&config_settings_package,
|
||||||
build_isolation,
|
build_isolation,
|
||||||
|
&extra_build_requires,
|
||||||
link_mode,
|
link_mode,
|
||||||
&build_options,
|
&build_options,
|
||||||
&build_hashes,
|
&build_hashes,
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,9 @@ use uv_resolver::{
|
||||||
};
|
};
|
||||||
use uv_torch::{TorchMode, TorchStrategy};
|
use uv_torch::{TorchMode, TorchStrategy};
|
||||||
use uv_types::{BuildIsolation, HashStrategy};
|
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::WorkspaceCache;
|
||||||
|
use uv_workspace::pyproject::ExtraBuildDependencies;
|
||||||
|
|
||||||
use crate::commands::pip::loggers::{DefaultInstallLogger, DefaultResolveLogger, InstallLogger};
|
use crate::commands::pip::loggers::{DefaultInstallLogger, DefaultResolveLogger, InstallLogger};
|
||||||
use crate::commands::pip::operations::Modifications;
|
use crate::commands::pip::operations::Modifications;
|
||||||
|
|
@ -78,6 +79,7 @@ pub(crate) async fn pip_install(
|
||||||
config_settings_package: &PackageConfigSettings,
|
config_settings_package: &PackageConfigSettings,
|
||||||
no_build_isolation: bool,
|
no_build_isolation: bool,
|
||||||
no_build_isolation_package: Vec<PackageName>,
|
no_build_isolation_package: Vec<PackageName>,
|
||||||
|
extra_build_dependencies: &ExtraBuildDependencies,
|
||||||
build_options: BuildOptions,
|
build_options: BuildOptions,
|
||||||
modifications: Modifications,
|
modifications: Modifications,
|
||||||
python_version: Option<PythonVersion>,
|
python_version: Option<PythonVersion>,
|
||||||
|
|
@ -99,6 +101,15 @@ pub(crate) async fn pip_install(
|
||||||
) -> anyhow::Result<ExitStatus> {
|
) -> anyhow::Result<ExitStatus> {
|
||||||
let start = std::time::Instant::now();
|
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()
|
let client_builder = BaseClientBuilder::new()
|
||||||
.retries_from_env()?
|
.retries_from_env()?
|
||||||
.connectivity(network_settings.connectivity)
|
.connectivity(network_settings.connectivity)
|
||||||
|
|
@ -413,6 +424,8 @@ pub(crate) async fn pip_install(
|
||||||
let state = SharedState::default();
|
let state = SharedState::default();
|
||||||
|
|
||||||
// Create a build dispatch.
|
// Create a build dispatch.
|
||||||
|
let extra_build_requires =
|
||||||
|
uv_distribution::ExtraBuildRequires::from_lowered(extra_build_dependencies.clone());
|
||||||
let build_dispatch = BuildDispatch::new(
|
let build_dispatch = BuildDispatch::new(
|
||||||
&client,
|
&client,
|
||||||
&cache,
|
&cache,
|
||||||
|
|
@ -426,6 +439,7 @@ pub(crate) async fn pip_install(
|
||||||
config_settings,
|
config_settings,
|
||||||
config_settings_package,
|
config_settings_package,
|
||||||
build_isolation,
|
build_isolation,
|
||||||
|
&extra_build_requires,
|
||||||
link_mode,
|
link_mode,
|
||||||
&build_options,
|
&build_options,
|
||||||
&build_hasher,
|
&build_hasher,
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,9 @@ use uv_resolver::{
|
||||||
};
|
};
|
||||||
use uv_torch::{TorchMode, TorchStrategy};
|
use uv_torch::{TorchMode, TorchStrategy};
|
||||||
use uv_types::{BuildIsolation, HashStrategy};
|
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::WorkspaceCache;
|
||||||
|
use uv_workspace::pyproject::ExtraBuildDependencies;
|
||||||
|
|
||||||
use crate::commands::pip::loggers::{DefaultInstallLogger, DefaultResolveLogger};
|
use crate::commands::pip::loggers::{DefaultInstallLogger, DefaultResolveLogger};
|
||||||
use crate::commands::pip::operations::Modifications;
|
use crate::commands::pip::operations::Modifications;
|
||||||
|
|
@ -67,6 +68,7 @@ pub(crate) async fn pip_sync(
|
||||||
config_settings_package: &PackageConfigSettings,
|
config_settings_package: &PackageConfigSettings,
|
||||||
no_build_isolation: bool,
|
no_build_isolation: bool,
|
||||||
no_build_isolation_package: Vec<PackageName>,
|
no_build_isolation_package: Vec<PackageName>,
|
||||||
|
extra_build_dependencies: &ExtraBuildDependencies,
|
||||||
build_options: BuildOptions,
|
build_options: BuildOptions,
|
||||||
python_version: Option<PythonVersion>,
|
python_version: Option<PythonVersion>,
|
||||||
python_platform: Option<TargetTriple>,
|
python_platform: Option<TargetTriple>,
|
||||||
|
|
@ -85,6 +87,15 @@ pub(crate) async fn pip_sync(
|
||||||
printer: Printer,
|
printer: Printer,
|
||||||
preview: Preview,
|
preview: Preview,
|
||||||
) -> Result<ExitStatus> {
|
) -> 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()
|
let client_builder = BaseClientBuilder::new()
|
||||||
.retries_from_env()?
|
.retries_from_env()?
|
||||||
.connectivity(network_settings.connectivity)
|
.connectivity(network_settings.connectivity)
|
||||||
|
|
@ -348,6 +359,8 @@ pub(crate) async fn pip_sync(
|
||||||
let state = SharedState::default();
|
let state = SharedState::default();
|
||||||
|
|
||||||
// Create a build dispatch.
|
// Create a build dispatch.
|
||||||
|
let extra_build_requires =
|
||||||
|
uv_distribution::ExtraBuildRequires::from_lowered(extra_build_dependencies.clone());
|
||||||
let build_dispatch = BuildDispatch::new(
|
let build_dispatch = BuildDispatch::new(
|
||||||
&client,
|
&client,
|
||||||
&cache,
|
&cache,
|
||||||
|
|
@ -361,6 +374,7 @@ pub(crate) async fn pip_sync(
|
||||||
config_settings,
|
config_settings,
|
||||||
config_settings_package,
|
config_settings_package,
|
||||||
build_isolation,
|
build_isolation,
|
||||||
|
&extra_build_requires,
|
||||||
link_mode,
|
link_mode,
|
||||||
&build_options,
|
&build_options,
|
||||||
&build_hasher,
|
&build_hasher,
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ use uv_python::{Interpreter, PythonDownloads, PythonEnvironment, PythonPreferenc
|
||||||
use uv_redacted::DisplaySafeUrl;
|
use uv_redacted::DisplaySafeUrl;
|
||||||
use uv_requirements::{NamedRequirementsResolver, RequirementsSource, RequirementsSpecification};
|
use uv_requirements::{NamedRequirementsResolver, RequirementsSource, RequirementsSpecification};
|
||||||
use uv_resolver::FlatIndex;
|
use uv_resolver::FlatIndex;
|
||||||
use uv_scripts::{Pep723ItemRef, Pep723Metadata, Pep723Script};
|
use uv_scripts::{Pep723Metadata, Pep723Script};
|
||||||
use uv_settings::PythonInstallMirrors;
|
use uv_settings::PythonInstallMirrors;
|
||||||
use uv_types::{BuildIsolation, HashStrategy};
|
use uv_types::{BuildIsolation, HashStrategy};
|
||||||
use uv_warnings::warn_user_once;
|
use uv_warnings::warn_user_once;
|
||||||
|
|
@ -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 {
|
for source in &requirements {
|
||||||
match source {
|
match source {
|
||||||
RequirementsSource::PyprojectToml(_) => {
|
RequirementsSource::PyprojectToml(_) => {
|
||||||
|
|
@ -212,7 +221,7 @@ pub(crate) async fn add(
|
||||||
|
|
||||||
// Discover the interpreter.
|
// Discover the interpreter.
|
||||||
let interpreter = ScriptInterpreter::discover(
|
let interpreter = ScriptInterpreter::discover(
|
||||||
Pep723ItemRef::Script(&script),
|
(&script).into(),
|
||||||
python.as_deref().map(PythonRequest::parse),
|
python.as_deref().map(PythonRequest::parse),
|
||||||
&network_settings,
|
&network_settings,
|
||||||
python_preference,
|
python_preference,
|
||||||
|
|
@ -428,6 +437,18 @@ pub(crate) async fn add(
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create a build dispatch.
|
// 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(
|
let build_dispatch = BuildDispatch::new(
|
||||||
&client,
|
&client,
|
||||||
cache,
|
cache,
|
||||||
|
|
@ -441,6 +462,7 @@ pub(crate) async fn add(
|
||||||
&settings.resolver.config_setting,
|
&settings.resolver.config_setting,
|
||||||
&settings.resolver.config_settings_package,
|
&settings.resolver.config_settings_package,
|
||||||
build_isolation,
|
build_isolation,
|
||||||
|
&extra_build_requires,
|
||||||
settings.resolver.link_mode,
|
settings.resolver.link_mode,
|
||||||
&settings.resolver.build_options,
|
&settings.resolver.build_options,
|
||||||
&build_hasher,
|
&build_hasher,
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use uv_normalize::{DefaultExtras, DefaultGroups, PackageName};
|
||||||
use uv_python::{PythonDownloads, PythonPreference, PythonRequest};
|
use uv_python::{PythonDownloads, PythonPreference, PythonRequest};
|
||||||
use uv_requirements::is_pylock_toml;
|
use uv_requirements::is_pylock_toml;
|
||||||
use uv_resolver::{PylockToml, RequirementsTxtExport};
|
use uv_resolver::{PylockToml, RequirementsTxtExport};
|
||||||
use uv_scripts::{Pep723ItemRef, Pep723Script};
|
use uv_scripts::Pep723Script;
|
||||||
use uv_settings::PythonInstallMirrors;
|
use uv_settings::PythonInstallMirrors;
|
||||||
use uv_workspace::{DiscoveryOptions, MemberDiscovery, VirtualProject, Workspace, WorkspaceCache};
|
use uv_workspace::{DiscoveryOptions, MemberDiscovery, VirtualProject, Workspace, WorkspaceCache};
|
||||||
|
|
||||||
|
|
@ -132,7 +132,7 @@ pub(crate) async fn export(
|
||||||
} else {
|
} else {
|
||||||
Some(match &target {
|
Some(match &target {
|
||||||
ExportTarget::Script(script) => ScriptInterpreter::discover(
|
ExportTarget::Script(script) => ScriptInterpreter::discover(
|
||||||
Pep723ItemRef::Script(script),
|
script.into(),
|
||||||
python.as_deref().map(PythonRequest::parse),
|
python.as_deref().map(PythonRequest::parse),
|
||||||
&network_settings,
|
&network_settings,
|
||||||
python_preference,
|
python_preference,
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use uv_cache::Cache;
|
||||||
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
||||||
use uv_configuration::{
|
use uv_configuration::{
|
||||||
Concurrency, Constraints, DependencyGroupsWithDefaults, DryRun, ExtrasSpecification, Preview,
|
Concurrency, Constraints, DependencyGroupsWithDefaults, DryRun, ExtrasSpecification, Preview,
|
||||||
Reinstall, Upgrade,
|
PreviewFeatures, Reinstall, Upgrade,
|
||||||
};
|
};
|
||||||
use uv_dispatch::BuildDispatch;
|
use uv_dispatch::BuildDispatch;
|
||||||
use uv_distribution::DistributionDatabase;
|
use uv_distribution::DistributionDatabase;
|
||||||
|
|
@ -32,7 +32,7 @@ use uv_resolver::{
|
||||||
FlatIndex, InMemoryIndex, Lock, Options, OptionsBuilder, PythonRequirement,
|
FlatIndex, InMemoryIndex, Lock, Options, OptionsBuilder, PythonRequirement,
|
||||||
ResolverEnvironment, ResolverManifest, SatisfiesResult, UniversalMarker,
|
ResolverEnvironment, ResolverManifest, SatisfiesResult, UniversalMarker,
|
||||||
};
|
};
|
||||||
use uv_scripts::{Pep723ItemRef, Pep723Script};
|
use uv_scripts::Pep723Script;
|
||||||
use uv_settings::PythonInstallMirrors;
|
use uv_settings::PythonInstallMirrors;
|
||||||
use uv_types::{BuildContext, BuildIsolation, EmptyInstalledPackages, HashStrategy};
|
use uv_types::{BuildContext, BuildIsolation, EmptyInstalledPackages, HashStrategy};
|
||||||
use uv_warnings::{warn_user, warn_user_once};
|
use uv_warnings::{warn_user, warn_user_once};
|
||||||
|
|
@ -42,7 +42,7 @@ use crate::commands::pip::loggers::{DefaultResolveLogger, ResolveLogger, Summary
|
||||||
use crate::commands::project::lock_target::LockTarget;
|
use crate::commands::project::lock_target::LockTarget;
|
||||||
use crate::commands::project::{
|
use crate::commands::project::{
|
||||||
ProjectError, ProjectInterpreter, ScriptInterpreter, UniversalState,
|
ProjectError, ProjectInterpreter, ScriptInterpreter, UniversalState,
|
||||||
init_script_python_requirement,
|
init_script_python_requirement, script_extra_build_requires,
|
||||||
};
|
};
|
||||||
use crate::commands::reporters::{PythonDownloadReporter, ResolverReporter};
|
use crate::commands::reporters::{PythonDownloadReporter, ResolverReporter};
|
||||||
use crate::commands::{ExitStatus, ScriptPath, diagnostics, pip};
|
use crate::commands::{ExitStatus, ScriptPath, diagnostics, pip};
|
||||||
|
|
@ -162,7 +162,7 @@ pub(crate) async fn lock(
|
||||||
.await?
|
.await?
|
||||||
.into_interpreter(),
|
.into_interpreter(),
|
||||||
LockTarget::Script(script) => ScriptInterpreter::discover(
|
LockTarget::Script(script) => ScriptInterpreter::discover(
|
||||||
Pep723ItemRef::Script(script),
|
script.into(),
|
||||||
python.as_deref().map(PythonRequest::parse),
|
python.as_deref().map(PythonRequest::parse),
|
||||||
&network_settings,
|
&network_settings,
|
||||||
python_preference,
|
python_preference,
|
||||||
|
|
@ -435,6 +435,7 @@ async fn do_lock(
|
||||||
config_settings_package,
|
config_settings_package,
|
||||||
no_build_isolation,
|
no_build_isolation,
|
||||||
no_build_isolation_package,
|
no_build_isolation_package,
|
||||||
|
extra_build_dependencies,
|
||||||
exclude_newer,
|
exclude_newer,
|
||||||
link_mode,
|
link_mode,
|
||||||
upgrade,
|
upgrade,
|
||||||
|
|
@ -442,6 +443,15 @@ async fn do_lock(
|
||||||
sources,
|
sources,
|
||||||
} = settings;
|
} = 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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Collect the requirements, etc.
|
// Collect the requirements, etc.
|
||||||
let members = target.members();
|
let members = target.members();
|
||||||
let packages = target.packages();
|
let packages = target.packages();
|
||||||
|
|
@ -664,6 +674,18 @@ async fn do_lock(
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create a build dispatch.
|
// 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_extra_build_requires((*script).into(), settings)?
|
||||||
|
}
|
||||||
|
};
|
||||||
let build_dispatch = BuildDispatch::new(
|
let build_dispatch = BuildDispatch::new(
|
||||||
&client,
|
&client,
|
||||||
cache,
|
cache,
|
||||||
|
|
@ -677,6 +699,7 @@ async fn do_lock(
|
||||||
config_setting,
|
config_setting,
|
||||||
config_settings_package,
|
config_settings_package,
|
||||||
build_isolation,
|
build_isolation,
|
||||||
|
&extra_build_requires,
|
||||||
*link_mode,
|
*link_mode,
|
||||||
build_options,
|
build_options,
|
||||||
&build_hasher,
|
&build_hasher,
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use uv_cache_key::cache_digest;
|
||||||
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
||||||
use uv_configuration::{
|
use uv_configuration::{
|
||||||
Concurrency, Constraints, DependencyGroupsWithDefaults, DryRun, ExtrasSpecification, Preview,
|
Concurrency, Constraints, DependencyGroupsWithDefaults, DryRun, ExtrasSpecification, Preview,
|
||||||
PreviewFeatures, Reinstall, SourceStrategy, Upgrade,
|
PreviewFeatures, Reinstall, Upgrade,
|
||||||
};
|
};
|
||||||
use uv_dispatch::{BuildDispatch, SharedState};
|
use uv_dispatch::{BuildDispatch, SharedState};
|
||||||
use uv_distribution::{DistributionDatabase, LoweredRequirement};
|
use uv_distribution::{DistributionDatabase, LoweredRequirement};
|
||||||
|
|
@ -46,6 +46,7 @@ use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy};
|
||||||
use uv_virtualenv::remove_virtualenv;
|
use uv_virtualenv::remove_virtualenv;
|
||||||
use uv_warnings::{warn_user, warn_user_once};
|
use uv_warnings::{warn_user, warn_user_once};
|
||||||
use uv_workspace::dependency_groups::DependencyGroupError;
|
use uv_workspace::dependency_groups::DependencyGroupError;
|
||||||
|
use uv_workspace::pyproject::ExtraBuildDependencies;
|
||||||
use uv_workspace::pyproject::PyProjectToml;
|
use uv_workspace::pyproject::PyProjectToml;
|
||||||
use uv_workspace::{RequiresPythonSources, Workspace, WorkspaceCache};
|
use uv_workspace::{RequiresPythonSources, Workspace, WorkspaceCache};
|
||||||
|
|
||||||
|
|
@ -1692,6 +1693,7 @@ pub(crate) async fn resolve_names(
|
||||||
link_mode,
|
link_mode,
|
||||||
no_build_isolation,
|
no_build_isolation,
|
||||||
no_build_isolation_package,
|
no_build_isolation_package,
|
||||||
|
extra_build_dependencies,
|
||||||
prerelease: _,
|
prerelease: _,
|
||||||
resolution: _,
|
resolution: _,
|
||||||
sources,
|
sources,
|
||||||
|
|
@ -1740,6 +1742,8 @@ pub(crate) async fn resolve_names(
|
||||||
let build_hasher = HashStrategy::default();
|
let build_hasher = HashStrategy::default();
|
||||||
|
|
||||||
// Create a build dispatch.
|
// Create a build dispatch.
|
||||||
|
let extra_build_requires =
|
||||||
|
uv_distribution::ExtraBuildRequires::from_lowered(extra_build_dependencies.clone());
|
||||||
let build_dispatch = BuildDispatch::new(
|
let build_dispatch = BuildDispatch::new(
|
||||||
&client,
|
&client,
|
||||||
cache,
|
cache,
|
||||||
|
|
@ -1753,6 +1757,7 @@ pub(crate) async fn resolve_names(
|
||||||
config_setting,
|
config_setting,
|
||||||
config_settings_package,
|
config_settings_package,
|
||||||
build_isolation,
|
build_isolation,
|
||||||
|
&extra_build_requires,
|
||||||
*link_mode,
|
*link_mode,
|
||||||
build_options,
|
build_options,
|
||||||
&build_hasher,
|
&build_hasher,
|
||||||
|
|
@ -1845,6 +1850,7 @@ pub(crate) async fn resolve_environment(
|
||||||
config_settings_package,
|
config_settings_package,
|
||||||
no_build_isolation,
|
no_build_isolation,
|
||||||
no_build_isolation_package,
|
no_build_isolation_package,
|
||||||
|
extra_build_dependencies,
|
||||||
exclude_newer,
|
exclude_newer,
|
||||||
link_mode,
|
link_mode,
|
||||||
upgrade: _,
|
upgrade: _,
|
||||||
|
|
@ -1948,6 +1954,8 @@ pub(crate) async fn resolve_environment(
|
||||||
let workspace_cache = WorkspaceCache::default();
|
let workspace_cache = WorkspaceCache::default();
|
||||||
|
|
||||||
// Create a build dispatch.
|
// Create a build dispatch.
|
||||||
|
let extra_build_requires =
|
||||||
|
uv_distribution::ExtraBuildRequires::from_lowered(extra_build_dependencies.clone());
|
||||||
let resolve_dispatch = BuildDispatch::new(
|
let resolve_dispatch = BuildDispatch::new(
|
||||||
&client,
|
&client,
|
||||||
cache,
|
cache,
|
||||||
|
|
@ -1961,6 +1969,7 @@ pub(crate) async fn resolve_environment(
|
||||||
config_setting,
|
config_setting,
|
||||||
config_settings_package,
|
config_settings_package,
|
||||||
build_isolation,
|
build_isolation,
|
||||||
|
&extra_build_requires,
|
||||||
*link_mode,
|
*link_mode,
|
||||||
build_options,
|
build_options,
|
||||||
&build_hasher,
|
&build_hasher,
|
||||||
|
|
@ -2028,6 +2037,7 @@ pub(crate) async fn sync_environment(
|
||||||
config_settings_package,
|
config_settings_package,
|
||||||
no_build_isolation,
|
no_build_isolation,
|
||||||
no_build_isolation_package,
|
no_build_isolation_package,
|
||||||
|
extra_build_dependencies,
|
||||||
exclude_newer,
|
exclude_newer,
|
||||||
link_mode,
|
link_mode,
|
||||||
compile_bytecode,
|
compile_bytecode,
|
||||||
|
|
@ -2086,6 +2096,8 @@ pub(crate) async fn sync_environment(
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create a build dispatch.
|
// Create a build dispatch.
|
||||||
|
let extra_build_requires =
|
||||||
|
uv_distribution::ExtraBuildRequires::from_lowered(extra_build_dependencies.clone());
|
||||||
let build_dispatch = BuildDispatch::new(
|
let build_dispatch = BuildDispatch::new(
|
||||||
&client,
|
&client,
|
||||||
cache,
|
cache,
|
||||||
|
|
@ -2099,6 +2111,7 @@ pub(crate) async fn sync_environment(
|
||||||
config_setting,
|
config_setting,
|
||||||
config_settings_package,
|
config_settings_package,
|
||||||
build_isolation,
|
build_isolation,
|
||||||
|
&extra_build_requires,
|
||||||
link_mode,
|
link_mode,
|
||||||
build_options,
|
build_options,
|
||||||
&build_hasher,
|
&build_hasher,
|
||||||
|
|
@ -2164,6 +2177,7 @@ pub(crate) async fn update_environment(
|
||||||
spec: RequirementsSpecification,
|
spec: RequirementsSpecification,
|
||||||
modifications: Modifications,
|
modifications: Modifications,
|
||||||
build_constraints: Constraints,
|
build_constraints: Constraints,
|
||||||
|
extra_build_requires: uv_distribution::ExtraBuildRequires,
|
||||||
settings: &ResolverInstallerSettings,
|
settings: &ResolverInstallerSettings,
|
||||||
network_settings: &NetworkSettings,
|
network_settings: &NetworkSettings,
|
||||||
state: &SharedState,
|
state: &SharedState,
|
||||||
|
|
@ -2194,6 +2208,7 @@ pub(crate) async fn update_environment(
|
||||||
link_mode,
|
link_mode,
|
||||||
no_build_isolation,
|
no_build_isolation,
|
||||||
no_build_isolation_package,
|
no_build_isolation_package,
|
||||||
|
extra_build_dependencies: _,
|
||||||
prerelease,
|
prerelease,
|
||||||
resolution,
|
resolution,
|
||||||
sources,
|
sources,
|
||||||
|
|
@ -2323,6 +2338,7 @@ pub(crate) async fn update_environment(
|
||||||
config_setting,
|
config_setting,
|
||||||
config_settings_package,
|
config_settings_package,
|
||||||
build_isolation,
|
build_isolation,
|
||||||
|
&extra_build_requires,
|
||||||
*link_mode,
|
*link_mode,
|
||||||
build_options,
|
build_options,
|
||||||
&build_hasher,
|
&build_hasher,
|
||||||
|
|
@ -2537,40 +2553,9 @@ pub(crate) fn script_specification(
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Determine the working directory for the script.
|
let script_dir = script.directory()?;
|
||||||
let script_dir = match &script {
|
let script_indexes = script.indexes(settings.sources);
|
||||||
Pep723ItemRef::Script(script) => std::path::absolute(&script.path)?
|
let script_sources = script.sources(settings.sources);
|
||||||
.parent()
|
|
||||||
.expect("script path has no parent")
|
|
||||||
.to_owned(),
|
|
||||||
Pep723ItemRef::Stdin(..) | Pep723ItemRef::Remote(..) => std::env::current_dir()?,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Collect any `tool.uv.index` from the script.
|
|
||||||
let empty = Vec::default();
|
|
||||||
let script_indexes = match settings.sources {
|
|
||||||
SourceStrategy::Enabled => script
|
|
||||||
.metadata()
|
|
||||||
.tool
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|tool| tool.uv.as_ref())
|
|
||||||
.and_then(|uv| uv.top_level.index.as_deref())
|
|
||||||
.unwrap_or(&empty),
|
|
||||||
SourceStrategy::Disabled => &empty,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Collect any `tool.uv.sources` from the script.
|
|
||||||
let empty = BTreeMap::default();
|
|
||||||
let script_sources = match settings.sources {
|
|
||||||
SourceStrategy::Enabled => script
|
|
||||||
.metadata()
|
|
||||||
.tool
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|tool| tool.uv.as_ref())
|
|
||||||
.and_then(|uv| uv.sources.as_ref())
|
|
||||||
.unwrap_or(&empty),
|
|
||||||
SourceStrategy::Disabled => &empty,
|
|
||||||
};
|
|
||||||
|
|
||||||
let requirements = dependencies
|
let requirements = dependencies
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -2634,6 +2619,51 @@ pub(crate) fn script_specification(
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determine the extra build requires for a script.
|
||||||
|
#[allow(clippy::result_large_err)]
|
||||||
|
pub(crate) fn script_extra_build_requires(
|
||||||
|
script: Pep723ItemRef<'_>,
|
||||||
|
settings: &ResolverSettings,
|
||||||
|
) -> Result<uv_distribution::ExtraBuildRequires, ProjectError> {
|
||||||
|
let script_dir = script.directory()?;
|
||||||
|
let script_indexes = script.indexes(settings.sources);
|
||||||
|
let script_sources = script.sources(settings.sources);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(uv_distribution::ExtraBuildRequires::from_lowered(
|
||||||
|
extra_build_dependencies,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
/// Warn if the user provides (e.g.) an `--index-url` in a requirements file.
|
/// Warn if the user provides (e.g.) an `--index-url` in a requirements file.
|
||||||
fn warn_on_requirements_txt_setting(spec: &RequirementsSpecification, settings: &ResolverSettings) {
|
fn warn_on_requirements_txt_setting(spec: &RequirementsSpecification, settings: &ResolverSettings) {
|
||||||
let RequirementsSpecification {
|
let RequirementsSpecification {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ use uv_fs::Simplified;
|
||||||
use uv_normalize::{DEV_DEPENDENCIES, DefaultExtras, DefaultGroups};
|
use uv_normalize::{DEV_DEPENDENCIES, DefaultExtras, DefaultGroups};
|
||||||
use uv_pep508::PackageName;
|
use uv_pep508::PackageName;
|
||||||
use uv_python::{PythonDownloads, PythonPreference, PythonRequest};
|
use uv_python::{PythonDownloads, PythonPreference, PythonRequest};
|
||||||
use uv_scripts::{Pep723ItemRef, Pep723Metadata, Pep723Script};
|
use uv_scripts::{Pep723Metadata, Pep723Script};
|
||||||
use uv_settings::PythonInstallMirrors;
|
use uv_settings::PythonInstallMirrors;
|
||||||
use uv_warnings::warn_user_once;
|
use uv_warnings::warn_user_once;
|
||||||
use uv_workspace::pyproject::DependencyType;
|
use uv_workspace::pyproject::DependencyType;
|
||||||
|
|
@ -261,7 +261,7 @@ pub(crate) async fn remove(
|
||||||
}
|
}
|
||||||
RemoveTarget::Script(script) => {
|
RemoveTarget::Script(script) => {
|
||||||
let interpreter = ScriptInterpreter::discover(
|
let interpreter = ScriptInterpreter::discover(
|
||||||
Pep723ItemRef::Script(&script),
|
(&script).into(),
|
||||||
python.as_deref().map(PythonRequest::parse),
|
python.as_deref().map(PythonRequest::parse),
|
||||||
&network_settings,
|
&network_settings,
|
||||||
python_preference,
|
python_preference,
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,8 @@ use crate::commands::project::lock_target::LockTarget;
|
||||||
use crate::commands::project::{
|
use crate::commands::project::{
|
||||||
EnvironmentSpecification, PreferenceLocation, ProjectEnvironment, ProjectError,
|
EnvironmentSpecification, PreferenceLocation, ProjectEnvironment, ProjectError,
|
||||||
ScriptEnvironment, ScriptInterpreter, UniversalState, WorkspacePython,
|
ScriptEnvironment, ScriptInterpreter, UniversalState, WorkspacePython,
|
||||||
default_dependency_groups, script_specification, update_environment,
|
default_dependency_groups, script_extra_build_requires, script_specification,
|
||||||
validate_project_requires_python,
|
update_environment, validate_project_requires_python,
|
||||||
};
|
};
|
||||||
use crate::commands::reporters::PythonDownloadReporter;
|
use crate::commands::reporters::PythonDownloadReporter;
|
||||||
use crate::commands::{ExitStatus, diagnostics, project};
|
use crate::commands::{ExitStatus, diagnostics, project};
|
||||||
|
|
@ -359,6 +359,8 @@ 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.
|
// Install the script requirements, if necessary. Otherwise, use an isolated environment.
|
||||||
if let Some(spec) = script_specification((&script).into(), &settings.resolver)? {
|
if let Some(spec) = script_specification((&script).into(), &settings.resolver)? {
|
||||||
|
let script_extra_build_requires =
|
||||||
|
script_extra_build_requires((&script).into(), &settings.resolver)?;
|
||||||
let environment = ScriptEnvironment::get_or_init(
|
let environment = ScriptEnvironment::get_or_init(
|
||||||
(&script).into(),
|
(&script).into(),
|
||||||
python.as_deref().map(PythonRequest::parse),
|
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,
|
spec,
|
||||||
modifications,
|
modifications,
|
||||||
build_constraints.unwrap_or_default(),
|
build_constraints.unwrap_or_default(),
|
||||||
|
script_extra_build_requires,
|
||||||
&settings,
|
&settings,
|
||||||
&network_settings,
|
&network_settings,
|
||||||
&sync_state,
|
&sync_state,
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
|
||||||
use uv_configuration::{
|
use uv_configuration::{
|
||||||
Concurrency, Constraints, DependencyGroups, DependencyGroupsWithDefaults, DryRun, EditableMode,
|
Concurrency, Constraints, DependencyGroups, DependencyGroupsWithDefaults, DryRun, EditableMode,
|
||||||
ExtrasSpecification, ExtrasSpecificationWithDefaults, HashCheckingMode, InstallOptions,
|
ExtrasSpecification, ExtrasSpecificationWithDefaults, HashCheckingMode, InstallOptions,
|
||||||
Preview, PreviewFeatures, TargetTriple,
|
Preview, PreviewFeatures, TargetTriple, Upgrade,
|
||||||
};
|
};
|
||||||
use uv_dispatch::BuildDispatch;
|
use uv_dispatch::BuildDispatch;
|
||||||
use uv_distribution_types::{
|
use uv_distribution_types::{
|
||||||
|
|
@ -26,11 +26,11 @@ use uv_normalize::{DefaultExtras, DefaultGroups, PackageName};
|
||||||
use uv_pep508::{MarkerTree, VersionOrUrl};
|
use uv_pep508::{MarkerTree, VersionOrUrl};
|
||||||
use uv_pypi_types::{ParsedArchiveUrl, ParsedGitUrl, ParsedUrl};
|
use uv_pypi_types::{ParsedArchiveUrl, ParsedGitUrl, ParsedUrl};
|
||||||
use uv_python::{PythonDownloads, PythonEnvironment, PythonPreference, PythonRequest};
|
use uv_python::{PythonDownloads, PythonEnvironment, PythonPreference, PythonRequest};
|
||||||
use uv_resolver::{FlatIndex, Installable, Lock};
|
use uv_resolver::{FlatIndex, ForkStrategy, Installable, Lock, PrereleaseMode, ResolutionMode};
|
||||||
use uv_scripts::{Pep723ItemRef, Pep723Script};
|
use uv_scripts::Pep723Script;
|
||||||
use uv_settings::PythonInstallMirrors;
|
use uv_settings::PythonInstallMirrors;
|
||||||
use uv_types::{BuildIsolation, HashStrategy};
|
use uv_types::{BuildIsolation, HashStrategy};
|
||||||
use uv_warnings::warn_user;
|
use uv_warnings::{warn_user, warn_user_once};
|
||||||
use uv_workspace::pyproject::Source;
|
use uv_workspace::pyproject::Source;
|
||||||
use uv_workspace::{DiscoveryOptions, MemberDiscovery, VirtualProject, Workspace, WorkspaceCache};
|
use uv_workspace::{DiscoveryOptions, MemberDiscovery, VirtualProject, Workspace, WorkspaceCache};
|
||||||
|
|
||||||
|
|
@ -43,11 +43,14 @@ use crate::commands::project::lock::{LockMode, LockOperation, LockResult};
|
||||||
use crate::commands::project::lock_target::LockTarget;
|
use crate::commands::project::lock_target::LockTarget;
|
||||||
use crate::commands::project::{
|
use crate::commands::project::{
|
||||||
PlatformState, ProjectEnvironment, ProjectError, ScriptEnvironment, UniversalState,
|
PlatformState, ProjectEnvironment, ProjectError, ScriptEnvironment, UniversalState,
|
||||||
default_dependency_groups, detect_conflicts, script_specification, update_environment,
|
default_dependency_groups, detect_conflicts, script_extra_build_requires, script_specification,
|
||||||
|
update_environment,
|
||||||
};
|
};
|
||||||
use crate::commands::{ExitStatus, diagnostics};
|
use crate::commands::{ExitStatus, diagnostics};
|
||||||
use crate::printer::Printer;
|
use crate::printer::Printer;
|
||||||
use crate::settings::{InstallerSettingsRef, NetworkSettings, ResolverInstallerSettings};
|
use crate::settings::{
|
||||||
|
InstallerSettingsRef, NetworkSettings, ResolverInstallerSettings, ResolverSettings,
|
||||||
|
};
|
||||||
|
|
||||||
/// Sync the project environment.
|
/// Sync the project environment.
|
||||||
#[allow(clippy::fn_params_excessive_bools)]
|
#[allow(clippy::fn_params_excessive_bools)]
|
||||||
|
|
@ -164,7 +167,7 @@ pub(crate) async fn sync(
|
||||||
),
|
),
|
||||||
SyncTarget::Script(script) => SyncEnvironment::Script(
|
SyncTarget::Script(script) => SyncEnvironment::Script(
|
||||||
ScriptEnvironment::get_or_init(
|
ScriptEnvironment::get_or_init(
|
||||||
Pep723ItemRef::Script(script),
|
script.into(),
|
||||||
python.as_deref().map(PythonRequest::parse),
|
python.as_deref().map(PythonRequest::parse),
|
||||||
&network_settings,
|
&network_settings,
|
||||||
python_preference,
|
python_preference,
|
||||||
|
|
@ -222,8 +225,9 @@ pub(crate) async fn sync(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the requirements from the script.
|
// Parse the requirements from the script.
|
||||||
let spec = script_specification(Pep723ItemRef::Script(script), &settings.resolver)?
|
let spec = script_specification(script.into(), &settings.resolver)?.unwrap_or_default();
|
||||||
.unwrap_or_default();
|
let script_extra_build_requires =
|
||||||
|
script_extra_build_requires(script.into(), &settings.resolver)?;
|
||||||
|
|
||||||
// Parse the build constraints from the script.
|
// Parse the build constraints from the script.
|
||||||
let build_constraints = script
|
let build_constraints = script
|
||||||
|
|
@ -248,6 +252,7 @@ pub(crate) async fn sync(
|
||||||
spec,
|
spec,
|
||||||
modifications,
|
modifications,
|
||||||
build_constraints.unwrap_or_default(),
|
build_constraints.unwrap_or_default(),
|
||||||
|
script_extra_build_requires,
|
||||||
&settings,
|
&settings,
|
||||||
&network_settings,
|
&network_settings,
|
||||||
&PlatformState::default(),
|
&PlatformState::default(),
|
||||||
|
|
@ -579,6 +584,7 @@ pub(super) async fn do_sync(
|
||||||
config_settings_package,
|
config_settings_package,
|
||||||
no_build_isolation,
|
no_build_isolation,
|
||||||
no_build_isolation_package,
|
no_build_isolation_package,
|
||||||
|
extra_build_dependencies,
|
||||||
exclude_newer,
|
exclude_newer,
|
||||||
link_mode,
|
link_mode,
|
||||||
compile_bytecode,
|
compile_bytecode,
|
||||||
|
|
@ -587,6 +593,52 @@ pub(super) async fn do_sync(
|
||||||
sources,
|
sources,
|
||||||
} = settings;
|
} = 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: exclude_newer.clone(),
|
||||||
|
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(),
|
||||||
|
};
|
||||||
|
script_extra_build_requires((*script).into(), &resolver_settings)?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let client_builder = BaseClientBuilder::new()
|
let client_builder = BaseClientBuilder::new()
|
||||||
.retries_from_env()?
|
.retries_from_env()?
|
||||||
.connectivity(network_settings.connectivity)
|
.connectivity(network_settings.connectivity)
|
||||||
|
|
@ -715,10 +767,11 @@ pub(super) async fn do_sync(
|
||||||
config_setting,
|
config_setting,
|
||||||
config_settings_package,
|
config_settings_package,
|
||||||
build_isolation,
|
build_isolation,
|
||||||
|
&extra_build_requires,
|
||||||
link_mode,
|
link_mode,
|
||||||
build_options,
|
build_options,
|
||||||
&build_hasher,
|
&build_hasher,
|
||||||
exclude_newer,
|
exclude_newer.clone(),
|
||||||
sources,
|
sources,
|
||||||
workspace_cache.clone(),
|
workspace_cache.clone(),
|
||||||
concurrency,
|
concurrency,
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use uv_normalize::DefaultGroups;
|
||||||
use uv_pep508::PackageName;
|
use uv_pep508::PackageName;
|
||||||
use uv_python::{PythonDownloads, PythonPreference, PythonRequest, PythonVersion};
|
use uv_python::{PythonDownloads, PythonPreference, PythonRequest, PythonVersion};
|
||||||
use uv_resolver::{PackageMap, TreeDisplay};
|
use uv_resolver::{PackageMap, TreeDisplay};
|
||||||
use uv_scripts::{Pep723ItemRef, Pep723Script};
|
use uv_scripts::Pep723Script;
|
||||||
use uv_settings::PythonInstallMirrors;
|
use uv_settings::PythonInstallMirrors;
|
||||||
use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceCache};
|
use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceCache};
|
||||||
|
|
||||||
|
|
@ -86,7 +86,7 @@ pub(crate) async fn tree(
|
||||||
} else {
|
} else {
|
||||||
Some(match target {
|
Some(match target {
|
||||||
LockTarget::Script(script) => ScriptInterpreter::discover(
|
LockTarget::Script(script) => ScriptInterpreter::discover(
|
||||||
Pep723ItemRef::Script(script),
|
script.into(),
|
||||||
python.as_deref().map(PythonRequest::parse),
|
python.as_deref().map(PythonRequest::parse),
|
||||||
network_settings,
|
network_settings,
|
||||||
python_preference,
|
python_preference,
|
||||||
|
|
@ -203,6 +203,7 @@ pub(crate) async fn tree(
|
||||||
config_settings_package: _,
|
config_settings_package: _,
|
||||||
no_build_isolation: _,
|
no_build_isolation: _,
|
||||||
no_build_isolation_package: _,
|
no_build_isolation_package: _,
|
||||||
|
extra_build_dependencies: _,
|
||||||
exclude_newer: _,
|
exclude_newer: _,
|
||||||
link_mode: _,
|
link_mode: _,
|
||||||
upgrade: _,
|
upgrade: _,
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ use uv_requirements::{RequirementsSource, RequirementsSpecification};
|
||||||
use uv_settings::{PythonInstallMirrors, ResolverInstallerOptions, ToolOptions};
|
use uv_settings::{PythonInstallMirrors, ResolverInstallerOptions, ToolOptions};
|
||||||
use uv_tool::InstalledTools;
|
use uv_tool::InstalledTools;
|
||||||
use uv_warnings::warn_user;
|
use uv_warnings::warn_user;
|
||||||
use uv_workspace::WorkspaceCache;
|
use uv_workspace::{WorkspaceCache, pyproject::ExtraBuildDependencies};
|
||||||
|
|
||||||
use crate::commands::ExitStatus;
|
use crate::commands::ExitStatus;
|
||||||
use crate::commands::pip::loggers::{DefaultInstallLogger, DefaultResolveLogger};
|
use crate::commands::pip::loggers::{DefaultInstallLogger, DefaultResolveLogger};
|
||||||
|
|
@ -439,6 +439,7 @@ pub(crate) async fn install(
|
||||||
spec,
|
spec,
|
||||||
Modifications::Exact,
|
Modifications::Exact,
|
||||||
Constraints::from_requirements(build_constraints.iter().cloned()),
|
Constraints::from_requirements(build_constraints.iter().cloned()),
|
||||||
|
uv_distribution::ExtraBuildRequires::from_lowered(ExtraBuildDependencies::default()),
|
||||||
&settings,
|
&settings,
|
||||||
&network_settings,
|
&network_settings,
|
||||||
&state,
|
&state,
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ use uv_requirements::RequirementsSpecification;
|
||||||
use uv_settings::{Combine, PythonInstallMirrors, ResolverInstallerOptions, ToolOptions};
|
use uv_settings::{Combine, PythonInstallMirrors, ResolverInstallerOptions, ToolOptions};
|
||||||
use uv_tool::InstalledTools;
|
use uv_tool::InstalledTools;
|
||||||
use uv_warnings::write_error_chain;
|
use uv_warnings::write_error_chain;
|
||||||
use uv_workspace::WorkspaceCache;
|
use uv_workspace::{WorkspaceCache, pyproject::ExtraBuildDependencies};
|
||||||
|
|
||||||
use crate::commands::pip::loggers::{
|
use crate::commands::pip::loggers::{
|
||||||
DefaultInstallLogger, SummaryResolveLogger, UpgradeInstallLogger,
|
DefaultInstallLogger, SummaryResolveLogger, UpgradeInstallLogger,
|
||||||
|
|
@ -337,6 +337,7 @@ async fn upgrade_tool(
|
||||||
spec,
|
spec,
|
||||||
Modifications::Exact,
|
Modifications::Exact,
|
||||||
build_constraints,
|
build_constraints,
|
||||||
|
uv_distribution::ExtraBuildRequires::from_lowered(ExtraBuildDependencies::default()),
|
||||||
&settings,
|
&settings,
|
||||||
network_settings,
|
network_settings,
|
||||||
&state,
|
&state,
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ use uv_shell::{Shell, shlex_posix, shlex_windows};
|
||||||
use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, BuildStack, HashStrategy};
|
use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, BuildStack, HashStrategy};
|
||||||
use uv_virtualenv::OnExisting;
|
use uv_virtualenv::OnExisting;
|
||||||
use uv_warnings::warn_user;
|
use uv_warnings::warn_user;
|
||||||
|
use uv_workspace::pyproject::ExtraBuildDependencies;
|
||||||
use uv_workspace::{DiscoveryOptions, VirtualProject, WorkspaceCache, WorkspaceError};
|
use uv_workspace::{DiscoveryOptions, VirtualProject, WorkspaceCache, WorkspaceError};
|
||||||
|
|
||||||
use crate::commands::ExitStatus;
|
use crate::commands::ExitStatus;
|
||||||
|
|
@ -266,7 +267,8 @@ pub(crate) async fn venv(
|
||||||
|
|
||||||
// Do not allow builds
|
// Do not allow builds
|
||||||
let build_options = BuildOptions::new(NoBinary::None, NoBuild::All);
|
let build_options = BuildOptions::new(NoBinary::None, NoBuild::All);
|
||||||
|
let extra_build_requires =
|
||||||
|
uv_distribution::ExtraBuildRequires::from_lowered(ExtraBuildDependencies::default());
|
||||||
// Prep the build context.
|
// Prep the build context.
|
||||||
let build_dispatch = BuildDispatch::new(
|
let build_dispatch = BuildDispatch::new(
|
||||||
&client,
|
&client,
|
||||||
|
|
@ -281,6 +283,7 @@ pub(crate) async fn venv(
|
||||||
&config_settings,
|
&config_settings,
|
||||||
&config_settings_package,
|
&config_settings_package,
|
||||||
BuildIsolation::Isolated,
|
BuildIsolation::Isolated,
|
||||||
|
&extra_build_requires,
|
||||||
link_mode,
|
link_mode,
|
||||||
&build_options,
|
&build_options,
|
||||||
&build_hasher,
|
&build_hasher,
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ use uv_cli::{
|
||||||
ProjectCommand, PythonCommand, PythonNamespace, SelfCommand, SelfNamespace, ToolCommand,
|
ProjectCommand, PythonCommand, PythonNamespace, SelfCommand, SelfNamespace, ToolCommand,
|
||||||
ToolNamespace, TopLevelArgs, compat::CompatArgs,
|
ToolNamespace, TopLevelArgs, compat::CompatArgs,
|
||||||
};
|
};
|
||||||
use uv_configuration::min_stack_size;
|
use uv_configuration::{PreviewFeatures, min_stack_size};
|
||||||
use uv_fs::{CWD, Simplified};
|
use uv_fs::{CWD, Simplified};
|
||||||
#[cfg(feature = "self-update")]
|
#[cfg(feature = "self-update")]
|
||||||
use uv_pep440::release_specifiers_to_ranges;
|
use uv_pep440::release_specifiers_to_ranges;
|
||||||
|
|
@ -37,7 +37,7 @@ use uv_pypi_types::{ParsedDirectoryUrl, ParsedUrl};
|
||||||
use uv_python::PythonRequest;
|
use uv_python::PythonRequest;
|
||||||
use uv_requirements::{GroupsSpecification, RequirementsSource};
|
use uv_requirements::{GroupsSpecification, RequirementsSource};
|
||||||
use uv_requirements_txt::RequirementsTxtRequirement;
|
use uv_requirements_txt::RequirementsTxtRequirement;
|
||||||
use uv_scripts::{Pep723Error, Pep723Item, Pep723ItemRef, Pep723Metadata, Pep723Script};
|
use uv_scripts::{Pep723Error, Pep723Item, Pep723Metadata, Pep723Script};
|
||||||
use uv_settings::{Combine, EnvironmentOptions, FilesystemOptions, Options};
|
use uv_settings::{Combine, EnvironmentOptions, FilesystemOptions, Options};
|
||||||
use uv_static::EnvVars;
|
use uv_static::EnvVars;
|
||||||
use uv_warnings::{warn_user, warn_user_once};
|
use uv_warnings::{warn_user, warn_user_once};
|
||||||
|
|
@ -443,6 +443,16 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
||||||
// Resolve the settings from the command-line arguments and workspace configuration.
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||||
let args = PipCompileSettings::resolve(args, filesystem);
|
let args = PipCompileSettings::resolve(args, filesystem);
|
||||||
show_settings!(args);
|
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.
|
// Initialize the cache.
|
||||||
let cache = cache.init()?.with_refresh(
|
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.config_settings_package,
|
||||||
args.settings.no_build_isolation,
|
args.settings.no_build_isolation,
|
||||||
args.settings.no_build_isolation_package,
|
args.settings.no_build_isolation_package,
|
||||||
|
&args.settings.extra_build_dependencies,
|
||||||
args.settings.build_options,
|
args.settings.build_options,
|
||||||
args.settings.python_version,
|
args.settings.python_version,
|
||||||
args.settings.python_platform,
|
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.
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||||
let args = PipSyncSettings::resolve(args, filesystem);
|
let args = PipSyncSettings::resolve(args, filesystem);
|
||||||
show_settings!(args);
|
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.
|
// Initialize the cache.
|
||||||
let cache = cache.init()?.with_refresh(
|
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.config_settings_package,
|
||||||
args.settings.no_build_isolation,
|
args.settings.no_build_isolation,
|
||||||
args.settings.no_build_isolation_package,
|
args.settings.no_build_isolation_package,
|
||||||
|
&args.settings.extra_build_dependencies,
|
||||||
args.settings.build_options,
|
args.settings.build_options,
|
||||||
args.settings.python_version,
|
args.settings.python_version,
|
||||||
args.settings.python_platform,
|
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.
|
// Resolve the settings from the command-line arguments and workspace configuration.
|
||||||
let mut args = PipInstallSettings::resolve(args, filesystem);
|
let mut args = PipInstallSettings::resolve(args, filesystem);
|
||||||
show_settings!(args);
|
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(
|
let mut requirements = Vec::with_capacity(
|
||||||
args.package.len() + args.editables.len() + args.requirements.len(),
|
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.config_settings_package,
|
||||||
args.settings.no_build_isolation,
|
args.settings.no_build_isolation,
|
||||||
args.settings.no_build_isolation_package,
|
args.settings.no_build_isolation_package,
|
||||||
|
&args.settings.extra_build_dependencies,
|
||||||
args.settings.build_options,
|
args.settings.build_options,
|
||||||
args.modifications,
|
args.modifications,
|
||||||
args.settings.python_version,
|
args.settings.python_version,
|
||||||
|
|
@ -1467,7 +1500,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
||||||
|
|
||||||
if let Some(Pep723Item::Script(script)) = script {
|
if let Some(Pep723Item::Script(script)) = script {
|
||||||
commands::python_find_script(
|
commands::python_find_script(
|
||||||
Pep723ItemRef::Script(&script),
|
(&script).into(),
|
||||||
args.show_version,
|
args.show_version,
|
||||||
&globals.network_settings,
|
&globals.network_settings,
|
||||||
globals.python_preference,
|
globals.python_preference,
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ use uv_settings::{
|
||||||
use uv_static::EnvVars;
|
use uv_static::EnvVars;
|
||||||
use uv_torch::TorchMode;
|
use uv_torch::TorchMode;
|
||||||
use uv_warnings::warn_user_once;
|
use uv_warnings::warn_user_once;
|
||||||
use uv_workspace::pyproject::DependencyType;
|
use uv_workspace::pyproject::{DependencyType, ExtraBuildDependencies};
|
||||||
use uv_workspace::pyproject_mut::AddBoundsKind;
|
use uv_workspace::pyproject_mut::AddBoundsKind;
|
||||||
|
|
||||||
use crate::commands::ToolRunCommand;
|
use crate::commands::ToolRunCommand;
|
||||||
|
|
@ -2714,6 +2714,7 @@ pub(crate) struct InstallerSettingsRef<'a> {
|
||||||
pub(crate) config_settings_package: &'a PackageConfigSettings,
|
pub(crate) config_settings_package: &'a PackageConfigSettings,
|
||||||
pub(crate) no_build_isolation: bool,
|
pub(crate) no_build_isolation: bool,
|
||||||
pub(crate) no_build_isolation_package: &'a [PackageName],
|
pub(crate) no_build_isolation_package: &'a [PackageName],
|
||||||
|
pub(crate) extra_build_dependencies: &'a ExtraBuildDependencies,
|
||||||
pub(crate) exclude_newer: ExcludeNewer,
|
pub(crate) exclude_newer: ExcludeNewer,
|
||||||
pub(crate) link_mode: LinkMode,
|
pub(crate) link_mode: LinkMode,
|
||||||
pub(crate) compile_bytecode: bool,
|
pub(crate) compile_bytecode: bool,
|
||||||
|
|
@ -2740,6 +2741,7 @@ pub(crate) struct ResolverSettings {
|
||||||
pub(crate) link_mode: LinkMode,
|
pub(crate) link_mode: LinkMode,
|
||||||
pub(crate) no_build_isolation: bool,
|
pub(crate) no_build_isolation: bool,
|
||||||
pub(crate) no_build_isolation_package: Vec<PackageName>,
|
pub(crate) no_build_isolation_package: Vec<PackageName>,
|
||||||
|
pub(crate) extra_build_dependencies: ExtraBuildDependencies,
|
||||||
pub(crate) prerelease: PrereleaseMode,
|
pub(crate) prerelease: PrereleaseMode,
|
||||||
pub(crate) resolution: ResolutionMode,
|
pub(crate) resolution: ResolutionMode,
|
||||||
pub(crate) sources: SourceStrategy,
|
pub(crate) sources: SourceStrategy,
|
||||||
|
|
@ -2792,6 +2794,7 @@ impl From<ResolverOptions> for ResolverSettings {
|
||||||
config_settings_package: value.config_settings_package.unwrap_or_default(),
|
config_settings_package: value.config_settings_package.unwrap_or_default(),
|
||||||
no_build_isolation: value.no_build_isolation.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(),
|
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,
|
exclude_newer: value.exclude_newer,
|
||||||
link_mode: value.link_mode.unwrap_or_default(),
|
link_mode: value.link_mode.unwrap_or_default(),
|
||||||
sources: SourceStrategy::from_args(value.no_sources.unwrap_or_default()),
|
sources: SourceStrategy::from_args(value.no_sources.unwrap_or_default()),
|
||||||
|
|
@ -2889,6 +2892,7 @@ impl From<ResolverInstallerOptions> for ResolverInstallerSettings {
|
||||||
link_mode: value.link_mode.unwrap_or_default(),
|
link_mode: value.link_mode.unwrap_or_default(),
|
||||||
no_build_isolation: value.no_build_isolation.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(),
|
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(),
|
prerelease: value.prerelease.unwrap_or_default(),
|
||||||
resolution: value.resolution.unwrap_or_default(),
|
resolution: value.resolution.unwrap_or_default(),
|
||||||
sources: SourceStrategy::from_args(value.no_sources.unwrap_or_default()),
|
sources: SourceStrategy::from_args(value.no_sources.unwrap_or_default()),
|
||||||
|
|
@ -2931,6 +2935,7 @@ pub(crate) struct PipSettings {
|
||||||
pub(crate) torch_backend: Option<TorchMode>,
|
pub(crate) torch_backend: Option<TorchMode>,
|
||||||
pub(crate) no_build_isolation: bool,
|
pub(crate) no_build_isolation: bool,
|
||||||
pub(crate) no_build_isolation_package: Vec<PackageName>,
|
pub(crate) no_build_isolation_package: Vec<PackageName>,
|
||||||
|
pub(crate) extra_build_dependencies: ExtraBuildDependencies,
|
||||||
pub(crate) build_options: BuildOptions,
|
pub(crate) build_options: BuildOptions,
|
||||||
pub(crate) allow_empty_requirements: bool,
|
pub(crate) allow_empty_requirements: bool,
|
||||||
pub(crate) strict: bool,
|
pub(crate) strict: bool,
|
||||||
|
|
@ -2998,6 +3003,7 @@ impl PipSettings {
|
||||||
only_binary,
|
only_binary,
|
||||||
no_build_isolation,
|
no_build_isolation,
|
||||||
no_build_isolation_package,
|
no_build_isolation_package,
|
||||||
|
extra_build_dependencies,
|
||||||
strict,
|
strict,
|
||||||
extra,
|
extra,
|
||||||
all_extras,
|
all_extras,
|
||||||
|
|
@ -3057,6 +3063,7 @@ impl PipSettings {
|
||||||
config_settings_package: top_level_config_settings_package,
|
config_settings_package: top_level_config_settings_package,
|
||||||
no_build_isolation: top_level_no_build_isolation,
|
no_build_isolation: top_level_no_build_isolation,
|
||||||
no_build_isolation_package: top_level_no_build_isolation_package,
|
no_build_isolation_package: top_level_no_build_isolation_package,
|
||||||
|
extra_build_dependencies: top_level_extra_build_dependencies,
|
||||||
exclude_newer: top_level_exclude_newer,
|
exclude_newer: top_level_exclude_newer,
|
||||||
link_mode: top_level_link_mode,
|
link_mode: top_level_link_mode,
|
||||||
compile_bytecode: top_level_compile_bytecode,
|
compile_bytecode: top_level_compile_bytecode,
|
||||||
|
|
@ -3093,6 +3100,8 @@ impl PipSettings {
|
||||||
let no_build_isolation = no_build_isolation.combine(top_level_no_build_isolation);
|
let no_build_isolation = no_build_isolation.combine(top_level_no_build_isolation);
|
||||||
let no_build_isolation_package =
|
let no_build_isolation_package =
|
||||||
no_build_isolation_package.combine(top_level_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 = args
|
let exclude_newer = args
|
||||||
.exclude_newer
|
.exclude_newer
|
||||||
.combine(exclude_newer)
|
.combine(exclude_newer)
|
||||||
|
|
@ -3196,6 +3205,10 @@ impl PipSettings {
|
||||||
.no_build_isolation_package
|
.no_build_isolation_package
|
||||||
.combine(no_build_isolation_package)
|
.combine(no_build_isolation_package)
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
|
extra_build_dependencies: args
|
||||||
|
.extra_build_dependencies
|
||||||
|
.combine(extra_build_dependencies)
|
||||||
|
.unwrap_or_default(),
|
||||||
config_setting: args
|
config_setting: args
|
||||||
.config_settings
|
.config_settings
|
||||||
.combine(config_settings)
|
.combine(config_settings)
|
||||||
|
|
@ -3303,6 +3316,7 @@ impl<'a> From<&'a ResolverInstallerSettings> for InstallerSettingsRef<'a> {
|
||||||
config_settings_package: &settings.resolver.config_settings_package,
|
config_settings_package: &settings.resolver.config_settings_package,
|
||||||
no_build_isolation: settings.resolver.no_build_isolation,
|
no_build_isolation: settings.resolver.no_build_isolation,
|
||||||
no_build_isolation_package: &settings.resolver.no_build_isolation_package,
|
no_build_isolation_package: &settings.resolver.no_build_isolation_package,
|
||||||
|
extra_build_dependencies: &settings.resolver.extra_build_dependencies,
|
||||||
exclude_newer: settings.resolver.exclude_newer.clone(),
|
exclude_newer: settings.resolver.exclude_newer.clone(),
|
||||||
link_mode: settings.resolver.link_mode,
|
link_mode: settings.resolver.link_mode,
|
||||||
compile_bytecode: settings.compile_bytecode,
|
compile_bytecode: settings.compile_bytecode,
|
||||||
|
|
|
||||||
|
|
@ -3920,16 +3920,17 @@ fn config_settings_registry() {
|
||||||
.arg("iniconfig")
|
.arg("iniconfig")
|
||||||
.arg("--no-binary")
|
.arg("--no-binary")
|
||||||
.arg("iniconfig")
|
.arg("iniconfig")
|
||||||
.arg("-C=global-option=build_ext"), @r###"
|
.arg("-C=global-option=build_ext"), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Resolved 1 package in [TIME]
|
Resolved 1 package in [TIME]
|
||||||
|
Prepared 1 package in [TIME]
|
||||||
Installed 1 package in [TIME]
|
Installed 1 package in [TIME]
|
||||||
+ iniconfig==2.0.0
|
+ iniconfig==2.0.0
|
||||||
"###
|
"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Uninstall the package.
|
// Uninstall the package.
|
||||||
|
|
|
||||||
|
|
@ -184,6 +184,9 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -378,6 +381,9 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -573,6 +579,9 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -800,6 +809,9 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -962,6 +974,9 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -1168,6 +1183,9 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -1422,6 +1440,9 @@ fn resolve_index_url() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -1686,6 +1707,9 @@ fn resolve_index_url() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -1905,6 +1929,9 @@ fn resolve_find_links() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -2089,6 +2116,9 @@ fn resolve_top_level() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -2333,6 +2363,9 @@ fn resolve_top_level() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -2560,6 +2593,9 @@ fn resolve_top_level() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -2743,6 +2779,9 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -2910,6 +2949,9 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -3077,6 +3119,9 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -3246,6 +3291,9 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -3407,6 +3455,7 @@ fn resolve_tool() -> anyhow::Result<()> {
|
||||||
config_settings_package: None,
|
config_settings_package: None,
|
||||||
no_build_isolation: None,
|
no_build_isolation: None,
|
||||||
no_build_isolation_package: None,
|
no_build_isolation_package: None,
|
||||||
|
extra_build_dependencies: None,
|
||||||
exclude_newer: None,
|
exclude_newer: None,
|
||||||
exclude_newer_package: None,
|
exclude_newer_package: None,
|
||||||
link_mode: Some(
|
link_mode: Some(
|
||||||
|
|
@ -3455,6 +3504,9 @@ fn resolve_tool() -> anyhow::Result<()> {
|
||||||
link_mode: Clone,
|
link_mode: Clone,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
prerelease: IfNecessaryOrExplicit,
|
prerelease: IfNecessaryOrExplicit,
|
||||||
resolution: LowestDirect,
|
resolution: LowestDirect,
|
||||||
sources: Enabled,
|
sources: Enabled,
|
||||||
|
|
@ -3613,6 +3665,9 @@ fn resolve_poetry_toml() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -3848,6 +3903,9 @@ fn resolve_both() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -4087,6 +4145,9 @@ fn resolve_both_special_fields() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -4405,6 +4466,9 @@ fn resolve_config_file() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -4490,7 +4554,7 @@ fn resolve_config_file() -> anyhow::Result<()> {
|
||||||
|
|
|
|
||||||
1 | [project]
|
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`, `exclude-newer-package`, `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`, `exclude-newer-package`, `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`
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -4665,6 +4729,9 @@ fn resolve_skip_empty() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -4835,6 +4902,9 @@ fn resolve_skip_empty() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -5024,6 +5094,9 @@ fn allow_insecure_host() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -5274,6 +5347,9 @@ fn index_priority() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -5503,6 +5579,9 @@ fn index_priority() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -5738,6 +5817,9 @@ fn index_priority() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -5968,6 +6050,9 @@ fn index_priority() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -6205,6 +6290,9 @@ fn index_priority() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -6435,6 +6523,9 @@ fn index_priority() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -6609,6 +6700,9 @@ fn verify_hashes() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -6769,6 +6863,9 @@ fn verify_hashes() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -6927,6 +7024,9 @@ fn verify_hashes() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -7087,6 +7187,9 @@ fn verify_hashes() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -7245,6 +7348,9 @@ fn verify_hashes() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -7404,6 +7510,9 @@ fn verify_hashes() -> anyhow::Result<()> {
|
||||||
torch_backend: None,
|
torch_backend: None,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
build_options: BuildOptions {
|
build_options: BuildOptions {
|
||||||
no_binary: None,
|
no_binary: None,
|
||||||
no_build: None,
|
no_build: None,
|
||||||
|
|
@ -7501,7 +7610,7 @@ fn preview_features() {
|
||||||
show_settings: true,
|
show_settings: true,
|
||||||
preview: Preview {
|
preview: Preview {
|
||||||
flags: PreviewFeatures(
|
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,
|
python_preference: Managed,
|
||||||
|
|
@ -7572,6 +7681,9 @@ fn preview_features() {
|
||||||
link_mode: Clone,
|
link_mode: Clone,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
prerelease: IfNecessaryOrExplicit,
|
prerelease: IfNecessaryOrExplicit,
|
||||||
resolution: Highest,
|
resolution: Highest,
|
||||||
sources: Enabled,
|
sources: Enabled,
|
||||||
|
|
@ -7679,6 +7791,9 @@ fn preview_features() {
|
||||||
link_mode: Clone,
|
link_mode: Clone,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
prerelease: IfNecessaryOrExplicit,
|
prerelease: IfNecessaryOrExplicit,
|
||||||
resolution: Highest,
|
resolution: Highest,
|
||||||
sources: Enabled,
|
sources: Enabled,
|
||||||
|
|
@ -7715,7 +7830,7 @@ fn preview_features() {
|
||||||
show_settings: true,
|
show_settings: true,
|
||||||
preview: Preview {
|
preview: Preview {
|
||||||
flags: PreviewFeatures(
|
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,
|
python_preference: Managed,
|
||||||
|
|
@ -7786,6 +7901,9 @@ fn preview_features() {
|
||||||
link_mode: Clone,
|
link_mode: Clone,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
prerelease: IfNecessaryOrExplicit,
|
prerelease: IfNecessaryOrExplicit,
|
||||||
resolution: Highest,
|
resolution: Highest,
|
||||||
sources: Enabled,
|
sources: Enabled,
|
||||||
|
|
@ -7893,6 +8011,9 @@ fn preview_features() {
|
||||||
link_mode: Clone,
|
link_mode: Clone,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
prerelease: IfNecessaryOrExplicit,
|
prerelease: IfNecessaryOrExplicit,
|
||||||
resolution: Highest,
|
resolution: Highest,
|
||||||
sources: Enabled,
|
sources: Enabled,
|
||||||
|
|
@ -8000,6 +8121,9 @@ fn preview_features() {
|
||||||
link_mode: Clone,
|
link_mode: Clone,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
prerelease: IfNecessaryOrExplicit,
|
prerelease: IfNecessaryOrExplicit,
|
||||||
resolution: Highest,
|
resolution: Highest,
|
||||||
sources: Enabled,
|
sources: Enabled,
|
||||||
|
|
@ -8109,6 +8233,9 @@ fn preview_features() {
|
||||||
link_mode: Clone,
|
link_mode: Clone,
|
||||||
no_build_isolation: false,
|
no_build_isolation: false,
|
||||||
no_build_isolation_package: [],
|
no_build_isolation_package: [],
|
||||||
|
extra_build_dependencies: ExtraBuildDependencies(
|
||||||
|
{},
|
||||||
|
),
|
||||||
prerelease: IfNecessaryOrExplicit,
|
prerelease: IfNecessaryOrExplicit,
|
||||||
resolution: Highest,
|
resolution: Highest,
|
||||||
sources: Enabled,
|
sources: Enabled,
|
||||||
|
|
|
||||||
|
|
@ -1567,6 +1567,401 @@ fn sync_build_isolation_extra() -> Result<()> {
|
||||||
Ok(())
|
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
|
/// 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
|
/// 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
|
/// 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(())
|
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]
|
#[test]
|
||||||
fn virtual_no_build() -> Result<()> {
|
fn virtual_no_build() -> Result<()> {
|
||||||
let context = TestContext::new("3.12");
|
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 }
|
### [`index`](#index) {: #index }
|
||||||
|
|
||||||
The indexes to use when resolving dependencies.
|
The indexes to use when resolving dependencies.
|
||||||
|
|
@ -1127,6 +1149,36 @@ Accepts package-date pairs in a dictionary format.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### [`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-index-url`](#extra-index-url) {: #extra-index-url }
|
||||||
|
|
||||||
Extra URLs of package indexes to use, in addition to `--index-url`.
|
Extra URLs of package indexes to use, in addition to `--index-url`.
|
||||||
|
|
@ -2616,6 +2668,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 }
|
#### [`extra-index-url`](#pip_extra-index-url) {: #pip_extra-index-url }
|
||||||
<span id="extra-index-url"></span>
|
<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/ExtraBuildDependencies"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"extra-index-url": {
|
"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.)",
|
"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": [
|
"type": [
|
||||||
|
|
@ -873,6 +884,15 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(Z|[+-]\\d{2}:\\d{2}))?$"
|
"pattern": "^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(Z|[+-]\\d{2}:\\d{2}))?$"
|
||||||
},
|
},
|
||||||
|
"ExtraBuildDependencies": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/Requirement"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"ExtraName": {
|
"ExtraName": {
|
||||||
"description": "The normalized name of an extra dependency.\n\nConverts the name to lowercase and collapses runs of `-`, `_`, and `.` down to a single `-`.\nFor example, `---`, `.`, and `__` are all converted to a single `-`.\n\nSee:\n- <https://peps.python.org/pep-0685/#specification/>\n- <https://packaging.python.org/en/latest/specifications/name-normalization/>",
|
"description": "The normalized name of an extra dependency.\n\nConverts the name to lowercase and collapses runs of `-`, `_`, and `.` down to a single `-`.\nFor example, `---`, `.`, and `__` are all converted to a single `-`.\n\nSee:\n- <https://peps.python.org/pep-0685/#specification/>\n- <https://packaging.python.org/en/latest/specifications/name-normalization/>",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
|
@ -1315,6 +1335,17 @@
|
||||||
"$ref": "#/definitions/ExtraName"
|
"$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.",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/ExtraBuildDependencies"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"extra-index-url": {
|
"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).",
|
"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": [
|
"type": [
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue