Skip to main content

Storybook-like visual testing for Python, powered by Streamlit

Project description

Historybook: Storybook-like inspection for Python pipelines

image PyPI - Downloads image image

Storybook for Python. Inspect every pipeline in your project on a single page.

Historybook is a thin Streamlit app that walks your repo, finds all history files, and aggregates them behind a searchable sidebar menu. Each "history" is just a function you decorate — when the user picks it from the menu, Historybook runs the function and renders whatever Streamlit output it produces.

Why

Visual testing for backend pipelines without spinning up an API server and a JS frontend. If you just want to poke at a pipeline — step through stages, swap inputs, see intermediate outputs — a full web stack is overkill. Write a function, decorate it, run historybook.

Good fits:

  • Step-by-step visualisation of multi-stage pipelines (OCR, ETL, ML inference, data cleaning).
  • Inspecting intermediate artefacts (images, DataFrames, JSON) during development.
  • Demoing internal tools to teammates without deploying anything.

Install

pip install historybook          # or: uv add --dev historybook

Historybook is a development tool, so prefer uv add --dev (or pip install into a dev-only env) — there's no reason to ship it as a runtime dependency.

Quick start

1. Add [tool.historybook] to your pyproject.toml:

[tool.historybook]
roots = ["."]                    # directories to scan (relative to pyproject.toml)

[tool.historybook.theme]
primaryColor = "#2563eb"         # optional

2. Write a history file. Any file matching *_histories.py or *.histories.py anywhere under roots is auto-discovered.

# src/myproject/ocr.histories.py
import streamlit as st
from historybook import component, history

@component("OCR Pipeline", tags=["ocr"])
class OcrPipeline:
    @history("Single Page")
    def single_page(self):
        st.image("samples/page1.png")
        st.json({"confidence": 0.97, "lang": "en"})

    @history("Multi Page")
    def multi_page(self):
        for i in range(3):
            st.image(f"samples/page{i}.png")

3. Launch the app from anywhere inside the repo:

historybook

A Streamlit page opens with a sidebar grouped by tag → component → history. Type in the search box to filter; click any history to run it in the main pane.

Discovery rules

  • Historybook walks up from the cwd to find pyproject.toml, then scans each directory listed in [tool.historybook].roots.
  • It rglobs for *_histories.py and *.histories.py.
  • Optional per-project setup lives in .historybook/main.py (like Storybook's .storybook/main.ts). It runs once in the parent process before Streamlit starts — good for setting env vars that Streamlit must inherit.

Pipeline diagram component

Historybook ships with a Mermaid-based pipeline diagram helper with live status updates — useful for visualising DAGs while they execute.

import streamlit as st
from historybook import component, history
from historybook.components import pipeline_diagram

@component("Document Pipeline", tags=["ocr"])
class DocPipeline:
    @history("Linear flow")
    def linear(self):
        diagram = pipeline_diagram(
            steps=["Input", "Rotate", "X-Cut", "Y-Cut", "Output"],
            statuses={"Input": "done", "Rotate": "running"},
        )
        if st.button("Next step"):
            diagram.update({"Input": "done", "Rotate": "done", "X-Cut": "running"})

    @history("DAG with parallel paths")
    def dag(self):
        pipeline_diagram(
            edges=[
                ("Input", "Rotate"),
                ("Rotate", "X-Cut"),
                ("X-Cut", "Y-Cut Page 1"),
                ("X-Cut", "Y-Cut Page 2"),
                ("Y-Cut Page 1", "Grade"),
                ("Y-Cut Page 2", "Grade"),
            ],
            statuses={"Input": "done", "Rotate": "running"},
            icons={"Input": "📄", "Grade": "🎯"},
            direction="LR",      # or "TD"
        )

Statuses: "waiting" (default), "running" (pulsing blue), "done" (green with ✓), "error" (red with ✗). Running edges get an animated dashed stroke. Call diagram.update(new_statuses) to re-render in place.

Excluding history files from other tools

History files are executed by Historybook, not imported by your app — so they're usually noise for linters, type checkers, test runners, and package builds. Suggested pyproject.toml snippets:

# pytest — skip collection (including --doctest-modules)
[tool.pytest.ini_options]
addopts = "--ignore-glob=**/*_histories.py --ignore-glob=**/*.histories.py"

# pyright / basedpyright — skip type checking
[tool.pyright]
ignore = ["**/*_histories.py", "**/*.histories.py"]

# ruff — skip linting
[tool.ruff]
extend-exclude = ["**/*_histories.py", "**/*.histories.py"]

# hatchling — don't ship history files in the wheel/sdist
[tool.hatch.build]
exclude = ["**/*_histories.py", "**/*.histories.py"]

Notes:

  • pytest: --ignore-glob is the canonical escape hatch; for finer control, use collect_ignore_glob in a conftest.py.
  • pyright: prefer ignore over excludeexclude replaces pyright's default exclude list (node_modules, __pycache__, etc.), ignore adds to it.
  • ruff: extend-exclude preserves ruff's defaults (.git, .venv, …); plain exclude replaces them.
  • hatchling: patterns are gitignore-style. If you set packages/include explicitly, also exclude there.

API reference

from historybook import component, history
  • @component(name: str, *, tags: list[str] | None = None) — class decorator. Registers the class as a component grouped under the given tag(s) in the sidebar.
  • @history(name: str) — method decorator. Marks a method on a @component class as a selectable history. The method takes self only and renders with Streamlit calls.
from historybook.components import pipeline_diagram
  • pipeline_diagram(*, steps=..., edges=..., statuses=..., icons=..., direction="LR", height=150) — Mermaid flowchart. Pass steps (linear) or edges (DAG), not both. Returns a PipelineDiagram with an update(statuses) method.

CLI

historybook                      # run from anywhere inside the repo
historybook --root path/to/dir   # override the scan root

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

historybook-0.0.1.tar.gz (14.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

historybook-0.0.1-py3-none-any.whl (15.3 kB view details)

Uploaded Python 3

File details

Details for the file historybook-0.0.1.tar.gz.

File metadata

  • Download URL: historybook-0.0.1.tar.gz
  • Upload date:
  • Size: 14.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for historybook-0.0.1.tar.gz
Algorithm Hash digest
SHA256 652f706b419fccc649e7b437b561c7967550b779ccb4f8a57ec3ab4883aa81f2
MD5 c2315d9096268290ec03c29ddf7fba11
BLAKE2b-256 f30653c60de769bdb347e2bde2cf97cd548c01b156c8284dc2821260697957e6

See more details on using hashes here.

File details

Details for the file historybook-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: historybook-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 15.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for historybook-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a7db9ea80c5ad5de7699d092b5c6f774f735b6c9949ce270734363d4e82109cf
MD5 973c7d7c8ed92285a144c1fd9150127b
BLAKE2b-256 9657009a4dd31bdc1f19e8b57f7e983e6c61a312fba2fee0a43076334dd82d18

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page