Lightweight asyncio task tracking as call tree and DAG
Project description
aionode
Lightweight asyncio task tracking with dependency graphs and progress rendering.
Installation
pip install aionode
For Rich table rendering:
pip install aionode[viz]
Quick Start
import asyncio
import aionode
async def fetch_data() -> list[int]:
await asyncio.sleep(1)
return list(range(100))
async def process(data: list[int]) -> int:
await asyncio.sleep(0.5)
return sum(data)
async def pipeline() -> None:
async with asyncio.TaskGroup() as tg:
fetch = tg.create_task(aionode.node(fetch_data)(), name="fetch")
tg.create_task(aionode.node(process)(aionode.resolve(fetch)), name="process")
async def main() -> None:
root = asyncio.create_task(aionode.track(pipeline)(), name="pipeline")
root_id = await aionode.get_task_id(root)
graph = aionode.TaskGraph(root_id=root_id)
await aionode.watch(graph, interval=0.3)
await root
asyncio.run(main())
Core Concepts
node(func, wait_for=[], track=True, auto_progress=True)
Wraps an async function as a DAG node. Use resolve() to pass awaitables as arguments — they are gathered concurrently before the function is called. Sync functions must be wrapped with make_async first.
# Async function — pass upstream tasks with resolve()
fetch = tg.create_task(aionode.node(fetch_data)(), name="fetch")
process_task = tg.create_task(aionode.node(process)(aionode.resolve(fetch)), name="process")
# Sync function — wrap with make_async first
summarize = tg.create_task(
aionode.node(aionode.make_async(my_sync_fn))(aionode.resolve(process_task)),
name="summarize",
)
# Side-only dependency (no value passed): use wait_for
task_b = tg.create_task(aionode.node(cleanup, wait_for=[fetch])(), name="cleanup")
resolve(awaitable)
Marks an awaitable to be resolved before being passed as an argument to node(). This preserves type information — the type checker sees resolve(task: Task[T]) as returning T.
result = await aionode.node(process)(aionode.resolve(upstream_task))
track(func, start=True)
Tracks a coroutine by registering it in the task graph. Use this for the root task or tasks that don't need node()'s dependency resolution.
root = asyncio.create_task(aionode.track(my_coro)(), name="root")
TaskGraph
Query the dependency graph:
graph = aionode.TaskGraph(root_id=root_id)
graph.nodes() # All tasks in topological order
graph.roots() # Tasks with no upstream deps
graph.leaves() # Tasks with no downstream dependents
graph.upstream(task_id) # Transitive upstream deps
graph.downstream(task_id) # Transitive downstream dependents
graph.summary() # {TaskStatus: count}
graph.critical_path() # Longest-duration path
Rendering
# Auto-detect Rich or fall back to ANSI text
renderer = aionode.get_render()
# Force plain text
renderer = aionode.get_render(rich=False)
# Live-updating display
await aionode.watch(graph, interval=0.5, renderer=renderer)
Task Inspection
task_id = await aionode.get_task_id(asyncio_task)
info = aionode.get_task(task_id)
info.status # TaskStatus: WAITING, RUNNING, DONE, FAILED, CANCELLED
info.duration() # Elapsed seconds
info.description # Task name
info.deps # Upstream dependency IDs
info.dependents # Downstream dependent IDs
info.logs # Accumulated log output
await aionode.log("processing record 42") # Append to current task's logs
API Reference
| Function | Description |
|---|---|
node(func, wait_for, track, auto_progress) |
Wrap an async function as a DAG node |
resolve(awaitable) |
Mark an awaitable to be resolved as a node argument |
track(func, start) |
Track a coroutine in the task graph |
get_task_id(task, timeout) |
Get the task ID for an asyncio.Task |
get_task(task_id) |
Get TaskInfo by ID |
remove_task(task_id) |
Remove a task and its descendants |
log(value, end) |
Append to the current task's logs |
make_async(func) |
Run a sync function in a thread |
make_async_generator(gen) |
Async iterate a sync iterator via threads |
TaskGraph(root_id) |
Create a graph view rooted at a task |
TaskGraph.from_task(task) |
Create a graph from an asyncio.Task |
TaskGraph.current() |
Graph over all tasks in the current loop |
get_render(rich, bar_width, ...) |
Get a configured render function |
watch(graph, interval, renderer) |
Live-render until all tasks finish |
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
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 aionode-0.1.0.tar.gz.
File metadata
- Download URL: aionode-0.1.0.tar.gz
- Upload date:
- Size: 7.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
61f2f812c5384de2857726fc4c6c2071212de9dca25b792adfbf621d5040b1ff
|
|
| MD5 |
d2c1c24efddf5c8aabbc963a4e77417a
|
|
| BLAKE2b-256 |
230739c76f369e2c16bcf01d6d6b3872fc4bf63e3dc0c3215203e82aa869ce18
|
Provenance
The following attestation bundles were made for aionode-0.1.0.tar.gz:
Publisher:
publish.yml on MatteoDep/aionode
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aionode-0.1.0.tar.gz -
Subject digest:
61f2f812c5384de2857726fc4c6c2071212de9dca25b792adfbf621d5040b1ff - Sigstore transparency entry: 1185130073
- Sigstore integration time:
-
Permalink:
MatteoDep/aionode@c15333a5c84186ea8a3b69d430d305ced1df3773 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/MatteoDep
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c15333a5c84186ea8a3b69d430d305ced1df3773 -
Trigger Event:
push
-
Statement type:
File details
Details for the file aionode-0.1.0-py3-none-any.whl.
File metadata
- Download URL: aionode-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d69524a5c22571fbda28c5dc463642cb29fc9d2b54c854931b6e24b24675ddf0
|
|
| MD5 |
82963167b9cee9514b478dbe9c187845
|
|
| BLAKE2b-256 |
8dcc8a6d08b9437ed22127484cfd86fe73598417e4138fa683e0eaea2750f1d8
|
Provenance
The following attestation bundles were made for aionode-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on MatteoDep/aionode
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aionode-0.1.0-py3-none-any.whl -
Subject digest:
d69524a5c22571fbda28c5dc463642cb29fc9d2b54c854931b6e24b24675ddf0 - Sigstore transparency entry: 1185130077
- Sigstore integration time:
-
Permalink:
MatteoDep/aionode@c15333a5c84186ea8a3b69d430d305ced1df3773 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/MatteoDep
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c15333a5c84186ea8a3b69d430d305ced1df3773 -
Trigger Event:
push
-
Statement type: