mafw.devtools.dependencies.compare

Dependency comparison engine for MAFw lockfiles.

This module provides data models and rendering functions for comparing dependency lockfiles across Python versions. It supports JSON, markdown, and Rich terminal output formats.

Module Attributes

EXTENSION_FORMAT_MAP

Mapping from recognized file extensions to output format identifiers.

Functions

compare_packages(latest_packages, ...)

Compare two package dictionaries and classify differences.

render_comparison_json(results)

Render comparison results as a JSON document string.

render_comparison_markdown(results)

Render comparison results as a markdown document string.

render_comparison_rich(results, console)

Render comparison results to the terminal using Rich panels and tables.

resolve_output_format(explicit_format, ...)

Determine the effective output format based on CLI arguments.

Classes

PackageChange(package_name, change_type, ...)

A single dependency change between reference and latest lockfiles.

VersionComparisonResult(python_version, changes)

Comparison result for a single Python version.

class mafw.devtools.dependencies.compare.PackageChange(package_name: str, change_type: Literal['ADDED', 'REMOVED', 'UPDATED'], reference_version: str | None, new_version: str | None)[source]

Bases: object

A single dependency change between reference and latest lockfiles.

Each instance represents one package that was added, removed, or updated between the reference and the latest resolved dependency set.

Parameters:
  • package_name – Normalized (lowercase) package name.

  • change_type – Classification of the change (ADDED, REMOVED, UPDATED).

  • reference_version – Version in the reference file, None for ADDED entries.

  • new_version – Version in the latest file, None for REMOVED entries.

class mafw.devtools.dependencies.compare.VersionComparisonResult(python_version: str, changes: list[~mafw.devtools.dependencies.compare.PackageChange] = <factory>)[source]

Bases: object

Comparison result for a single Python version.

Holds all detected dependency changes for a given Python interpreter version.

Parameters:
  • python_version – Python version string (e.g. "3.12").

  • changes – Sorted list of package changes for this version.

property has_changes: bool

Return True if there is at least one dependency change.

mafw.devtools.dependencies.compare.compare_packages(latest_packages: dict[str, dict[str, Any]], reference_packages: dict[str, dict[str, Any]]) list[PackageChange][source]

Compare two package dictionaries and classify differences.

Both dictionaries are expected to be keyed by lowercase package name. The function classifies each difference into one of three categories:

  • ADDED: package present in latest but absent from reference.

  • REMOVED: package present in reference but absent from latest.

  • UPDATED: package present in both but with a different version or marker.

Parameters:
  • latest_packages (dict[str, dict[str, Any]]) – Packages from the freshly compiled lockfile, keyed by lowercase name.

  • reference_packages (dict[str, dict[str, Any]]) – Packages from the reference lockfile, keyed by lowercase name.

Returns:

List of PackageChange entries sorted alphabetically by package name.

Return type:

list[PackageChange]

mafw.devtools.dependencies.compare.render_comparison_json(results: list[VersionComparisonResult]) str[source]

Render comparison results as a JSON document string.

Produces a JSON object with:

  • timestamp: ISO 8601 generation time.

  • python_versions: ordered list of all Python versions tested.

  • results: dictionary keyed by Python version, each value being a list of change entries (empty list when no differences exist for that version).

Each change entry contains package_name, change_type, reference_version (null for ADDED), and new_version (null for REMOVED).

Parameters:

results (list[VersionComparisonResult]) – Comparison results for each Python version.

Returns:

Formatted JSON string with 2-space indentation.

Return type:

str

mafw.devtools.dependencies.compare.render_comparison_markdown(results: list[VersionComparisonResult]) str[source]

Render comparison results as a markdown document string.

Produces a structured markdown report with a title, an ISO 8601 timestamp, and per-version sections containing ADDED, REMOVED, and UPDATED tables. Versions with no dependency changes are omitted from the output.

Parameters:

results (list[VersionComparisonResult]) – List of comparison results, one per Python version.

Returns:

Complete markdown document as a string.

Return type:

str

mafw.devtools.dependencies.compare.render_comparison_rich(results: list[VersionComparisonResult], console: Console) None[source]

Render comparison results to the terminal using Rich panels and tables.

Displays a title panel, followed by a section per Python version containing ADDED, REMOVED, and UPDATED subsections in that fixed order. Within each subsection, entries are sorted alphabetically by package name.

When no changes are detected across all Python versions, a single informational message is printed instead.

Parameters:
  • results (list[VersionComparisonResult]) – Comparison results for each Python version.

  • console (Console) – Rich Console instance for output.

mafw.devtools.dependencies.compare.resolve_output_format(explicit_format: str | None, output_file: Path | None) str[source]

Determine the effective output format based on CLI arguments.

The resolution follows a priority order that avoids ambiguity between an explicitly requested format and the file extension of the output path:

  1. If output_file has a recognized extension and explicit_format is set:

    • Match (e.g., json + .json): return the format.

    • Conflict (e.g., json + .md): raise click.UsageError.

  2. If output_file has a recognized extension and explicit_format is None: infer the format from the extension.

  3. If output_file has an unrecognized extension and explicit_format is set: return the explicit format.

  4. Otherwise: return "markdown" as the default.

Parameters:
  • explicit_format (str | None) – The value of --format if explicitly provided by the user, or None when omitted.

  • output_file (Path | None) – The value of --output-file, or None when omitted.

Returns:

The resolved format string ("markdown" or "json").

Return type:

str

Raises:

click.UsageError – When explicit_format conflicts with the format inferred from the file extension.

mafw.devtools.dependencies.compare.EXTENSION_FORMAT_MAP: dict[str, str] = {'.json': 'json', '.md': 'markdown'}

Mapping from recognized file extensions to output format identifiers.