Lightweight, decorator-based async dataflow framework for high-concurrency ETL pipelines
Project description
🥔 Pipeline Potato
Pipeline Potato is a lightweight, decorator-based Asynchronous Dataflow Framework for Python. It is designed to simplify the creation of high-concurrency ETL pipelines, specifically optimized for I/O-bound workloads like API orchestration, cloud storage scraping, and large-scale data migration.
✨ Key Features
- Declarative Concurrency: Control the throughput of individual steps using simple decorators (
@step,@tree_traversal). - Automatic Back-pressure: Built-in
buffer_sizemanagement ensures your memory stays lean, even when producers are faster than consumers. - Async-First: Built from the ground up for
asyncio, making it highly efficient for thousands of concurrent network connections. - Zero Boilerplate: No complex worker management or manual queue handling. Just define your logic and let the "Potato" handle the distribution.
🛠 At a Glance
@step(
concurrency=50,
buffer_size=100,
page_size=10
)
async def process_data(p: APotato, payload: list):
# This step runs 50 instances concurrently
# It automatically handles batching based on your page_size
result = await call_external_api(payload)
# Pass the results to the next stage in the pipeline.
# This call blocks until space is available in next_step's buffer queue.
# Each step has its own buffer (controlled by buffer_size) to store payloads.
# Execution resumes only after all results are pushed to the buffer.
await p(next_step, [result])
📖 Example: Downloading AWS Permissions
This example demonstrates how to build a pipeline that fetches all AWS service permissions by crawling AWS's public service reference API, available here: https://servicereference.us-east-1.amazonaws.com/v1/service-list.json
import asyncio
import json
import time
import aiohttp
from pipeline_potato import APotato, pipeline
from pipeline_potato.steps import entry_point, step
class AwsPermissionsCrawler:
aiohttp_session = None
total_services = 0
total_actions = 0
@entry_point
async def start_aws_discovery(p: APotato) -> None:
"""The entry point fetches the master service list."""
url = "https://servicereference.us-east-1.amazonaws.com/v1/service-list.json"
async with AwsPermissionsCrawler.aiohttp_session.get(url) as response:
services = json.loads(await response.text())
for service_info in services:
payload = (service_info["service"], service_info["url"])
await p(fetch_service_details, [payload])
@step(
concurrency=5, # Run up to 5 HTTP requests in parallel
buffer_size=100, # Prevent memory bloat by capping the input queue
page_size=1 # Process one service per task instance
)
async def fetch_service_details(_: APotato, payload: list) -> None:
"""Fetch actions for each AWS service."""
service_name, url = payload[0]
async with AwsPermissionsCrawler.aiohttp_session.get(url) as response:
data = json.loads(await response.text())
actions = data.get("Actions", [])
print(f"✅ {service_name}: {len(actions)} actions")
AwsPermissionsCrawler.total_services += 1
AwsPermissionsCrawler.total_actions += len(actions)
async def main() -> None:
start_time = time.time()
connector = aiohttp.TCPConnector(limit=0, limit_per_host=0)
async with aiohttp.ClientSession(connector=connector) as session:
AwsPermissionsCrawler.aiohttp_session = session
await pipeline(start_aws_discovery)
duration = time.time() - start_time
print(f"Done! {AwsPermissionsCrawler.total_actions} actions across {AwsPermissionsCrawler.total_services} services in {duration:.2f} seconds.")
if __name__ == "__main__":
asyncio.run(main())
What's happening here:
- Entry Point (
@entry_point): Fetches the master list of AWS services and dispatches each service to the next step. - Worker Step (
@step): Processes each service with controlled concurrency (5 parallel requests), fetching the detailed actions list. - Back-pressure: The
buffer_size=100ensures that iffetch_service_detailsfalls behind, the entry point will automatically slow down.
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 pipeline_potato-1.0.0a1.tar.gz.
File metadata
- Download URL: pipeline_potato-1.0.0a1.tar.gz
- Upload date:
- Size: 19.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8d15178afe14ae669edf9f21e77f15a13ce87755971225841b3895718ee32348
|
|
| MD5 |
28414bbafda49a098a47d1ddf14fe975
|
|
| BLAKE2b-256 |
c87dd4dac275e78e9b4246526295eb958c8c14a75a77e7fcae01a034dba538ec
|
File details
Details for the file pipeline_potato-1.0.0a1-py3-none-any.whl.
File metadata
- Download URL: pipeline_potato-1.0.0a1-py3-none-any.whl
- Upload date:
- Size: 31.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ad80565a865a589bfc573d6c8b3e894ecc135be0ae5e1b8cf9727d78c3fb5f43
|
|
| MD5 |
a95529b71759f9dadd37b2dff11a843b
|
|
| BLAKE2b-256 |
a40264725e38b01f9021996a650432244d91a83f37535a30cc5c86280779133e
|