Reusable Rich-based braille spinner and transient live panel for CLI output
Project description
rich_transient
Reusable Rich-based braille spinner and transient live panel for CLI output. Use it to show streaming subprocess or task output in a live-updating panel that disappears when the task finishes, with an animated status line.
Requires: Python 3.11+, rich>=13.7.1
Installation
From PyPI:
pip install rich-transient
Standalone (from this repo):
pip install -e /path/to/AutoIaC/rich_transient
As part of AutoIaC:
pip install -e /path/to/AutoIaC
# installs both auto_iac and rich_transient
Quick start: transient live panel
Wrap a long-running task so its output streams into a live panel; when the task ends, the panel is cleared (transient) and only your final message remains.
from rich_transient import transient_live_panel
with transient_live_panel("Installing dependencies") as panel:
def do_work():
# Simulate streaming output
for i in range(20):
print(f"Step {i + 1}/20...")
return "done"
result = panel.run_task(do_work)
print(f"Result: {result}")
The panel shows a scrolling tail of output and an animated braille spinner in the status line; when run_task returns, the panel is removed.
Using the panel API
The context manager yields an object with three methods:
| Method | Description |
|---|---|
panel.append(line: str) |
Add a line to the panel content (e.g. from a subprocess stdout). |
panel.set_status(text: str) |
Update the status line shown next to the spinner (e.g. "Downloading X..."). |
panel.run_task(callable) |
Run a callable in a background thread; the panel refreshes until it completes. Returns the callable's return value; re-raises any exception. |
Streaming subprocess output into the panel:
import subprocess
from rich_transient import transient_live_panel
with transient_live_panel("Running tests") as panel:
def run():
proc = subprocess.Popen(
["pytest", "-v"],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
)
for line in proc.stdout:
panel.append(line.rstrip())
proc.wait()
return proc.returncode
exit_code = panel.run_task(run)
print(f"Tests exited with code {exit_code}")
Updating the status line:
with transient_live_panel("Building") as panel:
def build():
panel.set_status("Compiling...")
# do compile
panel.set_status("Linking...")
# do link
return 0
panel.run_task(build)
Braille spinner
Use the spinner frames for your own live UI (e.g. a custom table or status line).
With Rich console.status() — use the built-in braille spinner so the whole app shares one style:
from rich.console import Console
from rich_transient import braille_spinner_for_status
console = Console()
with console.status("Loading state...", spinner=braille_spinner_for_status()) as status:
do_work()
status.update("Almost done...")
Custom live UI — use get_braille_frame() so you don't duplicate the frame math:
import time
from rich.console import Console
from rich.live import Live
from rich_transient import SPINNER_BRAILLE, LIVE_REFRESH_PER_SECOND, get_braille_frame
console = Console()
def make_status():
frame = get_braille_frame()
return f"{SPINNER_BRAILLE[frame]} Working..."
with Live(make_status(), refresh_per_second=LIVE_REFRESH_PER_SECOND, console=console) as live:
for _ in range(20):
time.sleep(0.1)
live.update(make_status())
Exports:
SPINNER_BRAILLE— tuple of 10 braille characters for animation frames.LIVE_REFRESH_PER_SECOND— default refresh rate (8.0) for live displays.get_braille_frame()— current animation frame index (use withSPINNER_BRAILLE[i]).braille_spinner_for_status()— Registers the braille spinner with Rich and returns the name"braille"forconsole.status(spinner=...).register_braille_spinner()— Idempotent registration of the braille spinner in Rich's SPINNERS dict (called automatically bybraille_spinner_for_status()).
Presets and options
Presets control buffer size and visible lines:
preset="default"— max_lines=100, display_lines=24 (short steps).preset="streaming"— max_lines=200, display_lines=28 (long streaming output).
Override per call:
with transient_live_panel(
"Long log",
preset="streaming",
max_lines=500,
display_lines=40,
) as panel:
panel.run_task(my_task)
Custom Rich theme: pass a Console so the panel uses your theme:
from rich.console import Console
from rich.theme import Theme
from rich_transient import transient_live_panel
my_theme = Theme({"info": "cyan", "success": "green"})
console = Console(theme=my_theme)
with transient_live_panel("Task", console=console) as panel:
panel.run_task(my_task)
Configuration
For full control, use TransientPanelConfig and TRANSIENT_PANEL_PRESETS:
from rich_transient import (
TransientPanelConfig,
TRANSIENT_PANEL_PRESETS,
transient_live_panel,
)
# Use a built-in preset
cfg = TRANSIENT_PANEL_PRESETS["streaming"]
# Or build your own
custom = TransientPanelConfig(
max_lines=300,
display_lines=30,
default_status="Processing...",
border_style="blue",
)
with transient_live_panel("Custom", config=custom) as panel:
panel.run_task(my_task)
API summary
| Export | Type | Description |
|---|---|---|
SPINNER_BRAILLE |
tuple[str, ...] |
Braille spinner frames. |
LIVE_REFRESH_PER_SECOND |
float |
Default refresh rate for live displays. |
get_braille_frame() |
() -> int |
Current animation frame index for use with SPINNER_BRAILLE. |
braille_spinner_for_status() |
() -> str |
Registers braille spinner with Rich and returns "braille" for console.status(spinner=...). |
register_braille_spinner() |
() -> None |
Idempotent registration of braille spinner in Rich's SPINNERS. |
TransientPanelConfig |
dataclass | Panel configuration (max_lines, display_lines, border_style, etc.). |
TRANSIENT_PANEL_PRESETS |
dict[str, TransientPanelConfig] |
"default" and "streaming" presets. |
transient_live_panel(...) |
context manager | Yields an object with append, set_status, run_task. |
Project details
Release history Release notifications | RSS feed
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 rich_transient-0.1.0.tar.gz.
File metadata
- Download URL: rich_transient-0.1.0.tar.gz
- Upload date:
- Size: 6.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
75d94dc460e09b7eab28ff9edb1250f11845ddf0779f7bc1b4ea38bcd2177855
|
|
| MD5 |
f518931812b5a9cf6b994593896f2431
|
|
| BLAKE2b-256 |
c442190457c50886c982493ebb9ad35454a1bc733e5a56bca7c847edc225b9f3
|
File details
Details for the file rich_transient-0.1.0-py3-none-any.whl.
File metadata
- Download URL: rich_transient-0.1.0-py3-none-any.whl
- Upload date:
- Size: 7.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
02e0fc85506534cd39a0e168928743dbd98bb4d77695e0fc1845052bb51d2d19
|
|
| MD5 |
4ab60afdae5b19de4026c0d566718e89
|
|
| BLAKE2b-256 |
fa4ab842d4c09a0229bb527ca866c4fb3a0549b655c2d58f660cf719bb289ec4
|