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 15, 2024
1 parent 9cb9841 commit 3f1d3f7
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 21 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)
}
}
}
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.dev().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 @@ -19940,7 +19940,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 @@ -20000,7 +20000,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
6 changes: 3 additions & 3 deletions crates/uv/tests/it/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -792,7 +792,7 @@ fn sync_build_isolation_extra() -> Result<()> {
File "<string>", line 8, in <module>
ModuleNotFoundError: No module named 'hatchling'
help: `source-distribution` was included because `project==0.1.0` depends on `source-distribution`
help: `source-distribution` was included because `project[compile]==0.1.0` depends on `source-distribution`
"###);

// Running `uv sync` with `--all-extras` should also fail.
Expand Down 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 3f1d3f7

Please sign in to comment.