Better build error messages (#9660)

Build failures are one of the most common user facing failures that
aren't "obivous" errors (such as typos) or resolver errors. Currently,
they show more technical details than being focussed on this being an
error in a subprocess that is either on the side of the package or -
more likely - in the build environment, e.g. the user needs to install a
dev package or their python version is incompatible.

The new error message clearly delineates the part that's important (this
is a build backend problem) from the internals (we called this hook) and
is consistent about which part of the dist building stage failed. We
have to calibrate the exact wording of the error message some more. Most
of the implementation is working around the orphan rule, (this)error
rules and trait rules, so it came out more of a refactoring than
intended.

Example:


![image](https://github.com/user-attachments/assets/2bc12992-db79-4362-a444-fd0d94594b77)
This commit is contained in:
konsti 2024-12-17 16:44:32 +01:00 committed by GitHub
parent b7df5dbaf3
commit ebc6d20d9d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 426 additions and 262 deletions

3
Cargo.lock generated
View file

@ -4585,7 +4585,6 @@ name = "uv-build-frontend"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"anstream", "anstream",
"anyhow",
"fs-err 3.0.0", "fs-err 3.0.0",
"indoc", "indoc",
"insta", "insta",
@ -4834,6 +4833,7 @@ dependencies = [
"futures", "futures",
"itertools 0.13.0", "itertools 0.13.0",
"rustc-hash", "rustc-hash",
"thiserror 2.0.3",
"tokio", "tokio",
"tracing", "tracing",
"uv-build-backend", "uv-build-backend",
@ -4847,6 +4847,7 @@ dependencies = [
"uv-git", "uv-git",
"uv-install-wheel", "uv-install-wheel",
"uv-installer", "uv-installer",
"uv-platform-tags",
"uv-pypi-types", "uv-pypi-types",
"uv-python", "uv-python",
"uv-resolver", "uv-resolver",

View file

@ -30,7 +30,6 @@ uv-types = { workspace = true }
uv-virtualenv = { workspace = true } uv-virtualenv = { workspace = true }
anstream = { workspace = true } anstream = { workspace = true }
anyhow = { workspace = true }
fs-err = { workspace = true } fs-err = { workspace = true }
indoc = { workspace = true } indoc = { workspace = true }
itertools = { workspace = true } itertools = { workspace = true }

View file

@ -5,16 +5,17 @@ use std::path::PathBuf;
use std::process::ExitStatus; use std::process::ExitStatus;
use std::sync::LazyLock; use std::sync::LazyLock;
use crate::PythonRunnerOutput;
use owo_colors::OwoColorize; use owo_colors::OwoColorize;
use regex::Regex; use regex::Regex;
use thiserror::Error; use thiserror::Error;
use tracing::error; use tracing::error;
use uv_configuration::BuildOutput; use uv_configuration::BuildOutput;
use uv_distribution_types::IsBuildBackendError;
use uv_fs::Simplified; use uv_fs::Simplified;
use uv_pep440::Version; use uv_pep440::Version;
use uv_pep508::PackageName; use uv_pep508::PackageName;
use uv_types::AnyErrorBuild;
use crate::PythonRunnerOutput;
/// e.g. `pygraphviz/graphviz_wrap.c:3020:10: fatal error: graphviz/cgraph.h: No such file or directory` /// e.g. `pygraphviz/graphviz_wrap.c:3020:10: fatal error: graphviz/cgraph.h: No such file or directory`
static MISSING_HEADER_RE_GCC: LazyLock<Regex> = LazyLock::new(|| { static MISSING_HEADER_RE_GCC: LazyLock<Regex> = LazyLock::new(|| {
@ -68,19 +69,47 @@ pub enum Error {
#[error("Editable installs with setup.py legacy builds are unsupported, please specify a build backend in pyproject.toml")] #[error("Editable installs with setup.py legacy builds are unsupported, please specify a build backend in pyproject.toml")]
EditableSetupPy, EditableSetupPy,
#[error("Failed to resolve requirements from {0}")] #[error("Failed to resolve requirements from {0}")]
RequirementsResolve(&'static str, #[source] anyhow::Error), RequirementsResolve(&'static str, #[source] AnyErrorBuild),
#[error("Failed to install requirements from {0}")] #[error("Failed to install requirements from {0}")]
RequirementsInstall(&'static str, #[source] anyhow::Error), RequirementsInstall(&'static str, #[source] AnyErrorBuild),
#[error("Failed to create temporary virtualenv")] #[error("Failed to create temporary virtualenv")]
Virtualenv(#[from] uv_virtualenv::Error), Virtualenv(#[from] uv_virtualenv::Error),
// Build backend errors
#[error("Failed to run `{0}`")] #[error("Failed to run `{0}`")]
CommandFailed(PathBuf, #[source] io::Error), CommandFailed(PathBuf, #[source] io::Error),
#[error(transparent)] #[error("The build backend returned an error")]
BuildBackend(#[from] BuildBackendError), BuildBackend(#[from] BuildBackendError),
#[error(transparent)] #[error("The build backend returned an error")]
MissingHeader(#[from] MissingHeaderError), MissingHeader(#[from] MissingHeaderError),
#[error("Failed to build PATH for build script")] #[error("Failed to build PATH for build script")]
BuildScriptPath(#[source] env::JoinPathsError), BuildScriptPath(#[source] env::JoinPathsError),
// For the convenience of typing `setup_build` properly.
#[error("Building source distributions for {0} is disabled")]
NoSourceDistBuild(PackageName),
#[error("Building source distributions is disabled")]
NoSourceDistBuilds,
}
impl IsBuildBackendError for Error {
fn is_build_backend_error(&self) -> bool {
match self {
Self::Io(_)
| Self::Lowering(_)
| Self::InvalidSourceDist(_)
| Self::InvalidPyprojectTomlSyntax(_)
| Self::InvalidPyprojectTomlSchema(_)
| Self::EditableSetupPy
| Self::RequirementsResolve(_, _)
| Self::RequirementsInstall(_, _)
| Self::Virtualenv(_)
| Self::NoSourceDistBuild(_)
| Self::NoSourceDistBuilds => false,
Self::CommandFailed(_, _)
| Self::BuildBackend(_)
| Self::MissingHeader(_)
| Self::BuildScriptPath(_) => true,
}
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -247,6 +276,13 @@ impl Display for BuildBackendError {
writeln!(f)?; writeln!(f)?;
} }
write!(
f,
"\n{}{} This usually indicates a problem with the package or the build environment.",
"hint".bold().cyan(),
":".bold()
)?;
Ok(()) Ok(())
} }
} }
@ -416,7 +452,10 @@ mod test {
assert!(matches!(err, Error::MissingHeader { .. })); assert!(matches!(err, Error::MissingHeader { .. }));
// Unix uses exit status, Windows uses exit code. // Unix uses exit status, Windows uses exit code.
let formatted = err.to_string().replace("exit status: ", "exit code: "); let formatted = std::error::Error::source(&err)
.unwrap()
.to_string()
.replace("exit status: ", "exit code: ");
let formatted = anstream::adapter::strip_str(&formatted); let formatted = anstream::adapter::strip_str(&formatted);
insta::assert_snapshot!(formatted, @r###" insta::assert_snapshot!(formatted, @r###"
Failed building wheel through setup.py (exit code: 0) Failed building wheel through setup.py (exit code: 0)
@ -471,7 +510,10 @@ mod test {
); );
assert!(matches!(err, Error::MissingHeader { .. })); assert!(matches!(err, Error::MissingHeader { .. }));
// Unix uses exit status, Windows uses exit code. // Unix uses exit status, Windows uses exit code.
let formatted = err.to_string().replace("exit status: ", "exit code: "); let formatted = std::error::Error::source(&err)
.unwrap()
.to_string()
.replace("exit status: ", "exit code: ");
let formatted = anstream::adapter::strip_str(&formatted); let formatted = anstream::adapter::strip_str(&formatted);
insta::assert_snapshot!(formatted, @r###" insta::assert_snapshot!(formatted, @r###"
Failed building wheel through setup.py (exit code: 0) Failed building wheel through setup.py (exit code: 0)
@ -516,7 +558,10 @@ mod test {
); );
assert!(matches!(err, Error::MissingHeader { .. })); assert!(matches!(err, Error::MissingHeader { .. }));
// Unix uses exit status, Windows uses exit code. // Unix uses exit status, Windows uses exit code.
let formatted = err.to_string().replace("exit status: ", "exit code: "); let formatted = std::error::Error::source(&err)
.unwrap()
.to_string()
.replace("exit status: ", "exit code: ");
let formatted = anstream::adapter::strip_str(&formatted); let formatted = anstream::adapter::strip_str(&formatted);
insta::assert_snapshot!(formatted, @r###" insta::assert_snapshot!(formatted, @r###"
Failed building wheel through setup.py (exit code: 0) Failed building wheel through setup.py (exit code: 0)
@ -559,7 +604,10 @@ mod test {
); );
assert!(matches!(err, Error::MissingHeader { .. })); assert!(matches!(err, Error::MissingHeader { .. }));
// Unix uses exit status, Windows uses exit code. // Unix uses exit status, Windows uses exit code.
let formatted = err.to_string().replace("exit status: ", "exit code: "); let formatted = std::error::Error::source(&err)
.unwrap()
.to_string()
.replace("exit status: ", "exit code: ");
let formatted = anstream::adapter::strip_str(&formatted); let formatted = anstream::adapter::strip_str(&formatted);
insta::assert_snapshot!(formatted, @r###" insta::assert_snapshot!(formatted, @r###"
Failed building wheel through setup.py (exit code: 0) Failed building wheel through setup.py (exit code: 0)

View file

@ -7,7 +7,6 @@ mod error;
use fs_err as fs; use fs_err as fs;
use indoc::formatdoc; use indoc::formatdoc;
use itertools::Itertools; use itertools::Itertools;
use owo_colors::OwoColorize;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use serde::de::{value, IntoDeserializer, SeqAccess, Visitor}; use serde::de::{value, IntoDeserializer, SeqAccess, Visitor};
use serde::{de, Deserialize, Deserializer}; use serde::{de, Deserialize, Deserializer};
@ -36,7 +35,7 @@ use uv_pep508::PackageName;
use uv_pypi_types::{Requirement, VerbatimParsedUrl}; use uv_pypi_types::{Requirement, VerbatimParsedUrl};
use uv_python::{Interpreter, PythonEnvironment}; use uv_python::{Interpreter, PythonEnvironment};
use uv_static::EnvVars; use uv_static::EnvVars;
use uv_types::{BuildContext, BuildIsolation, SourceBuildTrait}; use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, SourceBuildTrait};
pub use crate::error::{Error, MissingHeaderCause}; pub use crate::error::{Error, MissingHeaderCause};
@ -325,7 +324,7 @@ impl SourceBuild {
build_context build_context
.install(&resolved_requirements, &venv) .install(&resolved_requirements, &venv)
.await .await
.map_err(|err| Error::RequirementsInstall("`build-system.requires`", err))?; .map_err(|err| Error::RequirementsInstall("`build-system.requires`", err.into()))?;
} else { } else {
debug!("Proceeding without build isolation"); debug!("Proceeding without build isolation");
} }
@ -423,7 +422,9 @@ impl SourceBuild {
let resolved_requirements = build_context let resolved_requirements = build_context
.resolve(&default_backend.requirements) .resolve(&default_backend.requirements)
.await .await
.map_err(|err| Error::RequirementsResolve("`setup.py` build", err))?; .map_err(|err| {
Error::RequirementsResolve("`setup.py` build", err.into())
})?;
*resolution = Some(resolved_requirements.clone()); *resolution = Some(resolved_requirements.clone());
resolved_requirements resolved_requirements
} }
@ -431,7 +432,9 @@ impl SourceBuild {
build_context build_context
.resolve(&pep517_backend.requirements) .resolve(&pep517_backend.requirements)
.await .await
.map_err(|err| Error::RequirementsResolve("`build-system.requires`", err))? .map_err(|err| {
Error::RequirementsResolve("`build-system.requires`", err.into())
})?
}, },
) )
} }
@ -622,8 +625,8 @@ impl SourceBuild {
if !output.status.success() { if !output.status.success() {
return Err(Error::from_command_output( return Err(Error::from_command_output(
format!( format!(
"Build backend failed to determine metadata through `{}`", "Call to `{}.prepare_metadata_for_build_{}` failed",
format!("prepare_metadata_for_build_{}", self.build_kind).green() self.pep517_backend.backend, self.build_kind
), ),
&output, &output,
self.level, self.level,
@ -745,9 +748,8 @@ impl SourceBuild {
if !output.status.success() { if !output.status.success() {
return Err(Error::from_command_output( return Err(Error::from_command_output(
format!( format!(
"Build backend failed to build {} through `{}`", "Call to `{}.build_{}` failed",
self.build_kind, pep517_backend.backend, self.build_kind
format!("build_{}", self.build_kind).green(),
), ),
&output, &output,
self.level, self.level,
@ -761,8 +763,8 @@ impl SourceBuild {
if !output_dir.join(&distribution_filename).is_file() { if !output_dir.join(&distribution_filename).is_file() {
return Err(Error::from_command_output( return Err(Error::from_command_output(
format!( format!(
"Build backend failed to produce {} through `{}`: `{distribution_filename}` not found", "Call to `{}.build_{}` failed",
self.build_kind, format!("build_{}", self.build_kind).green(), pep517_backend.backend, self.build_kind
), ),
&output, &output,
self.level, self.level,
@ -776,11 +778,11 @@ impl SourceBuild {
} }
impl SourceBuildTrait for SourceBuild { impl SourceBuildTrait for SourceBuild {
async fn metadata(&mut self) -> anyhow::Result<Option<PathBuf>> { async fn metadata(&mut self) -> Result<Option<PathBuf>, AnyErrorBuild> {
Ok(self.get_metadata_without_build().await?) Ok(self.get_metadata_without_build().await?)
} }
async fn wheel<'a>(&'a self, wheel_dir: &'a Path) -> anyhow::Result<String> { async fn wheel<'a>(&'a self, wheel_dir: &'a Path) -> Result<String, AnyErrorBuild> {
Ok(self.build(wheel_dir).await?) Ok(self.build(wheel_dir).await?)
} }
} }
@ -858,8 +860,8 @@ async fn create_pep517_build_environment(
if !output.status.success() { if !output.status.success() {
return Err(Error::from_command_output( return Err(Error::from_command_output(
format!( format!(
"Build backend failed to determine requirements with `{}`", "Call to `{}.build_{}` failed",
format!("build_{build_kind}()").green() pep517_backend.backend, build_kind
), ),
&output, &output,
level, level,
@ -869,37 +871,27 @@ async fn create_pep517_build_environment(
)); ));
} }
// Read the requirements from the output file. // Read and deserialize the requirements from the output file.
let contents = fs_err::read(&outfile).map_err(|err| { let read_requires_result = fs_err::read(&outfile)
Error::from_command_output( .map_err(|err| err.to_string())
format!( .and_then(|contents| serde_json::from_slice(&contents).map_err(|err| err.to_string()));
"Build backend failed to read requirements from `{}`: {err}", let extra_requires: Vec<uv_pep508::Requirement<VerbatimParsedUrl>> = match read_requires_result
format!("get_requires_for_build_{build_kind}").green(), {
), Ok(extra_requires) => extra_requires,
&output, Err(err) => {
level, return Err(Error::from_command_output(
package_name, format!(
package_version, "Call to `{}.get_requires_for_build_{}` failed: {}",
version_id, pep517_backend.backend, build_kind, err
) ),
})?; &output,
level,
// Deserialize the requirements from the output file. package_name,
let extra_requires: Vec<uv_pep508::Requirement<VerbatimParsedUrl>> = package_version,
serde_json::from_slice::<Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>(&contents) version_id,
.map_err(|err| { ))
Error::from_command_output( }
format!( };
"Build backend failed to return requirements from `{}`: {err}",
format!("get_requires_for_build_{build_kind}").green(),
),
&output,
level,
package_name,
package_version,
version_id,
)
})?;
// If necessary, lower the requirements. // If necessary, lower the requirements.
let extra_requires = match source_strategy { let extra_requires = match source_strategy {
@ -937,15 +929,16 @@ async fn create_pep517_build_environment(
.cloned() .cloned()
.chain(extra_requires) .chain(extra_requires)
.collect(); .collect();
let resolution = build_context let resolution = build_context.resolve(&requirements).await.map_err(|err| {
.resolve(&requirements) Error::RequirementsResolve("`build-system.requires`", AnyErrorBuild::from(err))
.await })?;
.map_err(|err| Error::RequirementsResolve("`build-system.requires`", err))?;
build_context build_context
.install(&resolution, venv) .install(&resolution, venv)
.await .await
.map_err(|err| Error::RequirementsInstall("`build-system.requires`", err))?; .map_err(|err| {
Error::RequirementsInstall("`build-system.requires`", AnyErrorBuild::from(err))
})?;
} }
Ok(()) Ok(())

View file

@ -28,6 +28,7 @@ uv-distribution-types = { workspace = true }
uv-git = { workspace = true } uv-git = { workspace = true }
uv-install-wheel = { workspace = true } uv-install-wheel = { workspace = true }
uv-installer = { workspace = true } uv-installer = { workspace = true }
uv-platform-tags = { workspace = true }
uv-pypi-types = { workspace = true } uv-pypi-types = { workspace = true }
uv-python = { workspace = true } uv-python = { workspace = true }
uv-resolver = { workspace = true } uv-resolver = { workspace = true }
@ -38,5 +39,6 @@ anyhow = { workspace = true }
futures = { workspace = true } futures = { workspace = true }
itertools = { workspace = true } itertools = { workspace = true }
rustc-hash = { workspace = true } rustc-hash = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true } tokio = { workspace = true }
tracing = { workspace = true } tracing = { workspace = true }

View file

@ -5,10 +5,11 @@
use std::ffi::{OsStr, OsString}; use std::ffi::{OsStr, OsString};
use std::path::Path; use std::path::Path;
use anyhow::{anyhow, Context, Result}; use anyhow::{Context, Result};
use futures::FutureExt; use futures::FutureExt;
use itertools::Itertools; use itertools::Itertools;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use thiserror::Error;
use tracing::{debug, instrument, trace}; use tracing::{debug, instrument, trace};
use uv_build_backend::check_direct_build; use uv_build_backend::check_direct_build;
use uv_build_frontend::{SourceBuild, SourceBuildContext}; use uv_build_frontend::{SourceBuild, SourceBuildContext};
@ -22,8 +23,8 @@ use uv_configuration::{BuildOutput, Concurrency};
use uv_distribution::DistributionDatabase; use uv_distribution::DistributionDatabase;
use uv_distribution_filename::DistFilename; use uv_distribution_filename::DistFilename;
use uv_distribution_types::{ use uv_distribution_types::{
CachedDist, DependencyMetadata, IndexCapabilities, IndexLocations, Name, Resolution, CachedDist, DependencyMetadata, IndexCapabilities, IndexLocations, IsBuildBackendError, Name,
SourceDist, VersionOrUrlRef, Resolution, SourceDist, VersionOrUrlRef,
}; };
use uv_git::GitResolver; use uv_git::GitResolver;
use uv_installer::{Installer, Plan, Planner, Preparer, SitePackages}; use uv_installer::{Installer, Plan, Planner, Preparer, SitePackages};
@ -33,7 +34,43 @@ use uv_resolver::{
ExcludeNewer, FlatIndex, Flexibility, InMemoryIndex, Manifest, OptionsBuilder, ExcludeNewer, FlatIndex, Flexibility, InMemoryIndex, Manifest, OptionsBuilder,
PythonRequirement, Resolver, ResolverEnvironment, PythonRequirement, Resolver, ResolverEnvironment,
}; };
use uv_types::{BuildContext, BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight}; use uv_types::{
AnyErrorBuild, BuildContext, BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight,
};
#[derive(Debug, Error)]
pub enum BuildDispatchError {
#[error(transparent)]
BuildFrontend(#[from] AnyErrorBuild),
#[error(transparent)]
Tags(#[from] uv_platform_tags::TagsError),
#[error(transparent)]
Resolve(#[from] uv_resolver::ResolveError),
#[error(transparent)]
Join(#[from] tokio::task::JoinError),
#[error(transparent)]
Anyhow(#[from] anyhow::Error),
#[error(transparent)]
Prepare(#[from] uv_installer::PrepareError),
}
impl IsBuildBackendError for BuildDispatchError {
fn is_build_backend_error(&self) -> bool {
match self {
BuildDispatchError::Tags(_)
| BuildDispatchError::Resolve(_)
| BuildDispatchError::Join(_)
| BuildDispatchError::Anyhow(_)
| BuildDispatchError::Prepare(_) => false,
BuildDispatchError::BuildFrontend(err) => err.is_build_backend_error(),
}
}
}
/// The main implementation of [`BuildContext`], used by the CLI, see [`BuildContext`] /// The main implementation of [`BuildContext`], used by the CLI, see [`BuildContext`]
/// documentation. /// documentation.
@ -124,6 +161,7 @@ impl<'a> BuildDispatch<'a> {
} }
} }
#[allow(refining_impl_trait)]
impl<'a> BuildContext for BuildDispatch<'a> { impl<'a> BuildContext for BuildDispatch<'a> {
type SourceDistBuilder = SourceBuild; type SourceDistBuilder = SourceBuild;
@ -167,7 +205,10 @@ impl<'a> BuildContext for BuildDispatch<'a> {
self.index_locations self.index_locations
} }
async fn resolve<'data>(&'data self, requirements: &'data [Requirement]) -> Result<Resolution> { async fn resolve<'data>(
&'data self,
requirements: &'data [Requirement],
) -> Result<Resolution, BuildDispatchError> {
let python_requirement = PythonRequirement::from_interpreter(self.interpreter); let python_requirement = PythonRequirement::from_interpreter(self.interpreter);
let marker_env = self.interpreter.resolver_marker_environment(); let marker_env = self.interpreter.resolver_marker_environment();
let tags = self.interpreter.tags()?; let tags = self.interpreter.tags()?;
@ -215,7 +256,7 @@ impl<'a> BuildContext for BuildDispatch<'a> {
&'data self, &'data self,
resolution: &'data Resolution, resolution: &'data Resolution,
venv: &'data PythonEnvironment, venv: &'data PythonEnvironment,
) -> Result<Vec<CachedDist>> { ) -> Result<Vec<CachedDist>, BuildDispatchError> {
debug!( debug!(
"Installing in {} in {}", "Installing in {} in {}",
resolution resolution
@ -325,7 +366,7 @@ impl<'a> BuildContext for BuildDispatch<'a> {
sources: SourceStrategy, sources: SourceStrategy,
build_kind: BuildKind, build_kind: BuildKind,
build_output: BuildOutput, build_output: BuildOutput,
) -> Result<SourceBuild> { ) -> Result<SourceBuild, uv_build_frontend::Error> {
let dist_name = dist.map(uv_distribution_types::Name::name); let dist_name = dist.map(uv_distribution_types::Name::name);
let dist_version = dist let dist_version = dist
.map(uv_distribution_types::DistributionMetadata::version_or_url) .map(uv_distribution_types::DistributionMetadata::version_or_url)
@ -342,13 +383,12 @@ impl<'a> BuildContext for BuildDispatch<'a> {
// We always allow editable builds // We always allow editable builds
&& !matches!(build_kind, BuildKind::Editable) && !matches!(build_kind, BuildKind::Editable)
{ {
if let Some(dist) = dist { let err = if let Some(dist) = dist {
return Err(anyhow!( uv_build_frontend::Error::NoSourceDistBuild(dist.name().clone())
"Building source distributions for {} is disabled", } else {
dist.name() uv_build_frontend::Error::NoSourceDistBuilds
)); };
} return Err(err);
return Err(anyhow!("Building source distributions is disabled"));
} }
let builder = SourceBuild::setup( let builder = SourceBuild::setup(
@ -382,7 +422,7 @@ impl<'a> BuildContext for BuildDispatch<'a> {
output_dir: &'data Path, output_dir: &'data Path,
build_kind: BuildKind, build_kind: BuildKind,
version_id: Option<&'data str>, version_id: Option<&'data str>,
) -> Result<Option<DistFilename>> { ) -> Result<Option<DistFilename>, BuildDispatchError> {
// Direct builds are a preview feature with the uv build backend. // Direct builds are a preview feature with the uv build backend.
if self.preview.is_disabled() { if self.preview.is_disabled() {
trace!("Preview is disabled, not checking for direct build"); trace!("Preview is disabled, not checking for direct build");

View file

@ -1,13 +1,19 @@
use crate::{DistRef, Edge, Name, Node, Resolution, ResolvedDist}; use crate::{BuiltDist, Dist, DistRef, Edge, Name, Node, Resolution, ResolvedDist, SourceDist};
use petgraph::prelude::EdgeRef; use petgraph::prelude::EdgeRef;
use petgraph::Direction; use petgraph::Direction;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fmt::{Display, Formatter}; use std::fmt::{Debug, Display, Formatter};
use uv_normalize::{ExtraName, GroupName, PackageName}; use uv_normalize::{ExtraName, GroupName, PackageName};
use uv_pep440::Version; use uv_pep440::Version;
use version_ranges::Ranges; use version_ranges::Ranges;
/// Inspect whether an error type is a build error.
pub trait IsBuildBackendError: std::error::Error + Send + Sync + 'static {
/// Returns whether the build backend failed to build the package, so it's not a uv error.
fn is_build_backend_error(&self) -> bool;
}
/// The operation(s) that failed when reporting an error with a distribution. /// The operation(s) that failed when reporting an error with a distribution.
#[derive(Debug)] #[derive(Debug)]
pub enum DistErrorKind { pub enum DistErrorKind {
@ -18,6 +24,29 @@ pub enum DistErrorKind {
Read, Read,
} }
impl DistErrorKind {
pub fn from_dist_and_err(dist: &Dist, err: &impl IsBuildBackendError) -> Self {
if err.is_build_backend_error() {
DistErrorKind::BuildBackend
} else {
match dist {
Dist::Built(BuiltDist::Path(_)) => DistErrorKind::Read,
Dist::Source(SourceDist::Path(_) | SourceDist::Directory(_)) => {
DistErrorKind::Build
}
Dist::Built(_) => DistErrorKind::Download,
Dist::Source(source_dist) => {
if source_dist.is_local() {
DistErrorKind::Build
} else {
DistErrorKind::DownloadAndBuild
}
}
}
}
}
}
impl Display for DistErrorKind { impl Display for DistErrorKind {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { match self {

View file

@ -8,10 +8,12 @@ use zip::result::ZipError;
use crate::metadata::MetadataError; use crate::metadata::MetadataError;
use uv_client::WrappedReqwestError; use uv_client::WrappedReqwestError;
use uv_distribution_filename::WheelFilenameError; use uv_distribution_filename::WheelFilenameError;
use uv_distribution_types::IsBuildBackendError;
use uv_fs::Simplified; use uv_fs::Simplified;
use uv_normalize::PackageName; use uv_normalize::PackageName;
use uv_pep440::{Version, VersionSpecifiers}; use uv_pep440::{Version, VersionSpecifiers};
use uv_pypi_types::{HashAlgorithm, HashDigest, ParsedUrlError}; use uv_pypi_types::{HashAlgorithm, HashDigest, ParsedUrlError};
use uv_types::AnyErrorBuild;
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum Error { pub enum Error {
@ -52,7 +54,7 @@ pub enum Error {
// Build error // Build error
#[error(transparent)] #[error(transparent)]
Build(anyhow::Error), Build(AnyErrorBuild),
#[error("Built wheel has an invalid filename")] #[error("Built wheel has an invalid filename")]
WheelFilename(#[from] WheelFilenameError), WheelFilename(#[from] WheelFilenameError),
#[error("Package metadata name `{metadata}` does not match given name `{given}`")] #[error("Package metadata name `{metadata}` does not match given name `{given}`")]
@ -174,6 +176,15 @@ impl From<reqwest_middleware::Error> for Error {
} }
} }
impl IsBuildBackendError for Error {
fn is_build_backend_error(&self) -> bool {
match self {
Self::Build(err) => err.is_build_backend_error(),
_ => false,
}
}
}
impl Error { impl Error {
/// Construct a hash mismatch error. /// Construct a hash mismatch error.
pub fn hash_mismatch( pub fn hash_mismatch(

View file

@ -1879,7 +1879,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
Some(&source.to_string()), Some(&source.to_string()),
) )
.await .await
.map_err(Error::Build)? .map_err(|err| Error::Build(err.into()))?
{ {
// In the uv build backend, the normalized filename and the disk filename are the same. // In the uv build backend, the normalized filename and the disk filename are the same.
name.to_string() name.to_string()
@ -1900,7 +1900,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
BuildOutput::Debug, BuildOutput::Debug,
) )
.await .await
.map_err(Error::Build)? .map_err(|err| Error::Build(err.into()))?
.wheel(temp_dir.path()) .wheel(temp_dir.path())
.await .await
.map_err(Error::Build)? .map_err(Error::Build)?
@ -1976,7 +1976,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
BuildOutput::Debug, BuildOutput::Debug,
) )
.await .await
.map_err(Error::Build)?; .map_err(|err| Error::Build(err.into()))?;
// Build the metadata. // Build the metadata.
let dist_info = builder.metadata().await.map_err(Error::Build)?; let dist_info = builder.metadata().await.map_err(Error::Build)?;

View file

@ -226,20 +226,15 @@ pub enum Error {
impl Error { impl Error {
/// Create an [`Error`] from a distribution error. /// Create an [`Error`] from a distribution error.
fn from_dist(dist: Dist, cause: uv_distribution::Error, resolution: &Resolution) -> Self { fn from_dist(dist: Dist, err: uv_distribution::Error, resolution: &Resolution) -> Self {
let kind = match &dist {
Dist::Built(_) => DistErrorKind::Download,
Dist::Source(dist) => {
if dist.is_local() {
DistErrorKind::Build
} else {
DistErrorKind::DownloadAndBuild
}
}
};
let chain = let chain =
DerivationChain::from_resolution(resolution, (&dist).into()).unwrap_or_default(); DerivationChain::from_resolution(resolution, (&dist).into()).unwrap_or_default();
Self::Dist(kind, Box::new(dist), chain, cause) Self::Dist(
DistErrorKind::from_dist_and_err(&dist, &err),
Box::new(dist),
chain,
err,
)
} }
} }

View file

@ -34,20 +34,12 @@ pub enum Error {
impl Error { impl Error {
/// Create an [`Error`] from a distribution error. /// Create an [`Error`] from a distribution error.
pub(crate) fn from_dist(dist: Dist, cause: uv_distribution::Error) -> Self { pub(crate) fn from_dist(dist: Dist, err: uv_distribution::Error) -> Self {
match dist { Self::Dist(
Dist::Built(dist) => { DistErrorKind::from_dist_and_err(&dist, &err),
Self::Dist(DistErrorKind::Download, Box::new(Dist::Built(dist)), cause) Box::new(dist),
} err,
Dist::Source(dist) => { )
let kind = if dist.is_local() {
DistErrorKind::Build
} else {
DistErrorKind::DownloadAndBuild
};
Self::Dist(kind, Box::new(Dist::Source(dist)), cause)
}
}
} }
} }

View file

@ -1059,36 +1059,11 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
MetadataResponse::Error(dist, err) => { MetadataResponse::Error(dist, err) => {
// TODO(charlie): Add derivation chain for URL dependencies. In practice, this isn't // TODO(charlie): Add derivation chain for URL dependencies. In practice, this isn't
// critical since we fetch URL dependencies _prior_ to invoking the resolver. // critical since we fetch URL dependencies _prior_ to invoking the resolver.
let chain = DerivationChain::default();
let (kind, dist) = match &**dist {
Dist::Built(built_dist @ BuiltDist::Path(_)) => {
(DistErrorKind::Read, Dist::Built(built_dist.clone()))
}
Dist::Source(source_dist @ SourceDist::Path(_)) => {
(DistErrorKind::Build, Dist::Source(source_dist.clone()))
}
Dist::Source(source_dist @ SourceDist::Directory(_)) => {
(DistErrorKind::Build, Dist::Source(source_dist.clone()))
}
Dist::Built(built_dist) => {
(DistErrorKind::Download, Dist::Built(built_dist.clone()))
}
Dist::Source(source_dist) => {
if source_dist.is_local() {
(DistErrorKind::Build, Dist::Source(source_dist.clone()))
} else {
(
DistErrorKind::DownloadAndBuild,
Dist::Source(source_dist.clone()),
)
}
}
};
return Err(ResolveError::Dist( return Err(ResolveError::Dist(
kind, DistErrorKind::from_dist_and_err(dist, &**err),
Box::new(dist), dist.clone(),
chain, DerivationChain::default(),
(*err).clone(), err.clone(),
)); ));
} }
}; };
@ -1446,35 +1421,11 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
MetadataResponse::Error(dist, err) => { MetadataResponse::Error(dist, err) => {
let chain = DerivationChainBuilder::from_state(id, version, pubgrub) let chain = DerivationChainBuilder::from_state(id, version, pubgrub)
.unwrap_or_default(); .unwrap_or_default();
let (kind, dist) = match &**dist {
Dist::Built(built_dist @ BuiltDist::Path(_)) => {
(DistErrorKind::Read, Dist::Built(built_dist.clone()))
}
Dist::Source(source_dist @ SourceDist::Path(_)) => {
(DistErrorKind::Build, Dist::Source(source_dist.clone()))
}
Dist::Source(source_dist @ SourceDist::Directory(_)) => {
(DistErrorKind::Build, Dist::Source(source_dist.clone()))
}
Dist::Built(built_dist) => {
(DistErrorKind::Download, Dist::Built(built_dist.clone()))
}
Dist::Source(source_dist) => {
if source_dist.is_local() {
(DistErrorKind::Build, Dist::Source(source_dist.clone()))
} else {
(
DistErrorKind::DownloadAndBuild,
Dist::Source(source_dist.clone()),
)
}
}
};
return Err(ResolveError::Dist( return Err(ResolveError::Dist(
kind, DistErrorKind::from_dist_and_err(dist, &**err),
Box::new(dist), dist.clone(),
chain, chain,
(*err).clone(), err.clone(),
)); ));
} }
}; };
@ -2353,22 +2304,6 @@ impl ForkState {
// A dependency from the root package or requirements.txt. // A dependency from the root package or requirements.txt.
debug!("Adding direct dependency: {package}{version}"); debug!("Adding direct dependency: {package}{version}");
let name = package.name_no_root().unwrap();
// Catch cases where we pass a package once by name with extras and then once as
// URL for the specific distribution.
has_url = has_url
|| dependencies
.iter()
.filter(|other_dep| *other_dep != dependency)
.filter(|other_dep| {
other_dep
.package
.name()
.is_some_and(|other_name| other_name == name)
})
.any(|other_dep| other_dep.url.is_some());
// Warn the user if a direct dependency lacks a lower bound in `--lowest` resolution. // Warn the user if a direct dependency lacks a lower bound in `--lowest` resolution.
let missing_lower_bound = version let missing_lower_bound = version
.bounding_range() .bounding_range()
@ -2383,6 +2318,7 @@ impl ForkState {
"The direct dependency `{name}` is unpinned. \ "The direct dependency `{name}` is unpinned. \
Consider setting a lower bound when using `--resolution lowest` \ Consider setting a lower bound when using `--resolution lowest` \
to avoid using outdated versions.", to avoid using outdated versions.",
name = package.name_no_root().unwrap(),
); );
} }
} }

View file

@ -1,4 +1,6 @@
use std::fmt::{Debug, Display, Formatter};
use std::future::Future; use std::future::Future;
use std::ops::Deref;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use uv_distribution_filename::DistFilename; use uv_distribution_filename::DistFilename;
@ -9,8 +11,8 @@ use uv_configuration::{
BuildKind, BuildOptions, BuildOutput, ConfigSettings, LowerBound, SourceStrategy, BuildKind, BuildOptions, BuildOutput, ConfigSettings, LowerBound, SourceStrategy,
}; };
use uv_distribution_types::{ use uv_distribution_types::{
CachedDist, DependencyMetadata, IndexCapabilities, IndexLocations, InstalledDist, Resolution, CachedDist, DependencyMetadata, IndexCapabilities, IndexLocations, InstalledDist,
SourceDist, IsBuildBackendError, Resolution, SourceDist,
}; };
use uv_git::GitResolver; use uv_git::GitResolver;
use uv_pep508::PackageName; use uv_pep508::PackageName;
@ -47,7 +49,7 @@ use uv_python::{Interpreter, PythonEnvironment};
/// │ │ │ /// │ │ │
/// └─────────────┐ │ ┌──────────────┘ /// └─────────────┐ │ ┌──────────────┘
/// ┌──┴────┴────┴───┐ /// ┌──┴────┴────┴───┐
/// │ uv-types /// │ uv-types
/// └────────────────┘ /// └────────────────┘
/// ``` /// ```
/// ///
@ -94,7 +96,7 @@ pub trait BuildContext {
fn resolve<'a>( fn resolve<'a>(
&'a self, &'a self,
requirements: &'a [Requirement], requirements: &'a [Requirement],
) -> impl Future<Output = Result<Resolution>> + 'a; ) -> impl Future<Output = Result<Resolution, impl IsBuildBackendError>> + 'a;
/// Install the given set of package versions into the virtual environment. The environment must /// Install the given set of package versions into the virtual environment. The environment must
/// use the same base Python as [`BuildContext::interpreter`] /// use the same base Python as [`BuildContext::interpreter`]
@ -102,7 +104,7 @@ pub trait BuildContext {
&'a self, &'a self,
resolution: &'a Resolution, resolution: &'a Resolution,
venv: &'a PythonEnvironment, venv: &'a PythonEnvironment,
) -> impl Future<Output = Result<Vec<CachedDist>>> + 'a; ) -> impl Future<Output = Result<Vec<CachedDist>, impl IsBuildBackendError>> + 'a;
/// Set up a source distribution build by installing the required dependencies. A wrapper for /// Set up a source distribution build by installing the required dependencies. A wrapper for
/// `uv_build::SourceBuild::setup`. /// `uv_build::SourceBuild::setup`.
@ -121,7 +123,7 @@ pub trait BuildContext {
sources: SourceStrategy, sources: SourceStrategy,
build_kind: BuildKind, build_kind: BuildKind,
build_output: BuildOutput, build_output: BuildOutput,
) -> impl Future<Output = Result<Self::SourceDistBuilder>> + 'a; ) -> impl Future<Output = Result<Self::SourceDistBuilder, impl IsBuildBackendError>> + 'a;
/// Build by calling directly into the uv build backend without PEP 517, if possible. /// Build by calling directly into the uv build backend without PEP 517, if possible.
/// ///
@ -136,7 +138,7 @@ pub trait BuildContext {
output_dir: &'a Path, output_dir: &'a Path,
build_kind: BuildKind, build_kind: BuildKind,
version_id: Option<&'a str>, version_id: Option<&'a str>,
) -> impl Future<Output = Result<Option<DistFilename>>> + 'a; ) -> impl Future<Output = Result<Option<DistFilename>, impl IsBuildBackendError>> + 'a;
} }
/// A wrapper for `uv_build::SourceBuild` to avoid cyclical crate dependencies. /// A wrapper for `uv_build::SourceBuild` to avoid cyclical crate dependencies.
@ -150,7 +152,7 @@ pub trait SourceBuildTrait {
/// ///
/// Returns the metadata directory if we're having a PEP 517 build and the /// Returns the metadata directory if we're having a PEP 517 build and the
/// `prepare_metadata_for_build_wheel` hook exists /// `prepare_metadata_for_build_wheel` hook exists
fn metadata(&mut self) -> impl Future<Output = Result<Option<PathBuf>>>; fn metadata(&mut self) -> impl Future<Output = Result<Option<PathBuf>, AnyErrorBuild>>;
/// A wrapper for `uv_build::SourceBuild::build`. /// A wrapper for `uv_build::SourceBuild::build`.
/// ///
@ -159,7 +161,10 @@ pub trait SourceBuildTrait {
/// Returns the filename of the built wheel inside the given `wheel_dir`. The filename is a /// Returns the filename of the built wheel inside the given `wheel_dir`. The filename is a
/// string and not a `WheelFilename` because the on disk filename might not be normalized in the /// string and not a `WheelFilename` because the on disk filename might not be normalized in the
/// same way as uv would. /// same way as uv would.
fn wheel<'a>(&'a self, wheel_dir: &'a Path) -> impl Future<Output = Result<String>> + 'a; fn wheel<'a>(
&'a self,
wheel_dir: &'a Path,
) -> impl Future<Output = Result<String, AnyErrorBuild>> + 'a;
} }
/// A wrapper for [`uv_installer::SitePackages`] /// A wrapper for [`uv_installer::SitePackages`]
@ -181,3 +186,61 @@ impl InstalledPackagesProvider for EmptyInstalledPackages {
std::iter::empty() std::iter::empty()
} }
} }
/// `anyhow::Error`-like wrapper type for [`BuildDispatch`] method return values, that also makes
/// `IsBuildBackendError` work as `thiserror` `#[source]`.
///
/// The errors types have the same problem as [`BuildDispatch`] generally: The `uv-resolver`,
/// `uv-installer` and `uv-build-frontend` error types all reference each other:
/// Resolution and installation may need to build packages, while the build frontend needs to
/// resolve and install for the PEP 517 build environment.
///
/// Usually, `anyhow::Error` is opaque error type of choice. In this case though, we error type
/// that we can inspect on whether it's a build backend error with [`IsBuildBackendError`], and
/// `anyhow::Error` does not allow attaching more traits. The next choice would be
/// `Box<dyn std::error::Error + IsBuildFrontendError + Send + Sync + 'static>`, but `thiserror`
/// complains about the internal `AsDynError` not being implemented when being used as `#[source]`.
/// This struct is an otherwise transparent error wrapper that thiserror recognizes.
pub struct AnyErrorBuild(Box<dyn IsBuildBackendError>);
impl Debug for AnyErrorBuild {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Debug::fmt(&self.0, f)
}
}
impl Display for AnyErrorBuild {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.0, f)
}
}
impl std::error::Error for AnyErrorBuild {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.0.source()
}
#[allow(deprecated)]
fn description(&self) -> &str {
self.0.description()
}
#[allow(deprecated)]
fn cause(&self) -> Option<&dyn std::error::Error> {
self.0.cause()
}
}
impl<T: IsBuildBackendError> From<T> for AnyErrorBuild {
fn from(err: T) -> Self {
Self(Box::new(err))
}
}
impl Deref for AnyErrorBuild {
type Target = dyn IsBuildBackendError;
fn deref(&self) -> &Self::Target {
&*self.0
}
}

View file

@ -42,7 +42,7 @@ use uv_python::{
use uv_requirements::RequirementsSource; use uv_requirements::RequirementsSource;
use uv_resolver::{ExcludeNewer, FlatIndex, RequiresPython}; use uv_resolver::{ExcludeNewer, FlatIndex, RequiresPython};
use uv_settings::PythonInstallMirrors; use uv_settings::PythonInstallMirrors;
use uv_types::{BuildContext, BuildIsolation, HashStrategy}; use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, HashStrategy};
use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceError}; use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceError};
#[derive(Debug, Error)] #[derive(Debug, Error)]
@ -66,7 +66,7 @@ enum Error {
#[error(transparent)] #[error(transparent)]
BuildBackend(#[from] uv_build_backend::Error), BuildBackend(#[from] uv_build_backend::Error),
#[error(transparent)] #[error(transparent)]
BuildDispatch(anyhow::Error), BuildDispatch(AnyErrorBuild),
#[error(transparent)] #[error(transparent)]
BuildFrontend(#[from] uv_build_frontend::Error), BuildFrontend(#[from] uv_build_frontend::Error),
#[error("Failed to write message")] #[error("Failed to write message")]
@ -923,7 +923,7 @@ async fn build_sdist(
build_output, build_output,
) )
.await .await
.map_err(Error::BuildDispatch)?; .map_err(|err| Error::BuildDispatch(err.into()))?;
let filename = builder.build(output_dir).await?; let filename = builder.build(output_dir).await?;
BuildMessage::Build { BuildMessage::Build {
filename: DistFilename::SourceDistFilename( filename: DistFilename::SourceDistFilename(
@ -1020,7 +1020,7 @@ async fn build_wheel(
build_output, build_output,
) )
.await .await
.map_err(Error::BuildDispatch)?; .map_err(|err| Error::BuildDispatch(err.into()))?;
let filename = builder.build(output_dir).await?; let filename = builder.build(output_dir).await?;
BuildMessage::Build { BuildMessage::Build {
filename: DistFilename::WheelFilename( filename: DistFilename::WheelFilename(

View file

@ -26,7 +26,7 @@ use uv_python::{
use uv_resolver::{ExcludeNewer, FlatIndex}; use uv_resolver::{ExcludeNewer, FlatIndex};
use uv_settings::PythonInstallMirrors; use uv_settings::PythonInstallMirrors;
use uv_shell::{shlex_posix, shlex_windows, Shell}; use uv_shell::{shlex_posix, shlex_windows, Shell};
use uv_types::{BuildContext, BuildIsolation, HashStrategy}; use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, HashStrategy};
use uv_warnings::{warn_user, warn_user_once}; use uv_warnings::{warn_user, warn_user_once};
use uv_workspace::{DiscoveryOptions, VirtualProject, WorkspaceError}; use uv_workspace::{DiscoveryOptions, VirtualProject, WorkspaceError};
@ -113,7 +113,7 @@ enum VenvError {
#[error("Failed to install seed packages")] #[error("Failed to install seed packages")]
#[diagnostic(code(uv::venv::seed))] #[diagnostic(code(uv::venv::seed))]
Seed(#[source] anyhow::Error), Seed(#[source] AnyErrorBuild),
#[error("Failed to extract interpreter tags")] #[error("Failed to extract interpreter tags")]
#[diagnostic(code(uv::venv::tags))] #[diagnostic(code(uv::venv::tags))]
@ -360,11 +360,11 @@ async fn venv_impl(
let resolution = build_dispatch let resolution = build_dispatch
.resolve(&requirements) .resolve(&requirements)
.await .await
.map_err(VenvError::Seed)?; .map_err(|err| VenvError::Seed(err.into()))?;
let installed = build_dispatch let installed = build_dispatch
.install(&resolution, &venv) .install(&resolution, &venv)
.await .await
.map_err(VenvError::Seed)?; .map_err(|err| VenvError::Seed(err.into()))?;
let changelog = Changelog::from_installed(installed); let changelog = Changelog::from_installed(installed);
DefaultInstallLogger DefaultInstallLogger

View file

@ -897,7 +897,9 @@ fn fail() -> Result<()> {
from setuptools import setup from setuptools import setup
IndentationError: unexpected indent IndentationError: unexpected indent
× Failed to build `[TEMP_DIR]/project` × Failed to build `[TEMP_DIR]/project`
Build backend failed to determine requirements with `build_sdist()` (exit status: 1) The build backend returned an error
Call to `setuptools.build_meta.build_sdist` failed (exit status: 1)
hint: This usually indicates a problem with the package or the build environment.
"###); "###);
Ok(()) Ok(())
@ -1345,7 +1347,9 @@ fn build_all_with_failure() -> Result<()> {
Successfully built dist/member_a-0.1.0.tar.gz Successfully built dist/member_a-0.1.0.tar.gz
Successfully built dist/member_a-0.1.0-py3-none-any.whl Successfully built dist/member_a-0.1.0-py3-none-any.whl
× Failed to build `member-b @ [TEMP_DIR]/project/packages/member_b` × Failed to build `member-b @ [TEMP_DIR]/project/packages/member_b`
Build backend failed to determine requirements with `build_sdist()` (exit status: 1) The build backend returned an error
Call to `setuptools.build_meta.build_sdist` failed (exit status: 1)
hint: This usually indicates a problem with the package or the build environment.
Successfully built dist/project-0.1.0.tar.gz Successfully built dist/project-0.1.0.tar.gz
Successfully built dist/project-0.1.0-py3-none-any.whl Successfully built dist/project-0.1.0-py3-none-any.whl
"###); "###);

View file

@ -5559,7 +5559,8 @@ fn fail_to_add_revert_project() -> Result<()> {
----- stderr ----- ----- stderr -----
Resolved 3 packages in [TIME] Resolved 3 packages in [TIME]
× Failed to build `child @ file://[TEMP_DIR]/child` × Failed to build `child @ file://[TEMP_DIR]/child`
Build backend failed to determine requirements with `build_wheel()` (exit status: 1) The build backend returned an error
Call to `setuptools.build_meta.build_wheel` failed (exit status: 1)
[stderr] [stderr]
Traceback (most recent call last): Traceback (most recent call last):
@ -5574,6 +5575,7 @@ fn fail_to_add_revert_project() -> Result<()> {
File "<string>", line 1, in <module> File "<string>", line 1, in <module>
ZeroDivisionError: division by zero ZeroDivisionError: division by zero
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` help: `child` was included because `parent` (v0.1.0) depends on `child`
"###); "###);
@ -5668,7 +5670,8 @@ fn fail_to_edit_revert_project() -> Result<()> {
----- stderr ----- ----- stderr -----
Resolved 3 packages in [TIME] Resolved 3 packages in [TIME]
× Failed to build `child @ file://[TEMP_DIR]/child` × Failed to build `child @ file://[TEMP_DIR]/child`
Build backend failed to determine requirements with `build_wheel()` (exit status: 1) The build backend returned an error
Call to `setuptools.build_meta.build_wheel` failed (exit status: 1)
[stderr] [stderr]
Traceback (most recent call last): Traceback (most recent call last):
@ -5683,6 +5686,7 @@ fn fail_to_edit_revert_project() -> Result<()> {
File "<string>", line 1, in <module> File "<string>", line 1, in <module>
ZeroDivisionError: division by zero ZeroDivisionError: division by zero
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` help: `child` was included because `parent` (v0.1.0) depends on `child`
"###); "###);

View file

@ -19497,8 +19497,9 @@ fn lock_derivation_chain_prod() -> Result<()> {
----- stdout ----- ----- stdout -----
----- stderr ----- ----- stderr -----
× Failed to download and build `wsgiref==0.1.2` × Failed to build `wsgiref==0.1.2`
Build backend failed to determine requirements with `build_wheel()` (exit status: 1) The build backend returned an error
Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1)
[stderr] [stderr]
Traceback (most recent call last): Traceback (most recent call last):
@ -19518,6 +19519,7 @@ fn lock_derivation_chain_prod() -> Result<()> {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)? SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
hint: This usually indicates a problem with the package or the build environment.
help: `wsgiref` (v0.1.2) was included because `project` (v0.1.0) depends on `wsgiref==0.1.2` help: `wsgiref` (v0.1.2) was included because `project` (v0.1.0) depends on `wsgiref==0.1.2`
"###); "###);
@ -19555,8 +19557,9 @@ fn lock_derivation_chain_extra() -> Result<()> {
----- stdout ----- ----- stdout -----
----- stderr ----- ----- stderr -----
× Failed to download and build `wsgiref==0.1.2` × Failed to build `wsgiref==0.1.2`
Build backend failed to determine requirements with `build_wheel()` (exit status: 1) The build backend returned an error
Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1)
[stderr] [stderr]
Traceback (most recent call last): Traceback (most recent call last):
@ -19576,6 +19579,7 @@ fn lock_derivation_chain_extra() -> Result<()> {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)? SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
hint: This usually indicates a problem with the package or the build environment.
help: `wsgiref` (v0.1.2) was included because `project[wsgi]` (v0.1.0) depends on `wsgiref>=0.1` help: `wsgiref` (v0.1.2) was included because `project[wsgi]` (v0.1.0) depends on `wsgiref>=0.1`
"###); "###);
@ -19615,8 +19619,9 @@ fn lock_derivation_chain_group() -> Result<()> {
----- stdout ----- ----- stdout -----
----- stderr ----- ----- stderr -----
× Failed to download and build `wsgiref==0.1.2` × Failed to build `wsgiref==0.1.2`
Build backend failed to determine requirements with `build_wheel()` (exit status: 1) The build backend returned an error
Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1)
[stderr] [stderr]
Traceback (most recent call last): Traceback (most recent call last):
@ -19636,6 +19641,7 @@ fn lock_derivation_chain_group() -> Result<()> {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)? SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
hint: This usually indicates a problem with the package or the build environment.
help: `wsgiref` (v0.1.2) was included because `project:wsgi` (v0.1.0) depends on `wsgiref` help: `wsgiref` (v0.1.2) was included because `project:wsgi` (v0.1.0) depends on `wsgiref`
"###); "###);
@ -19686,8 +19692,9 @@ fn lock_derivation_chain_extended() -> Result<()> {
----- stdout ----- ----- stdout -----
----- stderr ----- ----- stderr -----
× Failed to download and build `wsgiref==0.1.2` × Failed to build `wsgiref==0.1.2`
Build backend failed to determine requirements with `build_wheel()` (exit status: 1) The build backend returned an error
Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1)
[stderr] [stderr]
Traceback (most recent call last): Traceback (most recent call last):
@ -19707,6 +19714,7 @@ fn lock_derivation_chain_extended() -> Result<()> {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)? SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
hint: This usually indicates a problem with the package or the build environment.
help: `wsgiref` (v0.1.2) was included because `project` (v0.1.0) depends on `child` (v0.1.0) which depends on `wsgiref>=0.1, <0.2` help: `wsgiref` (v0.1.2) was included because `project` (v0.1.0) depends on `child` (v0.1.0) which depends on `wsgiref>=0.1, <0.2`
"###); "###);

View file

@ -13781,8 +13781,9 @@ fn compile_derivation_chain() -> Result<()> {
----- stdout ----- ----- stdout -----
----- stderr ----- ----- stderr -----
× Failed to download and build `wsgiref==0.1.2` × Failed to build `wsgiref==0.1.2`
Build backend failed to determine requirements with `build_wheel()` (exit status: 1) The build backend returned an error
Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1)
[stderr] [stderr]
Traceback (most recent call last): Traceback (most recent call last):
@ -13802,6 +13803,7 @@ fn compile_derivation_chain() -> Result<()> {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)? SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
hint: This usually indicates a problem with the package or the build environment.
help: `wsgiref` (v0.1.2) was included because `child` (v0.1.0) depends on `wsgiref` help: `wsgiref` (v0.1.2) was included because `child` (v0.1.0) depends on `wsgiref`
"### "###
); );

View file

@ -303,7 +303,8 @@ dependencies = ["flask==1.0.x"]
----- stderr ----- ----- stderr -----
× Failed to build `project @ file://[TEMP_DIR]/path_dep` × Failed to build `project @ file://[TEMP_DIR]/path_dep`
Build backend failed to determine requirements with `build_wheel()` (exit status: 1) The build backend returned an error
Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1)
[stdout] [stdout]
configuration error: `project.dependencies[0]` must be pep508 configuration error: `project.dependencies[0]` must be pep508
@ -355,6 +356,8 @@ dependencies = ["flask==1.0.x"]
raise ValueError(f"{error}/n{summary}") from None raise ValueError(f"{error}/n{summary}") from None
ValueError: invalid pyproject.toml config: `project.dependencies[0]`. ValueError: invalid pyproject.toml config: `project.dependencies[0]`.
configuration error: `project.dependencies[0]` must be pep508 configuration error: `project.dependencies[0]` must be pep508
hint: This usually indicates a problem with the package or the build environment.
"### "###
); );
@ -4059,13 +4062,16 @@ fn no_build_isolation() -> Result<()> {
----- stdout ----- ----- stdout -----
----- stderr ----- ----- stderr -----
× Failed to download and build `anyio @ https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz` × Failed to build `anyio @ https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz`
Build backend failed to determine metadata through `prepare_metadata_for_build_wheel` (exit status: 1) The build backend returned an error
Call to `setuptools.build_meta.prepare_metadata_for_build_wheel` failed (exit status: 1)
[stderr] [stderr]
Traceback (most recent call last): Traceback (most recent call last):
File "<string>", line 8, in <module> File "<string>", line 8, in <module>
ModuleNotFoundError: No module named 'setuptools' ModuleNotFoundError: No module named 'setuptools'
hint: This usually indicates a problem with the package or the build environment.
"### "###
); );
@ -4127,13 +4133,16 @@ fn respect_no_build_isolation_env_var() -> Result<()> {
----- stdout ----- ----- stdout -----
----- stderr ----- ----- stderr -----
× Failed to download and build `anyio @ https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz` × Failed to build `anyio @ https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz`
Build backend failed to determine metadata through `prepare_metadata_for_build_wheel` (exit status: 1) The build backend returned an error
Call to `setuptools.build_meta.prepare_metadata_for_build_wheel` failed (exit status: 1)
[stderr] [stderr]
Traceback (most recent call last): Traceback (most recent call last):
File "<string>", line 8, in <module> File "<string>", line 8, in <module>
ModuleNotFoundError: No module named 'setuptools' ModuleNotFoundError: No module named 'setuptools'
hint: This usually indicates a problem with the package or the build environment.
"### "###
); );
@ -7124,13 +7133,16 @@ fn install_build_isolation_package() -> Result<()> {
----- stdout ----- ----- stdout -----
----- stderr ----- ----- stderr -----
× Failed to download and build `iniconfig @ https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz` × Failed to build `iniconfig @ https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz`
Build backend failed to determine metadata through `prepare_metadata_for_build_wheel` (exit status: 1) The build backend returned an error
Call to `hatchling.build.prepare_metadata_for_build_wheel` failed (exit status: 1)
[stderr] [stderr]
Traceback (most recent call last): Traceback (most recent call last):
File "<string>", line 8, in <module> File "<string>", line 8, in <module>
ModuleNotFoundError: No module named 'hatchling' ModuleNotFoundError: No module named 'hatchling'
hint: This usually indicates a problem with the package or the build environment.
"### "###
); );
@ -7383,8 +7395,9 @@ fn sklearn() {
----- stdout ----- ----- stdout -----
----- stderr ----- ----- stderr -----
× Failed to download and build `sklearn==0.0.post12` × Failed to build `sklearn==0.0.post12`
Build backend failed to determine requirements with `build_wheel()` (exit status: 1) The build backend returned an error
Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1)
[stderr] [stderr]
The 'sklearn' PyPI package is deprecated, use 'scikit-learn' The 'sklearn' PyPI package is deprecated, use 'scikit-learn'
@ -7403,6 +7416,7 @@ fn sklearn() {
More information is available at More information is available at
https://github.com/scikit-learn/sklearn-pypi-package https://github.com/scikit-learn/sklearn-pypi-package
hint: This usually indicates a problem with the package or the build environment.
help: `sklearn` is often confused for `scikit-learn` Did you mean to install `scikit-learn` instead? help: `sklearn` is often confused for `scikit-learn` Did you mean to install `scikit-learn` instead?
"### "###
); );
@ -7439,8 +7453,9 @@ fn resolve_derivation_chain() -> Result<()> {
----- stdout ----- ----- stdout -----
----- stderr ----- ----- stderr -----
× Failed to download and build `wsgiref==0.1.2` × Failed to build `wsgiref==0.1.2`
Build backend failed to determine requirements with `build_wheel()` (exit status: 1) The build backend returned an error
Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1)
[stderr] [stderr]
Traceback (most recent call last): Traceback (most recent call last):
@ -7460,6 +7475,7 @@ fn resolve_derivation_chain() -> Result<()> {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)? SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
hint: This usually indicates a problem with the package or the build environment.
help: `wsgiref` (v0.1.2) was included because `project` (v0.1.0) depends on `wsgiref` help: `wsgiref` (v0.1.2) was included because `project` (v0.1.0) depends on `wsgiref`
"### "###
); );

View file

@ -4169,7 +4169,7 @@ fn require_hashes_wheel_path_mismatch() -> Result<()> {
----- stderr ----- ----- stderr -----
Resolved 1 package in [TIME] Resolved 1 package in [TIME]
× Failed to download `tqdm @ file://[WORKSPACE]/scripts/links/tqdm-1000.0.0-py3-none-any.whl` × Failed to read `tqdm @ file://[WORKSPACE]/scripts/links/tqdm-1000.0.0-py3-none-any.whl`
Hash mismatch for `tqdm @ file://[WORKSPACE]/scripts/links/tqdm-1000.0.0-py3-none-any.whl` Hash mismatch for `tqdm @ file://[WORKSPACE]/scripts/links/tqdm-1000.0.0-py3-none-any.whl`
Expected: Expected:

View file

@ -761,14 +761,16 @@ fn sync_build_isolation_package() -> Result<()> {
----- stderr ----- ----- stderr -----
Resolved 2 packages in [TIME] Resolved 2 packages in [TIME]
× Failed to download and build `source-distribution @ https://files.pythonhosted.org/packages/10/1f/57aa4cce1b1abf6b433106676e15f9fa2c92ed2bd4cf77c3b50a9e9ac773/source_distribution-0.0.1.tar.gz` × Failed to build `source-distribution @ https://files.pythonhosted.org/packages/10/1f/57aa4cce1b1abf6b433106676e15f9fa2c92ed2bd4cf77c3b50a9e9ac773/source_distribution-0.0.1.tar.gz`
Build backend failed to build wheel through `build_wheel` (exit status: 1) The build backend returned an error
Call to `hatchling.build.build_wheel` failed (exit status: 1)
[stderr] [stderr]
Traceback (most recent call last): Traceback (most recent call last):
File "<string>", line 8, in <module> File "<string>", line 8, in <module>
ModuleNotFoundError: No module named 'hatchling' ModuleNotFoundError: No module named 'hatchling'
hint: This usually indicates a problem with the package or the build environment.
help: `source-distribution` was included because `project` (v0.1.0) depends on `source-distribution` help: `source-distribution` was included because `project` (v0.1.0) depends on `source-distribution`
"###); "###);
@ -852,14 +854,16 @@ fn sync_build_isolation_extra() -> Result<()> {
----- stderr ----- ----- stderr -----
Resolved [N] packages in [TIME] Resolved [N] packages in [TIME]
× Failed to download and build `source-distribution @ https://files.pythonhosted.org/packages/10/1f/57aa4cce1b1abf6b433106676e15f9fa2c92ed2bd4cf77c3b50a9e9ac773/source_distribution-0.0.1.tar.gz` × Failed to build `source-distribution @ https://files.pythonhosted.org/packages/10/1f/57aa4cce1b1abf6b433106676e15f9fa2c92ed2bd4cf77c3b50a9e9ac773/source_distribution-0.0.1.tar.gz`
Build backend failed to build wheel through `build_wheel` (exit status: 1) The build backend returned an error
Call to `hatchling.build.build_wheel` failed (exit status: 1)
[stderr] [stderr]
Traceback (most recent call last): Traceback (most recent call last):
File "<string>", line 8, in <module> File "<string>", line 8, in <module>
ModuleNotFoundError: No module named 'hatchling' ModuleNotFoundError: No module named 'hatchling'
hint: This usually indicates a problem with the package or the build environment.
help: `source-distribution` was included because `project[compile]` (v0.1.0) depends on `source-distribution` help: `source-distribution` was included because `project[compile]` (v0.1.0) depends on `source-distribution`
"###); "###);
@ -871,14 +875,16 @@ fn sync_build_isolation_extra() -> Result<()> {
----- stderr ----- ----- stderr -----
Resolved [N] packages in [TIME] Resolved [N] packages in [TIME]
× Failed to download and build `source-distribution @ https://files.pythonhosted.org/packages/10/1f/57aa4cce1b1abf6b433106676e15f9fa2c92ed2bd4cf77c3b50a9e9ac773/source_distribution-0.0.1.tar.gz` × Failed to build `source-distribution @ https://files.pythonhosted.org/packages/10/1f/57aa4cce1b1abf6b433106676e15f9fa2c92ed2bd4cf77c3b50a9e9ac773/source_distribution-0.0.1.tar.gz`
Build backend failed to build wheel through `build_wheel` (exit status: 1) The build backend returned an error
Call to `hatchling.build.build_wheel` failed (exit status: 1)
[stderr] [stderr]
Traceback (most recent call last): Traceback (most recent call last):
File "<string>", line 8, in <module> File "<string>", line 8, in <module>
ModuleNotFoundError: No module named 'hatchling' ModuleNotFoundError: No module named 'hatchling'
hint: This usually indicates a problem with the package or the build environment.
help: `source-distribution` was included because `project[compile]` (v0.1.0) depends on `source-distribution` help: `source-distribution` was included because `project[compile]` (v0.1.0) depends on `source-distribution`
"###); "###);
@ -4953,8 +4959,9 @@ fn sync_derivation_chain() -> Result<()> {
----- stderr ----- ----- stderr -----
Resolved 2 packages in [TIME] Resolved 2 packages in [TIME]
× Failed to download and build `wsgiref==0.1.2` × Failed to build `wsgiref==0.1.2`
Build backend failed to determine requirements with `build_wheel()` (exit status: 1) The build backend returned an error
Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1)
[stderr] [stderr]
Traceback (most recent call last): Traceback (most recent call last):
@ -4974,6 +4981,7 @@ fn sync_derivation_chain() -> Result<()> {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)? SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
hint: This usually indicates a problem with the package or the build environment.
help: `wsgiref` (v0.1.2) was included because `project` (v0.1.0) depends on `wsgiref` help: `wsgiref` (v0.1.2) was included because `project` (v0.1.0) depends on `wsgiref`
"###); "###);
@ -5017,8 +5025,9 @@ fn sync_derivation_chain_extra() -> Result<()> {
----- stderr ----- ----- stderr -----
Resolved 2 packages in [TIME] Resolved 2 packages in [TIME]
× Failed to download and build `wsgiref==0.1.2` × Failed to build `wsgiref==0.1.2`
Build backend failed to determine requirements with `build_wheel()` (exit status: 1) The build backend returned an error
Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1)
[stderr] [stderr]
Traceback (most recent call last): Traceback (most recent call last):
@ -5038,6 +5047,7 @@ fn sync_derivation_chain_extra() -> Result<()> {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)? SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
hint: This usually indicates a problem with the package or the build environment.
help: `wsgiref` (v0.1.2) was included because `project[wsgi]` (v0.1.0) depends on `wsgiref` help: `wsgiref` (v0.1.2) was included because `project[wsgi]` (v0.1.0) depends on `wsgiref`
"###); "###);
@ -5083,8 +5093,9 @@ fn sync_derivation_chain_group() -> Result<()> {
----- stderr ----- ----- stderr -----
Resolved 2 packages in [TIME] Resolved 2 packages in [TIME]
× Failed to download and build `wsgiref==0.1.2` × Failed to build `wsgiref==0.1.2`
Build backend failed to determine requirements with `build_wheel()` (exit status: 1) The build backend returned an error
Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1)
[stderr] [stderr]
Traceback (most recent call last): Traceback (most recent call last):
@ -5104,6 +5115,7 @@ fn sync_derivation_chain_group() -> Result<()> {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)? SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
hint: This usually indicates a problem with the package or the build environment.
help: `wsgiref` (v0.1.2) was included because `project:wsgi` (v0.1.0) depends on `wsgiref` help: `wsgiref` (v0.1.2) was included because `project:wsgi` (v0.1.0) depends on `wsgiref`
"###); "###);

View file

@ -1469,8 +1469,9 @@ fn tool_install_uninstallable() {
----- stderr ----- ----- stderr -----
Resolved 1 package in [TIME] Resolved 1 package in [TIME]
× Failed to download and build `pyenv==0.0.1` × Failed to build `pyenv==0.0.1`
Build backend failed to build wheel through `build_wheel` (exit status: 1) The build backend returned an error
Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1)
[stdout] [stdout]
running bdist_wheel running bdist_wheel
@ -1486,6 +1487,9 @@ fn tool_install_uninstallable() {
https://github.com/pyenv/pyenv#installation https://github.com/pyenv/pyenv#installation
# #
hint: This usually indicates a problem with the package or the build environment.
"###); "###);
// Ensure the tool environment is not created. // Ensure the tool environment is not created.

View file

@ -12,22 +12,23 @@ unsupported version of Python:
```console ```console
$ uv pip install -p 3.13 'numpy<1.20' $ uv pip install -p 3.13 'numpy<1.20'
Resolved 1 package in 62ms Resolved 1 package in 62ms
× Failed to download and build `numpy==1.19.5` × Failed to build `numpy==1.19.5`
├─▶ Build backend failed to determine requirements with `build_wheel()` (exit status: 1) ├─▶ The build backend returned an error
╰─▶ Call to `setuptools.build_meta:__legacy__.build_wheel()` failed (exit status: 1)
[stderr] [stderr]
Traceback (most recent call last): Traceback (most recent call last):
File "<string>", line 8, in <module> File "<string>", line 8, in <module>
from setuptools.build_meta import __legacy__ as backend from setuptools.build_meta import __legacy__ as backend
│ File "/Users/example/.cache/uv/builds-v0/.tmp96A0WB/lib/python3.13/site-packages/setuptools/__init__.py", line 9, in <module> File "/home/konsti/.cache/uv/builds-v0/.tmpi4bgKb/lib/python3.13/site-packages/setuptools/__init__.py", line 9, in <module>
import distutils.core import distutils.core
ModuleNotFoundError: No module named 'distutils' ModuleNotFoundError: No module named 'distutils'
╰─▶ distutils was removed from the standard library in Python 3.12. Consider adding a constraint hint: `distutils` was removed from the standard library in Python 3.12. Consider adding a constraint (like `numpy >1.19.5`) to avoid building a version of `numpy` that depends
(like `numpy >1.19.5`) to avoid building a version of numpy that depends on distutils. on `distutils`.
``` ```
Notice that the error message is prefaced by "Build backend failed to determine requirements". Notice that the error message is prefaced by "The build backend returned an error".
The build failure includes the `[stderr]` (and `[stdout]`, if present) from the build backend that The build failure includes the `[stderr]` (and `[stdout]`, if present) from the build backend that
was used for the build. The error logs are not from uv itself. was used for the build. The error logs are not from uv itself.
@ -118,8 +119,9 @@ If the build error mentions a missing command, for example, `gcc`:
<!-- docker run --platform linux/x86_64 -it ghcr.io/astral-sh/uv:python3.10-bookworm-slim /bin/bash -c "uv pip install --system pysha3==1.0.2" --> <!-- docker run --platform linux/x86_64 -it ghcr.io/astral-sh/uv:python3.10-bookworm-slim /bin/bash -c "uv pip install --system pysha3==1.0.2" -->
```hl_lines="17" ```hl_lines="17"
× Failed to download and build `pysha3==1.0.2` × Failed to build `pysha3==1.0.2`
╰─▶ Build backend failed to build wheel through `build_wheel` (exit status: 1) ├─▶ The build backend returned an error
╰─▶ Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1)
[stdout] [stdout]
running bdist_wheel running bdist_wheel
@ -130,8 +132,8 @@ If the build error mentions a missing command, for example, `gcc`:
running build_ext running build_ext
building '_pysha3' extension building '_pysha3' extension
creating build/temp.linux-x86_64-cpython-310/Modules/_sha3 creating build/temp.linux-x86_64-cpython-310/Modules/_sha3
gcc -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -DPY_WITH_KECCAK=1 -I/root/.cache/uv/builds-v0/.tmpxAJdUa/include -I/usr/local/include/python3.10 -c Modules/_sha3/sha3module.c -o gcc -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -DPY_WITH_KECCAK=1 -I/root/.cache/uv/builds-v0/.tmp8V4iEk/include -I/usr/local/include/python3.10 -c
build/temp.linux-x86_64-cpython-310/Modules/_sha3/sha3module.o Modules/_sha3/sha3module.c -o build/temp.linux-x86_64-cpython-310/Modules/_sha3/sha3module.o
[stderr] [stderr]
error: command 'gcc' failed: No such file or directory error: command 'gcc' failed: No such file or directory
@ -165,8 +167,9 @@ For example, installing `pygraphviz` requires Graphviz to be installed:
<!-- docker run --platform linux/x86_64 -it ghcr.io/astral-sh/uv:python3.12-bookworm /bin/bash -c "uv pip install --system 'pygraphviz'" --> <!-- docker run --platform linux/x86_64 -it ghcr.io/astral-sh/uv:python3.12-bookworm /bin/bash -c "uv pip install --system 'pygraphviz'" -->
```hl_lines="18-19" ```hl_lines="18-19"
× Failed to download and build `pygraphviz==1.14` × Failed to build `pygraphviz==1.14`
╰─▶ Build backend failed to build wheel through `build_wheel` (exit status: 1) ├─▶ The build backend returned an error
╰─▶ Call to `setuptools.build_meta.build_wheel` failed (exit status: 1)
[stdout] [stdout]
running bdist_wheel running bdist_wheel
@ -215,8 +218,9 @@ dependency:
<!-- docker run --platform linux/x86_64 -it ghcr.io/astral-sh/uv:python3.12-bookworm-slim /bin/bash -c "uv pip install --system chumpy" --> <!-- docker run --platform linux/x86_64 -it ghcr.io/astral-sh/uv:python3.12-bookworm-slim /bin/bash -c "uv pip install --system chumpy" -->
```hl_lines="7" ```hl_lines="7"
× Failed to download and build `chumpy==0.70` × Failed to build `chumpy==0.70`
╰─▶ Build backend failed to determine requirements with `build_wheel()` (exit status: 1) ├─▶ The build backend returned an error
╰─▶ Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1)
[stderr] [stderr]
Traceback (most recent call last): Traceback (most recent call last):
@ -270,8 +274,9 @@ apache-beam<=2.49.0
<!-- docker run --platform linux/x86_64 -it ghcr.io/astral-sh/uv:python3.10-bookworm-slim /bin/bash -c "printf 'dill<0.3.9,>=0.2.2\napache-beam<=2.49.0' | uv pip compile -" --> <!-- docker run --platform linux/x86_64 -it ghcr.io/astral-sh/uv:python3.10-bookworm-slim /bin/bash -c "printf 'dill<0.3.9,>=0.2.2\napache-beam<=2.49.0' | uv pip compile -" -->
```hl_lines="1" ```hl_lines="1"
× Failed to download and build `apache-beam==2.0.0` × Failed to build `apache-beam==2.0.0`
╰─▶ Build backend failed to determine requirements with `build_wheel()` (exit status: 1) ├─▶ The build backend returned an error
╰─▶ Call to `setuptools.build_meta:__legacy__.build_wheel` failed (exit status: 1)
[stderr] [stderr]
... ...