A lightweight Python library for building interruptible, generator-driven ETL pipelines as directed graphs.
Project description
yieldgraph
Build interruptible, generator-driven ETL pipelines as directed graphs — in pure Python.
What is yieldgraph?
yieldgraph lets you compose data-processing pipelines by connecting plain Python
callables into a directed graph. Each callable becomes a Node. Nodes are linked
by Edges — lightweight queues that carry data tuples downstream. Call graph.run()
and the pipeline does the rest.
There is no framework to learn. Your business logic stays in ordinary Python functions. yieldgraph just wires them together and gets out of the way.
Features
- Pure Python, zero runtime dependencies — stdlib only;
loguruis optional. - Generator-native —
yieldzero, one, or many results per input; everything stays lazy. - Cooperative cancellation — set
graph.cancelled = Trueor pressCtrl+C; the pipeline stops cleanly at the nextyield. - Fan-out branching — attach multiple downstream chains to any node with a single
add_chaincall. - Threaded mode — flip
YIELDGRAPH_THREADED=1to run all nodes concurrently; edges become thread-safe blocking queues automatically. - Built-in observability — every node exposes
n_consumed,n_produced,errors, and aprogressfraction you can poll at any time.
Installation
pip install yieldgraph
From source:
git clone https://github.com/j4ggr/yieldgraph.git
cd yieldgraph
pip install -e .
Quick start
from yieldgraph import Graph
def source(graph):
"""Emit raw records — receives the Graph instance as first argument."""
for row in [
{"name": "Alice", "score": 95},
{"name": "Bob", "score": 72},
{"name": "Carol", "score": 88},
]:
yield row
def grade(record):
"""Add a pass/fail label to each record."""
record["grade"] = "pass" if record["score"] >= 85 else "fail"
yield record
def format_output(record):
"""Format as a human-readable string."""
yield f"{record['name']}: {record['grade']} ({record['score']})"
g = Graph()
g.add_chain(source, grade, format_output)
g.run()
for row in g.output:
print(row[0])
# Alice: pass (95)
# Bob: fail (72)
# Carol: pass (88)
Fan-out — multiple downstream chains
def source(graph):
for x in range(1, 6):
yield x
def store_db(x):
yield f"db:{x}"
def send_queue(x):
yield f"mq:{x}"
g = Graph()
g.add_chain(source, store_db) # chain 1
g.add_chain(source, send_queue) # chain 2 — same source, parallel branch
g.run()
print(g.output)
# [('db:1',), ('db:2',), ..., ('mq:1',), ('mq:2',), ...]
Cooperative cancellation
def source(graph):
for i in range(1_000_000):
if i >= 5:
graph.cancelled = True # stop cleanly after this item
return
yield i
g = Graph()
g.add_chain(source, process)
g.run()
print(len(g.output)) # 5
print(g.cancelled) # True
Threaded execution
YIELDGRAPH_THREADED=1 python my_pipeline.py
Or in Python before the run:
import os
os.environ["YIELDGRAPH_THREADED"] = "1"
g = Graph()
g.add_chain(fetch_from_api, transform, write_to_db)
g.run()
Error handling
Exceptions raised inside a node are caught per-item and stored — they never abort the pipeline. Inspect them after the run:
g.run()
for name, node in g.nodes.items():
if node.n_errors:
print(f"{name}: {node.n_errors} error(s)")
for err in node.errors:
print(f" {type(err).__name__}: {err}")
if g.succeeded:
print(f"Done — {len(g.output)} rows produced")
Status & progress
| Expression | Type | Description |
|---|---|---|
g.output |
list[tuple] |
All tuples emitted by terminal nodes |
g.succeeded |
bool |
Finished without errors |
g.has_output |
bool |
Finished and produced at least one row |
g.error |
str |
Graph-level error description (empty on success) |
g.step |
str |
Human-readable label of the currently executing node |
g.progress |
int |
0–100 % progress of the current node |
g.cancelled |
bool |
Whether the run was cancelled |
g.finished |
bool |
Whether run() has returned |
Documentation
Full guides and API reference at https://j4ggr.github.io/yieldgraph/
Development
# Install dev dependencies
pdm install -G test -G doc
# Run tests
pdm run pytest
# Build docs locally
pdm run mkdocs serve
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file yieldgraph-0.1.0.tar.gz.
File metadata
- Download URL: yieldgraph-0.1.0.tar.gz
- Upload date:
- Size: 29.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: pdm/2.26.2 CPython/3.12.3 Windows/11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a15bcfc9d99422623411df11f464bf32795c12f656ef938846d7a1fdab6cd2a4
|
|
| MD5 |
64cfb2322deb91a5e9b00d274c70fe00
|
|
| BLAKE2b-256 |
f25992a7d4e6eeb4644117605671638c0e733f44b22d191b25ad6798e6667e90
|
File details
Details for the file yieldgraph-0.1.0-py3-none-any.whl.
File metadata
- Download URL: yieldgraph-0.1.0-py3-none-any.whl
- Upload date:
- Size: 23.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: pdm/2.26.2 CPython/3.12.3 Windows/11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f4033d6ab351983635b2275a13670de7ec858c1cabb28b86b8cdc8c55045ea0
|
|
| MD5 |
f7451d57adbd75b51746f2ac9e9fadc0
|
|
| BLAKE2b-256 |
78c949d6fe29ae6b0ae27d9faaca31a6560a3014cba59ca52e5e31b8841faffb
|