Pass around index with associated metadata (#12406)

## Summary

This PR modifies the requirement source entities to store a (new)
container struct that wraps `IndexUrl`. This will allow us to store
user-defined metadata alongside `IndexUrl`, and propagate that metadata
throughout resolution.

Specifically, I need to store the "kind" of the index (Simple API vs.
`--find-links`), but I also ran into this problem when I tried to add
support for overriding `Cache-Control` headers on a per-index basis: at
present, we have no way to passing around metadata alongside an
`IndexUrl`.
This commit is contained in:
Charlie Marsh 2025-03-24 10:15:49 -04:00 committed by GitHub
parent c3442e822e
commit 1865e0a6ee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 213 additions and 80 deletions

View File

@ -3,7 +3,17 @@ use url::Url;
/// When to use authentication.
#[derive(
Copy, Clone, Debug, Default, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize,
Copy,
Clone,
Debug,
Default,
Hash,
Eq,
PartialEq,
Ord,
PartialOrd,
serde::Serialize,
serde::Deserialize,
)]
#[serde(rename_all = "kebab-case")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]

View File

@ -13,14 +13,14 @@ use reqwest_middleware::ClientWithMiddleware;
use tokio::sync::Semaphore;
use tracing::{info_span, instrument, trace, warn, Instrument};
use url::Url;
use uv_auth::UrlAuthPolicies;
use uv_auth::UrlAuthPolicies;
use uv_cache::{Cache, CacheBucket, CacheEntry, WheelCache};
use uv_configuration::KeyringProviderType;
use uv_configuration::{IndexStrategy, TrustedHost};
use uv_distribution_filename::{DistFilename, SourceDistFilename, WheelFilename};
use uv_distribution_types::{
BuiltDist, File, FileLocation, Index, IndexCapabilities, IndexUrl, IndexUrls, Name,
BuiltDist, File, FileLocation, IndexCapabilities, IndexMetadataRef, IndexUrl, IndexUrls, Name,
};
use uv_metadata::{read_metadata_async_seek, read_metadata_async_stream};
use uv_normalize::PackageName;
@ -255,16 +255,17 @@ impl RegistryClient {
}
/// Return the appropriate index URLs for the given [`PackageName`].
fn index_urls_for(&self, package_name: &PackageName) -> impl Iterator<Item = &IndexUrl> {
fn index_urls_for(&self, package_name: &PackageName) -> impl Iterator<Item = IndexMetadataRef> {
self.torch_backend
.as_ref()
.and_then(|torch_backend| {
torch_backend
.applies_to(package_name)
.then(|| torch_backend.index_urls())
.map(|indexes| indexes.map(IndexMetadataRef::from))
})
.map(Either::Left)
.unwrap_or_else(|| Either::Right(self.index_urls.indexes().map(Index::url)))
.unwrap_or_else(|| Either::Right(self.index_urls.indexes().map(IndexMetadataRef::from)))
}
/// Return the appropriate [`IndexStrategy`] for the given [`PackageName`].
@ -288,10 +289,10 @@ impl RegistryClient {
pub async fn simple<'index>(
&'index self,
package_name: &PackageName,
index: Option<&'index IndexUrl>,
index: Option<IndexMetadataRef<'index>>,
capabilities: &IndexCapabilities,
download_concurrency: &Semaphore,
) -> Result<Vec<(&'index IndexUrl, OwnedArchive<SimpleMetadata>)>, Error> {
) -> Result<Vec<(IndexMetadataRef<'index>, OwnedArchive<SimpleMetadata>)>, Error> {
// If `--no-index` is specified, avoid fetching regardless of whether the index is implicit,
// explicit, etc.
if self.index_urls.no_index() {
@ -312,7 +313,7 @@ impl RegistryClient {
for index in indexes {
let _permit = download_concurrency.acquire().await;
if let Some(metadata) = self
.simple_single_index(package_name, index, capabilities)
.simple_single_index(package_name, index.url(), capabilities)
.await?
{
results.push((index, metadata));
@ -327,7 +328,7 @@ impl RegistryClient {
.map(|index| async move {
let _permit = download_concurrency.acquire().await;
let metadata = self
.simple_single_index(package_name, index, capabilities)
.simple_single_index(package_name, index.url(), capabilities)
.await?;
Ok((index, metadata))
})
@ -369,9 +370,9 @@ impl RegistryClient {
capabilities: &IndexCapabilities,
) -> Result<Option<OwnedArchive<SimpleMetadata>>, Error> {
// Format the URL for PyPI.
let mut url: Url = index.clone().into();
let mut url = index.url().clone();
url.path_segments_mut()
.map_err(|()| ErrorKind::CannotBeABase(index.clone().into()))?
.map_err(|()| ErrorKind::CannotBeABase(index.url().clone()))?
.pop_if_empty()
.push(package_name.as_ref())
// The URL *must* end in a trailing slash for proper relative path behavior

View File

@ -10,7 +10,9 @@ use crate::index_name::{IndexName, IndexNameError};
use crate::origin::Origin;
use crate::{IndexUrl, IndexUrlError};
#[derive(Debug, Clone, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
#[derive(
Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, serde::Serialize, serde::Deserialize,
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(rename_all = "kebab-case")]
pub struct Index {
@ -200,6 +202,20 @@ impl Index {
}
}
impl From<IndexUrl> for Index {
fn from(value: IndexUrl) -> Self {
Self {
name: None,
url: value,
explicit: false,
default: false,
origin: None,
publish_url: None,
authenticate: AuthPolicy::default(),
}
}
}
impl FromStr for Index {
type Err = IndexSourceError;
@ -235,6 +251,76 @@ impl FromStr for Index {
}
}
/// An [`IndexUrl`] along with the metadata necessary to query the index.
#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct IndexMetadata {
pub url: IndexUrl,
// /// The type of the index.
// ///
// /// Indexes can either be PEP 503-compliant (i.e., a registry implementing the Simple API) or
// /// structured as a flat list of distributions (e.g., `--find-links`). In both cases, indexes
// /// can point to either local or remote resources.
// #[serde(default)]
// pub r#type: IndexKind,
}
impl IndexMetadata {
/// Return a reference to the [`IndexMetadata`].
pub fn as_ref(&self) -> IndexMetadataRef<'_> {
let Self { url } = self;
IndexMetadataRef { url }
}
/// Consume the [`IndexMetadata`] and return the [`IndexUrl`].
pub fn into_url(self) -> IndexUrl {
self.url
}
}
/// A reference to an [`IndexMetadata`].
#[derive(Debug, Copy, Clone)]
pub struct IndexMetadataRef<'a> {
pub url: &'a IndexUrl,
}
impl IndexMetadata {
/// Return the [`IndexUrl`] of the index.
pub fn url(&self) -> &IndexUrl {
&self.url
}
}
impl IndexMetadataRef<'_> {
/// Return the [`IndexUrl`] of the index.
pub fn url(&self) -> &IndexUrl {
self.url
}
}
impl<'a> From<&'a IndexMetadata> for IndexMetadataRef<'a> {
fn from(value: &'a IndexMetadata) -> Self {
Self { url: &value.url }
}
}
impl<'a> From<&'a IndexUrl> for IndexMetadataRef<'a> {
fn from(value: &'a IndexUrl) -> Self {
Self { url: value }
}
}
impl<'a> From<&'a Index> for IndexMetadataRef<'a> {
fn from(value: &'a Index) -> Self {
Self { url: &value.url }
}
}
impl From<IndexUrl> for IndexMetadata {
fn from(value: IndexUrl) -> Self {
Self { url: value }
}
}
/// An error that can occur when parsing an [`Index`].
#[derive(Error, Debug)]
pub enum IndexSourceError {

View File

@ -9,7 +9,7 @@ use uv_small_str::SmallString;
/// The normalized name of an index.
///
/// Index names may contain letters, digits, hyphens, underscores, and periods, and must be ASCII.
#[derive(Debug, Clone, Hash, Eq, PartialEq, serde::Serialize)]
#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, serde::Serialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct IndexName(SmallString);

View File

@ -1,5 +1,5 @@
/// The origin of a piece of configuration.
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum Origin {
/// The setting was provided via the CLI.
Cli,

View File

@ -14,6 +14,9 @@ use uv_pep440::VersionSpecifiers;
use uv_pep508::{
marker, MarkerEnvironment, MarkerTree, RequirementOrigin, VerbatimUrl, VersionOrUrl,
};
use crate::{IndexMetadata, IndexUrl};
use uv_pypi_types::{
ConflictItem, Hashes, ParsedArchiveUrl, ParsedDirectoryUrl, ParsedGitUrl, ParsedPathUrl,
ParsedUrl, ParsedUrlError, VerbatimParsedUrl,
@ -320,7 +323,7 @@ impl Display for Requirement {
} => {
write!(f, "{specifier}")?;
if let Some(index) = index {
write!(f, " (index: {index})")?;
write!(f, " (index: {})", index.url)?;
}
}
RequirementSource::Url { url, .. } => {
@ -368,7 +371,7 @@ pub enum RequirementSource {
Registry {
specifier: VersionSpecifiers,
/// Choose a version from the index at the given URL.
index: Option<Url>,
index: Option<IndexMetadata>,
/// The conflict item associated with the source, if any.
conflict: Option<ConflictItem>,
},
@ -600,7 +603,7 @@ impl Display for RequirementSource {
} => {
write!(f, "{specifier}")?;
if let Some(index) = index {
write!(f, " (index: {index})")?;
write!(f, " (index: {})", index.url)?;
}
}
Self::Url { url, .. } => {
@ -662,12 +665,13 @@ impl From<RequirementSource> for RequirementSourceWire {
match value {
RequirementSource::Registry {
specifier,
mut index,
index,
conflict,
} => {
if let Some(index) = index.as_mut() {
redact_credentials(index);
}
let index = index.map(|index| index.url.into_url()).map(|mut index| {
redact_credentials(&mut index);
index
});
Self::Registry {
specifier,
index,
@ -775,7 +779,8 @@ impl TryFrom<RequirementSourceWire> for RequirementSource {
conflict,
} => Ok(Self::Registry {
specifier,
index,
index: index
.map(|index| IndexMetadata::from(IndexUrl::from(VerbatimUrl::from_url(index)))),
conflict,
}),
RequirementSourceWire::Git { git } => {

View File

@ -3,7 +3,9 @@ use uv_normalize::{ExtraName, GroupName, PackageName};
use uv_pep508::MarkerTree;
use uv_pypi_types::{HashDigest, HashDigests};
use crate::{BuiltDist, Diagnostic, Dist, Name, RequirementSource, ResolvedDist, SourceDist};
use crate::{
BuiltDist, Diagnostic, Dist, IndexMetadata, Name, RequirementSource, ResolvedDist, SourceDist,
};
/// A set of packages pinned at specific versions.
///
@ -229,7 +231,7 @@ impl From<&ResolvedDist> for RequirementSource {
wheel.filename.version.clone(),
),
),
index: Some(wheel.index.url().clone()),
index: Some(IndexMetadata::from(wheel.index.clone())),
conflict: None,
}
}
@ -252,7 +254,7 @@ impl From<&ResolvedDist> for RequirementSource {
specifier: uv_pep440::VersionSpecifiers::from(
uv_pep440::VersionSpecifier::equals_version(sdist.version.clone()),
),
index: Some(sdist.index.url().clone()),
index: Some(IndexMetadata::from(sdist.index.clone())),
conflict: None,
},
Dist::Source(SourceDist::DirectUrl(sdist)) => {

View File

@ -8,7 +8,7 @@ use url::Url;
use uv_distribution_filename::DistExtension;
use uv_distribution_types::{
Index, IndexLocations, IndexName, Origin, Requirement, RequirementSource,
Index, IndexLocations, IndexMetadata, IndexName, Origin, Requirement, RequirementSource,
};
use uv_git_types::{GitReference, GitUrl, GitUrlParseError};
use uv_normalize::{ExtraName, GroupName, PackageName};
@ -222,7 +222,9 @@ impl LoweredRequirement {
.find(|Index { name, .. }| {
name.as_ref().is_some_and(|name| *name == index)
})
.map(|Index { url: index, .. }| index.clone())
.map(|index| IndexMetadata {
url: index.url.clone(),
})
else {
return Err(LoweringError::MissingIndex(
requirement.name.clone(),
@ -238,7 +240,7 @@ impl LoweredRequirement {
})
}
});
let source = registry_source(&requirement, index.into_url(), conflict);
let source = registry_source(&requirement, index, conflict);
(source, marker)
}
Source::Workspace {
@ -445,7 +447,9 @@ impl LoweredRequirement {
.find(|Index { name, .. }| {
name.as_ref().is_some_and(|name| *name == index)
})
.map(|Index { url: index, .. }| index.clone())
.map(|index| IndexMetadata {
url: index.url.clone(),
})
else {
return Err(LoweringError::MissingIndex(
requirement.name.clone(),
@ -453,7 +457,7 @@ impl LoweredRequirement {
));
};
let conflict = None;
let source = registry_source(&requirement, index.into_url(), conflict);
let source = registry_source(&requirement, index, conflict);
(source, marker)
}
Source::Workspace { .. } => {
@ -627,7 +631,7 @@ fn url_source(
/// Convert a registry source into a [`RequirementSource`].
fn registry_source(
requirement: &uv_pep508::Requirement<VerbatimParsedUrl>,
index: Url,
index: IndexMetadata,
conflict: Option<ConflictItem>,
) -> RequirementSource {
match &requirement.version_or_url {

View File

@ -479,7 +479,7 @@ pub async fn check_url(
let response = match registry_client
.simple(
filename.name(),
Some(index_url),
Some(index_url.into()),
index_capabilities,
download_concurrency,
)

View File

@ -1,5 +1,5 @@
use rustc_hash::FxHashMap;
use uv_distribution_types::IndexUrl;
use uv_distribution_types::IndexMetadata;
use uv_normalize::PackageName;
use crate::resolver::ResolverEnvironment;
@ -7,24 +7,24 @@ use crate::ResolveError;
/// See [`crate::resolver::ForkState`].
#[derive(Default, Debug, Clone)]
pub(crate) struct ForkIndexes(FxHashMap<PackageName, IndexUrl>);
pub(crate) struct ForkIndexes(FxHashMap<PackageName, IndexMetadata>);
impl ForkIndexes {
/// Get the [`IndexUrl`] previously used for a package in this fork.
pub(crate) fn get(&self, package_name: &PackageName) -> Option<&IndexUrl> {
/// Get the [`Index`] previously used for a package in this fork.
pub(crate) fn get(&self, package_name: &PackageName) -> Option<&IndexMetadata> {
self.0.get(package_name)
}
/// Check that this is the only [`IndexUrl`] used for this package in this fork.
/// Check that this is the only [`Index`] used for this package in this fork.
pub(crate) fn insert(
&mut self,
package_name: &PackageName,
index: &IndexUrl,
index: &IndexMetadata,
env: &ResolverEnvironment,
) -> Result<(), ResolveError> {
if let Some(previous) = self.0.insert(package_name.clone(), index.clone()) {
if &previous != index {
let mut conflicts = vec![previous.to_string(), index.to_string()];
let mut conflicts = vec![previous.url.to_string(), index.url.to_string()];
conflicts.sort();
return Err(ResolveError::ConflictingIndexesForEnvironment {
package_name: package_name.clone(),

View File

@ -27,9 +27,9 @@ use uv_distribution_filename::{
use uv_distribution_types::{
redact_credentials, BuiltDist, DependencyMetadata, DirectUrlBuiltDist, DirectUrlSourceDist,
DirectorySourceDist, Dist, DistributionMetadata, FileLocation, GitSourceDist, IndexLocations,
IndexUrl, Name, PathBuiltDist, PathSourceDist, RegistryBuiltDist, RegistryBuiltWheel,
RegistrySourceDist, RemoteSource, Requirement, RequirementSource, ResolvedDist, StaticMetadata,
ToUrlError, UrlString,
IndexMetadata, IndexUrl, Name, PathBuiltDist, PathSourceDist, RegistryBuiltDist,
RegistryBuiltWheel, RegistrySourceDist, RemoteSource, Requirement, RequirementSource,
ResolvedDist, StaticMetadata, ToUrlError, UrlString,
};
use uv_fs::{relative_to, PortablePath, PortablePathBuf};
use uv_git::{RepositoryReference, ResolvedRepositoryReference};
@ -4563,12 +4563,17 @@ fn normalize_requirement(
}
RequirementSource::Registry {
specifier,
mut index,
index,
conflict,
} => {
if let Some(index) = index.as_mut() {
redact_credentials(index);
}
// Round-trip the index to remove anything apart from the URL.
let index = index
.map(|index| index.url.into_url())
.map(|mut index| {
redact_credentials(&mut index);
index
})
.map(|index| IndexMetadata::from(IndexUrl::from(VerbatimUrl::from_url(index))));
Ok(Requirement {
name: requirement.name,
extras: requirement.extras,

View File

@ -11,7 +11,7 @@ use rustc_hash::FxHashMap;
use uv_configuration::{IndexStrategy, NoBinary, NoBuild};
use uv_distribution_types::{
IncompatibleDist, IncompatibleSource, IncompatibleWheel, Index, IndexCapabilities,
IndexLocations, IndexUrl,
IndexLocations, IndexMetadata, IndexUrl,
};
use uv_normalize::PackageName;
use uv_pep440::{Version, VersionSpecifiers};
@ -727,7 +727,7 @@ impl PubGrubReportFormatter<'_> {
env: &ResolverEnvironment,
tags: Option<&Tags>,
) -> Option<PubGrubHint> {
let response = if let Some(url) = fork_indexes.get(name) {
let response = if let Some(url) = fork_indexes.get(name).map(IndexMetadata::url) {
index.explicit().get(&(name.clone(), url.clone()))
} else {
index.implicit().get(name)

View File

@ -13,7 +13,9 @@ use crate::resolver::Request;
use crate::{
InMemoryIndex, PythonRequirement, ResolveError, ResolverEnvironment, VersionsResponse,
};
use uv_distribution_types::{CompatibleDist, DistributionMetadata, IndexCapabilities, IndexUrl};
use uv_distribution_types::{
CompatibleDist, DistributionMetadata, IndexCapabilities, IndexMetadata,
};
use uv_normalize::PackageName;
use uv_pep440::Version;
use uv_pep508::MarkerTree;
@ -81,7 +83,7 @@ impl BatchPrefetcher {
pub(crate) fn prefetch_batches(
&mut self,
next: &PubGrubPackage,
index: Option<&IndexUrl>,
index: Option<&IndexMetadata>,
version: &Version,
current_range: &Range<Version>,
unchangeable_constraints: Option<&Term<Range<Version>>>,
@ -110,7 +112,7 @@ impl BatchPrefetcher {
self.prefetch_runner
.index
.explicit()
.wait_blocking(&(name.clone(), index.clone()))
.wait_blocking(&(name.clone(), index.url().clone()))
.ok_or_else(|| ResolveError::UnregisteredTask(name.to_string()))?
} else {
self.prefetch_runner

View File

@ -1,6 +1,5 @@
use uv_distribution_types::{IndexUrl, RequirementSource};
use uv_distribution_types::{IndexMetadata, RequirementSource};
use uv_normalize::PackageName;
use uv_pep508::VerbatimUrl;
use uv_pypi_types::ConflictItem;
use crate::resolver::ForkMap;
@ -24,7 +23,7 @@ pub(crate) struct Indexes(ForkMap<Entry>);
#[derive(Debug, Clone)]
struct Entry {
index: IndexUrl,
index: IndexMetadata,
conflict: Option<ConflictItem>,
}
@ -46,7 +45,9 @@ impl Indexes {
else {
continue;
};
let index = IndexUrl::from(VerbatimUrl::from_url(index.clone()));
let index = IndexMetadata {
url: index.url.clone(),
};
let conflict = conflict.clone();
indexes.add(&requirement, Entry { index, conflict });
}
@ -60,7 +61,7 @@ impl Indexes {
}
/// Return the explicit index used for a package in the given fork.
pub(crate) fn get(&self, name: &PackageName, env: &ResolverEnvironment) -> Vec<&IndexUrl> {
pub(crate) fn get(&self, name: &PackageName, env: &ResolverEnvironment) -> Vec<&IndexMetadata> {
let entries = self.0.get(name, env);
entries
.iter()

View File

@ -25,8 +25,8 @@ use uv_distribution::DistributionDatabase;
use uv_distribution_types::{
BuiltDist, CompatibleDist, DerivationChain, Dist, DistErrorKind, DistributionMetadata,
IncompatibleDist, IncompatibleSource, IncompatibleWheel, IndexCapabilities, IndexLocations,
IndexUrl, InstalledDist, PythonRequirementKind, RemoteSource, Requirement, ResolvedDist,
ResolvedDistRef, SourceDist, VersionOrUrlRef,
IndexMetadata, IndexUrl, InstalledDist, PythonRequirementKind, RemoteSource, Requirement,
ResolvedDist, ResolvedDistRef, SourceDist, VersionOrUrlRef,
};
use uv_git::GitResolver;
use uv_normalize::{ExtraName, GroupName, PackageName};
@ -494,7 +494,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
let decision = self.choose_version(
next_package,
next_id,
index,
index.map(IndexMetadata::url),
term_intersection.unwrap_positive(),
&mut state.pins,
&preferences,
@ -925,7 +925,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
&self,
package: &PubGrubPackage,
url: Option<&VerbatimParsedUrl>,
index: Option<&IndexUrl>,
index: Option<&IndexMetadata>,
request_sink: &Sender<Request>,
) -> Result<(), ResolveError> {
// Ignore unresolved URL packages, i.e., packages that use a direct URL in some forks.
@ -945,7 +945,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
&self,
package: &PubGrubPackage,
url: Option<&VerbatimParsedUrl>,
index: Option<&IndexUrl>,
index: Option<&IndexMetadata>,
request_sink: &Sender<Request>,
) -> Result<(), ResolveError> {
// Only request real packages.
@ -969,7 +969,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
if self
.index
.explicit()
.register((name.clone(), index.clone()))
.register((name.clone(), index.url().clone()))
{
request_sink.blocking_send(Request::Package(name.clone(), Some(index.clone())))?;
}
@ -2249,7 +2249,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
Ok(Some(Response::Package(
package_name,
index,
index.map(IndexMetadata::into_url),
package_versions,
)))
}
@ -2449,7 +2449,9 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
continue;
}
let versions_response = if let Some(index) = fork_indexes.get(name) {
self.index.explicit().get(&(name.clone(), index.clone()))
self.index
.explicit()
.get(&(name.clone(), index.url().clone()))
} else {
self.index.implicit().get(name)
};
@ -3166,7 +3168,7 @@ impl ResolutionDependencyEdge {
#[allow(clippy::large_enum_variant)]
pub(crate) enum Request {
/// A request to fetch the metadata for a package.
Package(PackageName, Option<IndexUrl>),
Package(PackageName, Option<IndexMetadata>),
/// A request to fetch the metadata for a built or source distribution.
Dist(Dist),
/// A request to fetch the metadata from an already-installed distribution.

View File

@ -3,7 +3,9 @@ use std::sync::Arc;
use uv_configuration::BuildOptions;
use uv_distribution::{ArchiveMetadata, DistributionDatabase, Reporter};
use uv_distribution_types::{Dist, IndexCapabilities, IndexUrl, InstalledDist, RequestedDist};
use uv_distribution_types::{
Dist, IndexCapabilities, IndexMetadata, IndexMetadataRef, InstalledDist, RequestedDist,
};
use uv_normalize::PackageName;
use uv_pep440::{Version, VersionSpecifiers};
use uv_platform_tags::Tags;
@ -78,7 +80,7 @@ pub trait ResolverProvider {
fn get_package_versions<'io>(
&'io self,
package_name: &'io PackageName,
index: Option<&'io IndexUrl>,
index: Option<&'io IndexMetadata>,
) -> impl Future<Output = PackageVersionsResult> + 'io;
/// Get the metadata for a distribution.
@ -150,13 +152,18 @@ impl<Context: BuildContext> ResolverProvider for DefaultResolverProvider<'_, Con
async fn get_package_versions<'io>(
&'io self,
package_name: &'io PackageName,
index: Option<&'io IndexUrl>,
index: Option<&'io IndexMetadata>,
) -> PackageVersionsResult {
let result = self
.fetcher
.client()
.manual(|client, semaphore| {
client.simple(package_name, index, self.capabilities, semaphore)
client.simple(
package_name,
index.map(IndexMetadataRef::from),
self.capabilities,
semaphore,
)
})
.await;
@ -171,7 +178,7 @@ impl<Context: BuildContext> ResolverProvider for DefaultResolverProvider<'_, Con
VersionMap::from_metadata(
metadata,
package_name,
index,
index.url(),
self.tags.as_ref(),
&self.requires_python,
&self.allowed_yanks,

View File

@ -2,7 +2,7 @@ use tokio::sync::Semaphore;
use tracing::debug;
use uv_client::{RegistryClient, VersionFiles};
use uv_distribution_filename::DistFilename;
use uv_distribution_types::{IndexCapabilities, IndexUrl};
use uv_distribution_types::{IndexCapabilities, IndexMetadataRef, IndexUrl};
use uv_normalize::PackageName;
use uv_platform_tags::Tags;
use uv_resolver::{ExcludeNewer, PrereleaseMode, RequiresPython};
@ -34,7 +34,12 @@ impl LatestClient<'_> {
let archives = match self
.client
.simple(package, index, self.capabilities, download_concurrency)
.simple(
package,
index.map(IndexMetadataRef::from),
self.capabilities,
download_concurrency,
)
.await
{
Ok(archives) => archives,

View File

@ -1,17 +1,15 @@
use crate::commands::reporters::PublishReporter;
use crate::commands::{human_readable_bytes, ExitStatus};
use crate::printer::Printer;
use crate::settings::NetworkSettings;
use anyhow::{bail, Context, Result};
use console::Term;
use owo_colors::OwoColorize;
use std::fmt::Write;
use std::iter;
use std::sync::Arc;
use std::time::Duration;
use anyhow::{bail, Context, Result};
use console::Term;
use owo_colors::OwoColorize;
use tokio::sync::Semaphore;
use tracing::{debug, info};
use url::Url;
use uv_cache::Cache;
use uv_client::{AuthIntegration, BaseClient, BaseClientBuilder, RegistryClientBuilder};
use uv_configuration::{KeyringProviderType, TrustedPublishing};
@ -21,6 +19,11 @@ use uv_publish::{
};
use uv_warnings::warn_user_once;
use crate::commands::reporters::PublishReporter;
use crate::commands::{human_readable_bytes, ExitStatus};
use crate::printer::Printer;
use crate::settings::NetworkSettings;
pub(crate) async fn publish(
paths: Vec<String>,
publish_url: Url,

View File

@ -15331,7 +15331,7 @@ fn lock_explicit_default_index() -> Result<()> {
DEBUG No workspace root found, using project root
DEBUG Ignoring existing lockfile due to mismatched requirements for: `project==0.1.0`
Requested: {Requirement { name: PackageName("anyio"), extras: [], groups: [], marker: true, source: Registry { specifier: VersionSpecifiers([]), index: None, conflict: None }, origin: None }}
Existing: {Requirement { name: PackageName("iniconfig"), extras: [], groups: [], marker: true, source: Registry { specifier: VersionSpecifiers([VersionSpecifier { operator: Equal, version: "2.0.0" }]), index: Some(Url { scheme: "https", cannot_be_a_base: false, username: "", password: None, host: Some(Domain("test.pypi.org")), port: None, path: "/simple", query: None, fragment: None }), conflict: None }, origin: None }}
Existing: {Requirement { name: PackageName("iniconfig"), extras: [], groups: [], marker: true, source: Registry { specifier: VersionSpecifiers([VersionSpecifier { operator: Equal, version: "2.0.0" }]), index: Some(IndexMetadata { url: Url(VerbatimUrl { url: Url { scheme: "https", cannot_be_a_base: false, username: "", password: None, host: Some(Domain("test.pypi.org")), port: None, path: "/simple", query: None, fragment: None }, given: None }) }), conflict: None }, origin: None }}
DEBUG Solving with installed Python version: 3.12.[X]
DEBUG Solving with target Python version: >=3.12
DEBUG Adding direct dependency: project*