mirror of
https://github.com/astral-sh/uv.git
synced 2025-09-26 20:19:08 +00:00
Allow displaying the derivation tree (#6124)
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. "### ); ```
This commit is contained in:
parent
f2d6718038
commit
d7abe827d6
1 changed files with 58 additions and 0 deletions
|
@ -8,6 +8,7 @@ use rustc_hash::FxHashMap;
|
||||||
use distribution_types::{BuiltDist, IndexLocations, InstalledDist, SourceDist};
|
use distribution_types::{BuiltDist, IndexLocations, InstalledDist, SourceDist};
|
||||||
use pep440_rs::Version;
|
use pep440_rs::Version;
|
||||||
use pep508_rs::MarkerTree;
|
use pep508_rs::MarkerTree;
|
||||||
|
use tracing::trace;
|
||||||
use uv_normalize::PackageName;
|
use uv_normalize::PackageName;
|
||||||
|
|
||||||
use crate::candidate_selector::CandidateSelector;
|
use crate::candidate_selector::CandidateSelector;
|
||||||
|
@ -228,6 +229,13 @@ impl std::fmt::Display for NoSolutionError {
|
||||||
drop_root_dependency_on_project(&mut tree, project);
|
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);
|
let report = DefaultStringReporter::report_with_formatter(&tree, &formatter);
|
||||||
write!(f, "{report}")?;
|
write!(f, "{report}")?;
|
||||||
|
|
||||||
|
@ -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
|
/// Given a [`DerivationTree`], collapse any `NoVersion` incompatibilities for workspace members
|
||||||
/// to avoid saying things like "only <workspace-member>==0.1.0 is available".
|
/// to avoid saying things like "only <workspace-member>==0.1.0 is available".
|
||||||
fn collapse_no_versions_of_workspace_members(
|
fn collapse_no_versions_of_workspace_members(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue