Name | ratatui-py JSON |
Version |
0.3.7
JSON |
| download |
home_page | None |
Summary | Python bindings for ratatui_ffi (Ratatui C ABI) via ctypes |
upload_time | 2025-09-10 00:20:32 |
maintainer | None |
docs_url | None |
author | holo-q |
requires_python | >=3.8 |
license | MIT License
Copyright (c) 2025 holo-q
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
|
keywords |
ratatui
tui
terminal-ui
terminal
ffi
ctypes
rust
bindings
widgets
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# ratatui-py — Python bindings for Ratatui (Rust TUI)
[](https://pypi.org/project/ratatui-py/)


[](https://github.com/holo-q/ratatui-py/actions/workflows/docs.yml)
[](https://github.com/holo-q/ratatui-py/actions/workflows/ci.yml)
Fast, zero-build Python bindings for [ratatui_ffi], the C ABI for
[Ratatui] — a modern Rust library for building rich terminal user
interfaces (TUIs). Use Ratatui’s performant rendering and widget set
from Python via `ctypes`, with prebuilt shared libraries bundled for
Linux, macOS, and Windows.
Key features:
- Zero-build install: bundles a prebuilt shared library when available
and falls back to building from source when configured.
- Cross‑platform: loads `libratatui_ffi.so` (Linux), `libratatui_ffi.dylib` (macOS), or `ratatui_ffi.dll` (Windows).
- Idiomatic Python wrappers: start quickly with `Terminal`, `Paragraph`, `List`, `Table`, `Gauge`, and more.
- Minimal overhead: direct FFI calls using `ctypes`.
- Layout helpers: `margin`, `split_h`, `split_v` for quick UI splits.
## Installation
Use uv for a fast, reproducible install:
```
uv add ratatui-py
```
Try the interactive demos without installing into your environment:
```
uvx --from ratatui-py ratatui-py-demos
# or a specific one
uvx --from ratatui-py ratatui-py-dashboard
```
## Quick start
```python
from ratatui_py import Terminal, Paragraph
with Terminal() as term:
p = Paragraph.from_text("Hello from Python!\nThis is ratatui.\n\nPress any key to exit.")
p.set_block_title("Demo", show_border=True)
term.draw_paragraph(p)
term.next_event(5000) # wait for key or 5s
```
### Run loop helper
Prefer a simple app pattern? Use `App`:
```python
from ratatui_py import App, Terminal, Paragraph
def render(term: Terminal, state: dict) -> None:
w, h = term.size()
p = Paragraph.from_text("Hello ratatui-py!\nPress q to quit.")
p.set_block_title("Demo", True)
term.draw_paragraph(p, (0, 0, w, h))
def on_event(term: Terminal, evt: dict, state: dict) -> bool:
return not (evt.get("kind") == "key" and evt.get("ch") in (ord('q'), ord('Q')))
App(render=render, on_event=on_event, tick_ms=250).run({})
```
## Widgets demo (List + Table + Gauge)
```python
from ratatui_py import Terminal, List, Table, Gauge, Style, FFI_COLOR
with Terminal() as term:
lst = List()
for i in range(5):
lst.append_item(f"Item {i}")
lst.set_selected(2)
lst.set_block_title("List", True)
tbl = Table()
tbl.set_headers(["A", "B", "C"])
tbl.append_row(["1", "2", "3"])
tbl.append_row(["x", "y", "z"])
tbl.set_block_title("Table", True)
g = Gauge().ratio(0.42).label("42%")
g.set_block_title("Gauge", True)
term.draw_list(lst, (0,0,20,6))
term.draw_table(tbl, (0,6,20,6))
term.draw_gauge(g, (0,12,20,3))
```
## Demos (via uvx, no install)
The easiest way to try things out is with `uvx` — it downloads and runs the
demo entry points in an isolated, ephemeral environment:
```
uvx --from ratatui-py ratatui-py-demos
uvx --from ratatui-py ratatui-py-dashboard
uvx --from ratatui-py ratatui-py-hello
```
If you’ve already installed the package, the same commands are available on
your PATH (e.g., `ratatui-py-demos`).
## Environment variables
- `RATATUI_FFI_LIB`: absolute path to a prebuilt shared library to bundle/load.
- `RATATUI_FFI_SRC`: path to local ratatui-ffi source to build with cargo.
- `RATATUI_FFI_GIT`: override git URL (default `https://github.com/holo-q/ratatui-ffi.git`).
- `RATATUI_FFI_TAG`: git tag/commit to fetch for bundling (default `v0.1.5`).
### Advanced installation and bundling
If you need precise control over the bundled Rust library, you can direct how
the shared library is sourced. On install, the package tries strategies in the
following order until one succeeds:
1) Use a prebuilt artifact when `RATATUI_FFI_LIB` points to a `.so/.dylib/.dll`.
2) Build from local sources when `RATATUI_FFI_SRC` is set (runs `cargo build`).
3) Clone and build `holo-q/ratatui-ffi` at `RATATUI_FFI_TAG`.
The chosen library is copied into `ratatui_py/_bundled/` and auto‑loaded at
runtime. Most users do not need this; it’s provided for reproducible builds
and development workflows.
### Demo/recording behavior toggles
- `RATATUI_PY_RECORDING=1`: optimize demo runner for recording. Enables inline mode, synchronized updates, and frame coalescing.
- `RATATUI_PY_FPS=NN`: target redraw rate in FPS (default 30). Use higher (e.g., 60) for snappier feel while recording.
- `RATATUI_PY_STATIC=1`: freeze animations for perfectly stable captures; input still works.
- `RATATUI_PY_NO_CODE=1`: hide the right‑hand code pane in the demo hub to reduce churn and draw only the live demo.
- `RATATUI_PY_SYNC=1`: force synchronized update bracketing even outside recording (usually not needed).
- `RATATUI_FFI_NO_ALTSCR=1`: render inline (no alternate screen) so scrollback is preserved. The demo runner enables this by default.
## Utilities for responsive apps
The `ratatui_py.util` module provides helpers to keep your UI snappy under load:
- `frame_begin(budget_ms=12)`: start a frame time budget. In heavy loops, periodically check `fb.should_yield()` and return to the event loop to avoid input backlog.
- `BackgroundTask(fn, loop=False)`: run work in a thread. Use when your workload releases the GIL (e.g., FFI/Rust, NumPy, I/O). Call `task.start()`, do `task.peek()` each frame to get the latest result, and `task.stop()` on shutdown.
- `ProcessTask(fn, loop=False, start_method='spawn')`: run CPU-bound work in a separate process (bypasses the GIL). The worker receives a context with:
- `ctx.recv_latest(timeout=0)`: read the most recent submitted job (drops stale ones).
- `ctx.publish(result)`: send back a result (older ones are dropped).
- `ctx.should_stop()`: check for cooperative shutdown.
Example (looping worker):
```python
from ratatui_py import ProcessTask
def worker(ctx):
params = None
while not ctx.should_stop():
msg = ctx.recv_latest(timeout=0.01)
if msg is not None:
params = msg
if params is None:
continue
result = do_heavy_compute(params) # pure CPU ok here
ctx.publish(result)
task = ProcessTask(worker, loop=True)
task.start()
task.submit({"zoom": 1.25})
# In your render loop: latest = task.peek()
# On shutdown: task.stop(join=True, terminate=True)
```
Tip: Prefer `BackgroundTask` when your computation releases the GIL; prefer `ProcessTask` for pure-Python CPU work where threading won’t help.
## Typed API (developer ergonomics)
Use the typed helpers for clear, discoverable code and great editor support:
- Rect/Point/Size dataclasses and `RectLike` union — pass either a `Rect` or a tuple to draw calls; layout helpers also offer typed variants:
```python
from ratatui_py import Rect, margin_rect, split_v_rect
area = Rect(0, 0, 80, 24)
body = margin_rect(area, all=1)
left, right = split_v_rect(body, 0.4, 0.6, gap=1)
```
- Color enum with `Style`: write `Style(fg=Color.LightBlue)` instead of raw integers.
Fluent helpers for emphasis: `Style().bold().underlined()` (uses `Mod` flags).
- Typed events: prefer `next_event_typed()` for dataclass events with enums:
```python
from ratatui_py import Terminal, KeyCode
with Terminal() as term:
evt = term.next_event_typed(100)
if evt and evt.kind == 'key' and evt.code == KeyCode.Left:
... # move selection
```
- Batched frames via a context manager:
```python
from ratatui_py import Terminal, Paragraph, Rect
with Terminal() as term:
p1 = Paragraph.from_text("Left")
p2 = Paragraph.from_text("Right")
with term.frame() as f:
f.paragraph(p1, Rect(0, 0, 20, 3))
f.paragraph(p2, Rect(20, 0, 20, 3))
# f.ok is True/False depending on `draw_frame`
```
- Key binding helper:
```python
from ratatui_py import Terminal, Keymap, KeyCode, KeyMods
km = Keymap()
km.bind(KeyCode.Left, KeyMods.NONE, lambda e: print('←'))
with Terminal() as term:
evt = term.next_event_typed(100)
if evt:
km.handle(evt)
```
- Convenience prelude:
```python
from ratatui_py.prelude import * # Terminal, Paragraph, Rect, Color, etc.
```
## Platform support
- Linux: `x86_64` is tested; other targets may work with a compatible `ratatui_ffi` build.
- macOS: Apple Silicon and Intel are supported via `dylib`.
- Windows: supported via `ratatui_ffi.dll`.
## Recording (flicker‑free, with scrollback)
The demos are tuned for clean screencasts:
- Inline viewport by default (no alternate screen) so your terminal scrollback remains intact.
- Whole‑frame synchronized updates to avoid partial‑frame flicker in recorders.
- Event‑driven redraw with key‑repeat draining for responsive navigation.
Quick start with asciinema (no shell prompt in the cast):
```
# Record the dashboard only (80x24), smooth and flicker‑free
asciinema rec -q --cols 80 --rows 24 --idle-time-limit 2 \
-c 'RATATUI_PY_RECORDING=1 RATATUI_PY_FPS=60 uv run ratatui-py-dashboard' \
docs/assets/dashboard.cast --overwrite
# Or record the demo hub (hide code pane for minimal churn)
asciinema rec -q --cols 80 --rows 24 --idle-time-limit 2 \
-c 'RATATUI_PY_RECORDING=1 RATATUI_PY_NO_CODE=1 RATATUI_PY_FPS=60 uv run ratatui-py-demos' \
docs/assets/demos.cast --overwrite
```
Prefer a GIF for GitHub’s README preview? Convert the cast:
```
# Using asciinema-agg (install locally or use its container image)
asciinema-agg --fps 30 --idle 2 docs/assets/dashboard.cast docs/assets/dashboard.gif
```
Notes:
- To absolutely eliminate motion during capture, add `RATATUI_PY_STATIC=1`.
- If your terminal still shows artifacts, record inside tmux: `tmux new -As rec` then run the same command.
- GitHub READMEs cannot embed a `.cast` player; use a GIF/MP4 and link to the `.cast` in docs.
## Troubleshooting
- Build toolchain not found: set `RATATUI_FFI_LIB` to a prebuilt shared library or install Rust (`cargo`) and retry.
- Wrong library picked up: ensure `RATATUI_FFI_LIB` points to a library matching your OS/arch.
- Import errors on fresh install: reinstall in a clean venv to ensure the bundled library is present.
### Terminal behavior and “clashes” cheat‑sheet
Ratatui (via crossterm) uses raw mode and (optionally) the alternate screen. Some terminal environments or Python shells can interact with these features in surprising ways. This section lists common scenarios and how to address them.
- Scrollback appears “lost”
- Alt screen replaces the visible buffer; your scrollback is preserved but hidden until exit.
- Fix: leave alt screen off (default in this package) or exit the app. To force alt screen: set `RATATUI_FFI_ALTSCR=1`.
- Keystrokes echo on screen, or input feels “sticky”
- Raw mode controls whether the terminal echoes input and how keys are delivered.
- Fix: raw mode is on by default here; to disable (e.g. for logging), set `RATATUI_FFI_NO_RAW=1`.
- Integrated terminals (VS Code, JetBrains, Jupyter, ipython)
- Some shells may buffer or handle ANSI differently; full‑screen TUIs might flicker.
- Fix: run from a regular terminal (e.g., GNOME Terminal, iTerm2, Windows Terminal). For diagnostics, disable alt screen and enable logging (see below).
- tmux/screen quirks
- Multiplexers change terminfo and may alter mouse/keypress behavior or scrollback.
- Fix: prefer alt screen in tmux (`RATATUI_FFI_ALTSCR=1`). If scrollback is a priority, keep alt screen off and accept in‑place updates.
- WSL/ConPTY (Windows)
- ConPTY handling can differ across versions; ensure you’re using Windows Terminal or a recent console host.
- If you see rendering anomalies, try disabling alt screen first.
- CI/headless usage
- TUIs require a TTY; instead, use headless render helpers like `headless_render_*` and `ratatui_headless_render_frame` to snapshot output for tests.
- Unicode/emoji rendering
- Ensure your locale is UTF‑8 and your font supports the glyphs you render. Some terminals need explicit configuration.
### Stable diagnostics and backtraces
Turn on robust diagnostics only when needed:
```bash
# rich diagnostics without alt screen
RATATUI_PY_DEBUG=1 uv run ratatui-py-demos
# or enable flags individually
RUST_BACKTRACE=full \
RATATUI_FFI_TRACE=1 \
RATATUI_FFI_NO_ALTSCR=1 \
RATATUI_FFI_PROFILE=debug \
RATATUI_FFI_LOG=ratatui_ffi.log \
uv run ratatui-py-demos
```
What these do:
- `RUST_BACKTRACE=full`: line‑accurate Rust backtraces on panics.
- `RATATUI_FFI_TRACE=1`: prints ENTER/EXIT lines for FFI calls and panics.
- `RATATUI_FFI_NO_ALTSCR=1`: avoids alt screen so logs remain visible.
- `RATATUI_FFI_PROFILE=debug`: bundles the debug cdylib for accurate symbols.
- `RATATUI_FFI_LOG=…`: saves all FFI logs to a file (recreated per run). Set `RATATUI_FFI_LOG_APPEND=1` to append.
Advanced:
- Python faulthandler: `PYTHONFAULTHANDLER=1` to dump tracebacks on signals.
- gdb/lldb: `gdb --args python -m ratatui_py.demo_runner` → `run`, then `bt full` on crash.
### Known pitfalls we harden against
- Dangling handles in batched frames (use‑after‑free)
- Cause: passing raw FFI pointers without keeping owners alive across `draw_frame`.
- Mitigation: Python wrapper retains strong references to widget owners for the duration of the draw.
- Out‑of‑bounds rectangles
- Cause: computing rects larger than the frame area.
- Mitigation: FFI clamps rects to the current frame before rendering.
- Panics inside FFI draw
- Cause: invalid inputs or internal errors.
- Mitigation: All FFI draw/init/free are wrapped with `catch_unwind`, logging the panic and backtrace and returning `false` rather than aborting.
If you still hit rendering anomalies or crashes, please open an issue with:
- Your OS/terminal, whether under tmux/screen/WSL.
- The exact command and environment variables used.
- `ratatui_ffi.log` and the console backtrace (if any).
- A minimal script to reproduce.
## Why ratatui-py?
Build rich, fast TUIs in Python without giving up a modern rendering engine.
- Performance‑first core: rendering and layout are powered by a Rust engine, so
complex scenes, charts, and animations stay smooth even at high FPS. Python
drives app logic; Rust does the pixel pushing.
- Batteries included UI: tables, lists, gauges, charts, sparklines, blocks,
borders, and a flexible layout system (constraints, margins, splits).
- Record‑ready output: synchronized updates, inline mode (no alt‑screen), and
frame coalescing produce clean casts in asciinema and similar tools.
- Practical ergonomics: a small, idiomatic wrapper (`Terminal`, widgets, and
`DrawCmd`) and layout helpers (`split_h`, `split_v`, `margin`).
- Testability: headless render helpers generate text snapshots for fast,
deterministic tests in CI without a TTY.
How this differs from common pure‑Python TUI stacks (respectfully, no names):
- Rendering model
- ratatui‑py: double‑buffered composition with batched draws; minimizes
cursor movement and reduces flicker/tearing.
- Pure‑Python stacks often stream writes and cursor moves directly; simple
UIs are fine, but complex scenes can require extra care to stay flicker‑free.
- Throughput and headroom
- ratatui‑py: high throughput under load (widgets + charts at 30–60 FPS) by
offloading rendering to Rust.
- Pure‑Python: perfectly adequate for text‑heavy apps; very dense scenes or
heavy per‑frame styling can stutter without extra optimization.
- Widgets and visuals
- ratatui‑py: ships with performance‑oriented widgets (charts/sparklines,
gauges, tables) and consistent borders/colors across terminals.
- Pure‑Python: highly hackable, often favoring line‑editing/REPL workflows;
advanced visuals may need custom drawing code.
- Packaging trade‑offs
- ratatui‑py: uses a small shared library (bundled wheels or build‑from‑source
paths provided). In exchange, you get Rust‑level rendering speed.
- Pure‑Python: zero external binary; simplest to vendor or embed.
When to pick which (rules of thumb)
- Choose ratatui‑py if you want smooth charts/dashboards, dense widgets,
flicker‑free recording, or you expect to push the terminal hard.
- Choose a Python‑only stack when you want a tiny dependency footprint, focus
on line editing/REPL flows, or prefer fully dynamic patch‑and‑reload cycles.
## Links
- PyPI: https://pypi.org/project/ratatui-py/
- Source: https://github.com/holo-q/ratatui-py
- Ratatui (Rust): https://github.com/ratatui-org/ratatui
- ratatui_ffi: https://github.com/holo-q/ratatui-ffi
## License
MIT — see [LICENSE](./LICENSE).
[ratatui_ffi]: https://github.com/holo-q/ratatui-ffi
[Ratatui]: https://github.com/ratatui-org/ratatui
Demo preview

