Skip to main content

Analytic provenance tracking middleware for exploratory process mining.

Project description

pmprov

Ask DeepWiki

Analytic provenance tracking middleware for exploratory process mining notebooks.

pmprov automatically records every meaningful decision an analyst makes during a Jupyter or Marimo session — which functions were called, with what arguments, on which data, and how the data changed — without requiring any modification to analyst code.


How it works

Your cell code  →  AST rewriter  →  trace_step()  →  DuckDB/SQLite + Parquet
                   (transparent)     (non-blocking)

Every top-level function call is intercepted at the AST level, wrapped with a lightweight tracer, and recorded as a node in a provenance tree. The analyst's variables contain exactly the same values they would without the middleware.


Getting started

Prerequisites: Python ≥ 3.13, uv

git clone https://github.com/alvarobernal2412/pmprov.git
cd pmprov
uv pip install -e ".[full]"

In a Jupyter notebook:

from tracker import init_jupyter, operation_type
import pandas as pd
import pm4py

# Register semantic labels for third-party functions (optional but recommended)
operation_type("data_loading",      pd.read_csv)
operation_type("process_discovery", pm4py.discover_petri_net_inductive)

# Start tracking — one call, no other changes to your code
rt = init_jupyter(history_name="My analysis")

# Your normal analysis code below — provenance is captured automatically
event_log = pd.read_csv("data/log.csv", parse_dates=["time:timestamp"])
net, im, fm = pm4py.discover_petri_net_inductive(event_log)

In a Marimo notebook:

Marimo support requires a one-time setup step. The middleware patches Marimo's AST compiler at Python startup via sitecustomize.py, which must be placed in your virtual environment (already in place if installed via uv).

Structural requirement: Marimo's reactive DAG is built from the original cell code before the AST rewriter runs. This means the rewriter cannot inject dependency edges automatically. To guarantee that init_marimo() runs before any tracked cell, combine your path setup and init_marimo() call in one cell and export all imports (pd, constants, etc.) from it. Downstream cells then depend on those names naturally, which implicitly orders them after init — no need to add rt to every cell's parameters.

# ── Setup + init (one cell) ───────────────────────────────────────────────────
@app.cell
def _():
    import sys, pandas as pd
    from pathlib import Path
    from tracker import init_marimo, operation_type

    # ... path setup ...

    rt = init_marimo(history_name="My analysis")
    operation_type("data_loading", pd.read_csv)

    def settle():
        rt.storage._executor.submit(lambda: None).result()

    return pd, rt, settle, DATA_FILE  # export everything downstream cells need


# ── Analysis cells — no `rt` needed in params ─────────────────────────────────
@app.cell
def _(DATA_FILE, pd):          # depends on pd + DATA_FILE → init already ran
    event_log = pd.read_csv(DATA_FILE, parse_dates=["time:timestamp"])
    return (event_log,)

Run with:

uv run marimo run examples/marimo/provenance_demo.py
# or for interactive editing:
uv run marimo edit examples/marimo/provenance_demo.py

Note: Provenance capture works in Marimo. Some introspection features (interactive widget, manual checkout) are not yet validated in the Marimo environment.

Inspect the provenance graph:

rt.list_states()           # table of all recorded steps
rt.show_graph()            # static matplotlib tree
rt.show_graph_widget()     # interactive Jupyter widget (Jupyter only)

Branch from a past state:

branch = rt.checkout("paste-state-id-here", branch_name="experiment-v2")

See examples/jupyter/provenance_demo.ipynb for a full Jupyter walkthrough and examples/marimo/provenance_demo.py for the Marimo equivalent, both using the RTFM dataset.


Optional extras

Extra What it adds
duckdb DuckDB storage backend (preferred)
parquet DataFrame artifact persistence via pyarrow
graph show_graph() via networkx + matplotlib
widgets show_graph_widget() interactive panel
marimo Marimo notebook support
full Everything above
uv pip install -e ".[full]"

Project structure

models/    Pydantic v2 domain models (provenance entities)
tracker/   Runtime middleware (AST rewriter, tracer, storage)
examples/  Demo notebook + RTFM dataset helpers

Running tests

uv sync --all-extras --dev
uv run pytest

Git hooks (optional)

Enforces the test suite and conventional commit format (≤ 45 chars) on every commit:

uv run pre-commit install && uv run pre-commit install --hook-type commit-msg

Skip this step if you prefer to run checks manually.


Contributing

See CONTRIBUTING.md.

License

Apache 2.0 — see LICENSE.

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

pmprov-0.1.0.tar.gz (51.6 kB view details)

Uploaded Source

Built Distribution

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

pmprov-0.1.0-py3-none-any.whl (58.5 kB view details)

Uploaded Python 3

File details

Details for the file pmprov-0.1.0.tar.gz.

File metadata

  • Download URL: pmprov-0.1.0.tar.gz
  • Upload date:
  • Size: 51.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.25 {"installer":{"name":"uv","version":"0.11.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pmprov-0.1.0.tar.gz
Algorithm Hash digest
SHA256 0356babaa0adae850dc53befb8a3b49e529eb5cbfff93c5e9c635360b4a83946
MD5 a204a8708582574fc39cc6dbbadfc0b2
BLAKE2b-256 ace2a2722d2dee3d351d1f3f2c63635d7e7cb5ddf8a6782e8b8a16c19c87fc76

See more details on using hashes here.

File details

Details for the file pmprov-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pmprov-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 58.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.25 {"installer":{"name":"uv","version":"0.11.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pmprov-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f9da7b3e94cdc3ffda5d8c0b491d55a043251ae644322fcc553faaac162d341a
MD5 d42e8cb7f456e3985c08c5e807370b54
BLAKE2b-256 4a9c21fadc431e7d9160885b6a0f4c43ba22a993d31afdd682fcdd8c5bc1d143

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