orchestrata_tools.diagram.module_diagram

Reference › orchestrata_tools › diagram › module_diagram

This module draws a Mermaid dependency graph between modules. ModuleDiagramGenerator.generate counts each module's imports, keeps the max_modules (default 30) modules with the most imports, and draws an edge for each import of an orchestrata_ultimate package where the target, cut to its first two dotted segments, is also in the kept set. The result is a MermaidDiagram titled "Module Dependencies", defined in class_diagram. It reads from an ASTIndex.

At a glance

Source src/orchestrata_tools/diagram/module_diagram.py
Lines of code 61
Classes 1
Functions 0
Imports (internal) orchestrata_tools.diagram.class_diagram, orchestrata_tools.parser.indexer
Imported by orchestrata_tools, orchestrata_tools.diagram
Tests that import it none

Class diagram

Class diagram orchestrata_tools.diagram.module_diagram

Dependency diagram

Dependency diagram orchestrata_tools.diagram.module_diagram

API

Classes

ModuleDiagramGenerator

Line 14

Generate Mermaid diagrams showing module dependencies.

Method Signature Summary
__init__ __init__(index: ASTIndex)
generate generate(max_modules: int = 30) -> MermaidDiagram Generate a module dependency diagram.

Source

Permalink: https://gitlab.com/MSamy/orchestrata-ultimate-architecture/-/blob/a4cbc2bdf/src/orchestrata_tools/diagram/module_diagram.py

"""Generate Mermaid module dependency diagrams."""

from __future__ import annotations

from collections import defaultdict
from typing import TYPE_CHECKING

from orchestrata_tools.diagram.class_diagram import MermaidDiagram

if TYPE_CHECKING:
    from orchestrata_tools.parser.indexer import ASTIndex


class ModuleDiagramGenerator:
    """Generate Mermaid diagrams showing module dependencies."""

    def __init__(self, index: ASTIndex):
        self.index = index

    def generate(self, max_modules: int = 30) -> MermaidDiagram:
        """Generate a module dependency diagram."""
        # Count imports between modules
        module_imports: dict[str, set[str]] = defaultdict(set)
        import_counts: dict[str, int] = defaultdict(int)

        for mod in self.index.codebase.modules:
            import_counts[mod.path] = len(mod.imports)
            for imp in mod.imports:
                if imp.module.startswith("orchestrata_ultimate"):
                    # Normalize to module path
                    parts = imp.module.split(".")
                    if len(parts) >= 2:
                        target = ".".join(parts[:2])
                        module_imports[mod.path].add(target)

        # Pick top modules by import count
        top_modules = sorted(
            import_counts,
            key=lambda m: import_counts[m],
            reverse=True,
        )[:max_modules]
        top_set = set(top_modules)

        lines = ["graph TD"]
        edges = []
        for mod_path in top_modules:
            safe_name = mod_path.replace(".", "_")
            lines.append(f'    {safe_name}["{mod_path}"]')
            for target in module_imports[mod_path]:
                if target in top_set:
                    target_safe = target.replace(".", "_")
                    edges.append(f"    {safe_name} --> {target_safe}")

        lines.extend(sorted(set(edges)))
        body = "\n".join(lines)
        return MermaidDiagram(
            title="Module Dependencies",
            body=body,
            node_count=len(top_modules),
            edge_count=len(set(edges)),
        )