# rkaos/python-codebase-visualizer architecture

> Architecture diagram of the GitHub repository rkaos/python-codebase-visualizer, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-24). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/rkaos/python-codebase-visualizer
- Repository: https://github.com/rkaos/python-codebase-visualizer

## Overview

1. **Two bounded subsystems**
   - The repo is split into a **Python analysis core** (`pyviz/`) and a **browser viewer** (`viewer/`).
   - The hard boundary between them is a **static artifact**: `graph.json` (plus a run manifest). The CLI produces it; the viewer consumes it.

2. **Primary data flow**
   - A user points `pyviz analyze` at a checked-out Python repo.
   - The analyzer discovers modules, parses ASTs, resolves imports/re-exports, extracts static edges, optionally traces runtime calls in-process, merges both sources, and emits a deterministic graph snapshot.
   - The viewer loads that snapshot from a local file picker and turns it into an interactive graph.

3. **Python analysis pipeline**
   - The core is organized as a **seven-stage pipeline**:
     - `p1_discovery`: find modules/packages in the target repo
     - `p2_parse`: parse ASTs and build symbol tables / relative import context
     - `p3_resolve`: resolve re-exports and wildcard imports transitively
     - `p4_edges`: extract static relationships like imports, calls, defines, inherits, decorates
     - `p5_trace`: optional runtime tracing of executed code paths
     - `p6_merge`: combine static and runtime evidence into a unified provenance model
     - `p7_emit`: write `graph.json`
   - This pipeline is the main architectural spine of the project.

4. **Static analysis vs runtime tracing**
   - Static analysis is the default and is designed to avoid false positives.
   - Runtime tracing is an optional augmentation used when the target repo’s test suite is run in-process.
   - The runtime layer is not a separate service; it must run inside the same Python interpreter because it installs profiling/monitoring hooks.

5. **Core modeling and graph contract**
   - `pyviz/models.py` defines the shared immutable data structures used across pipeline stages.
   - The emitted graph distinguishes **nodes** and **edges**, with metadata such as kind, provenance, confidence, caveats, and source line evidence.
   - The schema is the contract between backend and frontend, and output is deterministic for the same commit.

6. **Key analysis boundary: import resolution**
   - The standout logic is **P3 re-export resolution**, which resolves symbols through `__init__.py`, wildcard exports, and cycles.
   - This is important because the tool explicitly avoids the common mistake of treating package `__init__.py` as the final definition site when a symbol is actually defined deeper in the package.
   - Related import semantics are handled with CPython-like relative import rules in parsing.

7. **Graph semantics**
   - The graph tracks multiple relationship kinds, not just calls: `imports`, `calls`, `instantiates`, `inherits`, `decorates`, and `defines`.
   - Nodes also capture semantic attributes like async status, method kind, abstractness, framework entrypoints, MRO, and whether `__all__` is dynamic.
   - When static analysis cannot prove a call target, the system intentionally leaves it unresolved rather than guessing; runtime tracing can later recover it.

8. **Command-line interface and operational modes**
   - `pyviz` exposes `analyze`, `verify`, and `diff`.
   - `verify` is a CI-oriented integrity check for graph invariants, especially the rule that imports should not point to `__init__.py` when the real definition is elsewhere.
   - `diff` is a structural comparison mode for two graph snapshots, supporting snapshot-based analysis workflows.

9. **Viewer architecture**
   - The viewer is a **Next.js + React** application using **React Flow** for graph interaction and **Dagre**-style layout calculation.
   - Its main UI boundaries are:
     - file import / landing page
     - graph canvas with progressive disclosure
     - node detail panel
     - filter bar for kind/provenance/confidence
   - The design intentionally avoids loading huge repos as one giant graph; it starts at module/package level and expands into deeper symbols on demand.

10. **Testing and fixture strategy**
   - The `fixtures/` directory contains small, purpose-built Python packages that exercise edge cases: re-export chains, cycles, decorators, dynamic `__all__`, and unresolved attribute dispatch.
   - `tests/test_p3_resolve.py` focuses on the resolver in isolation, while `tests/test_invariants.py` runs end-to-end checks over the full pipeline.
   - This is an architecture with strong contract testing: the fixtures encode the supported language behaviors, and the emitted graph is validated against them.

11. **Deployment / hosting boundary**
   - The viewer can be deployed independently, including to Vercel, because it only needs the uploaded `graph.json`.
   - There is a deferred optional hosted-persistence/auth layer referenced in the README, but it is not part of the primary architecture; the shipped system is local-first and file-based.

12. **Useful diagram framing**
   - If drawing the architecture, the clearest split is:
     - **Input repo** → **Python analysis pipeline** → **graph.json artifact** → **Next.js viewer**
   - Around that core, annotate the optional runtime-tracing path, the CI validation path (`verify` + tests), and the fixtures used to prove correctness.

Main entry points: [`pyviz/cli.py`](https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/cli.py) (pyviz CLI), [`pyviz/pipeline/p3_resolve.py`](https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/pipeline/p3_resolve.py) (Resolve), [`viewer/components/GraphView.tsx`](https://github.com/rkaos/python-codebase-visualizer/blob/main/viewer/components/GraphView.tsx) (Graph canvas), [`pyviz/pipeline/p6_merge.py`](https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/pipeline/p6_merge.py) (Merge)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_grp_pyviz["Python core"]
  node_node_cli["pyviz CLI<br/>entrypoint<br/>[cli.py]"]
  node_node_models["Models<br/>schema model<br/>[models.py]"]
  node_node_p1["Discovery<br/>pipeline stage<br/>[p1_discovery.py]"]
  node_node_p2["Parse<br/>pipeline stage<br/>[p2_parse.py]"]
  node_node_p3["Resolve<br/>pipeline stage<br/>[p3_resolve.py]"]
  node_node_p4["Edges<br/>pipeline stage<br/>[p4_edges.py]"]
  node_node_p5["Trace<br/>optional stage<br/>[p5_trace.py]"]
  node_node_p6["Merge<br/>pipeline stage<br/>[p6_merge.py]"]
  node_node_p7["Emit<br/>output stage<br/>[p7_emit.py]"]
  node_node_verify["verify<br/>ci command<br/>[cli.py]"]
  node_node_diff["diff<br/>comparison command<br/>[cli.py]"]
end

subgraph group_grp_viewer["Viewer"]
  node_node_viewer["Viewer app<br/>nextjs app<br/>[page.tsx]"]
  node_node_import["File import<br/>ui entry<br/>[page.tsx]"]
  node_node_canvas["Graph canvas<br/>graph view<br/>[GraphView.tsx]"]
  node_node_panel["Node panel<br/>detail panel<br/>[NodePanel.tsx]"]
  node_node_filters["Filter bar<br/>ui filter<br/>[FilterBar.tsx]"]
  node_node_layout["Layout<br/>[layout.ts]"]
end

subgraph group_grp_validation["Validation"]
  node_node_tests["Tests<br/>test suite<br/>[test_invariants.py]"]
  node_node_resolver_tests["Resolver tests<br/>test suite<br/>[test_p3_resolve.py]"]
  node_node_fixtures["Fixtures<br/>fixture set"]
end

node_node_input_repo["Target repo<br/>input repo"]
node_node_graph_json["graph.json<br/>artifact"]

node_node_input_repo -->|"analyze"| node_node_cli
node_node_cli -->|"start"| node_node_p1
node_node_p1 -->|"modules"| node_node_p2
node_node_p2 -->|"symbols"| node_node_p3
node_node_p3 -->|"resolved refs"| node_node_p4
node_node_p4 -->|"static evidence"| node_node_p6
node_node_p5 -->|"runtime evidence"| node_node_p6
node_node_p6 -->|"unified graph"| node_node_p7
node_node_models -->|"types"| node_node_p1
node_node_models -->|"schema"| node_node_p6
node_node_p7 -->|"writes"| node_node_graph_json
node_node_graph_json -->|"consumed by"| node_node_viewer
node_node_viewer -->|"entry"| node_node_import
node_node_import -->|"load graph"| node_node_canvas
node_node_canvas -->|"select node"| node_node_panel
node_node_canvas -->|"refine"| node_node_filters
node_node_canvas -->|"layout"| node_node_layout
node_node_cli -.->|"verify"| node_node_verify
node_node_cli -.->|"diff"| node_node_diff
node_node_tests -.->|"covers"| node_node_p3
node_node_resolver_tests -.->|"covers"| node_node_p3
node_node_fixtures -->|"inputs"| node_node_resolver_tests
node_node_fixtures -->|"inputs"| node_node_tests
node_node_p5 -.->|"optional"| node_node_cli
node_node_p3 -->|"resolution data"| node_node_models

click node_node_cli "https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/cli.py"
click node_node_models "https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/models.py"
click node_node_p1 "https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/pipeline/p1_discovery.py"
click node_node_p2 "https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/pipeline/p2_parse.py"
click node_node_p3 "https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/pipeline/p3_resolve.py"
click node_node_p4 "https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/pipeline/p4_edges.py"
click node_node_p5 "https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/pipeline/p5_trace.py"
click node_node_p6 "https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/pipeline/p6_merge.py"
click node_node_p7 "https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/pipeline/p7_emit.py"
click node_node_verify "https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/cli.py"
click node_node_diff "https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/cli.py"
click node_node_viewer "https://github.com/rkaos/python-codebase-visualizer/blob/main/viewer/app/page.tsx"
click node_node_import "https://github.com/rkaos/python-codebase-visualizer/blob/main/viewer/app/page.tsx"
click node_node_canvas "https://github.com/rkaos/python-codebase-visualizer/blob/main/viewer/components/GraphView.tsx"
click node_node_panel "https://github.com/rkaos/python-codebase-visualizer/blob/main/viewer/components/NodePanel.tsx"
click node_node_filters "https://github.com/rkaos/python-codebase-visualizer/blob/main/viewer/components/FilterBar.tsx"
click node_node_layout "https://github.com/rkaos/python-codebase-visualizer/blob/main/viewer/lib/layout.ts"
click node_node_tests "https://github.com/rkaos/python-codebase-visualizer/blob/main/tests/test_invariants.py"
click node_node_resolver_tests "https://github.com/rkaos/python-codebase-visualizer/blob/main/tests/test_p3_resolve.py"
click node_node_fixtures "https://github.com/rkaos/python-codebase-visualizer/tree/main/fixtures"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_node_cli,node_node_models,node_node_p1,node_node_p2,node_node_p3,node_node_p4,node_node_p5,node_node_p6,node_node_p7,node_node_verify,node_node_diff toneBlue
class node_node_viewer,node_node_import,node_node_canvas,node_node_panel,node_node_filters,node_node_layout toneAmber
class node_node_tests,node_node_resolver_tests,node_node_fixtures toneMint
class node_node_input_repo,node_node_graph_json toneNeutral
```

## Components

### Python core

CLI, shared models, and the analysis pipeline that produces graph.json.

- [pyviz CLI](https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/cli.py): entrypoint · Exposes analyze, verify, and diff commands. · `pyviz/cli.py`
- [Models](https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/models.py): schema model · Shared immutable data structures and graph contract. · `pyviz/models.py`
- [Discovery](https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/pipeline/p1_discovery.py): pipeline stage · Finds modules and packages in the target repository. · `pyviz/pipeline/p1_discovery.py`
- [Parse](https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/pipeline/p2_parse.py): pipeline stage · Parses ASTs and builds symbol tables and import context. · `pyviz/pipeline/p2_parse.py`
- [Resolve](https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/pipeline/p3_resolve.py): pipeline stage · Resolves re-exports, wildcard imports, and cycles transitively. · `pyviz/pipeline/p3_resolve.py`
- [Edges](https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/pipeline/p4_edges.py): pipeline stage · Extracts static imports, calls, instantiates, inherits, decorates, and defines relationships. · `pyviz/pipeline/p4_edges.py`
- [Trace](https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/pipeline/p5_trace.py): optional stage · In-process runtime tracing to recover unresolved call targets. · `pyviz/pipeline/p5_trace.py`
- [Merge](https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/pipeline/p6_merge.py): pipeline stage · Combines static and runtime evidence into a unified provenance model. · `pyviz/pipeline/p6_merge.py`
- [Emit](https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/pipeline/p7_emit.py): output stage · Writes deterministic graph.json snapshots. · `pyviz/pipeline/p7_emit.py`
- [verify](https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/cli.py): ci command · Checks graph invariants and import-resolution rules. · `pyviz/cli.py`
- [diff](https://github.com/rkaos/python-codebase-visualizer/blob/main/pyviz/cli.py): comparison command · Compares two graph snapshots structurally. · `pyviz/cli.py`

### Viewer

Next.js app that loads and explores emitted graph snapshots.

- [Viewer app](https://github.com/rkaos/python-codebase-visualizer/blob/main/viewer/app/page.tsx): nextjs app · Browser UI for exploring emitted graphs. · `viewer/app/page.tsx`
- [File import](https://github.com/rkaos/python-codebase-visualizer/blob/main/viewer/app/page.tsx): ui entry · Loads a local graph.json from the user file picker. · `viewer/app/page.tsx`
- [Graph canvas](https://github.com/rkaos/python-codebase-visualizer/blob/main/viewer/components/GraphView.tsx): graph view · Interactive graph surface with progressive disclosure. · `viewer/components/GraphView.tsx`
- [Node panel](https://github.com/rkaos/python-codebase-visualizer/blob/main/viewer/components/NodePanel.tsx): detail panel · Shows node metadata, provenance, and relationships. · `viewer/components/NodePanel.tsx`
- [Filter bar](https://github.com/rkaos/python-codebase-visualizer/blob/main/viewer/components/FilterBar.tsx): ui filter · Filters by kind, provenance, and confidence. · `viewer/components/FilterBar.tsx`
- [Layout](https://github.com/rkaos/python-codebase-visualizer/blob/main/viewer/lib/layout.ts): layout engine · Computes Dagre-style graph layout. · `viewer/lib/layout.ts`

### Validation

Tests and fixtures that exercise analysis contracts and edge cases.

- [Tests](https://github.com/rkaos/python-codebase-visualizer/blob/main/tests/test_invariants.py): test suite · End-to-end invariants and resolver-focused checks. · `tests/test_invariants.py`
- [Resolver tests](https://github.com/rkaos/python-codebase-visualizer/blob/main/tests/test_p3_resolve.py): test suite · Isolated coverage for re-export and import resolution. · `tests/test_p3_resolve.py`
- [Fixtures](https://github.com/rkaos/python-codebase-visualizer/tree/main/fixtures): fixture set · Small Python packages that encode edge cases such as cycles, decorators, and dynamic __all__. · `fixtures`

### Other components

- **Target repo**: input repo · A checked-out Python codebase analyzed by the CLI.
- **graph.json**: artifact · Static contract consumed by the viewer.

## Connections

- Target repo → pyviz CLI: analyze · User points the CLI at a target repository.
- pyviz CLI → Discovery: start · Pipeline begins with module and package discovery.
- Discovery → Parse: modules · Discovered modules are parsed into AST-backed structures.
- Parse → Resolve: symbols · Parsed symbol tables and import context feed resolution.
- Resolve → Edges: resolved refs · Resolved definitions and imports drive static edge extraction.
- Edges → Merge: static evidence · Static relationships are merged with other evidence sources.
- Trace → Merge: runtime evidence · Optional tracing augments unresolved targets and call provenance.
- Merge → Emit: unified graph · Merged model is emitted as a deterministic snapshot.
- Models → Discovery: types · Pipeline stages share the same immutable model definitions.
- Models → Merge: schema · Merged provenance and graph entities use shared data structures.
- Emit → graph.json: writes · Emitter produces the repository-local graph artifact.
- graph.json → Viewer app: consumed by · Viewer loads the artifact directly from the local file system.
- Viewer app → File import: entry · The app starts at file import or landing page.
- File import → Graph canvas: load graph · Imported snapshot is rendered into an interactive canvas.
- Graph canvas → Node panel: select node · Selecting a node reveals details and evidence.
- Graph canvas → Filter bar: refine · Filters reduce visible nodes and edges.
- Graph canvas → Layout: layout · Graph positions are computed for the visible subgraph.
- pyviz CLI → verify: verify · CI checks invariants such as import targets and definition sites.
- pyviz CLI → diff: diff · CLI can compare two emitted graph snapshots.
- Tests → Resolve: covers · End-to-end tests validate the resolver and graph contracts.
- Resolver tests → Resolve: covers · Focused tests exercise re-export resolution behavior.
- Fixtures → Resolver tests: inputs · Purpose-built packages drive edge-case resolver scenarios.
- Fixtures → Tests: inputs · Fixtures support invariants and pipeline integration checks.
- Trace → pyviz CLI: optional · Tracing runs in-process as part of analysis, not as a separate service.
- Resolve → Models: resolution data · Resolved symbols are represented through shared graph models.
