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

View file

@ -8,10 +8,12 @@ use zip::result::ZipError;
use crate::metadata::MetadataError;
use uv_client::WrappedReqwestError;
use uv_distribution_filename::WheelFilenameError;
use uv_distribution_types::IsBuildBackendError;
use uv_fs::Simplified;
use uv_normalize::PackageName;
use uv_pep440::{Version, VersionSpecifiers};
use uv_pypi_types::{HashAlgorithm, HashDigest, ParsedUrlError};
use uv_types::AnyErrorBuild;
#[derive(Debug, thiserror::Error)]
pub enum Error {
@ -52,7 +54,7 @@ pub enum Error {
// Build error
#[error(transparent)]
Build(anyhow::Error),
Build(AnyErrorBuild),
#[error("Built wheel has an invalid filename")]
WheelFilename(#[from] WheelFilenameError),
#[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 {
/// Construct a hash mismatch error.
pub fn hash_mismatch(

View file

@ -1879,7 +1879,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
Some(&source.to_string()),
)
.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.
name.to_string()
@ -1900,7 +1900,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
BuildOutput::Debug,
)
.await
.map_err(Error::Build)?
.map_err(|err| Error::Build(err.into()))?
.wheel(temp_dir.path())
.await
.map_err(Error::Build)?
@ -1976,7 +1976,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
BuildOutput::Debug,
)
.await
.map_err(Error::Build)?;
.map_err(|err| Error::Build(err.into()))?;
// Build the metadata.
let dist_info = builder.metadata().await.map_err(Error::Build)?;