milo.livere-exports Kida's terminal live-rendering primitives for use
outside a full App event loop. Reach for it when you have a
straight-line script, a one-shot CLI command, or a background subroutine
that wants in-place updates without a reducer.
from milo.live import LiveRenderer, Spinner, stream_to_terminal, terminal_env
When to use which
| Situation | Use |
|---|---|
| Keyboard input, persistent state, multi-screen flow | App + TickCmd |
| One-shot progress for a script or command | LiveRenderer(context mgr) |
| Emit a template in chunks as it renders | stream_to_terminal |
| Just a spinner frame tuple | Spinner.BRAILLE / .DOTS |
The App harness owns the render loop, message filter, view state, and cursor
lifecycle.milo.livehands you raw primitives — simpler, but you write the
loop.
LiveRenderer
Context manager that overwrites its previous output on eachupdate().
Falls back to log-style appends when stdout is not a TTY.
from milo.live import LiveRenderer, terminal_env
env = terminal_env()
tpl = env.from_string("{{ spinner() }} {{ label }}", name="live")
with LiveRenderer(tpl, refresh_rate=0.08) as live:
live.start_auto(label="Working")
do_slow_thing()
live.update(label="Finalizing")
finalize()
LiveRenderer auto-injects a spinnercontext variable — call it in the
template ({{ spinner() }}) to emit and advance a frame on each render.
start_auto() / stop_auto()run a background refresh thread so animations
keep ticking between explicitupdate()calls.
Seeexamples/liverender/app.pyfor a runnable version.
Spinner
Animated spinner with four built-in frame sets:
Spinner.BRAILLE— ten-frame Braille dots (also aliasedDOTS)Spinner.LINE— four-frame ASCII (- \ | /)Spinner.ARROW— eight-frame directional arrow
Use the class attributes when you just need the frame tuple (for example,
feedingTickCmd animation inside an App):
# examples/spinner/app.py
from milo.live import Spinner
SPINNER = Spinner.BRAILLE # ('⠋', '⠙', '⠹', ...)
Instantiate Spinner(frames)only when you want a stateful, advancing
spinner outside aLiveRenderer(which already provides one).
stream_to_terminal
Render a template in chunks separated by{% flush %}boundaries, with a
configurable delay between chunks:
from milo.live import stream_to_terminal, terminal_env
env = terminal_env()
tpl = env.from_string(
"Starting...\n{% flush %}Step 1 done.\n{% flush %}Step 2 done.\n",
name="stream",
)
stream_to_terminal(tpl, delay=0.3)
Milo's built-in pipeline defs already place {% flush %}boundaries between
phases, so passing a pipeline template here will stream one phase at a time.
terminal_env
Returns a pre-configured KidaEnvironmentwith terminal autoescape — the
same autoescape milo uses internally. Prefer this overmilo.templates.get_env
for one-off live rendering that doesn't need milo's component loader chain.