[View asciinema cast](docs/assets/dashboard.cast)
Raw data
{
"_id": null,
"home_page": null,
"name": "ratatui-py",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "ratatui, tui, terminal-ui, terminal, ffi, ctypes, rust, bindings, widgets",
"author": "holo-q",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/25/96/fd2a2ba882c54e12ece21083b249a8323b6b9e0bf08673ebc7d37052c755/ratatui_py-0.3.7.tar.gz",
"platform": null,
"description": "# ratatui-py \u2014 Python bindings for Ratatui (Rust TUI)\n\n[](https://pypi.org/project/ratatui-py/)\n\n\n[](https://github.com/holo-q/ratatui-py/actions/workflows/docs.yml)\n[](https://github.com/holo-q/ratatui-py/actions/workflows/ci.yml)\n\nFast, zero-build Python bindings for [ratatui_ffi], the C ABI for\n[Ratatui] \u2014 a modern Rust library for building rich terminal user\ninterfaces (TUIs). Use Ratatui\u2019s performant rendering and widget set\nfrom Python via `ctypes`, with prebuilt shared libraries bundled for\nLinux, macOS, and Windows.\n\nKey features:\n- Zero-build install: bundles a prebuilt shared library when available\n and falls back to building from source when configured.\n- Cross\u2011platform: loads `libratatui_ffi.so` (Linux), `libratatui_ffi.dylib` (macOS), or `ratatui_ffi.dll` (Windows).\n- Idiomatic Python wrappers: start quickly with `Terminal`, `Paragraph`, `List`, `Table`, `Gauge`, and more.\n- Minimal overhead: direct FFI calls using `ctypes`.\n - Layout helpers: `margin`, `split_h`, `split_v` for quick UI splits.\n\n## Installation\n\nUse uv for a fast, reproducible install:\n\n```\nuv add ratatui-py\n```\n\nTry the interactive demos without installing into your environment:\n\n```\nuvx --from ratatui-py ratatui-py-demos\n# or a specific one\nuvx --from ratatui-py ratatui-py-dashboard\n```\n\n## Quick start\n\n```python\nfrom ratatui_py import Terminal, Paragraph\n\nwith Terminal() as term:\n p = Paragraph.from_text(\"Hello from Python!\\nThis is ratatui.\\n\\nPress any key to exit.\")\n p.set_block_title(\"Demo\", show_border=True)\n term.draw_paragraph(p)\n term.next_event(5000) # wait for key or 5s\n```\n\n### Run loop helper\n\nPrefer a simple app pattern? Use `App`:\n\n```python\nfrom ratatui_py import App, Terminal, Paragraph\n\ndef render(term: Terminal, state: dict) -> None:\n w, h = term.size()\n p = Paragraph.from_text(\"Hello ratatui-py!\\nPress q to quit.\")\n p.set_block_title(\"Demo\", True)\n term.draw_paragraph(p, (0, 0, w, h))\n\ndef on_event(term: Terminal, evt: dict, state: dict) -> bool:\n return not (evt.get(\"kind\") == \"key\" and evt.get(\"ch\") in (ord('q'), ord('Q')))\n\nApp(render=render, on_event=on_event, tick_ms=250).run({})\n```\n\n## Widgets demo (List + Table + Gauge)\n\n```python\nfrom ratatui_py import Terminal, List, Table, Gauge, Style, FFI_COLOR\n\nwith Terminal() as term:\n lst = List()\n for i in range(5):\n lst.append_item(f\"Item {i}\")\n lst.set_selected(2)\n lst.set_block_title(\"List\", True)\n\n tbl = Table()\n tbl.set_headers([\"A\", \"B\", \"C\"])\n tbl.append_row([\"1\", \"2\", \"3\"])\n tbl.append_row([\"x\", \"y\", \"z\"])\n tbl.set_block_title(\"Table\", True)\n\n g = Gauge().ratio(0.42).label(\"42%\")\n g.set_block_title(\"Gauge\", True)\n\n term.draw_list(lst, (0,0,20,6))\n term.draw_table(tbl, (0,6,20,6))\n term.draw_gauge(g, (0,12,20,3))\n```\n\n## Demos (via uvx, no install)\n\nThe easiest way to try things out is with `uvx` \u2014 it downloads and runs the\ndemo entry points in an isolated, ephemeral environment:\n\n```\nuvx --from ratatui-py ratatui-py-demos\nuvx --from ratatui-py ratatui-py-dashboard\nuvx --from ratatui-py ratatui-py-hello\n```\n\nIf you\u2019ve already installed the package, the same commands are available on\nyour PATH (e.g., `ratatui-py-demos`).\n\n\n## Environment variables\n- `RATATUI_FFI_LIB`: absolute path to a prebuilt shared library to bundle/load.\n- `RATATUI_FFI_SRC`: path to local ratatui-ffi source to build with cargo.\n- `RATATUI_FFI_GIT`: override git URL (default `https://github.com/holo-q/ratatui-ffi.git`).\n- `RATATUI_FFI_TAG`: git tag/commit to fetch for bundling (default `v0.1.5`).\n\n### Advanced installation and bundling\n\nIf you need precise control over the bundled Rust library, you can direct how\nthe shared library is sourced. On install, the package tries strategies in the\nfollowing order until one succeeds:\n\n1) Use a prebuilt artifact when `RATATUI_FFI_LIB` points to a `.so/.dylib/.dll`.\n2) Build from local sources when `RATATUI_FFI_SRC` is set (runs `cargo build`).\n3) Clone and build `holo-q/ratatui-ffi` at `RATATUI_FFI_TAG`.\n\nThe chosen library is copied into `ratatui_py/_bundled/` and auto\u2011loaded at\nruntime. Most users do not need this; it\u2019s provided for reproducible builds\nand development workflows.\n\n### Demo/recording behavior toggles\n- `RATATUI_PY_RECORDING=1`: optimize demo runner for recording. Enables inline mode, synchronized updates, and frame coalescing.\n- `RATATUI_PY_FPS=NN`: target redraw rate in FPS (default 30). Use higher (e.g., 60) for snappier feel while recording.\n- `RATATUI_PY_STATIC=1`: freeze animations for perfectly stable captures; input still works.\n- `RATATUI_PY_NO_CODE=1`: hide the right\u2011hand code pane in the demo hub to reduce churn and draw only the live demo.\n- `RATATUI_PY_SYNC=1`: force synchronized update bracketing even outside recording (usually not needed).\n- `RATATUI_FFI_NO_ALTSCR=1`: render inline (no alternate screen) so scrollback is preserved. The demo runner enables this by default.\n\n## Utilities for responsive apps\n\nThe `ratatui_py.util` module provides helpers to keep your UI snappy under load:\n\n- `frame_begin(budget_ms=12)`: start a frame time budget. In heavy loops, periodically check `fb.should_yield()` and return to the event loop to avoid input backlog.\n\n- `BackgroundTask(fn, loop=False)`: run work in a thread. Use when your workload releases the GIL (e.g., FFI/Rust, NumPy, I/O). Call `task.start()`, do `task.peek()` each frame to get the latest result, and `task.stop()` on shutdown.\n\n- `ProcessTask(fn, loop=False, start_method='spawn')`: run CPU-bound work in a separate process (bypasses the GIL). The worker receives a context with:\n - `ctx.recv_latest(timeout=0)`: read the most recent submitted job (drops stale ones).\n - `ctx.publish(result)`: send back a result (older ones are dropped).\n - `ctx.should_stop()`: check for cooperative shutdown.\n\nExample (looping worker):\n\n```python\nfrom ratatui_py import ProcessTask\n\ndef worker(ctx):\n params = None\n while not ctx.should_stop():\n msg = ctx.recv_latest(timeout=0.01)\n if msg is not None:\n params = msg\n if params is None:\n continue\n result = do_heavy_compute(params) # pure CPU ok here\n ctx.publish(result)\n\ntask = ProcessTask(worker, loop=True)\ntask.start()\ntask.submit({\"zoom\": 1.25})\n# In your render loop: latest = task.peek()\n# On shutdown: task.stop(join=True, terminate=True)\n```\n\nTip: Prefer `BackgroundTask` when your computation releases the GIL; prefer `ProcessTask` for pure-Python CPU work where threading won\u2019t help.\n\n## Typed API (developer ergonomics)\n\nUse the typed helpers for clear, discoverable code and great editor support:\n\n- Rect/Point/Size dataclasses and `RectLike` union \u2014 pass either a `Rect` or a tuple to draw calls; layout helpers also offer typed variants:\n\n```python\nfrom ratatui_py import Rect, margin_rect, split_v_rect\n\narea = Rect(0, 0, 80, 24)\nbody = margin_rect(area, all=1)\nleft, right = split_v_rect(body, 0.4, 0.6, gap=1)\n```\n\n- Color enum with `Style`: write `Style(fg=Color.LightBlue)` instead of raw integers.\n Fluent helpers for emphasis: `Style().bold().underlined()` (uses `Mod` flags).\n\n- Typed events: prefer `next_event_typed()` for dataclass events with enums:\n\n```python\nfrom ratatui_py import Terminal, KeyCode\n\nwith Terminal() as term:\n evt = term.next_event_typed(100)\n if evt and evt.kind == 'key' and evt.code == KeyCode.Left:\n ... # move selection\n```\n\n- Batched frames via a context manager:\n\n```python\nfrom ratatui_py import Terminal, Paragraph, Rect\n\nwith Terminal() as term:\n p1 = Paragraph.from_text(\"Left\")\n p2 = Paragraph.from_text(\"Right\")\n with term.frame() as f:\n f.paragraph(p1, Rect(0, 0, 20, 3))\n f.paragraph(p2, Rect(20, 0, 20, 3))\n # f.ok is True/False depending on `draw_frame`\n```\n\n- Key binding helper:\n\n```python\nfrom ratatui_py import Terminal, Keymap, KeyCode, KeyMods\n\nkm = Keymap()\nkm.bind(KeyCode.Left, KeyMods.NONE, lambda e: print('\u2190'))\n\nwith Terminal() as term:\n evt = term.next_event_typed(100)\n if evt:\n km.handle(evt)\n```\n\n- Convenience prelude:\n\n```python\nfrom ratatui_py.prelude import * # Terminal, Paragraph, Rect, Color, etc.\n```\n\n## Platform support\n- Linux: `x86_64` is tested; other targets may work with a compatible `ratatui_ffi` build.\n- macOS: Apple Silicon and Intel are supported via `dylib`.\n- Windows: supported via `ratatui_ffi.dll`.\n\n## Recording (flicker\u2011free, with scrollback)\n\nThe demos are tuned for clean screencasts:\n\n- Inline viewport by default (no alternate screen) so your terminal scrollback remains intact.\n- Whole\u2011frame synchronized updates to avoid partial\u2011frame flicker in recorders.\n- Event\u2011driven redraw with key\u2011repeat draining for responsive navigation.\n\nQuick start with asciinema (no shell prompt in the cast):\n\n```\n# Record the dashboard only (80x24), smooth and flicker\u2011free\nasciinema rec -q --cols 80 --rows 24 --idle-time-limit 2 \\\n -c 'RATATUI_PY_RECORDING=1 RATATUI_PY_FPS=60 uv run ratatui-py-dashboard' \\\n docs/assets/dashboard.cast --overwrite\n\n# Or record the demo hub (hide code pane for minimal churn)\nasciinema rec -q --cols 80 --rows 24 --idle-time-limit 2 \\\n -c 'RATATUI_PY_RECORDING=1 RATATUI_PY_NO_CODE=1 RATATUI_PY_FPS=60 uv run ratatui-py-demos' \\\n docs/assets/demos.cast --overwrite\n```\n\nPrefer a GIF for GitHub\u2019s README preview? Convert the cast:\n\n```\n# Using asciinema-agg (install locally or use its container image)\nasciinema-agg --fps 30 --idle 2 docs/assets/dashboard.cast docs/assets/dashboard.gif\n```\n\nNotes:\n- To absolutely eliminate motion during capture, add `RATATUI_PY_STATIC=1`.\n- If your terminal still shows artifacts, record inside tmux: `tmux new -As rec` then run the same command.\n- GitHub READMEs cannot embed a `.cast` player; use a GIF/MP4 and link to the `.cast` in docs.\n\n## Troubleshooting\n- Build toolchain not found: set `RATATUI_FFI_LIB` to a prebuilt shared library or install Rust (`cargo`) and retry.\n- Wrong library picked up: ensure `RATATUI_FFI_LIB` points to a library matching your OS/arch.\n- Import errors on fresh install: reinstall in a clean venv to ensure the bundled library is present.\n\n### Terminal behavior and \u201cclashes\u201d cheat\u2011sheet\n\nRatatui (via crossterm) uses raw mode and (optionally) the alternate screen. Some terminal environments or Python shells can interact with these features in surprising ways. This section lists common scenarios and how to address them.\n\n- Scrollback appears \u201clost\u201d\n - Alt screen replaces the visible buffer; your scrollback is preserved but hidden until exit.\n - Fix: leave alt screen off (default in this package) or exit the app. To force alt screen: set `RATATUI_FFI_ALTSCR=1`.\n\n- Keystrokes echo on screen, or input feels \u201csticky\u201d\n - Raw mode controls whether the terminal echoes input and how keys are delivered.\n - Fix: raw mode is on by default here; to disable (e.g. for logging), set `RATATUI_FFI_NO_RAW=1`.\n\n- Integrated terminals (VS Code, JetBrains, Jupyter, ipython)\n - Some shells may buffer or handle ANSI differently; full\u2011screen TUIs might flicker.\n - Fix: run from a regular terminal (e.g., GNOME Terminal, iTerm2, Windows Terminal). For diagnostics, disable alt screen and enable logging (see below).\n\n- tmux/screen quirks\n - Multiplexers change terminfo and may alter mouse/keypress behavior or scrollback.\n - Fix: prefer alt screen in tmux (`RATATUI_FFI_ALTSCR=1`). If scrollback is a priority, keep alt screen off and accept in\u2011place updates.\n\n- WSL/ConPTY (Windows)\n - ConPTY handling can differ across versions; ensure you\u2019re using Windows Terminal or a recent console host.\n - If you see rendering anomalies, try disabling alt screen first.\n\n- CI/headless usage\n - TUIs require a TTY; instead, use headless render helpers like `headless_render_*` and `ratatui_headless_render_frame` to snapshot output for tests.\n\n- Unicode/emoji rendering\n - Ensure your locale is UTF\u20118 and your font supports the glyphs you render. Some terminals need explicit configuration.\n\n### Stable diagnostics and backtraces\n\nTurn on robust diagnostics only when needed:\n\n```bash\n# rich diagnostics without alt screen\nRATATUI_PY_DEBUG=1 uv run ratatui-py-demos\n\n# or enable flags individually\nRUST_BACKTRACE=full \\\nRATATUI_FFI_TRACE=1 \\\nRATATUI_FFI_NO_ALTSCR=1 \\\nRATATUI_FFI_PROFILE=debug \\\nRATATUI_FFI_LOG=ratatui_ffi.log \\\nuv run ratatui-py-demos\n```\n\nWhat these do:\n- `RUST_BACKTRACE=full`: line\u2011accurate Rust backtraces on panics.\n- `RATATUI_FFI_TRACE=1`: prints ENTER/EXIT lines for FFI calls and panics.\n- `RATATUI_FFI_NO_ALTSCR=1`: avoids alt screen so logs remain visible.\n- `RATATUI_FFI_PROFILE=debug`: bundles the debug cdylib for accurate symbols.\n- `RATATUI_FFI_LOG=\u2026`: saves all FFI logs to a file (recreated per run). Set `RATATUI_FFI_LOG_APPEND=1` to append.\n\nAdvanced:\n- Python faulthandler: `PYTHONFAULTHANDLER=1` to dump tracebacks on signals.\n- gdb/lldb: `gdb --args python -m ratatui_py.demo_runner` \u2192 `run`, then `bt full` on crash.\n\n### Known pitfalls we harden against\n\n- Dangling handles in batched frames (use\u2011after\u2011free)\n - Cause: passing raw FFI pointers without keeping owners alive across `draw_frame`.\n - Mitigation: Python wrapper retains strong references to widget owners for the duration of the draw.\n\n- Out\u2011of\u2011bounds rectangles\n - Cause: computing rects larger than the frame area.\n - Mitigation: FFI clamps rects to the current frame before rendering.\n\n- Panics inside FFI draw\n - Cause: invalid inputs or internal errors.\n - Mitigation: All FFI draw/init/free are wrapped with `catch_unwind`, logging the panic and backtrace and returning `false` rather than aborting.\n\nIf you still hit rendering anomalies or crashes, please open an issue with:\n- Your OS/terminal, whether under tmux/screen/WSL.\n- The exact command and environment variables used.\n- `ratatui_ffi.log` and the console backtrace (if any).\n- A minimal script to reproduce.\n\n## Why ratatui-py?\n\nBuild rich, fast TUIs in Python without giving up a modern rendering engine.\n\n- Performance\u2011first core: rendering and layout are powered by a Rust engine, so\n complex scenes, charts, and animations stay smooth even at high FPS. Python\n drives app logic; Rust does the pixel pushing.\n- Batteries included UI: tables, lists, gauges, charts, sparklines, blocks,\n borders, and a flexible layout system (constraints, margins, splits).\n- Record\u2011ready output: synchronized updates, inline mode (no alt\u2011screen), and\n frame coalescing produce clean casts in asciinema and similar tools.\n- Practical ergonomics: a small, idiomatic wrapper (`Terminal`, widgets, and\n `DrawCmd`) and layout helpers (`split_h`, `split_v`, `margin`).\n- Testability: headless render helpers generate text snapshots for fast,\n deterministic tests in CI without a TTY.\n\nHow this differs from common pure\u2011Python TUI stacks (respectfully, no names):\n\n- Rendering model\n - ratatui\u2011py: double\u2011buffered composition with batched draws; minimizes\n cursor movement and reduces flicker/tearing.\n - Pure\u2011Python stacks often stream writes and cursor moves directly; simple\n UIs are fine, but complex scenes can require extra care to stay flicker\u2011free.\n\n- Throughput and headroom\n - ratatui\u2011py: high throughput under load (widgets + charts at 30\u201360 FPS) by\n offloading rendering to Rust.\n - Pure\u2011Python: perfectly adequate for text\u2011heavy apps; very dense scenes or\n heavy per\u2011frame styling can stutter without extra optimization.\n\n- Widgets and visuals\n - ratatui\u2011py: ships with performance\u2011oriented widgets (charts/sparklines,\n gauges, tables) and consistent borders/colors across terminals.\n - Pure\u2011Python: highly hackable, often favoring line\u2011editing/REPL workflows;\n advanced visuals may need custom drawing code.\n\n- Packaging trade\u2011offs\n - ratatui\u2011py: uses a small shared library (bundled wheels or build\u2011from\u2011source\n paths provided). In exchange, you get Rust\u2011level rendering speed.\n - Pure\u2011Python: zero external binary; simplest to vendor or embed.\n\nWhen to pick which (rules of thumb)\n- Choose ratatui\u2011py if you want smooth charts/dashboards, dense widgets,\n flicker\u2011free recording, or you expect to push the terminal hard.\n- Choose a Python\u2011only stack when you want a tiny dependency footprint, focus\n on line editing/REPL flows, or prefer fully dynamic patch\u2011and\u2011reload cycles.\n\n## Links\n- PyPI: https://pypi.org/project/ratatui-py/\n- Source: https://github.com/holo-q/ratatui-py\n- Ratatui (Rust): https://github.com/ratatui-org/ratatui\n- ratatui_ffi: https://github.com/holo-q/ratatui-ffi\n\n## License\nMIT \u2014 see [LICENSE](./LICENSE).\n\n[ratatui_ffi]: https://github.com/holo-q/ratatui-ffi\n[Ratatui]: https://github.com/ratatui-org/ratatui\nDemo preview\n\n\n\n[View asciinema cast](docs/assets/dashboard.cast)\n",
"bugtrack_url": null,
"license": "MIT License\n \n Copyright (c) 2025 holo-q\n \n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n \n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n \n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n \n ",
"summary": "Python bindings for ratatui_ffi (Ratatui C ABI) via ctypes",
"version": "0.3.7",
"project_urls": {
"Changelog": "https://github.com/holo-q/ratatui-py/blob/main/CHANGELOG.md",
"Documentation": "https://github.com/holo-q/ratatui-py#readme",
"Homepage": "https://github.com/holo-q/ratatui-py",
"Issues": "https://github.com/holo-q/ratatui-py/issues",
"Repository": "https://github.com/holo-q/ratatui-py"
},
"split_keywords": [
"ratatui",
" tui",
" terminal-ui",
" terminal",
" ffi",
" ctypes",
" rust",
" bindings",
" widgets"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "2596fd2a2ba882c54e12ece21083b249a8323b6b9e0bf08673ebc7d37052c755",
"md5": "445405ece666138d6ce6081e38bfa29a",
"sha256": "e478a48436a30b128a8888a5d22ccfa076cd7414f8551f32cb6e4f44a1f1b3b0"
},
"downloads": -1,
"filename": "ratatui_py-0.3.7.tar.gz",
"has_sig": false,
"md5_digest": "445405ece666138d6ce6081e38bfa29a",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 42507,
"upload_time": "2025-09-10T00:20:32",
"upload_time_iso_8601": "2025-09-10T00:20:32.724914Z",
"url": "https://files.pythonhosted.org/packages/25/96/fd2a2ba882c54e12ece21083b249a8323b6b9e0bf08673ebc7d37052c755/ratatui_py-0.3.7.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-09-10 00:20:32",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "holo-q",
"github_project": "ratatui-py",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "ratatui-py"
}