Skip to main content

A Python TUI library with differential rendering - port of @mariozechner/pi-tui

Project description

PyPiTUI

Terminal UIs that don't flicker. Native scrollback. 60fps.

PyPI Python License


from pypitui import TUI, Text, Input, ProcessTerminal

terminal = ProcessTerminal()
tui = TUI(terminal)

tui.add_child(Text("Hello, World!"))

inp = Input(placeholder="Type here...")
inp.on_submit = lambda v: print(f"You typed: {v}")
tui.add_child(inp)
tui.set_focus(inp)

tui.run()  # 60fps, no flicker, scrollback enabled

Why PyPiTUI?

Library Rendering Scrollback 60fps Size
curses Full redraw Built-in
Textual Full redraw ⚠️ ~50MB
Rich (Live) Full redraw ⚠️ ~10MB
PyPiTUI Differential ~100KB

Only changed lines redraw. No alternate screen buffer—your content flows into normal terminal scrollback.

Install

pip install pypitui
# pip install pypitui[rich]  # Optional: markdown, tables

Requires Python 3.12+.

Quick Start

from pypitui import (
    TUI, Container, Text, Input, SelectList, SelectItem,
    BorderedBox, ProcessTerminal, Key, matches_key
)

class App:
    def __init__(self):
        self.terminal = ProcessTerminal()
        self.tui = TUI(self.terminal)
        self.root = Container()
        self.tui.add_child(self.root)
        self.show_form()

    def show_form(self):
        """Compose a form from multiple components."""
        self.root.children.clear()

        # Container composes children vertically
        self.root.add_child(Text("User Registration"))
        self.root.add_child(Text("─" * 30))

        # Input with validation
        name_input = Input(placeholder="Enter username", max_length=20)
        self.root.add_child(name_input)

        # Another input
        email_input = Input(placeholder="Enter email")
        self.root.add_child(email_input)

        # Bordered box containing a list
        box = BorderedBox(title="Select Role")
        roles = SelectList([
            SelectItem("admin", "Administrator"),
            SelectItem("user", "Standard User"),
        ], max_visible=3)
        box.add_child(roles)
        self.root.add_child(box)

        self.tui.set_focus(name_input)

    def run(self):
        self.running = True
        self.tui.start()
        try:
            while self.running:
                data = self.terminal.read_sequence(timeout=0.05)
                if data and matches_key(data, Key.ctrl("c")):
                    break
                self.tui.handle_input(data)
                self.tui.request_render()
                self.tui.render_frame()
        finally:
            self.tui.stop()

App().run()

Components

  • Text — Multi-line text with wrapping
  • Input — Text input with cursor, validation
  • SelectList — Interactive selection with filtering
  • BorderedBox — Panel with borders and title
  • Container — Groups components vertically
  • OverlayOptions — Floating dialogs and modals

Critical Pattern: Reuse the TUI

Wrong: Creating new TUI instances breaks differential rendering.

# ❌ DON'T
def switch_screen():
    return TUI(terminal)  # Loses state!

Right: Clear containers, not the TUI.

# ✅ DO
class App:
    def __init__(self):
        self.tui = TUI(terminal)  # Create once
        self.root = Container()
        self.tui.add_child(self.root)

    def switch_screen(self):
        self.root.children.clear()  # Clear container
        self.root.add_child(Text("New Screen"))

Rich Integration

Optional Rich support for markdown and tables:

from pypitui.rich_components import Markdown, RichTable, RichText

tui.add_child(Markdown("# Hello\n\n**Bold** text"))

Development

git clone https://github.com/jeremysball/pypitui.git
cd pypitui && uv sync --extra dev

# Install pre-commit hooks (runs ruff, mypy, pytest)
git config core.hooksPath .githooks

uv run python examples/demo.py

API Reference

Import Purpose
TUI Main controller
Container, Text, Input, SelectList, BorderedBox Components
OverlayOptions, OverlayMargin Overlay positioning
Key, matches_key, parse_key Keyboard handling
ProcessTerminal, MockTerminal Terminal I/O

Full docs: LLMS.md

License

MIT — see LICENSE.


Inspired by pi-tui

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

pypitui-0.1.0.tar.gz (35.0 MB view details)

Uploaded Source

Built Distribution

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

pypitui-0.1.0-py3-none-any.whl (61.1 kB view details)

Uploaded Python 3

File details

Details for the file pypitui-0.1.0.tar.gz.

File metadata

  • Download URL: pypitui-0.1.0.tar.gz
  • Upload date:
  • Size: 35.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pypitui-0.1.0.tar.gz
Algorithm Hash digest
SHA256 dbb39702b9ede882a3f4720531d0f7b34fcc321af9c13ecd8efda450f2fcc495
MD5 edd4be97a5363add660abe38d562f05f
BLAKE2b-256 1ef223acb9153bcdcbbb169af37506e205574a8bbc384dce2f4bc1e575b12bca

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypitui-0.1.0.tar.gz:

Publisher: release.yml on jeremysball/pypitui

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pypitui-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pypitui-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 61.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pypitui-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 279d566369fcb38549147ec60ee23c8c0d521407eec71bcb3959589cc626bbe7
MD5 e8d79d28144f0f0004d54e31bdfa7ef6
BLAKE2b-256 a69bc6bd02fe3dd2cbd6e19a1395b130e4db57f9bbdce58a5ef1a1cc571921de

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypitui-0.1.0-py3-none-any.whl:

Publisher: release.yml on jeremysball/pypitui

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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