Skip to main content

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, plus the statements that change data without a call (df['c'] = ..., x = df[mask], loops that update a frame), 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)

Resuming a history: calling init_jupyter/init_marimo again with the same history_name (and the same db_path) resumes the prior history by default — your kernel restarted, but the analysis lineage picks up where it left off. Pass fresh=True to force a brand-new history instead. Calling with no history_name always starts fresh, unaffected by this. Note this isn't safe across two kernels running concurrently against the same db_path + history_name — they'd race on whose writes "win".

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.

Metadata

Release files for pmprov 0.8.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pmprov 0.8.0
File Size Uploaded Provenance Actions
pmprov-0.8.0.tar.gz 90.0 kB Without provenance Details for pmprov-0.8.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for pmprov 0.8.0
File Interpreter ABI Platform Actions
pmprov-0.8.0-py3-none-any.whl Python 3 none any Details for pmprov-0.8.0-py3-none-any.whl

Total release size: 191.6 kB

Release files / pmprov-0.8.0.tar.gz

Download URL pmprov-0.8.0.tar.gz
Size 90.0 kB
Tags Source
SHA-256 checksum
How to use checksums
f559af16608aa92cea2939d9118cad5ba821d45bcaf2fb4b32a09ba736eeed57
BLAKE2b-256 checksum
How to use checksums
0a0c7b65c5cd1b320e9edea9728c01913f05e64eaf7239d152e6d116be5f44f3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","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}

Release files / pmprov-0.8.0-py3-none-any.whl

Download URL pmprov-0.8.0-py3-none-any.whl
Size 101.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
02dc5be6685200de31baa7b79fdad4b10a3e698944d35eb6e14ac5d7f33269dd
BLAKE2b-256 checksum
How to use checksums
651dfc5d7e13d130a54358d2cbe84f717e639b2cf04a6c23f7879897717110cf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","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}

Security for pmprov 0.8.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page