Refactor unavailable metadata to shrink the resolver (#9769)

The resolver methods are already too large and complex, especially
`choose_version*`, so i wanted to shrink and simplify them a bit before
adding new methods to them.

I've split `MetadataResponse` into three variants: success, non-fatal
error (reported through pubgrub), fatal error (reported as error trace).
The resulting non-fatal `MetadataUnavailable` type is equivalent to the
`IncompletePackage` type, so they are now merged. (`UnavailableVersion`
is a bit different since, besides the extra `IncompatibleDist` variant,
it have no error source attached). This shows that the missing metadata
variant was unused, which I removed.

Tagging as error messages for the logging format changes.
This commit is contained in:
konsti 2024-12-10 17:46:53 +01:00 committed by GitHub
parent edf875e306
commit b751648bfe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 138 additions and 256 deletions

View file

@ -24,7 +24,7 @@ use crate::pubgrub::{PubGrubPackage, PubGrubPackageInner, PubGrubReportFormatter
use crate::python_requirement::PythonRequirement;
use crate::resolution::ConflictingDistributionError;
use crate::resolver::{
IncompletePackage, ResolverEnvironment, UnavailablePackage, UnavailableReason,
MetadataUnavailable, ResolverEnvironment, UnavailablePackage, UnavailableReason,
};
use crate::Options;
@ -145,7 +145,7 @@ pub struct NoSolutionError {
index_locations: IndexLocations,
index_capabilities: IndexCapabilities,
unavailable_packages: FxHashMap<PackageName, UnavailablePackage>,
incomplete_packages: FxHashMap<PackageName, BTreeMap<Version, IncompletePackage>>,
incomplete_packages: FxHashMap<PackageName, BTreeMap<Version, MetadataUnavailable>>,
fork_urls: ForkUrls,
env: ResolverEnvironment,
workspace_members: BTreeSet<PackageName>,
@ -163,7 +163,7 @@ impl NoSolutionError {
index_locations: IndexLocations,
index_capabilities: IndexCapabilities,
unavailable_packages: FxHashMap<PackageName, UnavailablePackage>,
incomplete_packages: FxHashMap<PackageName, BTreeMap<Version, IncompletePackage>>,
incomplete_packages: FxHashMap<PackageName, BTreeMap<Version, MetadataUnavailable>>,
fork_urls: ForkUrls,
env: ResolverEnvironment,
workspace_members: BTreeSet<PackageName>,

View file

@ -18,7 +18,7 @@ use crate::error::ErrorTree;
use crate::fork_urls::ForkUrls;
use crate::prerelease::AllowPrerelease;
use crate::python_requirement::{PythonRequirement, PythonRequirementSource};
use crate::resolver::{IncompletePackage, UnavailablePackage, UnavailableReason};
use crate::resolver::{MetadataUnavailable, UnavailablePackage, UnavailableReason};
use crate::{Flexibility, Options, RequiresPython, ResolverEnvironment};
use super::{PubGrubPackage, PubGrubPackageInner, PubGrubPython};
@ -548,7 +548,7 @@ impl PubGrubReportFormatter<'_> {
index_capabilities: &IndexCapabilities,
available_indexes: &FxHashMap<PackageName, BTreeSet<IndexUrl>>,
unavailable_packages: &FxHashMap<PackageName, UnavailablePackage>,
incomplete_packages: &FxHashMap<PackageName, BTreeMap<Version, IncompletePackage>>,
incomplete_packages: &FxHashMap<PackageName, BTreeMap<Version, MetadataUnavailable>>,
fork_urls: &ForkUrls,
env: &ResolverEnvironment,
workspace_members: &BTreeSet<PackageName>,
@ -679,7 +679,7 @@ impl PubGrubReportFormatter<'_> {
index_capabilities: &IndexCapabilities,
available_indexes: &FxHashMap<PackageName, BTreeSet<IndexUrl>>,
unavailable_packages: &FxHashMap<PackageName, UnavailablePackage>,
incomplete_packages: &FxHashMap<PackageName, BTreeMap<Version, IncompletePackage>>,
incomplete_packages: &FxHashMap<PackageName, BTreeMap<Version, MetadataUnavailable>>,
hints: &mut IndexSet<PubGrubHint>,
) {
let no_find_links = index_locations.flat_indexes().peekable().peek().is_none();
@ -694,11 +694,6 @@ impl PubGrubReportFormatter<'_> {
Some(UnavailablePackage::Offline) => {
hints.insert(PubGrubHint::Offline);
}
Some(UnavailablePackage::MissingMetadata) => {
hints.insert(PubGrubHint::MissingPackageMetadata {
package: package.clone(),
});
}
Some(UnavailablePackage::InvalidMetadata(reason)) => {
hints.insert(PubGrubHint::InvalidPackageMetadata {
package: package.clone(),
@ -720,37 +715,31 @@ impl PubGrubReportFormatter<'_> {
for (version, incomplete) in versions.iter().rev() {
if set.contains(version) {
match incomplete {
IncompletePackage::Offline => {
MetadataUnavailable::Offline => {
hints.insert(PubGrubHint::Offline);
}
IncompletePackage::MissingMetadata => {
hints.insert(PubGrubHint::MissingVersionMetadata {
package: package.clone(),
version: version.clone(),
});
}
IncompletePackage::InvalidMetadata(reason) => {
MetadataUnavailable::InvalidMetadata(reason) => {
hints.insert(PubGrubHint::InvalidVersionMetadata {
package: package.clone(),
version: version.clone(),
reason: reason.clone(),
reason: reason.to_string(),
});
}
IncompletePackage::InconsistentMetadata(reason) => {
MetadataUnavailable::InconsistentMetadata(reason) => {
hints.insert(PubGrubHint::InconsistentVersionMetadata {
package: package.clone(),
version: version.clone(),
reason: reason.clone(),
reason: reason.to_string(),
});
}
IncompletePackage::InvalidStructure(reason) => {
MetadataUnavailable::InvalidStructure(reason) => {
hints.insert(PubGrubHint::InvalidVersionStructure {
package: package.clone(),
version: version.clone(),
reason: reason.clone(),
reason: reason.to_string(),
});
}
IncompletePackage::RequiresPython(requires_python, python_version) => {
MetadataUnavailable::RequiresPython(requires_python, python_version) => {
hints.insert(PubGrubHint::IncompatibleBuildRequirement {
package: package.clone(),
version: version.clone(),
@ -882,8 +871,6 @@ pub(crate) enum PubGrubHint {
NoIndex,
/// A package was not found in the registry, but network access was disabled.
Offline,
/// Metadata for a package could not be found.
MissingPackageMetadata { package: PubGrubPackage },
/// Metadata for a package could not be parsed.
InvalidPackageMetadata {
package: PubGrubPackage,
@ -896,12 +883,6 @@ pub(crate) enum PubGrubHint {
// excluded from `PartialEq` and `Hash`
reason: String,
},
/// Metadata for a package version could not be found.
MissingVersionMetadata {
package: PubGrubPackage,
// excluded from `PartialEq` and `Hash`
version: Version,
},
/// Metadata for a package version could not be parsed.
InvalidVersionMetadata {
package: PubGrubPackage,
@ -992,18 +973,12 @@ enum PubGrubHintCore {
},
NoIndex,
Offline,
MissingPackageMetadata {
package: PubGrubPackage,
},
InvalidPackageMetadata {
package: PubGrubPackage,
},
InvalidPackageStructure {
package: PubGrubPackage,
},
MissingVersionMetadata {
package: PubGrubPackage,
},
InvalidVersionMetadata {
package: PubGrubPackage,
},
@ -1052,18 +1027,12 @@ impl From<PubGrubHint> for PubGrubHintCore {
}
PubGrubHint::NoIndex => Self::NoIndex,
PubGrubHint::Offline => Self::Offline,
PubGrubHint::MissingPackageMetadata { package, .. } => {
Self::MissingPackageMetadata { package }
}
PubGrubHint::InvalidPackageMetadata { package, .. } => {
Self::InvalidPackageMetadata { package }
}
PubGrubHint::InvalidPackageStructure { package, .. } => {
Self::InvalidPackageStructure { package }
}
PubGrubHint::MissingVersionMetadata { package, .. } => {
Self::MissingVersionMetadata { package }
}
PubGrubHint::InvalidVersionMetadata { package, .. } => {
Self::InvalidVersionMetadata { package }
}
@ -1162,15 +1131,6 @@ impl std::fmt::Display for PubGrubHint {
":".bold(),
)
}
Self::MissingPackageMetadata { package } => {
write!(
f,
"{}{} Metadata for `{}` could not be found, as the wheel is missing a `METADATA` file",
"hint".bold().cyan(),
":".bold(),
package.bold()
)
}
Self::InvalidPackageMetadata { package, reason } => {
write!(
f,
@ -1191,16 +1151,6 @@ impl std::fmt::Display for PubGrubHint {
textwrap::indent(reason, " ")
)
}
Self::MissingVersionMetadata { package, version } => {
write!(
f,
"{}{} Metadata for `{}` ({}) could not be found, as the wheel is missing a `METADATA` file",
"hint".bold().cyan(),
":".bold(),
package.cyan(),
format!("v{version}").cyan(),
)
}
Self::InvalidVersionMetadata {
package,
version,

View file

@ -1,5 +1,6 @@
use std::fmt::{Display, Formatter};
use crate::resolver::MetadataUnavailable;
use uv_distribution_types::IncompatibleDist;
use uv_pep440::{Version, VersionSpecifiers};
@ -21,17 +22,15 @@ impl Display for UnavailableReason {
}
}
/// The package version is unavailable and cannot be used. Unlike [`PackageUnavailable`], this
/// The package version is unavailable and cannot be used. Unlike [`MetadataUnavailable`], this
/// applies to a single version of the package.
///
/// Most variant are from [`MetadataResponse`] without the error source (since we don't format
/// the source).
/// Most variant are from [`MetadataResponse`] without the error source, since we don't format
/// the source and we want to merge unavailable messages across versions.
#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) enum UnavailableVersion {
/// Version is incompatible because it has no usable distributions
IncompatibleDist(IncompatibleDist),
/// The wheel metadata was not found.
MissingMetadata,
/// The wheel metadata was found, but could not be parsed.
InvalidMetadata,
/// The wheel metadata was found, but the metadata was inconsistent.
@ -49,7 +48,6 @@ impl UnavailableVersion {
pub(crate) fn message(&self) -> String {
match self {
UnavailableVersion::IncompatibleDist(invalid_dist) => format!("{invalid_dist}"),
UnavailableVersion::MissingMetadata => "not include a `METADATA` file".into(),
UnavailableVersion::InvalidMetadata => "invalid metadata".into(),
UnavailableVersion::InconsistentMetadata => "inconsistent metadata".into(),
UnavailableVersion::InvalidStructure => "an invalid package format".into(),
@ -63,7 +61,6 @@ impl UnavailableVersion {
pub(crate) fn singular_message(&self) -> String {
match self {
UnavailableVersion::IncompatibleDist(invalid_dist) => invalid_dist.singular_message(),
UnavailableVersion::MissingMetadata => format!("does {self}"),
UnavailableVersion::InvalidMetadata => format!("has {self}"),
UnavailableVersion::InconsistentMetadata => format!("has {self}"),
UnavailableVersion::InvalidStructure => format!("has {self}"),
@ -75,7 +72,6 @@ impl UnavailableVersion {
pub(crate) fn plural_message(&self) -> String {
match self {
UnavailableVersion::IncompatibleDist(invalid_dist) => invalid_dist.plural_message(),
UnavailableVersion::MissingMetadata => format!("do {self}"),
UnavailableVersion::InvalidMetadata => format!("have {self}"),
UnavailableVersion::InconsistentMetadata => format!("have {self}"),
UnavailableVersion::InvalidStructure => format!("have {self}"),
@ -91,6 +87,22 @@ impl Display for UnavailableVersion {
}
}
impl From<&MetadataUnavailable> for UnavailableVersion {
fn from(reason: &MetadataUnavailable) -> Self {
match reason {
MetadataUnavailable::Offline => UnavailableVersion::Offline,
MetadataUnavailable::InvalidMetadata(_) => UnavailableVersion::InvalidMetadata,
MetadataUnavailable::InconsistentMetadata(_) => {
UnavailableVersion::InconsistentMetadata
}
MetadataUnavailable::InvalidStructure(_) => UnavailableVersion::InvalidStructure,
MetadataUnavailable::RequiresPython(requires_python, _python_version) => {
UnavailableVersion::RequiresPython(requires_python.clone())
}
}
}
}
/// The package is unavailable and cannot be used.
#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) enum UnavailablePackage {
@ -100,8 +112,6 @@ pub(crate) enum UnavailablePackage {
Offline,
/// The package was not found in the registry.
NotFound,
/// The package metadata was not found.
MissingMetadata,
/// The package metadata was found, but could not be parsed.
InvalidMetadata(String),
/// The package has an invalid structure.
@ -114,7 +124,6 @@ impl UnavailablePackage {
UnavailablePackage::NoIndex => "not found in the provided package locations",
UnavailablePackage::Offline => "not found in the cache",
UnavailablePackage::NotFound => "not found in the package registry",
UnavailablePackage::MissingMetadata => "not include a `METADATA` file",
UnavailablePackage::InvalidMetadata(_) => "invalid metadata",
UnavailablePackage::InvalidStructure(_) => "an invalid package format",
}
@ -125,7 +134,6 @@ impl UnavailablePackage {
UnavailablePackage::NoIndex => format!("was {self}"),
UnavailablePackage::Offline => format!("was {self}"),
UnavailablePackage::NotFound => format!("was {self}"),
UnavailablePackage::MissingMetadata => format!("does {self}"),
UnavailablePackage::InvalidMetadata(_) => format!("has {self}"),
UnavailablePackage::InvalidStructure(_) => format!("has {self}"),
}
@ -138,22 +146,20 @@ impl Display for UnavailablePackage {
}
}
/// The package is unavailable at specific versions.
#[derive(Debug, Clone)]
pub(crate) enum IncompletePackage {
/// Network requests were disabled (i.e., `--offline`), and the wheel metadata was not found in the cache.
Offline,
/// The wheel metadata was not found.
MissingMetadata,
/// The wheel metadata was found, but could not be parsed.
InvalidMetadata(String),
/// The wheel metadata was found, but the metadata was inconsistent.
InconsistentMetadata(String),
/// The wheel has an invalid structure.
InvalidStructure(String),
/// The source distribution has a `requires-python` requirement that is not met by the installed
/// Python version (and static metadata is not available).
RequiresPython(VersionSpecifiers, Version),
impl From<&MetadataUnavailable> for UnavailablePackage {
fn from(reason: &MetadataUnavailable) -> Self {
match reason {
MetadataUnavailable::Offline => Self::Offline,
MetadataUnavailable::InvalidMetadata(err) => Self::InvalidMetadata(err.to_string()),
MetadataUnavailable::InconsistentMetadata(err) => {
Self::InvalidMetadata(err.to_string())
}
MetadataUnavailable::InvalidStructure(err) => Self::InvalidStructure(err.to_string()),
MetadataUnavailable::RequiresPython(..) => {
unreachable!("`requires-python` is only known upfront for registry distributions")
}
}
}
}
#[derive(Debug, Clone)]

View file

@ -55,7 +55,7 @@ use crate::python_requirement::PythonRequirement;
use crate::resolution::ResolverOutput;
use crate::resolution_mode::ResolutionStrategy;
pub(crate) use crate::resolver::availability::{
IncompletePackage, ResolverVersion, UnavailablePackage, UnavailableReason, UnavailableVersion,
ResolverVersion, UnavailablePackage, UnavailableReason, UnavailableVersion,
};
use crate::resolver::batch_prefetch::BatchPrefetcher;
pub use crate::resolver::derivation::DerivationChainBuilder;
@ -64,6 +64,7 @@ pub use crate::resolver::environment::ResolverEnvironment;
pub(crate) use crate::resolver::fork_map::{ForkMap, ForkSet};
pub(crate) use crate::resolver::urls::Urls;
use crate::universal_marker::{ConflictMarker, UniversalMarker};
pub(crate) use provider::MetadataUnavailable;
pub use crate::resolver::index::InMemoryIndex;
use crate::resolver::indexes::Indexes;
@ -118,7 +119,7 @@ struct ResolverState<InstalledPackages: InstalledPackagesProvider> {
/// Incompatibilities for packages that are entirely unavailable.
unavailable_packages: DashMap<PackageName, UnavailablePackage>,
/// Incompatibilities for packages that are unavailable at specific versions.
incomplete_packages: DashMap<PackageName, DashMap<Version, IncompletePackage>>,
incomplete_packages: DashMap<PackageName, DashMap<Version, MetadataUnavailable>>,
/// The options that were used to configure this resolver.
options: Options,
/// The reporter to use for this resolver.
@ -354,6 +355,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
state.priorities.get(&state.pubgrub.package_store[id])
})
else {
// All packages have been assigned, the fork has been successfully resolved
if tracing::enabled!(Level::DEBUG) {
prefetcher.log_tried_versions();
}
@ -919,40 +921,11 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
// If we failed to fetch the metadata for a URL, we can't proceed.
let metadata = match &*response {
MetadataResponse::Found(archive) => &archive.metadata,
MetadataResponse::Offline => {
MetadataResponse::Unavailable(reason) => {
self.unavailable_packages
.insert(name.clone(), UnavailablePackage::Offline);
.insert(name.clone(), reason.into());
return Ok(None);
}
MetadataResponse::MissingMetadata => {
self.unavailable_packages
.insert(name.clone(), UnavailablePackage::MissingMetadata);
return Ok(None);
}
MetadataResponse::InvalidMetadata(err) => {
self.unavailable_packages.insert(
name.clone(),
UnavailablePackage::InvalidMetadata(err.to_string()),
);
return Ok(None);
}
MetadataResponse::InconsistentMetadata(err) => {
self.unavailable_packages.insert(
name.clone(),
UnavailablePackage::InvalidMetadata(err.to_string()),
);
return Ok(None);
}
MetadataResponse::InvalidStructure(err) => {
self.unavailable_packages.insert(
name.clone(),
UnavailablePackage::InvalidStructure(err.to_string()),
);
return Ok(None);
}
MetadataResponse::RequiresPython(..) => {
unreachable!("`requires-python` is only known upfront for registry distributions")
}
MetadataResponse::Error(dist, err) => {
// TODO(charlie): Add derivation chain for URL dependencies. In practice, this isn't
// critical since we fetch URL dependencies _prior_ to invoking the resolver.
@ -1318,82 +1291,20 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
let metadata = match &*response {
MetadataResponse::Found(archive) => &archive.metadata,
MetadataResponse::Offline => {
MetadataResponse::Unavailable(reason) => {
let unavailable_version = UnavailableVersion::from(reason);
let message = unavailable_version.singular_message();
if let Some(err) = reason.source() {
// Show the detailed error for metadata parse errors.
warn!("{name} {message}: {err}");
} else {
warn!("{name} {message}");
}
self.incomplete_packages
.entry(name.clone())
.or_default()
.insert(version.clone(), IncompletePackage::Offline);
return Ok(Dependencies::Unavailable(UnavailableVersion::Offline));
}
MetadataResponse::MissingMetadata => {
self.incomplete_packages
.entry(name.clone())
.or_default()
.insert(version.clone(), IncompletePackage::MissingMetadata);
return Ok(Dependencies::Unavailable(
UnavailableVersion::MissingMetadata,
));
}
MetadataResponse::InvalidMetadata(err) => {
warn!("Unable to extract metadata for {name}: {err}");
self.incomplete_packages
.entry(name.clone())
.or_default()
.insert(
version.clone(),
IncompletePackage::InvalidMetadata(err.to_string()),
);
return Ok(Dependencies::Unavailable(
UnavailableVersion::InvalidMetadata,
));
}
MetadataResponse::InconsistentMetadata(err) => {
warn!("Unable to extract metadata for {name}: {err}");
self.incomplete_packages
.entry(name.clone())
.or_default()
.insert(
version.clone(),
IncompletePackage::InconsistentMetadata(err.to_string()),
);
return Ok(Dependencies::Unavailable(
UnavailableVersion::InconsistentMetadata,
));
}
MetadataResponse::InvalidStructure(err) => {
warn!("Unable to extract metadata for {name}: {err}");
self.incomplete_packages
.entry(name.clone())
.or_default()
.insert(
version.clone(),
IncompletePackage::InvalidStructure(err.to_string()),
);
return Ok(Dependencies::Unavailable(
UnavailableVersion::InvalidStructure,
));
}
MetadataResponse::RequiresPython(requires_python, python_version) => {
warn!(
"Unable to extract metadata for {name}: {}",
uv_distribution::Error::RequiresPython(
requires_python.clone(),
python_version.clone()
)
);
self.incomplete_packages
.entry(name.clone())
.or_default()
.insert(
version.clone(),
IncompletePackage::RequiresPython(
requires_python.clone(),
python_version.clone(),
),
);
return Ok(Dependencies::Unavailable(
UnavailableVersion::RequiresPython(requires_python.clone()),
));
.insert(version.clone(), reason.clone());
return Ok(Dependencies::Unavailable(unavailable_version));
}
MetadataResponse::Error(dist, err) => {
let chain = DerivationChainBuilder::from_state(id, version, pubgrub)
@ -1856,37 +1767,20 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
))),
);
}
Some(Response::Dist {
dist: Dist::Built(dist),
metadata,
}) => {
trace!("Received built distribution metadata for: {dist}");
match &metadata {
MetadataResponse::InvalidMetadata(err) => {
warn!("Unable to extract metadata for {dist}: {err}");
Some(Response::Dist { dist, metadata }) => {
let dist_kind = match dist {
Dist::Built(_) => "built",
Dist::Source(_) => "source",
};
trace!("Received {dist_kind} distribution metadata for: {dist}");
if let MetadataResponse::Unavailable(reason) = &metadata {
let message = UnavailableVersion::from(reason).singular_message();
if let Some(err) = reason.source() {
// Show the detailed error for metadata parse errors.
warn!("{dist} {message}: {err}");
} else {
warn!("{dist} {message}");
}
MetadataResponse::InvalidStructure(err) => {
warn!("Unable to extract metadata for {dist}: {err}");
}
_ => {}
}
self.index
.distributions()
.done(dist.version_id(), Arc::new(metadata));
}
Some(Response::Dist {
dist: Dist::Source(dist),
metadata,
}) => {
trace!("Received source distribution metadata for: {dist}");
match &metadata {
MetadataResponse::InvalidMetadata(err) => {
warn!("Unable to extract metadata for {dist}: {err}");
}
MetadataResponse::InvalidStructure(err) => {
warn!("Unable to extract metadata for {dist}: {err}");
}
_ => {}
}
self.index
.distributions()

View file

@ -34,21 +34,43 @@ pub enum VersionsResponse {
pub enum MetadataResponse {
/// The wheel metadata was found and parsed successfully.
Found(ArchiveMetadata),
/// The wheel metadata was not found.
MissingMetadata,
/// The wheel metadata was found, but could not be parsed.
InvalidMetadata(Box<uv_pypi_types::MetadataError>),
/// The wheel metadata was found, but the metadata was inconsistent.
InconsistentMetadata(Box<uv_distribution::Error>),
/// The wheel has an invalid structure.
InvalidStructure(Box<uv_metadata::Error>),
/// A non-fatal error.
Unavailable(MetadataUnavailable),
/// The distribution could not be built or downloaded, a fatal error.
Error(Box<Dist>, Arc<uv_distribution::Error>),
}
/// Non-fatal metadata fetching error.
///
/// This is also the unavailability reasons for a package, while version unavailability is separate
/// in [`UnavailableVersion`].
#[derive(Debug, Clone)]
pub enum MetadataUnavailable {
/// The wheel metadata was not found in the cache and the network is not available.
Offline,
/// The wheel metadata was found, but could not be parsed.
InvalidMetadata(Arc<uv_pypi_types::MetadataError>),
/// The wheel metadata was found, but the metadata was inconsistent.
InconsistentMetadata(Arc<uv_distribution::Error>),
/// The wheel has an invalid structure.
InvalidStructure(Arc<uv_metadata::Error>),
/// The source distribution has a `requires-python` requirement that is not met by the installed
/// Python version (and static metadata is not available).
RequiresPython(VersionSpecifiers, Version),
/// The distribution could not be built or downloaded.
Error(Box<Dist>, Arc<uv_distribution::Error>),
}
impl MetadataUnavailable {
/// Like [`std::error::Error::source`], but we don't want to derive the std error since our
/// formatting system is more custom.
pub(crate) fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
MetadataUnavailable::Offline => None,
MetadataUnavailable::InvalidMetadata(err) => Some(err),
MetadataUnavailable::InconsistentMetadata(err) => Some(err),
MetadataUnavailable::InvalidStructure(err) => Some(err),
MetadataUnavailable::RequiresPython(_, _) => None,
}
}
}
pub trait ResolverProvider {
@ -189,29 +211,39 @@ impl<'a, Context: BuildContext> ResolverProvider for DefaultResolverProvider<'a,
Ok(metadata) => Ok(MetadataResponse::Found(metadata)),
Err(err) => match err {
uv_distribution::Error::Client(client) => match client.into_kind() {
uv_client::ErrorKind::Offline(_) => Ok(MetadataResponse::Offline),
uv_client::ErrorKind::Offline(_) => {
Ok(MetadataResponse::Unavailable(MetadataUnavailable::Offline))
}
uv_client::ErrorKind::MetadataParseError(_, _, err) => {
Ok(MetadataResponse::InvalidMetadata(err))
}
uv_client::ErrorKind::Metadata(_, err) => {
Ok(MetadataResponse::InvalidStructure(Box::new(err)))
Ok(MetadataResponse::Unavailable(
MetadataUnavailable::InvalidMetadata(Arc::new(*err)),
))
}
uv_client::ErrorKind::Metadata(_, err) => Ok(MetadataResponse::Unavailable(
MetadataUnavailable::InvalidStructure(Arc::new(err)),
)),
kind => Err(uv_client::Error::from(kind).into()),
},
uv_distribution::Error::WheelMetadataVersionMismatch { .. } => {
Ok(MetadataResponse::InconsistentMetadata(Box::new(err)))
Ok(MetadataResponse::Unavailable(
MetadataUnavailable::InconsistentMetadata(Arc::new(err)),
))
}
uv_distribution::Error::WheelMetadataNameMismatch { .. } => {
Ok(MetadataResponse::InconsistentMetadata(Box::new(err)))
}
uv_distribution::Error::Metadata(err) => {
Ok(MetadataResponse::InvalidMetadata(Box::new(err)))
}
uv_distribution::Error::WheelMetadata(_, err) => {
Ok(MetadataResponse::InvalidStructure(err))
Ok(MetadataResponse::Unavailable(
MetadataUnavailable::InconsistentMetadata(Arc::new(err)),
))
}
uv_distribution::Error::Metadata(err) => Ok(MetadataResponse::Unavailable(
MetadataUnavailable::InvalidMetadata(Arc::new(err)),
)),
uv_distribution::Error::WheelMetadata(_, err) => Ok(MetadataResponse::Unavailable(
MetadataUnavailable::InvalidStructure(Arc::new(*err)),
)),
uv_distribution::Error::RequiresPython(requires_python, version) => {
Ok(MetadataResponse::RequiresPython(requires_python, version))
Ok(MetadataResponse::Unavailable(
MetadataUnavailable::RequiresPython(requires_python, version),
))
}
err => Ok(MetadataResponse::Error(
Box::new(dist.clone()),