meta_package_manager.summary module¶

End-of-run summary printing for mpm subcommands.

Every long-running subcommand (installed, outdated, search, dump, sbom) closes with a one-line summary written to stderr:

223 packages total (brew: 223).

Plus optional follow-up lines specific to that subcommand (the SBOM writer surfaces upstream-document merge counts and dependency-graph edge counts here). The whole summary is gated by the global --summary/--no-summary flag and respects the user’s choice across every subcommand uniformly.

Vocabulary note: “summary” describes the rendered text that lands on stderr. “Stats” describes the raw numbers fed into it (meta_package_manager.sbom.base.SBOM.stats() returns a dict of counts). The two terms stay distinct deliberately: the flag/module/function name reflects what the user sees; the data-side method keeps the unambiguous stats name.

This module is the single home of the summary contract:

The renderer stays in this module rather than scattered across each subcommand so the visual format is unique and obvious to find. The adapters live here too because their job is to translate subcommand-native shapes into the print contract, which is also summary-domain logic.

meta_package_manager.summary.print_summary(counts, notes=())[source]¶

Print a one-line per-category count to stderr, plus optional follow-up notes.

counts is a collections.Counter keyed by an opaque category label. The label is usually a package manager id, but the dump --brewfile subcommand uses Brewfile entry types and any future caller is free to use whatever bucket makes sense. The parameter is named counts rather than manager_stats to avoid lying about the key’s meaning.

Prints something like:

10 packages total (brew: 2, pip: 2, gem: 2, vscode: 2, npm: 2, composer: 0).

notes is an iterable of follow-up lines printed verbatim under the count line. mpm sbom uses it to surface facts that don’t fit the per-category-Counter shape: number of upstream SBOM documents merged into the aggregate, enrichment ratios, dependency-graph edge counts. Other subcommands today pass no notes; the count line is enough.

Always writes to stderr so the call site is free to pipe stdout elsewhere (a generated SBOM document, a TOML manifest, a Brewfile) without the summary polluting the output. Gated upstream by the global --summary/--no-summary flag; this function itself is unconditional once called.

Return type:

None

meta_package_manager.summary.package_counts(payload)[source]¶

Build a per-manager Counter from a typical subcommand payload.

installed, outdated, and search all stash their results in a {manager_id: {"packages": [...]}} dict. This helper turns that into the count-by-manager-id Counter that print_summary() accepts, eliminating the Counter({k: len(v["packages"]) for k, v in payload.items()}) boilerplate that appeared verbatim at three CLI call sites.

Mismatched payloads (an extractor that stashes packages under a different key, the dump --brewfile line-counter pass) build their Counter inline rather than wedging this helper into serving every shape.

Return type:

Counter[str]

meta_package_manager.summary.sbom_summary(sbom, bundled)[source]¶

Adapt meta_package_manager.sbom.base.SBOM.stats() to the print_summary() shape.

SBOM stats live on the renderer because the renderer knows what actually landed in the document (after dedup, after merge). This adapter flattens that structured dict into the count-line + follow-up-notes shape print_summary() consumes, conditioning each note on what the run actually did so --minimal scans, casks-only runs, and formats without a merge concept all stay tidy.

The function lives in this module (rather than next to the SBOM renderers) because its job is translating between two different data shapes: SBOM stats on one side, the print contract on the other. Summary-domain glue, not SBOM-domain logic.

Return type:

tuple[Counter, list[str]]