Pyper unifies synchronous and asynchronous execution. An AsyncPipeline is created whenever you wrap an async def function with task().
When composing pipelines using |, the resulting pipeline type follows these rules:
Pipeline + Pipeline = PipelinePipeline + AsyncPipeline = AsyncPipelineAsyncPipeline + Pipeline = AsyncPipelineAsyncPipeline + AsyncPipeline = AsyncPipeline
Rule of thumb: If a pipeline contains at least one asynchronous task, the entire resulting pipeline becomes an AsyncPipeline.
When using an AsyncPipeline, consumer functions must be able to handle AsyncIterable inputs (e.g., using async for).
import asyncio
import json
from typing import AsyncIterable, Dict
from pyper import task
async def step1(limit: int):
for i in range(limit):
yield {"data": i}
def step2(data: Dict):
return data | {"hello": "world"}
class AsyncJsonFileWriter:
def __init__(self, filepath):
self.filepath = filepath
async def __call__(self, data: AsyncIterable[Dict]):
# Must use 'async for' to consume AsyncIterable
data_list = [row async for row in data]
with open(self.filepath, 'w', encoding='utf-8') as f:
json.dump(data_list, f, indent=4)
async def main():
run = (
task(step1, branch=True)
| task(step2)
> AsyncJsonFileWriter("data.json")
)
await run(limit=10)
if __name__ == "__main__":
asyncio.run(main())