Rename ResolutionGraph to ResolverOutput (#9103)

## Summary

As discussed in Discord... This struct has evolved to include a lot of
information apart from the `petgraph::Graph`. And I want to add a graph
to the simplified `Resolution` type. So I think this name makes more
sense.
This commit is contained in:
Charlie Marsh 2024-11-14 09:51:11 -05:00 committed by GitHub
parent 02a7bb43d9
commit b37170df94
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 104 additions and 109 deletions

View file

@ -101,7 +101,7 @@ mod resolver {
use uv_python::Interpreter; use uv_python::Interpreter;
use uv_resolver::{ use uv_resolver::{
FlatIndex, InMemoryIndex, Manifest, OptionsBuilder, PythonRequirement, RequiresPython, FlatIndex, InMemoryIndex, Manifest, OptionsBuilder, PythonRequirement, RequiresPython,
ResolutionGraph, Resolver, ResolverEnvironment, Resolver, ResolverEnvironment, ResolverOutput,
}; };
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight}; use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight};
@ -139,7 +139,7 @@ mod resolver {
client: &RegistryClient, client: &RegistryClient,
interpreter: &Interpreter, interpreter: &Interpreter,
universal: bool, universal: bool,
) -> Result<ResolutionGraph> { ) -> Result<ResolverOutput> {
let build_isolation = BuildIsolation::default(); let build_isolation = BuildIsolation::default();
let build_options = BuildOptions::default(); let build_options = BuildOptions::default();
let concurrency = Concurrency::default(); let concurrency = Concurrency::default();

View file

@ -197,7 +197,7 @@ impl<'a> BuildContext for BuildDispatch<'a> {
EmptyInstalledPackages, EmptyInstalledPackages,
DistributionDatabase::new(self.client, self, self.concurrency.downloads), DistributionDatabase::new(self.client, self, self.concurrency.downloads),
)?; )?;
let graph = resolver.resolve().await.with_context(|| { let resolution = Resolution::from(resolver.resolve().await.with_context(|| {
format!( format!(
"No solution found when resolving: {}", "No solution found when resolving: {}",
requirements requirements
@ -205,8 +205,8 @@ impl<'a> BuildContext for BuildDispatch<'a> {
.map(|requirement| format!("`{requirement}`")) .map(|requirement| format!("`{requirement}`"))
.join(", ") .join(", ")
) )
})?; })?);
Ok(Resolution::from(graph)) Ok(resolution)
} }
#[instrument( #[instrument(

View file

@ -14,7 +14,7 @@ pub use prerelease::PrereleaseMode;
pub use python_requirement::PythonRequirement; pub use python_requirement::PythonRequirement;
pub use requires_python::{RequiresPython, RequiresPythonRange}; pub use requires_python::{RequiresPython, RequiresPythonRange};
pub use resolution::{ pub use resolution::{
AnnotationStyle, ConflictingDistributionError, DisplayResolutionGraph, ResolutionGraph, AnnotationStyle, ConflictingDistributionError, DisplayResolutionGraph, ResolverOutput,
}; };
pub use resolution_mode::ResolutionMode; pub use resolution_mode::ResolutionMode;
pub use resolver::{ pub use resolver::{

View file

@ -20,8 +20,8 @@ pub use crate::lock::tree::TreeDisplay;
use crate::requires_python::SimplifiedMarkerTree; use crate::requires_python::SimplifiedMarkerTree;
use crate::resolution::{AnnotatedDist, ResolutionGraphNode}; use crate::resolution::{AnnotatedDist, ResolutionGraphNode};
use crate::{ use crate::{
ExcludeNewer, InMemoryIndex, MetadataResponse, PrereleaseMode, RequiresPython, ResolutionGraph, ExcludeNewer, InMemoryIndex, MetadataResponse, PrereleaseMode, RequiresPython, ResolutionMode,
ResolutionMode, ResolverOutput,
}; };
use uv_cache_key::RepositoryUrl; use uv_cache_key::RepositoryUrl;
use uv_configuration::BuildOptions; use uv_configuration::BuildOptions;
@ -108,16 +108,16 @@ pub struct Lock {
} }
impl Lock { impl Lock {
/// Initialize a [`Lock`] from a [`ResolutionGraph`]. /// Initialize a [`Lock`] from a [`ResolverOutput`].
pub fn from_resolution_graph(graph: &ResolutionGraph, root: &Path) -> Result<Self, LockError> { pub fn from_resolution(resolution: &ResolverOutput, root: &Path) -> Result<Self, LockError> {
let mut packages = BTreeMap::new(); let mut packages = BTreeMap::new();
let requires_python = graph.requires_python.clone(); let requires_python = resolution.requires_python.clone();
// Determine the set of packages included at multiple versions. // Determine the set of packages included at multiple versions.
let mut seen = FxHashSet::default(); let mut seen = FxHashSet::default();
let mut duplicates = FxHashSet::default(); let mut duplicates = FxHashSet::default();
for node_index in graph.petgraph.node_indices() { for node_index in resolution.graph.node_indices() {
let ResolutionGraphNode::Dist(dist) = &graph.petgraph[node_index] else { let ResolutionGraphNode::Dist(dist) = &resolution.graph[node_index] else {
continue; continue;
}; };
if !dist.is_base() { if !dist.is_base() {
@ -129,8 +129,8 @@ impl Lock {
} }
// Lock all base packages. // Lock all base packages.
for node_index in graph.petgraph.node_indices() { for node_index in resolution.graph.node_indices() {
let ResolutionGraphNode::Dist(dist) = &graph.petgraph[node_index] else { let ResolutionGraphNode::Dist(dist) = &resolution.graph[node_index] else {
continue; continue;
}; };
if !dist.is_base() { if !dist.is_base() {
@ -140,7 +140,7 @@ impl Lock {
// If there are multiple distributions for the same package, include the markers of all // If there are multiple distributions for the same package, include the markers of all
// forks that included the current distribution. // forks that included the current distribution.
let fork_markers = if duplicates.contains(dist.name()) { let fork_markers = if duplicates.contains(dist.name()) {
graph resolution
.fork_markers .fork_markers
.iter() .iter()
.filter(|fork_markers| !fork_markers.is_disjoint(&dist.marker)) .filter(|fork_markers| !fork_markers.is_disjoint(&dist.marker))
@ -151,11 +151,11 @@ impl Lock {
}; };
let mut package = Package::from_annotated_dist(dist, fork_markers, root)?; let mut package = Package::from_annotated_dist(dist, fork_markers, root)?;
Self::remove_unreachable_wheels(graph, &requires_python, node_index, &mut package); Self::remove_unreachable_wheels(resolution, &requires_python, node_index, &mut package);
// Add all dependencies // Add all dependencies
for edge in graph.petgraph.edges(node_index) { for edge in resolution.graph.edges(node_index) {
let ResolutionGraphNode::Dist(dependency_dist) = &graph.petgraph[edge.target()] let ResolutionGraphNode::Dist(dependency_dist) = &resolution.graph[edge.target()]
else { else {
continue; continue;
}; };
@ -173,8 +173,8 @@ impl Lock {
} }
// Lock all extras and development dependencies. // Lock all extras and development dependencies.
for node_index in graph.petgraph.node_indices() { for node_index in resolution.graph.node_indices() {
let ResolutionGraphNode::Dist(dist) = &graph.petgraph[node_index] else { let ResolutionGraphNode::Dist(dist) = &resolution.graph[node_index] else {
continue; continue;
}; };
if let Some(extra) = dist.extra.as_ref() { if let Some(extra) = dist.extra.as_ref() {
@ -186,8 +186,9 @@ impl Lock {
} }
.into()); .into());
}; };
for edge in graph.petgraph.edges(node_index) { for edge in resolution.graph.edges(node_index) {
let ResolutionGraphNode::Dist(dependency_dist) = &graph.petgraph[edge.target()] let ResolutionGraphNode::Dist(dependency_dist) =
&resolution.graph[edge.target()]
else { else {
continue; continue;
}; };
@ -210,8 +211,9 @@ impl Lock {
} }
.into()); .into());
}; };
for edge in graph.petgraph.edges(node_index) { for edge in resolution.graph.edges(node_index) {
let ResolutionGraphNode::Dist(dependency_dist) = &graph.petgraph[edge.target()] let ResolutionGraphNode::Dist(dependency_dist) =
&resolution.graph[edge.target()]
else { else {
continue; continue;
}; };
@ -229,9 +231,9 @@ impl Lock {
let packages = packages.into_values().collect(); let packages = packages.into_values().collect();
let options = ResolverOptions { let options = ResolverOptions {
resolution_mode: graph.options.resolution_mode, resolution_mode: resolution.options.resolution_mode,
prerelease_mode: graph.options.prerelease_mode, prerelease_mode: resolution.options.prerelease_mode,
exclude_newer: graph.options.exclude_newer, exclude_newer: resolution.options.exclude_newer,
}; };
let lock = Self::new( let lock = Self::new(
VERSION, VERSION,
@ -241,7 +243,7 @@ impl Lock {
ResolverManifest::default(), ResolverManifest::default(),
Conflicts::empty(), Conflicts::empty(),
vec![], vec![],
graph.fork_markers.clone(), resolution.fork_markers.clone(),
)?; )?;
Ok(lock) Ok(lock)
} }
@ -251,7 +253,7 @@ impl Lock {
/// For example, a package included under `sys_platform == 'win32'` does not need Linux /// For example, a package included under `sys_platform == 'win32'` does not need Linux
/// wheels. /// wheels.
fn remove_unreachable_wheels( fn remove_unreachable_wheels(
graph: &ResolutionGraph, graph: &ResolverOutput,
requires_python: &RequiresPython, requires_python: &RequiresPython,
node_index: NodeIndex, node_index: NodeIndex,
locked_dist: &mut Package, locked_dist: &mut Package,
@ -288,20 +290,16 @@ impl Lock {
tag.starts_with(linux_tag) || tag == "linux_armv6l" || tag == "linux_armv7l" tag.starts_with(linux_tag) || tag == "linux_armv6l" || tag == "linux_armv7l"
}) })
}) { }) {
!graph.petgraph[node_index] !graph.graph[node_index].marker().is_disjoint(&LINUX_MARKERS)
.marker()
.is_disjoint(&LINUX_MARKERS)
} else if platform_tags } else if platform_tags
.iter() .iter()
.all(|tag| windows_tags.contains(&&**tag)) .all(|tag| windows_tags.contains(&&**tag))
{ {
!graph.petgraph[node_index] !graph.graph[node_index]
.marker() .marker()
.is_disjoint(&WINDOWS_MARKERS) .is_disjoint(&WINDOWS_MARKERS)
} else if platform_tags.iter().all(|tag| tag.starts_with("macosx_")) { } else if platform_tags.iter().all(|tag| tag.starts_with("macosx_")) {
!graph.petgraph[node_index] !graph.graph[node_index].marker().is_disjoint(&MAC_MARKERS)
.marker()
.is_disjoint(&MAC_MARKERS)
} else { } else {
true true
} }

View file

@ -12,14 +12,14 @@ use uv_normalize::PackageName;
use uv_pep508::MarkerTree; use uv_pep508::MarkerTree;
use crate::resolution::{RequirementsTxtDist, ResolutionGraphNode}; use crate::resolution::{RequirementsTxtDist, ResolutionGraphNode};
use crate::{ResolutionGraph, ResolverEnvironment}; use crate::{ResolverEnvironment, ResolverOutput};
/// A [`std::fmt::Display`] implementation for the resolution graph. /// A [`std::fmt::Display`] implementation for the resolution graph.
#[derive(Debug)] #[derive(Debug)]
#[allow(clippy::struct_excessive_bools)] #[allow(clippy::struct_excessive_bools)]
pub struct DisplayResolutionGraph<'a> { pub struct DisplayResolutionGraph<'a> {
/// The underlying graph. /// The underlying graph.
resolution: &'a ResolutionGraph, resolution: &'a ResolverOutput,
/// The resolver marker environment, used to determine the markers that apply to each package. /// The resolver marker environment, used to determine the markers that apply to each package.
env: &'a ResolverEnvironment, env: &'a ResolverEnvironment,
/// The packages to exclude from the output. /// The packages to exclude from the output.
@ -50,7 +50,7 @@ impl<'a> DisplayResolutionGraph<'a> {
/// Create a new [`DisplayResolutionGraph`] for the given graph. /// Create a new [`DisplayResolutionGraph`] for the given graph.
#[allow(clippy::fn_params_excessive_bools)] #[allow(clippy::fn_params_excessive_bools)]
pub fn new( pub fn new(
underlying: &'a ResolutionGraph, underlying: &'a ResolverOutput,
env: &'a ResolverEnvironment, env: &'a ResolverEnvironment,
no_emit_packages: &'a [PackageName], no_emit_packages: &'a [PackageName],
show_hashes: bool, show_hashes: bool,
@ -136,7 +136,7 @@ impl std::fmt::Display for DisplayResolutionGraph<'_> {
// We assign each package its propagated markers: In `requirements.txt`, we want a flat list // We assign each package its propagated markers: In `requirements.txt`, we want a flat list
// that for each package tells us if it should be installed on the current platform, without // that for each package tells us if it should be installed on the current platform, without
// looking at which packages depend on it. // looking at which packages depend on it.
let petgraph = self.resolution.petgraph.map( let graph = self.resolution.graph.map(
|_index, node| match node { |_index, node| match node {
ResolutionGraphNode::Root => DisplayResolutionGraphNode::Root, ResolutionGraphNode::Root => DisplayResolutionGraphNode::Root,
ResolutionGraphNode::Dist(dist) => { ResolutionGraphNode::Dist(dist) => {
@ -150,17 +150,17 @@ impl std::fmt::Display for DisplayResolutionGraph<'_> {
); );
// Reduce the graph, removing or combining extras for a given package. // Reduce the graph, removing or combining extras for a given package.
let petgraph = if self.include_extras { let graph = if self.include_extras {
combine_extras(&petgraph) combine_extras(&graph)
} else { } else {
strip_extras(&petgraph) strip_extras(&graph)
}; };
// Collect all packages. // Collect all packages.
let mut nodes = petgraph let mut nodes = graph
.node_indices() .node_indices()
.filter_map(|index| { .filter_map(|index| {
let dist = &petgraph[index]; let dist = &graph[index];
let name = dist.name(); let name = dist.name();
if self.no_emit_packages.contains(name) { if self.no_emit_packages.contains(name) {
return None; return None;
@ -199,9 +199,9 @@ impl std::fmt::Display for DisplayResolutionGraph<'_> {
if self.include_annotations { if self.include_annotations {
// Display all dependents (i.e., all packages that depend on the current package). // Display all dependents (i.e., all packages that depend on the current package).
let dependents = { let dependents = {
let mut dependents = petgraph let mut dependents = graph
.edges_directed(index, Direction::Incoming) .edges_directed(index, Direction::Incoming)
.map(|edge| &petgraph[edge.source()]) .map(|edge| &graph[edge.source()])
.map(uv_distribution_types::Name::name) .map(uv_distribution_types::Name::name)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
dependents.sort_unstable(); dependents.sort_unstable();

View file

@ -11,12 +11,12 @@ use uv_pep508::MarkerTree;
use uv_pypi_types::HashDigest; use uv_pypi_types::HashDigest;
pub use crate::resolution::display::{AnnotationStyle, DisplayResolutionGraph}; pub use crate::resolution::display::{AnnotationStyle, DisplayResolutionGraph};
pub(crate) use crate::resolution::graph::ResolutionGraphNode; pub(crate) use crate::resolution::output::ResolutionGraphNode;
pub use crate::resolution::graph::{ConflictingDistributionError, ResolutionGraph}; pub use crate::resolution::output::{ConflictingDistributionError, ResolverOutput};
pub(crate) use crate::resolution::requirements_txt::RequirementsTxtDist; pub(crate) use crate::resolution::requirements_txt::RequirementsTxtDist;
mod display; mod display;
mod graph; mod output;
mod requirements_txt; mod requirements_txt;
/// A pinned package with its resolved distribution and metadata. The [`ResolvedDist`] refers to a /// A pinned package with its resolved distribution and metadata. The [`ResolvedDist`] refers to a

View file

@ -35,12 +35,14 @@ use crate::{
pub(crate) type MarkersForDistribution = Vec<MarkerTree>; pub(crate) type MarkersForDistribution = Vec<MarkerTree>;
/// A complete resolution graph in which every node represents a pinned package and every edge /// The output of a successful resolution.
/// represents a dependency between two pinned packages. ///
/// Includes a complete resolution graph in which every node represents a pinned package and every
/// edge represents a dependency between two pinned packages.
#[derive(Debug)] #[derive(Debug)]
pub struct ResolutionGraph { pub struct ResolverOutput {
/// The underlying graph. /// The underlying graph.
pub(crate) petgraph: Graph<ResolutionGraphNode, MarkerTree, Directed>, pub(crate) graph: Graph<ResolutionGraphNode, MarkerTree, Directed>,
/// The range of supported Python versions. /// The range of supported Python versions.
pub(crate) requires_python: RequiresPython, pub(crate) requires_python: RequiresPython,
/// If the resolution had non-identical forks, store the forks in the lockfile so we can /// If the resolution had non-identical forks, store the forks in the lockfile so we can
@ -92,8 +94,8 @@ struct PackageRef<'a> {
group: Option<&'a GroupName>, group: Option<&'a GroupName>,
} }
impl ResolutionGraph { impl ResolverOutput {
/// Create a new graph from the resolved PubGrub state. /// Create a new [`ResolverOutput`] from the resolved PubGrub state.
pub(crate) fn from_state( pub(crate) fn from_state(
resolutions: &[Resolution], resolutions: &[Resolution],
requirements: &[Requirement], requirements: &[Requirement],
@ -108,14 +110,14 @@ impl ResolutionGraph {
options: Options, options: Options,
) -> Result<Self, ResolveError> { ) -> Result<Self, ResolveError> {
let size_guess = resolutions[0].nodes.len(); let size_guess = resolutions[0].nodes.len();
let mut petgraph: Graph<ResolutionGraphNode, MarkerTree, Directed> = let mut graph: Graph<ResolutionGraphNode, MarkerTree, Directed> =
Graph::with_capacity(size_guess, size_guess); Graph::with_capacity(size_guess, size_guess);
let mut inverse: FxHashMap<PackageRef, NodeIndex<u32>> = let mut inverse: FxHashMap<PackageRef, NodeIndex<u32>> =
FxHashMap::with_capacity_and_hasher(size_guess, FxBuildHasher); FxHashMap::with_capacity_and_hasher(size_guess, FxBuildHasher);
let mut diagnostics = Vec::new(); let mut diagnostics = Vec::new();
// Add the root node. // Add the root node.
let root_index = petgraph.add_node(ResolutionGraphNode::Root); let root_index = graph.add_node(ResolutionGraphNode::Root);
let mut package_markers: FxHashMap<PackageName, MarkersForDistribution> = let mut package_markers: FxHashMap<PackageName, MarkersForDistribution> =
FxHashMap::default(); FxHashMap::default();
@ -140,7 +142,7 @@ impl ResolutionGraph {
continue; continue;
} }
Self::add_version( Self::add_version(
&mut petgraph, &mut graph,
&mut inverse, &mut inverse,
&mut diagnostics, &mut diagnostics,
preferences, preferences,
@ -165,13 +167,7 @@ impl ResolutionGraph {
continue; continue;
} }
Self::add_edge( Self::add_edge(&mut graph, &mut inverse, root_index, edge, marker.clone());
&mut petgraph,
&mut inverse,
root_index,
edge,
marker.clone(),
);
} }
} }
@ -213,24 +209,24 @@ impl ResolutionGraph {
}; };
// Compute and apply the marker reachability. // Compute and apply the marker reachability.
let mut reachability = marker_reachability(&petgraph, &fork_markers); let mut reachability = marker_reachability(&graph, &fork_markers);
// Apply the reachability to the graph. // Apply the reachability to the graph.
for index in petgraph.node_indices() { for index in graph.node_indices() {
if let ResolutionGraphNode::Dist(dist) = &mut petgraph[index] { if let ResolutionGraphNode::Dist(dist) = &mut graph[index] {
dist.marker = reachability.remove(&index).unwrap_or_default(); dist.marker = reachability.remove(&index).unwrap_or_default();
} }
} }
// Discard any unreachable nodes. // Discard any unreachable nodes.
petgraph.retain_nodes(|graph, node| !graph[node].marker().is_false()); graph.retain_nodes(|graph, node| !graph[node].marker().is_false());
if matches!(resolution_strategy, ResolutionStrategy::Lowest) { if matches!(resolution_strategy, ResolutionStrategy::Lowest) {
report_missing_lower_bounds(&petgraph, &mut diagnostics); report_missing_lower_bounds(&graph, &mut diagnostics);
} }
let graph = Self { let output = Self {
petgraph, graph,
requires_python, requires_python,
diagnostics, diagnostics,
requirements: requirements.to_vec(), requirements: requirements.to_vec(),
@ -253,7 +249,7 @@ impl ResolutionGraph {
// versions of the same package into the same virtualenv. ---AG // versions of the same package into the same virtualenv. ---AG
if conflicts.is_empty() { if conflicts.is_empty() {
#[allow(unused_mut, reason = "Used in debug_assertions below")] #[allow(unused_mut, reason = "Used in debug_assertions below")]
let mut conflicting = graph.find_conflicting_distributions(); let mut conflicting = output.find_conflicting_distributions();
if !conflicting.is_empty() { if !conflicting.is_empty() {
tracing::warn!( tracing::warn!(
"found {} conflicting distributions in resolution, \ "found {} conflicting distributions in resolution, \
@ -275,7 +271,7 @@ impl ResolutionGraph {
return Err(ResolveError::ConflictingDistribution(err)); return Err(ResolveError::ConflictingDistribution(err));
} }
} }
Ok(graph) Ok(output)
} }
fn add_edge( fn add_edge(
@ -566,9 +562,9 @@ impl ResolutionGraph {
/// Returns an iterator over the distinct packages in the graph. /// Returns an iterator over the distinct packages in the graph.
fn dists(&self) -> impl Iterator<Item = &AnnotatedDist> { fn dists(&self) -> impl Iterator<Item = &AnnotatedDist> {
self.petgraph self.graph
.node_indices() .node_indices()
.filter_map(move |index| match &self.petgraph[index] { .filter_map(move |index| match &self.graph[index] {
ResolutionGraphNode::Root => None, ResolutionGraphNode::Root => None,
ResolutionGraphNode::Dist(dist) => Some(dist), ResolutionGraphNode::Dist(dist) => Some(dist),
}) })
@ -677,8 +673,8 @@ impl ResolutionGraph {
} }
let mut seen_marker_values = IndexSet::default(); let mut seen_marker_values = IndexSet::default();
for i in self.petgraph.node_indices() { for i in self.graph.node_indices() {
let ResolutionGraphNode::Dist(dist) = &self.petgraph[i] else { let ResolutionGraphNode::Dist(dist) = &self.graph[i] else {
continue; continue;
}; };
let version_id = match dist.version_or_url() { let version_id = match dist.version_or_url() {
@ -750,7 +746,7 @@ impl ResolutionGraph {
fn find_conflicting_distributions(&self) -> Vec<ConflictingDistributionError> { fn find_conflicting_distributions(&self) -> Vec<ConflictingDistributionError> {
let mut name_to_markers: BTreeMap<&PackageName, Vec<(&Version, &MarkerTree)>> = let mut name_to_markers: BTreeMap<&PackageName, Vec<(&Version, &MarkerTree)>> =
BTreeMap::new(); BTreeMap::new();
for node in self.petgraph.node_weights() { for node in self.graph.node_weights() {
let annotated_dist = match node { let annotated_dist = match node {
ResolutionGraphNode::Root => continue, ResolutionGraphNode::Root => continue,
ResolutionGraphNode::Dist(ref annotated_dist) => annotated_dist, ResolutionGraphNode::Dist(ref annotated_dist) => annotated_dist,
@ -818,8 +814,8 @@ impl Display for ConflictingDistributionError {
} }
} }
impl From<ResolutionGraph> for uv_distribution_types::Resolution { impl From<ResolverOutput> for uv_distribution_types::Resolution {
fn from(graph: ResolutionGraph) -> Self { fn from(graph: ResolverOutput) -> Self {
Self::new( Self::new(
graph graph
.dists() .dists()

View file

@ -56,7 +56,7 @@ use crate::pubgrub::{
PubGrubPython, PubGrubPython,
}; };
use crate::python_requirement::PythonRequirement; use crate::python_requirement::PythonRequirement;
use crate::resolution::ResolutionGraph; use crate::resolution::ResolverOutput;
use crate::resolution_mode::ResolutionStrategy; use crate::resolution_mode::ResolutionStrategy;
pub(crate) use crate::resolver::availability::{ pub(crate) use crate::resolver::availability::{
IncompletePackage, ResolverVersion, UnavailablePackage, UnavailableReason, UnavailableVersion, IncompletePackage, ResolverVersion, UnavailablePackage, UnavailableReason, UnavailableVersion,
@ -251,7 +251,7 @@ impl<Provider: ResolverProvider, InstalledPackages: InstalledPackagesProvider>
} }
/// Resolve a set of requirements into a set of pinned versions. /// Resolve a set of requirements into a set of pinned versions.
pub async fn resolve(self) -> Result<ResolutionGraph, ResolveError> { pub async fn resolve(self) -> Result<ResolverOutput, ResolveError> {
let state = Arc::new(self.state); let state = Arc::new(self.state);
let provider = Arc::new(self.provider); let provider = Arc::new(self.provider);
@ -291,7 +291,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
fn solve( fn solve(
self: Arc<Self>, self: Arc<Self>,
request_sink: Sender<Request>, request_sink: Sender<Request>,
) -> Result<ResolutionGraph, ResolveError> { ) -> Result<ResolverOutput, ResolveError> {
debug!( debug!(
"Solving with installed Python version: {}", "Solving with installed Python version: {}",
self.python_requirement.exact() self.python_requirement.exact()
@ -598,7 +598,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
for resolution in &resolutions { for resolution in &resolutions {
Self::trace_resolution(resolution); Self::trace_resolution(resolution);
} }
ResolutionGraph::from_state( ResolverOutput::from_state(
&resolutions, &resolutions,
&self.requirements, &self.requirements,
&self.constraints, &self.constraints,

View file

@ -37,7 +37,7 @@ use uv_requirements::{
}; };
use uv_resolver::{ use uv_resolver::{
DependencyMode, Exclusions, FlatIndex, InMemoryIndex, Manifest, Options, Preference, DependencyMode, Exclusions, FlatIndex, InMemoryIndex, Manifest, Options, Preference,
Preferences, PythonRequirement, ResolutionGraph, Resolver, ResolverEnvironment, Preferences, PythonRequirement, Resolver, ResolverEnvironment, ResolverOutput,
}; };
use uv_types::{HashStrategy, InFlight, InstalledPackagesProvider}; use uv_types::{HashStrategy, InFlight, InstalledPackagesProvider};
use uv_warnings::warn_user; use uv_warnings::warn_user;
@ -113,7 +113,7 @@ pub(crate) async fn resolve<InstalledPackages: InstalledPackagesProvider>(
options: Options, options: Options,
logger: Box<dyn ResolveLogger>, logger: Box<dyn ResolveLogger>,
printer: Printer, printer: Printer,
) -> Result<ResolutionGraph, Error> { ) -> Result<ResolverOutput, Error> {
let start = std::time::Instant::now(); let start = std::time::Instant::now();
// Resolve the requirements from the provided sources. // Resolve the requirements from the provided sources.

View file

@ -58,21 +58,22 @@ impl CachedEnvironment {
}; };
// Resolve the requirements with the interpreter. // Resolve the requirements with the interpreter.
let graph = resolve_environment( let resolution = Resolution::from(
spec, resolve_environment(
&interpreter, spec,
settings.as_ref().into(), &interpreter,
state, settings.as_ref().into(),
resolve, state,
connectivity, resolve,
concurrency, connectivity,
native_tls, concurrency,
allow_insecure_host, native_tls,
cache, allow_insecure_host,
printer, cache,
) printer,
.await?; )
let resolution = Resolution::from(graph); .await?,
);
// Hash the resolution by hashing the generated lockfile. // Hash the resolution by hashing the generated lockfile.
// TODO(charlie): If the resolution contains any mutable metadata (like a path or URL // TODO(charlie): If the resolution contains any mutable metadata (like a path or URL

View file

@ -659,7 +659,7 @@ async fn do_lock(
.relative_to(workspace)?; .relative_to(workspace)?;
let previous = existing_lock.map(ValidatedLock::into_lock); let previous = existing_lock.map(ValidatedLock::into_lock);
let lock = Lock::from_resolution_graph(&resolution, workspace.install_path())? let lock = Lock::from_resolution(&resolution, workspace.install_path())?
.with_manifest(manifest) .with_manifest(manifest)
.with_conflicts(workspace.conflicts()) .with_conflicts(workspace.conflicts())
.with_supported_environments( .with_supported_environments(

View file

@ -31,8 +31,8 @@ use uv_python::{
use uv_requirements::upgrade::{read_lock_requirements, LockedRequirements}; use uv_requirements::upgrade::{read_lock_requirements, LockedRequirements};
use uv_requirements::{NamedRequirementsResolver, RequirementsSpecification}; use uv_requirements::{NamedRequirementsResolver, RequirementsSpecification};
use uv_resolver::{ use uv_resolver::{
FlatIndex, Lock, OptionsBuilder, PythonRequirement, RequiresPython, ResolutionGraph, FlatIndex, Lock, OptionsBuilder, PythonRequirement, RequiresPython, ResolverEnvironment,
ResolverEnvironment, ResolverOutput,
}; };
use uv_scripts::Pep723Item; use uv_scripts::Pep723Item;
use uv_settings::PythonInstallMirrors; use uv_settings::PythonInstallMirrors;
@ -955,7 +955,7 @@ impl<'lock> EnvironmentSpecification<'lock> {
} }
} }
/// Run dependency resolution for an interpreter, returning the [`ResolutionGraph`]. /// Run dependency resolution for an interpreter, returning the [`ResolverOutput`].
pub(crate) async fn resolve_environment<'a>( pub(crate) async fn resolve_environment<'a>(
spec: EnvironmentSpecification<'_>, spec: EnvironmentSpecification<'_>,
interpreter: &Interpreter, interpreter: &Interpreter,
@ -968,7 +968,7 @@ pub(crate) async fn resolve_environment<'a>(
allow_insecure_host: &[TrustedHost], allow_insecure_host: &[TrustedHost],
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
) -> Result<ResolutionGraph, ProjectError> { ) -> Result<ResolverOutput, ProjectError> {
warn_on_requirements_txt_setting(&spec.requirements, settings); warn_on_requirements_txt_setting(&spec.requirements, settings);
let ResolverSettingsRef { let ResolverSettingsRef {