Add graphviz output to puffin-dev resolve-cli (#443)

I added output in graphviz DOT format to `puffin-dev resolve-cli` to
help with debugging resolutions. This requires tracking the requested
ranges in the graph. I also fixed the direction of the graph.

 Output for `black`:

```dot
digraph {
    0 [ label="click\n8.1.7"]
    1 [ label="black\n23.11.0"]
    2 [ label="packaging\n23.2"]
    3 [ label="mypy-extensions\n1.0.0"]
    4 [ label="tomli\n2.0.1"]
    5 [ label="pathspec\n0.11.2"]
    6 [ label="typing-extensions\n4.8.0"]
    7 [ label="platformdirs\n4.0.0"]
    1 -> 0 [ label=">=8.0.0"]
    1 -> 3 [ label=">=0.4.3"]
    1 -> 5 [ label=">=0.9.0"]
    1 -> 4 [ label=">=1.1.0"]
    1 -> 6 [ label=">=4.0.1"]
    1 -> 2 [ label=">=22.0"]
    1 -> 7 [ label=">=2"]
}
```


![image](4a440fcd-6248-4349-8e1a-c3e0363e42b1)

transformers:


![image](a13a693c-a8c0-4a4f-95d9-3458431c678a)

jupyter:


![graphviz](ef730033-6fd9-4ea9-ac93-8c874c19a101)
This commit is contained in:
konsti 2023-11-17 19:16:24 +01:00 committed by GitHub
parent d39e9b3499
commit bf71e7adcf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 79 additions and 10 deletions

View file

@ -3,6 +3,7 @@ use std::hash::BuildHasherDefault;
use colored::Colorize;
use fxhash::FxHashMap;
use petgraph::visit::EdgeRef;
use petgraph::Direction;
use pubgrub::range::Range;
use pubgrub::solver::{Kind, State};
use pubgrub::type_aliases::SelectedDependencies;
@ -51,7 +52,7 @@ impl Resolution {
/// A complete resolution graph in which every node represents a pinned package and every edge
/// represents a dependency between two pinned packages.
#[derive(Debug)]
pub struct Graph(petgraph::graph::Graph<Dist, (), petgraph::Directed>);
pub struct Graph(petgraph::graph::Graph<Dist, Range<PubGrubVersion>, petgraph::Directed>);
impl Graph {
/// Create a new graph from the resolved `PubGrub` state.
@ -98,8 +99,12 @@ impl Graph {
// Add every edge to the graph.
for (package, version) in selection {
for id in &state.incompatibilities[package] {
if let Kind::FromDependencyOf(self_package, self_version, dependency_package, _) =
&state.incompatibility_store[*id].kind
if let Kind::FromDependencyOf(
self_package,
self_version,
dependency_package,
dependency_range,
) = &state.incompatibility_store[*id].kind
{
let PubGrubPackage::Package(self_package, None, _) = self_package else {
continue;
@ -112,7 +117,7 @@ impl Graph {
if self_version.contains(version) {
let self_index = &inverse[self_package];
let dependency_index = &inverse[dependency_package];
graph.update_edge(*dependency_index, *self_index, ());
graph.update_edge(*self_index, *dependency_index, dependency_range.clone());
}
}
}
@ -179,6 +184,13 @@ impl Graph {
})
.collect()
}
/// Return the underlying graph.
pub fn petgraph(
&self,
) -> &petgraph::graph::Graph<Dist, Range<PubGrubVersion>, petgraph::Directed> {
&self.0
}
}
/// Write the graph in the `{name}=={version}` format of requirements.txt that pip uses.
@ -198,8 +210,8 @@ impl std::fmt::Display for Graph {
let mut edges = self
.0
.edges(index)
.map(|edge| &self.0[edge.target()])
.edges_directed(index, Direction::Incoming)
.map(|edge| &self.0[edge.source()])
.collect::<Vec<_>>();
edges.sort_unstable_by_key(|package| package.name());