masoora
Fluent builder for testable ETL pipelines in Python.
- Fluent chaining:
.with_read_step()/.with_transform_step()/.with_write_step() - Pydantic context: typed configuration passed to every step
- Data catalog: in-memory key → dataset store (polars/pandas/spark/dicts — anything)
- DAG resolution: declare steps in any order; cycles and missing inputs fail at
build() - Testable: mock reads/writes and assert on the catalog with a pytest fixture
Usage
from masoora import PipelineBuilder, PipelineContext
class MyContext(PipelineContext):
source_url: str
min_score: float = 0.5
def read_events(ctx: MyContext): ...
def score(ctx: MyContext, events): ...
def filter_top(ctx: MyContext, scored): ...
def write_db(ctx: MyContext, top): ...
pipeline = (
PipelineBuilder[MyContext]()
.with_read_step(read_events, output="events")
.with_transform_step(score, inputs=["events"], output="scored")
.with_transform_step(filter_top, inputs=["scored"], output="top")
.with_write_step(write_db, inputs=["top"])
.build()
)
catalog = pipeline.run(MyContext(source_url="https://..."))
Step signatures:
| Step kind | Signature | Effect |
|---|---|---|
| read | fn(ctx) -> dataset |
catalog[output] = result |
| transform | fn(ctx, *inputs) -> dataset |
catalog[output] = result |
| write | fn(ctx, *inputs) -> None |
terminal |
Steps may be declared in any order — build() topo-sorts them. Run only what's
needed for one output with pipeline.run(ctx, target="top"). Pre-populated
catalog keys are declared with .with_seed(key).
Parallel execution
pipeline.run(ctx, parallel=True) # thread pool, os.cpu_count() workers
pipeline.run(ctx, parallel=4) # explicit worker count
pipeline.run(ctx, executor=pool) # your Executor (not shut down by masoora)
Steps run concurrently in a ThreadPoolExecutor with dependency-driven
scheduling: each step starts the instant its own dependencies finish — there
is no level barrier, so unrelated slow steps never delay a ready branch.
Fail-fast: the first step error cancels queued work and raises
StepExecutionError immediately; already-running siblings finish in the
background.
Contract: steps must only read their declared input keys, write their own output key, and treat the context as read-only. Under this contract parallel results are identical to sequential.
Testing
from masoora import TestRunResult, make_pipeline_fixture
run_pipeline = make_pipeline_fixture(
pipeline,
MyContext(source_url="test"),
reads={"events": fake_events}, # read step is replaced, real source untouched
)
def test_top_events(run_pipeline: TestRunResult[MyContext]) -> None:
assert run_pipeline.catalog["top"] == expected
assert run_pipeline.written["top"] == expected # write step captured, not executed
Or without pytest: pipeline.to_testable(reads={...}).run(ctx) → TestRunResult.
Development
uv sync
uv run pytest
uv run ruff check .
uv run mypy src tests
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 masoora-0.1.0.tar.gz.
File metadata
- Download URL: masoora-0.1.0.tar.gz
- Upload date:
- Size: 9.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.10.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ee0804908160c7881709ea378f1935754f6c7c6a5336f1c6d66876219038ab17
|
|
| MD5 |
837717dd979bc1550d7034e38d3e0dc6
|
|
| BLAKE2b-256 |
c30f67abf58fa3238e0abf4363ced7812c6cb8bbae78b3148d9ace9096f392e0
|
File details
Details for the file masoora-0.1.0-py3-none-any.whl.
File metadata
- Download URL: masoora-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.10.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d50cb7c4388813cfa02b9485760ac0a265a216297f658bcda32c39a17d27c476
|
|
| MD5 |
3d84dbe0bf817cbe1765ef5e6d03fbac
|
|
| BLAKE2b-256 |
0fa7a9d5f7564f1b8b33ce9ddebb4735dd2b128ed1fdc8ef1da0bafff4a5ce4a
|