mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-04 10:58:28 +00:00
Improve error messaging when a dependency is not found (#1241)
Previously, whenever we encountered a missing package we would throw an error without information about why the package was requested. This meant that if a transitive dependency required a missing package, the user would have no idea why it was even selected. Here, we track `NotFound` and `NoIndex` errors as `NoVersions` incompatibilities with an attached reason. Improves our test coverage for `--no-index` without `--find-links`. The [snapshots](https://github.com/astral-sh/puffin/pull/1241/files#diff-3eea1658f165476252f1f061d0aa9f915aabdceafac21611cdf45019447f60ec) show a nice improvement. I think this will also enable backtracking to another version if some version of transitive dependency has a missing dependency. I'll write a scenario for that next. Requires https://github.com/zanieb/pubgrub/pull/22
This commit is contained in:
parent
be9125b0f0
commit
d090acf13d
13 changed files with 351 additions and 74 deletions
|
@ -17,7 +17,7 @@ use puffin_normalize::PackageName;
|
|||
use crate::candidate_selector::CandidateSelector;
|
||||
use crate::pubgrub::{PubGrubPackage, PubGrubPython, PubGrubReportFormatter};
|
||||
use crate::python_requirement::PythonRequirement;
|
||||
use crate::version_map::VersionMap;
|
||||
use crate::resolver::VersionsResponse;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum ResolveError {
|
||||
|
@ -168,7 +168,7 @@ impl NoSolutionError {
|
|||
mut self,
|
||||
python_requirement: &PythonRequirement,
|
||||
visited: &DashSet<PackageName>,
|
||||
package_versions: &OnceMap<PackageName, VersionMap>,
|
||||
package_versions: &OnceMap<PackageName, VersionsResponse>,
|
||||
) -> Self {
|
||||
let mut available_versions = IndexMap::default();
|
||||
for package in self.derivation_tree.packages() {
|
||||
|
@ -192,14 +192,16 @@ impl NoSolutionError {
|
|||
// these packages, but it's non-deterministic, and omitting them ensures that
|
||||
// we represent the state of the resolver at the time of failure.
|
||||
if visited.contains(name) {
|
||||
if let Some(version_map) = package_versions.get(name) {
|
||||
available_versions.insert(
|
||||
package.clone(),
|
||||
version_map
|
||||
.iter()
|
||||
.map(|(version, _)| version.clone())
|
||||
.collect(),
|
||||
);
|
||||
if let Some(response) = package_versions.get(name) {
|
||||
if let VersionsResponse::Found(ref version_map) = *response {
|
||||
available_versions.insert(
|
||||
package.clone(),
|
||||
version_map
|
||||
.iter()
|
||||
.map(|(version, _)| version.clone())
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ impl ReportFormatter<PubGrubPackage, Range<Version>> for PubGrubReportFormatter<
|
|||
External::NotRoot(package, version) => {
|
||||
format!("we are solving dependencies of {package} {version}")
|
||||
}
|
||||
External::NoVersions(package, set) => {
|
||||
External::NoVersions(package, set, reason) => {
|
||||
if matches!(package, PubGrubPackage::Python(_)) {
|
||||
if let Some(python) = self.python_requirement {
|
||||
if python.target() == python.installed() {
|
||||
|
@ -75,6 +75,17 @@ impl ReportFormatter<PubGrubPackage, Range<Version>> for PubGrubReportFormatter<
|
|||
);
|
||||
}
|
||||
let set = self.simplify_set(set, package);
|
||||
|
||||
// Check for a reason
|
||||
if let Some(reason) = reason {
|
||||
let formatted = if set.as_ref() == &Range::full() {
|
||||
format!("{package} {reason}")
|
||||
} else {
|
||||
format!("{package}{set} {reason}")
|
||||
};
|
||||
return formatted;
|
||||
}
|
||||
|
||||
if set.as_ref() == &Range::full() {
|
||||
format!("there are no versions of {package}")
|
||||
} else if set.as_singleton().is_some() {
|
||||
|
@ -353,7 +364,7 @@ impl PubGrubReportFormatter<'_> {
|
|||
let mut hints = IndexSet::default();
|
||||
match derivation_tree {
|
||||
DerivationTree::External(external) => match external {
|
||||
External::NoVersions(package, set) => {
|
||||
External::NoVersions(package, set, _) => {
|
||||
if set.bounds().any(Version::any_prerelease) {
|
||||
// A pre-release marker appeared in the version requirements.
|
||||
if !allowed_prerelease(package, selector) {
|
||||
|
|
|
@ -8,6 +8,7 @@ use petgraph::Direction;
|
|||
use pubgrub::range::Range;
|
||||
use pubgrub::solver::{Kind, State};
|
||||
use pubgrub::type_aliases::SelectedDependencies;
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
use url::Url;
|
||||
|
||||
|
@ -20,7 +21,8 @@ use pypi_types::{Hashes, Metadata21};
|
|||
|
||||
use crate::pins::FilePins;
|
||||
use crate::pubgrub::{PubGrubDistribution, PubGrubPackage, PubGrubPriority};
|
||||
use crate::version_map::VersionMap;
|
||||
use crate::resolver::VersionsResponse;
|
||||
|
||||
use crate::ResolveError;
|
||||
|
||||
/// A complete resolution graph in which every node represents a pinned package and every edge
|
||||
|
@ -42,7 +44,7 @@ impl ResolutionGraph {
|
|||
pub(crate) fn from_state(
|
||||
selection: &SelectedDependencies<PubGrubPackage, Version>,
|
||||
pins: &FilePins,
|
||||
packages: &OnceMap<PackageName, VersionMap>,
|
||||
packages: &OnceMap<PackageName, VersionsResponse>,
|
||||
distributions: &OnceMap<PackageId, Metadata21>,
|
||||
redirects: &DashMap<Url, Url>,
|
||||
state: &State<PubGrubPackage, Range<Version>, PubGrubPriority>,
|
||||
|
@ -68,12 +70,14 @@ impl ResolutionGraph {
|
|||
.clone();
|
||||
|
||||
// Add its hashes to the index.
|
||||
if let Some(version_map) = packages.get(package_name) {
|
||||
hashes.insert(package_name.clone(), {
|
||||
let mut hashes = version_map.hashes(version);
|
||||
hashes.sort_unstable();
|
||||
hashes
|
||||
});
|
||||
if let Some(versions_response) = packages.get(package_name) {
|
||||
if let VersionsResponse::Found(ref version_map) = *versions_response {
|
||||
hashes.insert(package_name.clone(), {
|
||||
let mut hashes = version_map.hashes(version);
|
||||
hashes.sort_unstable();
|
||||
hashes
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Add the distribution to the graph.
|
||||
|
@ -93,12 +97,14 @@ impl ResolutionGraph {
|
|||
};
|
||||
|
||||
// Add its hashes to the index.
|
||||
if let Some(version_map) = packages.get(package_name) {
|
||||
hashes.insert(package_name.clone(), {
|
||||
let mut hashes = version_map.hashes(version);
|
||||
hashes.sort_unstable();
|
||||
hashes
|
||||
});
|
||||
if let Some(versions_response) = packages.get(package_name) {
|
||||
if let VersionsResponse::Found(ref version_map) = *versions_response {
|
||||
hashes.insert(package_name.clone(), {
|
||||
let mut hashes = version_map.hashes(version);
|
||||
hashes.sort_unstable();
|
||||
hashes
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Add the distribution to the graph.
|
||||
|
|
|
@ -6,14 +6,14 @@ use once_map::OnceMap;
|
|||
use puffin_normalize::PackageName;
|
||||
use pypi_types::Metadata21;
|
||||
|
||||
use crate::version_map::VersionMap;
|
||||
use super::provider::VersionsResponse;
|
||||
|
||||
/// In-memory index of package metadata.
|
||||
#[derive(Default)]
|
||||
pub struct InMemoryIndex {
|
||||
/// A map from package name to the metadata for that package and the index where the metadata
|
||||
/// came from.
|
||||
pub(crate) packages: OnceMap<PackageName, VersionMap>,
|
||||
pub(crate) packages: OnceMap<PackageName, VersionsResponse>,
|
||||
|
||||
/// A map from package ID to metadata for that distribution.
|
||||
pub(crate) distributions: OnceMap<PackageId, Metadata21>,
|
||||
|
|
|
@ -47,9 +47,9 @@ use crate::resolver::allowed_urls::AllowedUrls;
|
|||
pub use crate::resolver::index::InMemoryIndex;
|
||||
use crate::resolver::provider::DefaultResolverProvider;
|
||||
pub use crate::resolver::provider::ResolverProvider;
|
||||
pub(crate) use crate::resolver::provider::VersionsResponse;
|
||||
use crate::resolver::reporter::Facade;
|
||||
pub use crate::resolver::reporter::{BuildId, Reporter};
|
||||
use crate::version_map::VersionMap;
|
||||
use crate::{DependencyMode, Options};
|
||||
|
||||
mod allowed_urls;
|
||||
|
@ -57,6 +57,23 @@ mod index;
|
|||
mod provider;
|
||||
mod reporter;
|
||||
|
||||
/// The package version is unavailable and cannot be used
|
||||
/// Unlike [`PackageUnavailable`] this applies to a single version of the package
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum UnavailableVersion {
|
||||
/// Version is incompatible due to the `Requires-Python` version specifiers for that package.
|
||||
RequiresPython(VersionSpecifiers),
|
||||
}
|
||||
|
||||
/// The package is unavailable and cannot be used
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum UnavailablePackage {
|
||||
/// The `--no-index` flag was passed and the package is not available locally
|
||||
NoIndex,
|
||||
/// The package was not found in the registry
|
||||
NotFound,
|
||||
}
|
||||
|
||||
pub struct Resolver<'a, Provider: ResolverProvider> {
|
||||
project: Option<PackageName>,
|
||||
requirements: Vec<Requirement>,
|
||||
|
@ -68,8 +85,10 @@ pub struct Resolver<'a, Provider: ResolverProvider> {
|
|||
python_requirement: PythonRequirement,
|
||||
selector: CandidateSelector,
|
||||
index: &'a InMemoryIndex,
|
||||
/// A map from [`PackageId`] to the `Requires-Python` version specifiers for that package.
|
||||
incompatibilities: DashMap<PackageId, VersionSpecifiers>,
|
||||
/// Incompatibilities for specific package versions
|
||||
unavailable_versions: DashMap<PackageId, UnavailableVersion>,
|
||||
/// Incompatibilities for packages that are entirely unavailable
|
||||
unavailable_packages: DashMap<PackageName, UnavailablePackage>,
|
||||
/// The set of all registry-based packages visited during resolution.
|
||||
visited: DashSet<PackageName>,
|
||||
editables: FxHashMap<PackageName, (LocalEditable, Metadata21)>,
|
||||
|
@ -170,7 +189,8 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
|
|||
|
||||
Self {
|
||||
index,
|
||||
incompatibilities: DashMap::default(),
|
||||
unavailable_versions: DashMap::default(),
|
||||
unavailable_packages: DashMap::default(),
|
||||
visited: DashSet::default(),
|
||||
selector,
|
||||
allowed_urls,
|
||||
|
@ -314,7 +334,30 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
|
|||
.term_intersection_for_package(&next)
|
||||
.expect("a package was chosen but we don't have a term.");
|
||||
|
||||
let inc = Incompatibility::no_versions(next.clone(), term_intersection.clone());
|
||||
let reason = {
|
||||
if let PubGrubPackage::Package(ref package_name, _, _) = next {
|
||||
// Check if the decision was due to the package being unavailable
|
||||
self.unavailable_packages
|
||||
.get(package_name)
|
||||
.map(|entry| match *entry {
|
||||
UnavailablePackage::NoIndex => {
|
||||
"was not found in the provided links"
|
||||
}
|
||||
UnavailablePackage::NotFound => {
|
||||
"was not found in the package registry"
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let inc = Incompatibility::no_versions(
|
||||
next.clone(),
|
||||
term_intersection.clone(),
|
||||
reason.map(ToString::to_string),
|
||||
);
|
||||
|
||||
state.add_incompatibility(inc);
|
||||
continue;
|
||||
}
|
||||
|
@ -510,7 +553,7 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
|
|||
|
||||
PubGrubPackage::Package(package_name, extra, None) => {
|
||||
// Wait for the metadata to be available.
|
||||
let version_map = self
|
||||
let versions_response = self
|
||||
.index
|
||||
.packages
|
||||
.wait(package_name)
|
||||
|
@ -519,6 +562,23 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
|
|||
.ok_or(ResolveError::Unregistered)?;
|
||||
self.visited.insert(package_name.clone());
|
||||
|
||||
let version_map = match *versions_response {
|
||||
VersionsResponse::Found(ref version_map) => version_map,
|
||||
// Short-circuit if we do not find any versions for the package
|
||||
VersionsResponse::NoIndex => {
|
||||
self.unavailable_packages
|
||||
.insert(package_name.clone(), UnavailablePackage::NoIndex);
|
||||
|
||||
return Ok(None);
|
||||
}
|
||||
VersionsResponse::NotFound => {
|
||||
self.unavailable_packages
|
||||
.insert(package_name.clone(), UnavailablePackage::NotFound);
|
||||
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(extra) = extra {
|
||||
debug!(
|
||||
"Searching for a compatible version of {package_name}[{extra}] ({range})",
|
||||
|
@ -528,16 +588,17 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
|
|||
}
|
||||
|
||||
// Find a compatible version.
|
||||
let Some(candidate) = self.selector.select(package_name, range, &version_map)
|
||||
else {
|
||||
let Some(candidate) = self.selector.select(package_name, range, version_map) else {
|
||||
// Short circuit: we couldn't find _any_ compatible versions for a package.
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
// If the version is incompatible, short-circuit.
|
||||
if let Some(requires_python) = candidate.validate(&self.python_requirement) {
|
||||
self.incompatibilities
|
||||
.insert(candidate.package_id(), requires_python.clone());
|
||||
self.unavailable_versions.insert(
|
||||
candidate.package_id(),
|
||||
UnavailableVersion::RequiresPython(requires_python.clone()),
|
||||
);
|
||||
return Ok(Some(candidate.version().clone()));
|
||||
}
|
||||
|
||||
|
@ -655,17 +716,29 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
|
|||
return Ok(Dependencies::Available(DependencyConstraints::default()));
|
||||
}
|
||||
|
||||
// Wait for the metadata to be available.
|
||||
// Determine the distribution to lookup
|
||||
let dist = match url {
|
||||
Some(url) => PubGrubDistribution::from_url(package_name, url),
|
||||
None => PubGrubDistribution::from_registry(package_name, version),
|
||||
};
|
||||
let package_id = dist.package_id();
|
||||
|
||||
// If the package does not exist in the registry, we cannot fetch its dependencies
|
||||
if self.unavailable_packages.get(package_name).is_some() {
|
||||
debug_assert!(
|
||||
false,
|
||||
"Dependencies were requested for a package that is not available"
|
||||
);
|
||||
return Ok(Dependencies::Unavailable(
|
||||
"The package is unavailable".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
// If the package is known to be incompatible, return the Python version as an
|
||||
// incompatibility, and skip fetching the metadata.
|
||||
if let Some(entry) = self.incompatibilities.get(&package_id) {
|
||||
let requires_python = entry;
|
||||
if let Some(entry) = self.unavailable_versions.get(&package_id) {
|
||||
// TODO(zanieb): Handle additional variants here
|
||||
let UnavailableVersion::RequiresPython(requires_python) = entry.value();
|
||||
let version = requires_python
|
||||
.iter()
|
||||
.map(PubGrubSpecifier::try_from)
|
||||
|
@ -682,6 +755,7 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
|
|||
return Ok(Dependencies::Available(constraints));
|
||||
}
|
||||
|
||||
// Wait for the metadata to be available.
|
||||
let metadata = self
|
||||
.index
|
||||
.distributions
|
||||
|
@ -779,13 +853,14 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
|
|||
match request {
|
||||
// Fetch package metadata from the registry.
|
||||
Request::Package(package_name) => {
|
||||
let version_map = self
|
||||
let package_versions = self
|
||||
.provider
|
||||
.get_version_map(&package_name)
|
||||
.get_package_versions(&package_name)
|
||||
.boxed()
|
||||
.await
|
||||
.map_err(ResolveError::Client)?;
|
||||
Ok(Some(Response::Package(package_name, version_map)))
|
||||
|
||||
Ok(Some(Response::Package(package_name, package_versions)))
|
||||
}
|
||||
|
||||
// Fetch distribution metadata from the distribution database.
|
||||
|
@ -817,24 +892,43 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
|
|||
// Pre-fetch the package and distribution metadata.
|
||||
Request::Prefetch(package_name, range) => {
|
||||
// Wait for the package metadata to become available.
|
||||
let version_map = self
|
||||
let versions_response = self
|
||||
.index
|
||||
.packages
|
||||
.wait(&package_name)
|
||||
.await
|
||||
.ok_or(ResolveError::Unregistered)?;
|
||||
|
||||
let version_map = match *versions_response {
|
||||
VersionsResponse::Found(ref version_map) => version_map,
|
||||
// Short-circuit if we did not find any versions for the package
|
||||
VersionsResponse::NoIndex => {
|
||||
self.unavailable_packages
|
||||
.insert(package_name.clone(), UnavailablePackage::NoIndex);
|
||||
|
||||
return Ok(None);
|
||||
}
|
||||
VersionsResponse::NotFound => {
|
||||
self.unavailable_packages
|
||||
.insert(package_name.clone(), UnavailablePackage::NotFound);
|
||||
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
|
||||
// Try to find a compatible version. If there aren't any compatible versions,
|
||||
// short-circuit and return `None`.
|
||||
let Some(candidate) = self.selector.select(&package_name, &range, &version_map)
|
||||
let Some(candidate) = self.selector.select(&package_name, &range, version_map)
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
// If the version is incompatible, short-circuit.
|
||||
if let Some(requires_python) = candidate.validate(&self.python_requirement) {
|
||||
self.incompatibilities
|
||||
.insert(candidate.package_id(), requires_python.clone());
|
||||
self.unavailable_versions.insert(
|
||||
candidate.package_id(),
|
||||
UnavailableVersion::RequiresPython(requires_python.clone()),
|
||||
);
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
|
@ -928,7 +1022,7 @@ impl Display for Request {
|
|||
#[allow(clippy::large_enum_variant)]
|
||||
enum Response {
|
||||
/// The returned metadata for a package hosted on a registry.
|
||||
Package(PackageName, VersionMap),
|
||||
Package(PackageName, VersionsResponse),
|
||||
/// The returned metadata for a distribution.
|
||||
Dist {
|
||||
dist: Dist,
|
||||
|
|
|
@ -18,15 +18,26 @@ use crate::python_requirement::PythonRequirement;
|
|||
use crate::version_map::VersionMap;
|
||||
use crate::yanks::AllowedYanks;
|
||||
|
||||
type VersionMapResponse = Result<VersionMap, puffin_client::Error>;
|
||||
type WheelMetadataResponse = Result<(Metadata21, Option<Url>), puffin_distribution::Error>;
|
||||
type PackageVersionsResult = Result<VersionsResponse, puffin_client::Error>;
|
||||
type WheelMetadataResult = Result<(Metadata21, Option<Url>), puffin_distribution::Error>;
|
||||
|
||||
/// The response when requesting versions for a package
|
||||
#[derive(Debug)]
|
||||
pub enum VersionsResponse {
|
||||
/// The package was found in the registry with the included versions
|
||||
Found(VersionMap),
|
||||
/// The package was not found in the registry
|
||||
NotFound,
|
||||
/// The package was not found in the local registry
|
||||
NoIndex,
|
||||
}
|
||||
|
||||
pub trait ResolverProvider: Send + Sync {
|
||||
/// Get the version map for a package.
|
||||
fn get_version_map<'io>(
|
||||
fn get_package_versions<'io>(
|
||||
&'io self,
|
||||
package_name: &'io PackageName,
|
||||
) -> impl Future<Output = VersionMapResponse> + Send + 'io;
|
||||
) -> impl Future<Output = PackageVersionsResult> + Send + 'io;
|
||||
|
||||
/// Get the metadata for a distribution.
|
||||
///
|
||||
|
@ -36,7 +47,7 @@ pub trait ResolverProvider: Send + Sync {
|
|||
fn get_or_build_wheel_metadata<'io>(
|
||||
&'io self,
|
||||
dist: &'io Dist,
|
||||
) -> impl Future<Output = WheelMetadataResponse> + Send + 'io;
|
||||
) -> impl Future<Output = WheelMetadataResult> + Send + 'io;
|
||||
|
||||
/// Set the [`puffin_distribution::Reporter`] to use for this installer.
|
||||
#[must_use]
|
||||
|
@ -104,7 +115,10 @@ impl<'a, Context: BuildContext + Send + Sync> ResolverProvider
|
|||
for DefaultResolverProvider<'a, Context>
|
||||
{
|
||||
/// Make a simple api request for the package and convert the result to a [`VersionMap`].
|
||||
async fn get_version_map<'io>(&'io self, package_name: &'io PackageName) -> VersionMapResponse {
|
||||
async fn get_package_versions<'io>(
|
||||
&'io self,
|
||||
package_name: &'io PackageName,
|
||||
) -> PackageVersionsResult {
|
||||
let result = self.client.simple(package_name).await;
|
||||
|
||||
// If the simple api request was successful, perform on the slow conversion to `VersionMap` on the tokio
|
||||
|
@ -114,7 +128,7 @@ impl<'a, Context: BuildContext + Send + Sync> ResolverProvider
|
|||
let self_send = self.inner.clone();
|
||||
let package_name_owned = package_name.clone();
|
||||
Ok(tokio::task::spawn_blocking(move || {
|
||||
VersionMap::from_metadata(
|
||||
VersionsResponse::Found(VersionMap::from_metadata(
|
||||
metadata,
|
||||
&package_name_owned,
|
||||
&index,
|
||||
|
@ -124,18 +138,24 @@ impl<'a, Context: BuildContext + Send + Sync> ResolverProvider
|
|||
self_send.exclude_newer.as_ref(),
|
||||
self_send.flat_index.get(&package_name_owned).cloned(),
|
||||
&self_send.no_binary,
|
||||
)
|
||||
))
|
||||
})
|
||||
.await
|
||||
.expect("Tokio executor failed, was there a panic?"))
|
||||
}
|
||||
Err(err) => match err.into_kind() {
|
||||
kind @ (puffin_client::ErrorKind::PackageNotFound(_)
|
||||
| puffin_client::ErrorKind::NoIndex(_)) => {
|
||||
puffin_client::ErrorKind::PackageNotFound(_) => {
|
||||
if let Some(flat_index) = self.flat_index.get(package_name).cloned() {
|
||||
Ok(VersionMap::from(flat_index))
|
||||
Ok(VersionsResponse::Found(VersionMap::from(flat_index)))
|
||||
} else {
|
||||
Err(kind.into())
|
||||
Ok(VersionsResponse::NotFound)
|
||||
}
|
||||
}
|
||||
puffin_client::ErrorKind::NoIndex(_) => {
|
||||
if let Some(flat_index) = self.flat_index.get(package_name).cloned() {
|
||||
Ok(VersionsResponse::Found(VersionMap::from(flat_index)))
|
||||
} else {
|
||||
Ok(VersionsResponse::NoIndex)
|
||||
}
|
||||
}
|
||||
kind => Err(kind.into()),
|
||||
|
@ -143,7 +163,7 @@ impl<'a, Context: BuildContext + Send + Sync> ResolverProvider
|
|||
}
|
||||
}
|
||||
|
||||
async fn get_or_build_wheel_metadata<'io>(&'io self, dist: &'io Dist) -> WheelMetadataResponse {
|
||||
async fn get_or_build_wheel_metadata<'io>(&'io self, dist: &'io Dist) -> WheelMetadataResult {
|
||||
self.fetcher.get_or_build_wheel_metadata(dist).await
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue