Composable I/O primitives for async Python
Project description
comio – Composable I/O
I/O primitives for async & sync Python. Designed to be used as:
import comio as io # async
import comio.sync as io # sync
Giving you io.Reader, io.Writer, io.Listener, etc. — a Go-like DX for Python.
Install
pip install comio
Usage
Async
Implement a Reader / Writer
Any object with the right method is a valid io.Reader or io.Writer — no base class needed.
import json
from dataclasses import dataclass
import comio as io
@dataclass
class Page:
items: list
next_cursor: object
class AsyncJsonL:
def __init__(self, f):
self.f = f
async def read(self, *, cursor=None, n=None) -> Page:
self.f.seek(cursor or 0)
line = self.f.readline()
if line == "":
return Page([], io.EOF)
return Page(items=[json.loads(line)], next_cursor=self.f.tell())
async def write(self, item: dict) -> None:
self.f.write(json.dumps(item) + "\n")
Read pages with scroll
reader = AsyncJsonL(open("data.jsonl"))
async for page in io.scroll(reader):
print(page.items)
Drain everything with read_all
items = await io.read_all(reader)
Resume from a cursor
items = await io.read_all(reader, cursor=saved_cursor)
Normalize a Reader into a Listener with as_listener
listener = io.as_listener(reader)
async for item in listener.listen():
process(item)
Buffered copy: Listener → Batcher
await io.copy(listener, batcher, n=100) # flush every 100 items
Streaming pipe with backpressure
import comio as io
from comio import pipe, PipeConfig
listener = io.as_listener(reader)
async def transform(item):
return {**item, "processed": True}
await pipe(listener, writer, transform, cfg=PipeConfig(buffer=10))
Glue pipes with asyncio queues
import asyncio
from comio import pipe
from comio.adapters.queue import QueueListener, QueueWriter
q: asyncio.Queue = asyncio.Queue()
glue_src = QueueListener(q)
glue_dst = QueueWriter(q)
async def transform(item):
return {**item, "step": 1}
async def enrich(item):
return {**item, "step": 2}
# pipe1: listener -> transform -> queue
await pipe(listener, glue_dst, transform)
glue_src.close()
# pipe2: queue -> enrich -> final destination
await pipe(glue_src, writer, enrich)
Sync
import json
from dataclasses import dataclass
import comio.sync as io
@dataclass
class Page:
items: list
next_cursor: object
class JsonL:
def __init__(self, f):
self.f = f
def read(self, *, cursor=None, n=None) -> Page:
self.f.seek(cursor or 0)
line = self.f.readline()
if line == "":
return Page([], io.EOF)
return Page(items=[json.loads(line)], next_cursor=self.f.tell())
def write(self, item: dict) -> None:
self.f.write(json.dumps(item) + "\n")
reader = JsonL(open("data.jsonl"))
for page in io.scroll(reader):
print(page.items)
items = io.read_all(reader)
listener = io.as_listener(reader)
for item in listener.listen():
process(item)
Protocols
Async (comio)
| Protocol | Method | Description |
|---|---|---|
Reader[T] |
read |
Pull a page of items |
Listener[T] |
listen |
Push items as an async iterator |
Writer[T] |
write |
Accept a single item |
Batcher[T] |
batch |
Accept a sequence of items |
Handler[I,O] |
__call__ |
Transform a single item |
Sync (comio.sync)
| Protocol | Method | Description |
|---|---|---|
Reader[T] |
read |
Pull a page of items |
Listener[T] |
listen |
Push items as an iterator |
Writer[T] |
write |
Accept a single item |
Batcher[T] |
batch |
Accept a sequence of items |
Adapters
| Adapter | Module | Implements |
|---|---|---|
QueueListener |
comio.adapters.queue |
Listener |
QueueWriter |
comio.adapters.queue |
Writer, Batcher |
Stdin |
comio.adapters.std |
Listener |
Stdout |
comio.adapters.std |
Writer, Batcher |
TextFileReader |
comio.adapters.text_file |
Reader |
TextFileWriter |
comio.adapters.text_file |
Writer, Batcher |
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
comio-0.3.0.tar.gz
(9.4 kB
view details)
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
comio-0.3.0-py3-none-any.whl
(9.9 kB
view details)
File details
Details for the file comio-0.3.0.tar.gz.
File metadata
- Download URL: comio-0.3.0.tar.gz
- Upload date:
- Size: 9.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8acbfbcc98bed19f633159f2ac36a2d157d94f7c0ed12fe8097f5d4810b2fe5f
|
|
| MD5 |
3d925b7d3aa19d30579476205bd02df5
|
|
| BLAKE2b-256 |
48082a12794bf3e9c25fb826c6ef9d15a3fe964a387faebbc9173af9d1118c5a
|
File details
Details for the file comio-0.3.0-py3-none-any.whl.
File metadata
- Download URL: comio-0.3.0-py3-none-any.whl
- Upload date:
- Size: 9.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6b044acd38eddad6cb9313111c80dc49b637ef1b91167330ff96820f34860d83
|
|
| MD5 |
b5f6c92d436c0fb61575bd74f2a00ca2
|
|
| BLAKE2b-256 |
53333c60619c2bf9f0127a53478e3a36351da8ad7d2966a20064310abc2d07f3
|