Filter uv tree to current platform by default (#5763)

## Summary

`uv tree` will now filter to the current platform by default. You can
pass `--universal` to show the entire tree.

Closes https://github.com/astral-sh/uv/issues/5760.
This commit is contained in:
Charlie Marsh 2024-08-05 14:51:18 -04:00 committed by GitHub
parent 865f9eeef7
commit 3156fccc85
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 64 additions and 15 deletions

View file

@ -1709,6 +1709,10 @@ pub struct PipShowArgs {
#[derive(Args)]
#[allow(clippy::struct_excessive_bools)]
pub struct PipTreeArgs {
/// Show the version constraint(s) imposed on each package.
#[arg(long)]
pub show_version_specifiers: bool,
#[command(flatten)]
pub tree: DisplayTreeArgs,
@ -2344,6 +2348,11 @@ pub struct RemoveArgs {
#[derive(Args)]
#[allow(clippy::struct_excessive_bools)]
pub struct TreeArgs {
/// Show the resolved package versions for all Python versions and platforms, rather than
/// filtering to those that are relevant for the current environment.
#[arg(long)]
pub universal: bool,
#[command(flatten)]
pub tree: DisplayTreeArgs,
@ -3054,8 +3063,4 @@ pub struct DisplayTreeArgs {
/// Show the reverse dependencies for the given package. This flag will invert the tree and display the packages that depend on the given package.
#[arg(long, alias = "reverse")]
pub invert: bool,
/// Show the version constraint(s) imposed on each package.
#[arg(long)]
pub show_version_specifiers: bool,
}

View file

@ -2650,6 +2650,7 @@ impl<'env> TreeDisplay<'env> {
/// Create a new [`DisplayDependencyGraph`] for the set of installed distributions.
pub fn new(
lock: &'env Lock,
markers: Option<&'env MarkerEnvironment>,
depth: usize,
prune: Vec<PackageName>,
package: Vec<PackageName>,
@ -2676,6 +2677,15 @@ impl<'env> TreeDisplay<'env> {
// Mark the dependency as a non-root node.
non_roots.insert(child);
// Skip dependencies that don't apply to the current environment.
if let Some(environment_markers) = markers {
if let Some(dependency_markers) = dependency.marker.as_ref() {
if !dependency_markers.evaluate(environment_markers, &[]) {
continue;
}
}
}
edges.entry(parent).or_default().push(child);
}

View file

@ -24,12 +24,12 @@ use crate::printer::Printer;
/// Display the installed packages in the current environment as a dependency tree.
#[allow(clippy::fn_params_excessive_bools)]
pub(crate) fn pip_tree(
show_version_specifiers: bool,
depth: u8,
prune: Vec<PackageName>,
package: Vec<PackageName>,
no_dedupe: bool,
invert: bool,
show_version_specifiers: bool,
strict: bool,
python: Option<&str>,
system: bool,

View file

@ -24,6 +24,7 @@ use super::SharedState;
pub(crate) async fn tree(
locked: bool,
frozen: bool,
universal: bool,
depth: u8,
prune: Vec<PackageName>,
package: Vec<PackageName>,
@ -79,7 +80,15 @@ pub(crate) async fn tree(
.await?;
// Render the tree.
let tree = TreeDisplay::new(&lock.lock, depth.into(), prune, package, no_dedupe, invert);
let tree = TreeDisplay::new(
&lock.lock,
(!universal).then(|| interpreter.markers()),
depth.into(),
prune,
package,
no_dedupe,
invert,
);
write!(printer.stdout(), "{tree}")?;

View file

@ -562,12 +562,12 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
let cache = cache.init()?;
commands::pip_tree(
args.show_version_specifiers,
args.depth,
args.prune,
args.package,
args.no_dedupe,
args.invert,
args.show_version_specifiers,
args.shared.strict,
args.shared.python.as_deref(),
args.shared.system,
@ -1121,6 +1121,7 @@ async fn run_project(
commands::tree(
args.locked,
args.frozen,
args.universal,
args.depth,
args.prune,
args.package,

View file

@ -769,6 +769,7 @@ impl RemoveSettings {
pub(crate) struct TreeSettings {
pub(crate) locked: bool,
pub(crate) frozen: bool,
pub(crate) universal: bool,
pub(crate) depth: u8,
pub(crate) prune: Vec<PackageName>,
pub(crate) package: Vec<PackageName>,
@ -783,6 +784,7 @@ impl TreeSettings {
pub(crate) fn resolve(args: TreeArgs, filesystem: Option<FilesystemOptions>) -> Self {
let TreeArgs {
tree,
universal,
locked,
frozen,
build,
@ -793,6 +795,7 @@ impl TreeSettings {
Self {
locked,
frozen,
universal,
depth: tree.depth,
prune: tree.prune,
package: tree.package,
@ -1357,12 +1360,12 @@ impl PipShowSettings {
#[allow(clippy::struct_excessive_bools)]
#[derive(Debug, Clone)]
pub(crate) struct PipTreeSettings {
pub(crate) show_version_specifiers: bool,
pub(crate) depth: u8,
pub(crate) prune: Vec<PackageName>,
pub(crate) package: Vec<PackageName>,
pub(crate) no_dedupe: bool,
pub(crate) invert: bool,
pub(crate) show_version_specifiers: bool,
// CLI-only settings.
pub(crate) shared: PipSettings,
}
@ -1371,6 +1374,7 @@ impl PipTreeSettings {
/// Resolve the [`PipTreeSettings`] from the CLI and workspace configuration.
pub(crate) fn resolve(args: PipTreeArgs, filesystem: Option<FilesystemOptions>) -> Self {
let PipTreeArgs {
show_version_specifiers,
tree,
strict,
no_strict,
@ -1381,11 +1385,11 @@ impl PipTreeSettings {
} = args;
Self {
show_version_specifiers,
depth: tree.depth,
prune: tree.prune,
no_dedupe: tree.no_dedupe,
invert: tree.invert,
show_version_specifiers: tree.show_version_specifiers,
package: tree.package,
// Shared settings.
shared: PipSettings::combine(

View file

@ -26,7 +26,7 @@ fn nested_dependencies() -> Result<()> {
"#,
)?;
uv_snapshot!(context.filters(), context.tree(), @r###"
uv_snapshot!(context.filters(), context.tree().arg("--universal"), @r###"
success: true
exit_code: 0
----- stdout -----
@ -132,7 +132,7 @@ fn frozen() -> Result<()> {
"#,
)?;
uv_snapshot!(context.filters(), context.tree(), @r###"
uv_snapshot!(context.filters(), context.tree().arg("--universal"), @r###"
success: true
exit_code: 0
----- stdout -----
@ -200,12 +200,31 @@ fn platform_dependencies() -> Result<()> {
"#,
)?;
// Should include `colorama`, even though it's only included on Windows.
// When `--universal` is _not_ provided, `colorama` should _not_ be included.
#[cfg(not(windows))]
uv_snapshot!(context.filters(), context.tree(), @r###"
success: true
exit_code: 0
----- stdout -----
project v0.1.0
black v24.3.0
click v8.1.7
mypy-extensions v1.0.0
packaging v24.0
pathspec v0.12.1
platformdirs v4.2.0
----- stderr -----
warning: `uv tree` is experimental and may change without warning
Resolved 8 packages in [TIME]
"###);
// Should include `colorama`, even though it's only included on Windows.
uv_snapshot!(context.filters(), context.tree().arg("--universal"), @r###"
success: true
exit_code: 0
----- stdout -----
project v0.1.0
black v24.3.0
click v8.1.7
colorama v0.4.6
@ -247,7 +266,7 @@ fn repeated_dependencies() -> Result<()> {
)?;
// Should include both versions of `anyio`, which have different dependencies.
uv_snapshot!(context.filters(), context.tree(), @r###"
uv_snapshot!(context.filters(), context.tree().arg("--universal"), @r###"
success: true
exit_code: 0
----- stdout -----
@ -321,7 +340,7 @@ fn repeated_version() -> Result<()> {
Url::from_file_path(context.temp_dir.join("v2")).unwrap(),
})?;
uv_snapshot!(context.filters(), context.tree(), @r###"
uv_snapshot!(context.filters(), context.tree().arg("--universal"), @r###"
success: true
exit_code: 0
----- stdout -----
@ -361,13 +380,14 @@ fn dev_dependencies() -> Result<()> {
# ...
requires-python = ">=3.12"
dependencies = ["iniconfig"]
[tool.uv]
dev-dependencies = ["anyio"]
"#,
)?;
// Dev dependencies should be omitted.
uv_snapshot!(context.filters(), context.tree(), @r###"
uv_snapshot!(context.filters(), context.tree().arg("--universal"), @r###"
success: true
exit_code: 0
----- stdout -----