Skip to content

Architecture

Project layout

pandera_ui/
  scanner.py            # Entry point: walks project, dispatches per file
  _extract_runtime.py   # Pass 1: dynamic import + introspection
  _extract_ast.py       # Pass 2: static AST parse (fallback)
  models.py             # Pydantic models: SchemaMetadata, ColumnMetadata, …
  server.py             # FastAPI: GET /api/schemas, GET /api/coverage, GET /
  cli.py                # Typer CLI entry point
  _console.py           # Optional rich output (spinner, summary table)
  _export.py            # Markdown and HTML renderers
  _coverage.py          # Documentation coverage calculator
frontend/
  index.html            # Single-page UI (vanilla JS, no build step)
  demo-data.json        # Pre-generated schema data for the live demo

Two-pass extraction

Schema discovery is the core of pandera-ui. Each .py file is processed in two passes:

.py file
┌─────────────────────────────┐
│  Pass 1: Runtime import     │  importlib.util.spec_from_file_location
│  • Full accuracy            │  → exec_module()
│  • Handles dynamic schemas  │  → inspect module attributes
│  • May fail (missing deps)  │
└─────────────┬───────────────┘
              │ success → SchemaMetadata (metadata_source="runtime")
              │ failure ↓
┌─────────────────────────────┐
│  Pass 2: AST fallback       │  ast.parse()
│  • No import side effects   │  → walk Call nodes
│  • Static literals only     │  → extract keyword arguments
│  • Always safe              │
└─────────────────────────────┘
         SchemaMetadata (metadata_source="ast")

When AST fallback is used

  • The file imports a library that isn't installed (e.g., a database connector)
  • Module-level code opens a network connection or reads a file
  • A circular import prevents loading

AST-extracted schemas get an AST badge in the UI so users know the extraction was incomplete.

What AST can and cannot extract

Can extract: string/int/float/bool literals, list/dict literals, simple attribute access (pa.Column, pa.Check.greater_than).

Cannot extract: values computed at runtime — function return values, variable references, f-strings, comprehensions.


Schema detection

A module attribute is recognized as a Pandera schema if it is:

  • An instance of pa.DataFrameSchema, or
  • A subclass of pa.DataFrameModel (i.e. issubclass(obj, pa.DataFrameModel) and obj is not pa.DataFrameModel)

Frontend

The UI is a single vanilla JS file — no framework, no build step. It fetches /api/schemas on load and renders the schema list client-side.

This keeps the package footprint small: the only runtime dependencies are FastAPI, uvicorn, typer, pydantic, pandera, numpy, and pandas.


Server state

The FastAPI app holds schemas in a module-level _schemas list. load_schemas(path) rescans the directory and replaces the list. In --watch mode, the watchdog handler calls load_schemas() on every .py file change — the in-memory state is updated atomically (GIL protects the list reassignment), and the next request to /api/schemas sees fresh data.


Optional dependencies

Extra Packages What it enables
rich rich>=13 Terminal spinner + summary table
watch watchdog>=3 --watch live-reload flag