Add dependents ("via ..." comments) in export command (#12350)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / lint (push) Waiting to run
CI / cargo clippy | ubuntu (push) Blocked by required conditions
CI / cargo clippy | windows (push) Blocked by required conditions
CI / cargo dev generate-all (push) Blocked by required conditions
CI / cargo shear (push) Waiting to run
CI / cargo test | ubuntu (push) Blocked by required conditions
CI / cargo test | macos (push) Blocked by required conditions
CI / cargo test | windows (push) Blocked by required conditions
CI / check windows trampoline | aarch64 (push) Blocked by required conditions
CI / check cache | macos aarch64 (push) Blocked by required conditions
CI / check windows trampoline | i686 (push) Blocked by required conditions
CI / check windows trampoline | x86_64 (push) Blocked by required conditions
CI / test windows trampoline | i686 (push) Blocked by required conditions
CI / test windows trampoline | x86_64 (push) Blocked by required conditions
CI / typos (push) Waiting to run
CI / check system | python3.12 via chocolatey (push) Blocked by required conditions
CI / mkdocs (push) Waiting to run
CI / build binary | linux libc (push) Blocked by required conditions
CI / build binary | linux musl (push) Blocked by required conditions
CI / build binary | macos aarch64 (push) Blocked by required conditions
CI / build binary | macos x86_64 (push) Blocked by required conditions
CI / build binary | windows x86_64 (push) Blocked by required conditions
CI / build binary | windows aarch64 (push) Blocked by required conditions
CI / cargo build (msrv) (push) Blocked by required conditions
CI / build binary | freebsd (push) Blocked by required conditions
CI / ecosystem test | pydantic/pydantic-core (push) Blocked by required conditions
CI / ecosystem test | prefecthq/prefect (push) Blocked by required conditions
CI / ecosystem test | pallets/flask (push) Blocked by required conditions
CI / smoke test | linux (push) Blocked by required conditions
CI / check system | alpine (push) Blocked by required conditions
CI / smoke test | macos (push) Blocked by required conditions
CI / smoke test | windows x86_64 (push) Blocked by required conditions
CI / smoke test | windows aarch64 (push) Blocked by required conditions
CI / integration test | conda on ubuntu (push) Blocked by required conditions
CI / integration test | deadsnakes python3.9 on ubuntu (push) Blocked by required conditions
CI / integration test | free-threaded on linux (push) Blocked by required conditions
CI / integration test | free-threaded on windows (push) Blocked by required conditions
CI / integration test | pypy on ubuntu (push) Blocked by required conditions
CI / integration test | pypy on windows (push) Blocked by required conditions
CI / integration test | graalpy on ubuntu (push) Blocked by required conditions
CI / integration test | graalpy on windows (push) Blocked by required conditions
CI / integration test | github actions (push) Blocked by required conditions
CI / integration test | determine publish changes (push) Blocked by required conditions
CI / integration test | uv publish (push) Blocked by required conditions
CI / integration test | uv_build (push) Blocked by required conditions
CI / check cache | ubuntu (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on fedora (push) Blocked by required conditions
CI / check system | python on ubuntu (push) Blocked by required conditions
CI / check system | python on opensuse (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | pyston (push) Blocked by required conditions
CI / check system | python on macos aarch64 (push) Blocked by required conditions
CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions
CI / check system | python on macos x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (push) Blocked by required conditions
CI / check system | python3.13 on windows x86-64 (push) Blocked by required conditions
CI / check system | x86-64 python3.13 on windows aarch64 (push) Blocked by required conditions
CI / check system | windows registry (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (push) Blocked by required conditions
CI / check system | python3.13 (push) Blocked by required conditions
CI / check system | conda3.11 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.8 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.11 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.11 on windows x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on windows x86-64 (push) Blocked by required conditions
CI / check system | amazonlinux (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows x86-64 (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions

Adding dependency trace/parent comments ("via ...") to the export
command output.
This is a similar behavior to the pip compile output.

#### Note to the eager reviewer:
First of all - thanks!  
Secondly, this is still a very rough draft. These are the first lines of
code I've ever written in Rust. This is still mostly an educational/fun
exercise for myself. If opening a Draft PR is creating too much noise -
I apologize and I will close it until it is ready.

## Summary

Resolves #7777

## Test Plan

- [X] manual command execution
- [x] update expected output in tests

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
This commit is contained in:
Zohar Meir 2025-03-28 17:37:53 +03:00 committed by GitHub
parent 2d8c8071cb
commit ab3bab1421
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 268 additions and 1 deletions

View file

@ -5,6 +5,7 @@ use std::fmt::Formatter;
use std::path::{Component, Path, PathBuf};
use either::Either;
use owo_colors::OwoColorize;
use petgraph::graph::NodeIndex;
use petgraph::prelude::EdgeRef;
use petgraph::visit::IntoNodeReferences;
@ -41,6 +42,7 @@ impl<'lock> RequirementsTxtExport<'lock> {
prune: &[PackageName],
extras: &ExtrasSpecification,
dev: &DependencyGroupsWithDefaults,
annotate: bool,
editable: EditableMode,
hashes: bool,
install_options: &'lock InstallOptions,
@ -312,6 +314,21 @@ impl<'lock> RequirementsTxtExport<'lock> {
.map(|(index, package)| Requirement {
package,
marker: reachability.remove(&index).unwrap_or_default(),
dependents: if annotate {
let mut dependents = graph
.edges_directed(index, Direction::Incoming)
.map(|edge| &graph[edge.source()])
.filter_map(|node| match node {
Node::Package(package) => Some(*package),
Node::Root => None,
})
.collect::<Vec<_>>();
dependents.sort_unstable_by_key(|package| package.name());
dependents.dedup_by_key(|package| package.name());
dependents
} else {
Vec::new()
},
})
.filter(|requirement| !requirement.marker.is_false())
.collect::<Vec<_>>();
@ -496,7 +513,12 @@ fn conflict_marker_reachability<'lock>(
impl std::fmt::Display for RequirementsTxtExport<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
// Write out each package.
for Requirement { package, marker } in &self.nodes {
for Requirement {
package,
marker,
dependents,
} in &self.nodes
{
match &package.id.source {
Source::Registry(_) => {
let version = package
@ -586,6 +608,20 @@ impl std::fmt::Display for RequirementsTxtExport<'_> {
}
writeln!(f)?;
// Add "via ..." comments for all dependents.
match dependents.as_slice() {
[] => {}
[dependent] => {
writeln!(f, "{}", format!(" # via {}", dependent.id.name).green())?;
}
_ => {
writeln!(f, "{}", " # via".green())?;
for &dependent in dependents {
writeln!(f, "{}", format!(" # {}", dependent.id.name).green())?;
}
}
}
}
Ok(())
@ -637,6 +673,7 @@ impl Reachable<MarkerTree> for Edge<'_> {
struct Requirement<'lock> {
package: &'lock Package,
marker: MarkerTree,
dependents: Vec<&'lock Package>,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]