Skip to content

Commit

Permalink
Include extras and dependency groups in derivation chains
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Nov 14, 2024
1 parent b3bbb50 commit d4174d4
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 20 deletions.
24 changes: 21 additions & 3 deletions crates/uv-distribution-types/src/derivation.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use uv_normalize::PackageName;
use uv_normalize::{ExtraName, GroupName, PackageName};
use uv_pep440::Version;
use version_ranges::Ranges;

Expand Down Expand Up @@ -65,6 +65,10 @@ impl IntoIterator for DerivationChain {
pub struct DerivationStep {
/// The name of the package.
pub name: PackageName,
/// The enabled extra of the package, if any.
pub extra: Option<ExtraName>,
/// The enabled dependency group of the package, if any.
pub group: Option<GroupName>,
/// The version of the package.
pub version: Version,
/// The constraints applied to the subsequent package in the chain.
Expand All @@ -73,9 +77,17 @@ pub struct DerivationStep {

impl DerivationStep {
/// Create a [`DerivationStep`] from a package name and version.
pub fn new(name: PackageName, version: Version, range: Ranges<Version>) -> Self {
pub fn new(
name: PackageName,
extra: Option<ExtraName>,
group: Option<GroupName>,
version: Version,
range: Ranges<Version>,
) -> Self {
Self {
name,
extra,
group,
version,
range,
}
Expand All @@ -84,6 +96,12 @@ impl DerivationStep {

impl std::fmt::Display for DerivationStep {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}=={}", self.name, self.version)
if let Some(extra) = &self.extra {
write!(f, "{}[{}]=={}", self.name, extra, self.version)
} else if let Some(group) = &self.group {
write!(f, "{}:{}=={}", self.name, group, self.version)
} else {
write!(f, "{}=={}", self.name, self.version)
}
}
}
18 changes: 18 additions & 0 deletions crates/uv-resolver/src/pubgrub/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,24 @@ impl PubGrubPackage {
}
}

/// Returns the group name associated with this PubGrub package, if it has
/// one.
pub(crate) fn group(&self) -> Option<&GroupName> {
match &**self {
// A root can never be a dependency of another package, and a `Python` pubgrub
// package is never returned by `get_dependencies`. So these cases never occur.
PubGrubPackageInner::Root(_)
| PubGrubPackageInner::Python(_)
| PubGrubPackageInner::Package { dev: None, .. }
| PubGrubPackageInner::Extra { .. }
| PubGrubPackageInner::Marker { .. } => None,
PubGrubPackageInner::Package {
dev: Some(ref dev), ..
}
| PubGrubPackageInner::Dev { ref dev, .. } => Some(dev),
}
}

/// Extracts a possible conflicting group from this package.
///
/// If this package can't possibly be classified as a conflicting group,
Expand Down
38 changes: 25 additions & 13 deletions crates/uv-resolver/src/resolver/derivation.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use std::collections::VecDeque;

use petgraph::visit::EdgeRef;
use petgraph::Direction;
use pubgrub::{Kind, Range, SelectedDependencies, State};
use rustc_hash::FxHashSet;

use uv_distribution_types::{
DerivationChain, DerivationStep, DistRef, Name, Node, Resolution, ResolvedDist,
DerivationChain, DerivationStep, DistRef, Edge, Name, Node, Resolution, ResolvedDist,
};
use uv_pep440::Version;

Expand Down Expand Up @@ -40,11 +41,11 @@ impl DerivationChainBuilder {

// Perform a BFS to find the shortest path to the root.
let mut queue = VecDeque::new();
queue.push_back((target, Vec::new()));
queue.push_back((target, None, None, Vec::new()));

// TODO(charlie): Consider respecting markers here.
let mut seen = FxHashSet::default();
while let Some((node, mut path)) = queue.pop_front() {
while let Some((node, extra, group, mut path)) = queue.pop_front() {
if !seen.insert(node) {
continue;
}
Expand All @@ -55,16 +56,25 @@ impl DerivationChainBuilder {
return Some(DerivationChain::from_iter(path));
}
Node::Dist { dist, .. } => {
path.push(DerivationStep::new(
dist.name().clone(),
dist.version().clone(),
Range::empty(),
));
for neighbor in resolution
.graph()
.neighbors_directed(node, Direction::Incoming)
{
queue.push_back((neighbor, path.clone()));
for edge in resolution.graph().edges_directed(node, Direction::Incoming) {
let mut path = path.clone();
path.push(DerivationStep::new(
dist.name().clone(),
extra.clone(),
group.clone(),
dist.version().clone(),
Range::empty(),
));
let target = edge.source();
let extra = match edge.weight() {
Edge::Optional(extra, ..) => Some(extra.clone()),
_ => None,
};
let group = match edge.weight() {
Edge::Dev(group, ..) => Some(group.clone()),
_ => None,
};
queue.push_back((target, extra, group, path));
}
}
}
Expand Down Expand Up @@ -109,6 +119,8 @@ impl DerivationChainBuilder {
// Add to the current path.
path.push(DerivationStep::new(
name.clone(),
p1.extra().cloned(),
p1.group().cloned(),
version.clone(),
v2.clone(),
));
Expand Down
4 changes: 2 additions & 2 deletions crates/uv/tests/it/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19337,7 +19337,7 @@ fn lock_derivation_chain_extra() -> Result<()> {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?

help: `wsgiref` was included because `project==0.1.0` depends on `wsgiref (>=0.1)`
help: `wsgiref` was included because `project[wsgi]==0.1.0` depends on `wsgiref (>=0.1)`
"###);

Ok(())
Expand Down Expand Up @@ -19397,7 +19397,7 @@ fn lock_derivation_chain_group() -> Result<()> {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?

help: `wsgiref` was included because `project==0.1.0` depends on `wsgiref (*)`
help: `wsgiref` was included because `project:wsgi==0.1.0` depends on `wsgiref (*)`
"###);

Ok(())
Expand Down
4 changes: 2 additions & 2 deletions crates/uv/tests/it/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4398,7 +4398,7 @@ fn sync_derivation_chain_extra() -> Result<()> {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
help: `wsgiref` was included because `project==0.1.0` depends on `wsgiref`
help: `wsgiref` was included because `project[wsgi]==0.1.0` depends on `wsgiref`
"###);

Ok(())
Expand Down Expand Up @@ -4464,7 +4464,7 @@ fn sync_derivation_chain_group() -> Result<()> {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
help: `wsgiref` was included because `project==0.1.0` depends on `wsgiref`
help: `wsgiref` was included because `project:wsgi==0.1.0` depends on `wsgiref`
"###);

Ok(())
Expand Down

0 comments on commit d4174d4

Please sign in to comment.