Skip to main content

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 with SPINNER_BRAILLE[i]).
  • braille_spinner_for_status() — Registers the braille spinner with Rich and returns the name "braille" for console.status(spinner=...).
  • register_braille_spinner() — Idempotent registration of the braille spinner in Rich's SPINNERS dict (called automatically by braille_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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rich_transient-0.1.0.tar.gz (6.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rich_transient-0.1.0-py3-none-any.whl (7.1 kB view details)

Uploaded Python 3

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

Hashes for rich_transient-0.1.0.tar.gz
Algorithm Hash digest
SHA256 75d94dc460e09b7eab28ff9edb1250f11845ddf0779f7bc1b4ea38bcd2177855
MD5 f518931812b5a9cf6b994593896f2431
BLAKE2b-256 c442190457c50886c982493ebb9ad35454a1bc733e5a56bca7c847edc225b9f3

See more details on using hashes here.

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

Hashes for rich_transient-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 02e0fc85506534cd39a0e168928743dbd98bb4d77695e0fc1845052bb51d2d19
MD5 4ab60afdae5b19de4026c0d566718e89
BLAKE2b-256 fa4ab842d4c09a0229bb527ca866c4fb3a0549b655c2d58f660cf719bb289ec4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page