Skip to content

Commit

Permalink
Allow displaying the derivation tree (#6124)
Browse files Browse the repository at this point in the history
I need this for debugging error messages.

I used an environment variable instead of a trace log so you can do
`UV_INTERNAL__SHOW_DERIVATION_TREE=1` and run a test to see the tree in
the test snapshot without further changes.

e.g.

```rust
    // Resolving should fail.
    uv_snapshot!(context.filters(), context.lock().arg("--preview").current_dir(&workspace), @r###"
    success: false
    exit_code: 1
    ----- stdout -----
    UV_INTERNAL__SHOW_DERIVATION_TREE
      root==0a0.dev0 depends on foo*
        root==0a0.dev0 depends on bar[some-extra]*
          foo==0.1.0 depends on anyio==4.1.0
            bar[some-extra]==0.1.0 depends on anyio==4.2.0
            no versions of bar[some-extra]<0.1.0 | >0.1.0

    ----- stderr -----
    Using Python 3.12.[X] interpreter at: [PYTHON-3.12]
      × No solution found when resolving dependencies:
      ╰─▶ Because only bar[some-extra]==0.1.0 is available and bar[some-extra] depends on anyio==4.2.0, we can conclude that all versions of bar[some-extra] depend on anyio==4.2.0.
          And because foo depends on anyio==4.1.0, we can conclude that foo and all versions of bar[some-extra] are incompatible.
          And because your workspace requires bar[some-extra] and foo, we can conclude that your workspace's requirements are unsatisfiable.
    "###
    );
```
  • Loading branch information
zanieb authored Aug 16, 2024
1 parent f2d6718 commit d7abe82
Showing 1 changed file with 58 additions and 0 deletions.
58 changes: 58 additions & 0 deletions crates/uv-resolver/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use rustc_hash::FxHashMap;
use distribution_types::{BuiltDist, IndexLocations, InstalledDist, SourceDist};
use pep440_rs::Version;
use pep508_rs::MarkerTree;
use tracing::trace;
use uv_normalize::PackageName;

use crate::candidate_selector::CandidateSelector;
Expand Down Expand Up @@ -228,6 +229,13 @@ impl std::fmt::Display for NoSolutionError {
drop_root_dependency_on_project(&mut tree, project);
}

// Display the tree if enabled
if std::env::var_os("UV_INTERNAL__SHOW_DERIVATION_TREE").is_some()
|| tracing::enabled!(tracing::Level::TRACE)
{
display_tree(&tree);
}

let report = DefaultStringReporter::report_with_formatter(&tree, &formatter);
write!(f, "{report}")?;

Expand All @@ -248,6 +256,56 @@ impl std::fmt::Display for NoSolutionError {
}
}

#[allow(clippy::print_stderr)]
fn display_tree(error: &DerivationTree<PubGrubPackage, Range<Version>, UnavailableReason>) {
let mut lines = Vec::new();
display_tree_inner(error, &mut lines, 0);
lines.reverse();

if std::env::var_os("UV_INTERNAL__SHOW_DERIVATION_TREE").is_some() {
eprintln!("Resolver error derivation tree\n{}", lines.join("\n"));
} else {
trace!("Resolver error derivation tree\n{}", lines.join("\n"));
}
}

fn display_tree_inner(
error: &DerivationTree<PubGrubPackage, Range<Version>, UnavailableReason>,
lines: &mut Vec<String>,
depth: usize,
) {
match error {
DerivationTree::Derived(derived) => {
display_tree_inner(&derived.cause1, lines, depth + 1);
display_tree_inner(&derived.cause2, lines, depth + 1);
}
DerivationTree::External(external) => {
let prefix = " ".repeat(depth).to_string();
match external {
External::FromDependencyOf(package, version, dependency, dependency_version) => {
lines.push(format!(
"{prefix}{package}{version} depends on {dependency}{dependency_version}"
));
}
External::Custom(package, versions, reason) => match reason {
UnavailableReason::Package(_) => {
lines.push(format!("{prefix}{package} {reason}"));
}
UnavailableReason::Version(_) => {
lines.push(format!("{prefix}{package}{versions} {reason}"));
}
},
External::NoVersions(package, versions) => {
lines.push(format!("{prefix}no versions of {package}{versions}"));
}
External::NotRoot(package, versions) => {
lines.push(format!("{prefix}not root {package}{versions}"));
}
}
}
}
}

/// Given a [`DerivationTree`], collapse any `NoVersion` incompatibilities for workspace members
/// to avoid saying things like "only <workspace-member>==0.1.0 is available".
fn collapse_no_versions_of_workspace_members(
Expand Down

0 comments on commit d7abe82

Please sign in to comment.