Agora — async-first ETL framework for Python.
Project description
Agora ETL Framework
Async-first ETL framework for Python.
Overview
agora-etl is a Python async ETL framework built around a Source → Middleware chain → Sink(s) model.
- Source emits records one at a time via an async generator
- Middleware chain transforms, filters, validates, or enriches each record
- Sink persists records to a destination
The pipeline builder is immutable — every .pipe() and .filter() returns a new instance. Calling .build() produces a runnable BoundPipeline. The framework handles checkpointing, dead-letter queues, retries, backpressure, and long-running scheduled workers so you can focus on the transformation logic.
Install
pip install agora-etl # core only
pip install "agora-etl[file]" # + Parquet support and faster JSONL
Quick start
Minimal pipeline — filter and print:
import asyncio
from dataclasses import dataclass
from agora import Pipeline, IterableSource
from agora.sinks.io.stdout import StdoutSink
@dataclass
class Event:
id: int
name: str
score: float
async def main():
summary = await (
Pipeline(IterableSource([
Event(id=1, name="alice", score=0.9),
Event(id=2, name="bob", score=0.4),
Event(id=3, name="carol", score=0.85),
]))
.filter(lambda r: r.score > 0.8)
.build(StdoutSink())
.run()
)
print(f"written={summary.records_written} dropped={summary.records_dropped}")
asyncio.run(main())
With DLQ — failed records are captured, pipeline continues:
import asyncio
from agora import Pipeline, IterableSource
from agora.core.middleware import Middleware
from agora.core.dlq import SQLiteDLQSink
from agora.sinks.io.stdout import StdoutSink
class EnrichMiddleware(Middleware[dict, dict]):
name = "enrich"
async def process(self, record: dict, ctx) -> dict | None:
if record.get("value") is None:
raise ValueError(f"missing value on record {record['id']}")
return {**record, "value": record["value"].upper()}
async def main():
summary = await (
Pipeline(IterableSource([
{"id": 1, "value": "hello"},
{"id": 2, "value": None}, # will fail → goes to DLQ
{"id": 3, "value": "world"},
]))
.pipe(EnrichMiddleware())
.build(
StdoutSink(),
dlq=SQLiteDLQSink(".dlq.db"),
)
.run()
)
print(f"written={summary.records_written} errored={summary.records_errored}")
print(f"run_id={summary.run_id}")
# written=2 errored=1
# run_id=<uuid> — use this to query .dlq.db: SELECT * FROM dlq_records WHERE run_id='...'
asyncio.run(main())
The middleware_error log lines are expected — they confirm record id=2 was caught and routed to the DLQ. The pipeline completed normally.
Or scaffold a project:
agora new my-pipeline
cd my-pipeline
agora run pipelines.example
Documentation
- Quickstart
- Pipelines
- Failure Handling
- Checkpointing
- Scheduling
- Testing
- Observability
- Sources · Sinks · Middlewares
- Architecture
- CLI
- Plugins
- Configuration
Built-in components
Sources
| Component | Description |
|---|---|
JsonLinesSource |
Stream records from a JSONL file |
CsvSource |
Stream records from a CSV file |
ParquetSource |
Stream records from a Parquet file ([file] extra) |
HTTPSource |
Abstract base for HTTP polling sources |
Sinks
| Component | Description |
|---|---|
JsonLinesSink |
Write records as JSONL |
CsvSink |
Write records as CSV |
ParquetSink |
Write records to Parquet ([file] extra) |
WebhookSink |
POST records to an HTTP endpoint |
StdoutSink |
Print records to stdout |
LogSink |
Emit records via the structured logger |
Middlewares
| Component | Description |
|---|---|
MapMiddleware |
Apply a function to each record |
FilterMiddleware |
Drop records that do not match a predicate |
RetryMiddleware |
Retry a middleware on exception with backoff |
ValidateMiddleware |
Validate records against a Pydantic model |
EnrichMiddleware |
Enrich records with data from an async callable |
DedupMiddleware |
Drop duplicate records by a computed key |
AIEnrichMiddleware |
Add fields using an LLM |
AIClassifyMiddleware |
Classify records into a fixed set of categories |
AIExtractMiddleware |
Extract structured fields from unstructured text |
AIBatchMiddleware |
Batch multiple records into a single LLM call |
CLI
agora new <name> # scaffold a new project
agora run <module> # run a pipeline once
agora worker # start the worker pool
agora dlq replay # replay failed records
agora plugins list # list registered plugins
agora version # print version
License
Apache 2.0 — see LICENSE.
Project details
Release history Release notifications | RSS feed
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 agora_etl-0.2.2.tar.gz.
File metadata
- Download URL: agora_etl-0.2.2.tar.gz
- Upload date:
- Size: 368.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28aca08da9a548054d1ed331aa2f776adda0bfd65a0170069e1257d0ffb4c0ed
|
|
| MD5 |
ea180b7df73275934c6d167ba18071b8
|
|
| BLAKE2b-256 |
695e637fed67d4a7098a67b3493db610fddd627a6bb48f78d1e7de282e34473b
|
Provenance
The following attestation bundles were made for agora_etl-0.2.2.tar.gz:
Publisher:
release.yml on thanhtham010891/agora-etl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agora_etl-0.2.2.tar.gz -
Subject digest:
28aca08da9a548054d1ed331aa2f776adda0bfd65a0170069e1257d0ffb4c0ed - Sigstore transparency entry: 1708729536
- Sigstore integration time:
-
Permalink:
thanhtham010891/agora-etl@98a0ab2dc6f687909757cd428f1d431763fa5bd2 -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/thanhtham010891
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@98a0ab2dc6f687909757cd428f1d431763fa5bd2 -
Trigger Event:
release
-
Statement type:
File details
Details for the file agora_etl-0.2.2-py3-none-any.whl.
File metadata
- Download URL: agora_etl-0.2.2-py3-none-any.whl
- Upload date:
- Size: 244.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ccc2c2893dc0485b314b2b2463e908c746e428f035c1b8e1c0d5aebafd645581
|
|
| MD5 |
2c303bf9bc2d05fb95a06cb981d80ac5
|
|
| BLAKE2b-256 |
462a1d134871d21d7e46cbdde7a9d6c5706798a04bcc49c0025ca945c05d1785
|
Provenance
The following attestation bundles were made for agora_etl-0.2.2-py3-none-any.whl:
Publisher:
release.yml on thanhtham010891/agora-etl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agora_etl-0.2.2-py3-none-any.whl -
Subject digest:
ccc2c2893dc0485b314b2b2463e908c746e428f035c1b8e1c0d5aebafd645581 - Sigstore transparency entry: 1708729583
- Sigstore integration time:
-
Permalink:
thanhtham010891/agora-etl@98a0ab2dc6f687909757cd428f1d431763fa5bd2 -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/thanhtham010891
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@98a0ab2dc6f687909757cd428f1d431763fa5bd2 -
Trigger Event:
release
-
Statement type: