Feeding a clanker? Grab this page as raw `.md` →

# AsyncFlow API


 Bases: `AnyWidget`


Live, source-linked timeline of a single async run.


Runs a coroutine on the notebook's own event loop and streams its task activity — spawn, suspend-at-`await`, resume, done — into a swimlane timeline that fills in as the run proceeds. One lane per task; solid bars are running, hatched bars are suspended at an `await`.


Example (marimo, top-level `await`)::


```
import asyncio
from wigglystuff import AsyncFlow

async def worker(name, delay):
    await asyncio.sleep(delay)
    return name

async def main():
    return await asyncio.gather(worker("A", 0.3), worker("B", 0.1))

flow = await AsyncFlow.trace(main())   # displays live, returns the widget
flow.result                            # ['A', 'B']
```


Requires `sys.monitoring` (Python 3.12+).

 Source code in `wigglystuff/async_flow.py`

```
def __init__(self, *, width: int = 0, **kwargs: Any) -> None:
    super().__init__(width=width, **kwargs)
    self.result: Any = None
```


## run `async`


```
run(coro: Any, *, targets: Iterable[Any] | None = None, poll_ms: int = 100) -> Any
```


Drive `coro` to completion, streaming events into the widget.


`targets` (functions/coroutines) add extra source files to capture; by default only the file of `coro` is tracked, which already picks up any coroutine defined alongside it.

 Source code in `wigglystuff/async_flow.py`

```
async def run(
    self,
    coro: Any,
    *,
    targets: Iterable[Any] | None = None,
    poll_ms: int = 100,
) -> Any:
    """Drive ``coro`` to completion, streaming events into the widget.

    ``targets`` (functions/coroutines) add extra source files to capture;
    by default only the file of ``coro`` is tracked, which already picks up
    any coroutine defined alongside it.
    """
    files = set()
    code = getattr(coro, "cr_code", None)
    if code is not None:
        files.add(code.co_filename)
    for target in targets or []:
        target_code = getattr(target, "__code__", None) or getattr(target, "cr_code", None)
        if target_code is not None:
            files.add(target_code.co_filename)

    logger = AsyncFlowLogger(files, on_event=None)
    self.events = []
    self.now_ms = 0.0
    self.running = True
    try:
        async with logger:
            task = asyncio.ensure_future(coro)
            while not task.done():
                self.now_ms = logger.now_ms()
                self.events = list(logger.events)
                await asyncio.sleep(poll_ms / 1000)
            self.result = await task
            self.now_ms = logger.now_ms()
            self.events = list(logger.events)
    finally:
        self.running = False
    return self.result
```


## trace `async` `classmethod`


```
trace(coro: Any, *, targets: Iterable[Any] | None = None, poll_ms: int = 100, width: int = 0) -> 'AsyncFlow'
```


Create the widget, display it, and trace `coro` live.


Returns the widget; the coroutine's return value is on `.result`.

 Source code in `wigglystuff/async_flow.py`

```
@classmethod
async def trace(
    cls,
    coro: Any,
    *,
    targets: Iterable[Any] | None = None,
    poll_ms: int = 100,
    width: int = 0,
) -> "AsyncFlow":
    """Create the widget, display it, and trace ``coro`` live.

    Returns the widget; the coroutine's return value is on ``.result``.
    """
    widget = cls(width=width)
    try:  # show it now so the timeline streams during the run
        import marimo as mo

        mo.output.append(widget)
    except Exception:  # noqa: BLE001 - display is best-effort (e.g. headless).
        pass
    await widget.run(coro, targets=targets, poll_ms=poll_ms)
    return widget
```


## Synced traitlets


| Traitlet | Type | Notes |
| --- | --- | --- |
| `events` | `list[dict]` | Captured event stream; re-synced on every poll tick so the timeline grows live. Each entry has `t_ms`, `coro`, `event`, `task`, `line`, `detail`. |
| `now_ms` | `float` | Elapsed wall-clock milliseconds; advances every tick so suspended bars keep growing during long sleeps. |
| `running` | `bool` | Whether a run is currently in flight. |
| `width` | `int` | Widget width in pixels; `0` grows to fit. |
