Skip to main content

pylier

Decorate your functions. Watch the pipeline that actually ran appear.

pylier infers data handoffs at runtime and renders an interactive graph of the pipeline that actually executed — no graph DSL, no manual edge wiring, no tracing framework to adopt. Watch it live while the pipeline runs, or export a standalone HTML file to share.

Python 3.12+ pylier GitHub stars No graph DSL No tracing framework

pylier Application Flow view showing nested fulfillment branches pylier Data Flow view showing value provenance across fulfillment branches

Application Flow

  • Direct argument, return, and exception handoffs between callers and callees.
  • Use it to understand how the application executes.

Data Flow

  • Producer-to-consumer value provenance.
  • Links each returned value directly to every decorated consumer.
  • Use it to understand where data goes and what moves through the pipeline.

Why pylier?

Pipeline diagrams rot the moment code changes. DAG frameworks want you to rewrite your code as a graph. pylier does neither: it reads the handoffs your code already performs and renders them.

Decorate, don't rebuild

Mark ordinary sync or async functions with @pylier.node. Your application code remains the pipeline.

Follow real data

Edges are inferred from the values passed between stages, so the graph reflects execution instead of a hand-maintained diagram.

Watch it live

Open a live in-process viewer that streams the graph as work happens; export a self-contained HTML file when you need to share.

How it compares

pylier Prefect / Dagster graphviz / diagrams OpenTelemetry
What it shows Data flow that actually ran Scheduler DAG of declared tasks Hand-drawn diagram Span tree of call timing
Edges Inferred at runtime Declared in code Drawn by hand Inferred, but per-call timing
Adopt it @pylier.node decorator Adopt a scheduler + rewrite as tasks Re-render on every change Instrument with a backend + storage
Output Live in-process viewer (+ portable HTML for sharing) A server / orchestrator Static image A telemetry backend
Data provenance Yes, per value fingerprint No (task I/O only) No No
Runtime cost Optional, level-gated Always-on scheduler None Always-on export

pylier is not a replacement for a scheduler or an observability backend — it's the thing you reach for when you want to see a pipeline, not run or monitor one.

Try demos

Quick start: document ingestion

#! uv add pylier
import pylier


@pylier.node
def embed(chunks: list[str]) -> list[dict]: ...


with pylier.trace("ingest"):
    embed(load("report.pdf"))

pylier.serve()  # live viewer at http://localhost:8765

The ingestion example is the fastest way to see pylier's value: a document branches into text and image paths, then concurrently embeds both branches before they converge at an indexing stage.

git clone https://github.com/theMladyPan/pylier.git
cd pylier
uv sync
uv run python -m examples.ingest serve
# viewer: http://localhost:8765

Open the viewer in a browser and watch the graph grow as work happens — a document branches into text and image paths, then concurrently embeds both branches before they converge at an indexing stage. To get a self-contained file for sharing instead:

uv run python -m examples.ingest html

pylier-ingest.html is a single file — no server required.

The whole API in one flow

import pylier


@pylier.node
def load_document(path: str) -> dict: ...


@pylier.node(_tags=["document", "text"])
def extract_text(document: dict) -> list[str]: ...


@pylier.node
def embed(chunks: list[str]) -> list[dict]: ...


with pylier.trace("document-ingest"):
    document = load_document("report.pdf")
    vectors = embed(extract_text(document))

pylier.render("document-ingest.html")  # interactive, standalone HTML

Autotrace without decorators

import pylier
import myapp.pipeline


pylier.autotrace()  # infers the caller's package or source root

with pylier.trace("request"):
    myapp.pipeline.run()

Limit it explicitly when your app spans multiple entry points:

pylier.autotrace(
    modules=["myapp.pipeline", "myapp.services"],
    allow_empty=False,
    min_exec_time=0.050,
)
  • Autotrace covers public Python-defined functions, methods, coroutines, generators, and async generators inside the selected scope.
  • modules=[...] matches exact module names and their submodules.
  • min_exec_time is measured in seconds. A positive threshold omits warm-up calls until one qualifying call promotes that code object; the first qualifying call is still omitted.
  • allow_empty=False buffers successful calls with no meaningful business input that return None and drops only the empty parent. For autotrace, parameters whose runtime value equals their declared default are treated as omitted for this filter; use allow_empty=True if you need those calls retained. Its committed children reconnect to the nearest retained caller or trace root when the call finishes.
  • Names starting with _, lambdas/comprehensions, module/class bodies, C callables, and code outside the selected scope are skipped.
  • An explicit @pylier.node wins; autotrace will not double-record it.
  • pylier.autotrace() requires Python 3.12+ with sys.monitoring available at runtime.

Notes

For a plain-Python transformation or join that loses value provenance, preserve its sources explicitly:

vectors = pylier.derive(text_vectors + image_vectors, from_=[text_vectors, image_vectors])

derive() returns the original value unchanged; its only job is to keep the branch lineage visible in the next decorated stage. See docs/records/derive-lineage.md for its exact behavior.

Built for useful traces

  • Signal over noise — use core, info, debug, and trace capture levels to control both captured nodes and metadata detail.
  • Useful inspection — filter by node tags; click graph nodes and edges for payload type, size, preview, and optional captured values. Full values require PYLIER_CAPTURE_VALUES=1 and remain bounded FIFO by count and bytes. To make an intentionally shareable debug bundle, use pylier.render("debug.html", embed_payloads=True); the bundled data is readable by anyone with the HTML file, so the default static render remains metadata-only. The published examples use this opt-in only because their data is synthetic.
  • Stream or sharepylier.serve() streams updates to a live in-process viewer with SSE; pylier.render() exports a portable HTML file for sharing.
  • Keep an audit trailpylier.trace(..., sidecar="trace.jsonl") writes already-resolved events to JSONL for offline consumers.

No tracing framework to adopt

pylier has no OpenTelemetry or other tracer dependency. It records its own local decorator traces and does not mutate ambient tracing context, so another tracer can instrument the same process independently. Autotrace uses stdlib sys.monitoring, so it adds no dependency beyond pydantic-settings for configuration. pylier ships a py.typed marker and full PEP 695 type annotations, so IDE autocompletion and type checkers work out of the box.

Development

uv run pytest
uv run ruff format src tests examples
uv run ruff check src tests examples

Versioning

pylier follows Semantic Versioning. Given a MAJOR.MINOR.PATCH version: breaking API changes bump MAJOR, backward-compatible additions bump MINOR, and fixes/patches bump PATCH. No silent breaking changes in minor releases — if you pin a minor version, upgrades within it stay safe.

Roadmap

pylier is a decorator-first local visualizer today. The direction, in priority order:

  • Framework helpers — optional extras that autotrace popular stacks: uv add "pylier[fastapi]" then pylier.instrument_fastapi() to trace HTTP endpoints, pylier[pydantic-ai] to autotrace / auto-spawn nodes for LLM agents, and so on. Helpers stay opt-in extras — the core stays dependency-light.
  • Live remote tracing — a dedicated server for online tracing of cloud / VM applications, so pipelines running outside your machine stream their graphs to a shared viewer (today the live viewer is in-process only).
  • UI redesign — a more polished, better-structured graph viewer and inspector.

None of these change the core contract: decorate a function, get the graph of what actually ran.

Contributing

Issues and pull requests are welcome at theMladyPan/pylier.

Release files for pylier 1.4.4

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

Source distribution (sdist)

Source distribution for pylier 1.4.4
File Size Uploaded
pylier-1.4.4.tar.gz 1.1 MB Details

Built distribution (wheel)

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

Total release size: 1.2 MB

Release files / pylier-1.4.4.tar.gz

Download URL pylier-1.4.4.tar.gz
Size 1.1 MB
Tags Source
SHA-256 checksum
How to use checksums
69af65159b0d18256a6f05e00622667398c42c2ed9e425e215a994ef76ac1d05
BLAKE2b-256 checksum
How to use checksums
ce1836850d13d4cac9e5b85e6b32d9bf4fc7bd33ce113b563197b26386cf3460
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","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 / pylier-1.4.4-py3-none-any.whl

Download URL pylier-1.4.4-py3-none-any.whl
Size 61.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
abb1665b17b3359a2e018ed5c4b47a7ed164f66d45a132cb1485e601014bcabd
BLAKE2b-256 checksum
How to use checksums
a32a94ba3a1925f85213d83360666f09172574fff7ccb41517cbd718cdea517c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","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 history Release notifications | RSS feed

1.4.6

2 release files

1.4.5

2 release files

This release

1.4.4 This release

2 release files

1.4.2

2 release files

1.4.0

2 release files

1.3.2

2 release files

1.3.1

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.1.0

2 release files

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