diff --git a/crates/uv-resolver/src/lock/tree.rs b/crates/uv-resolver/src/lock/tree.rs index 71d8c3a49..f3b273cfa 100644 --- a/crates/uv-resolver/src/lock/tree.rs +++ b/crates/uv-resolver/src/lock/tree.rs @@ -27,7 +27,7 @@ pub struct TreeDisplay<'env> { /// Prune the given packages from the display of the dependency tree. prune: Vec, /// Display only the specified packages. - package: Vec, + packages: Vec, /// Whether to de-duplicate the displayed dependencies. no_dedupe: bool, } @@ -39,7 +39,7 @@ impl<'env> TreeDisplay<'env> { markers: Option<&'env ResolverMarkerEnvironment>, depth: usize, prune: Vec, - package: Vec, + packages: Vec, no_dedupe: bool, invert: bool, ) -> Self { @@ -51,16 +51,27 @@ impl<'env> TreeDisplay<'env> { let mut optional_dependencies: FxHashMap<_, FxHashMap<_, Vec<_>>> = FxHashMap::default(); let mut dev_dependencies: FxHashMap<_, FxHashMap<_, Vec<_>>> = FxHashMap::default(); - for packages in &lock.packages { - for dependency in &packages.dependencies { + for package in &lock.packages { + for dependency in &package.dependencies { + // Skip dependencies that don't apply to the current environment. + if let Some(environment_markers) = markers { + if !dependency + .complexified_marker + .evaluate(environment_markers, &[]) + { + non_roots.insert(dependency.package_id.clone()); + continue; + } + } + let parent = if invert { &dependency.package_id } else { - &packages.id + &package.id }; let child = if invert { Cow::Owned(Dependency { - package_id: packages.id.clone(), + package_id: package.id.clone(), extra: dependency.extra.clone(), simplified_marker: dependency.simplified_marker.clone(), complexified_marker: dependency.complexified_marker.clone(), @@ -71,29 +82,30 @@ impl<'env> TreeDisplay<'env> { non_roots.insert(child.package_id.clone()); - // Skip dependencies that don't apply to the current environment. - if let Some(environment_markers) = markers { - if !dependency - .complexified_marker - .evaluate(environment_markers, &[]) - { - continue; - } - } - dependencies.entry(parent).or_default().push(child); } - for (extra, dependencies) in &packages.optional_dependencies { + for (extra, dependencies) in &package.optional_dependencies { for dependency in dependencies { + // Skip dependencies that don't apply to the current environment. + if let Some(environment_markers) = markers { + if !dependency + .complexified_marker + .evaluate(environment_markers, &[]) + { + non_roots.insert(dependency.package_id.clone()); + continue; + } + } + let parent = if invert { &dependency.package_id } else { - &packages.id + &package.id }; let child = if invert { Cow::Owned(Dependency { - package_id: packages.id.clone(), + package_id: package.id.clone(), extra: dependency.extra.clone(), simplified_marker: dependency.simplified_marker.clone(), complexified_marker: dependency.complexified_marker.clone(), @@ -104,16 +116,6 @@ impl<'env> TreeDisplay<'env> { non_roots.insert(child.package_id.clone()); - // Skip dependencies that don't apply to the current environment. - if let Some(environment_markers) = markers { - if !dependency - .complexified_marker - .evaluate(environment_markers, &[]) - { - continue; - } - } - optional_dependencies .entry(parent) .or_default() @@ -123,16 +125,27 @@ impl<'env> TreeDisplay<'env> { } } - for (group, dependencies) in &packages.dev_dependencies { + for (group, dependencies) in &package.dev_dependencies { for dependency in dependencies { + // Skip dependencies that don't apply to the current environment. + if let Some(environment_markers) = markers { + if !dependency + .complexified_marker + .evaluate(environment_markers, &[]) + { + non_roots.insert(dependency.package_id.clone()); + continue; + } + } + let parent = if invert { &dependency.package_id } else { - &packages.id + &package.id }; let child = if invert { Cow::Owned(Dependency { - package_id: packages.id.clone(), + package_id: package.id.clone(), extra: dependency.extra.clone(), simplified_marker: dependency.simplified_marker.clone(), complexified_marker: dependency.complexified_marker.clone(), @@ -143,16 +156,6 @@ impl<'env> TreeDisplay<'env> { non_roots.insert(child.package_id.clone()); - // Skip dependencies that don't apply to the current environment. - if let Some(environment_markers) = markers { - if !dependency - .complexified_marker - .evaluate(environment_markers, &[]) - { - continue; - } - } - dev_dependencies .entry(parent) .or_default() @@ -178,7 +181,7 @@ impl<'env> TreeDisplay<'env> { dev_dependencies, depth, prune, - package, + packages, no_dedupe, } } @@ -309,7 +312,7 @@ impl<'env> TreeDisplay<'env> { let mut path = Vec::new(); let mut lines = Vec::new(); - if self.package.is_empty() { + if self.packages.is_empty() { for id in &self.roots { path.clear(); lines.extend(self.visit(Node::Root(id), &mut visited, &mut path)); @@ -317,7 +320,7 @@ impl<'env> TreeDisplay<'env> { } else { let by_package: FxHashMap<_, _> = self.roots.iter().map(|id| (&id.name, id)).collect(); let mut first = true; - for package in &self.package { + for package in &self.packages { if std::mem::take(&mut first) { lines.push(String::new()); } diff --git a/crates/uv/tests/tree.rs b/crates/uv/tests/tree.rs index 3f33ace8d..4f1ec75c9 100644 --- a/crates/uv/tests/tree.rs +++ b/crates/uv/tests/tree.rs @@ -258,6 +258,52 @@ fn platform_dependencies() -> Result<()> { Ok(()) } +#[test] +fn platform_dependencies_inverted() -> Result<()> { + let context = TestContext::new("3.12"); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str( + r#" + [project] + name = "project" + version = "0.1.0" + requires-python = ">=3.12" + dependencies = [ + "click" + ] + "#, + )?; + + // When `--universal` is _not_ provided, `colorama` should _not_ be included. + #[cfg(not(windows))] + uv_snapshot!(context.filters(), context.tree().arg("--invert"), @r#" + success: true + exit_code: 0 + ----- stdout ----- + click v8.1.7 + └── project v0.1.0 + + ----- stderr ----- + Resolved 3 packages in [TIME] + "#); + + // Unless `--python-platform` is set to `windows`, in which case it should be included. + uv_snapshot!(context.filters(), context.tree().arg("--invert").arg("--python-platform").arg("windows"), @r#" + success: true + exit_code: 0 + ----- stdout ----- + colorama v0.4.6 + └── click v8.1.7 + └── project v0.1.0 + + ----- stderr ----- + Resolved 3 packages in [TIME] + "#); + + Ok(()) +} + #[test] fn repeated_dependencies() -> Result<()> { let context = TestContext::new("3.12");