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.2.2.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.2.2-py3-none-any.whl (62.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pypitui-0.2.2.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.2.2.tar.gz
Algorithm Hash digest
SHA256 30ecc1d0289aa9f5a551c986497acafb8d0ef78c80105ba694a372bbccc6ad01
MD5 9ef7cbe6fc0a201124168f226f9373ee
BLAKE2b-256 2742480ef11cab38a3de224cc5eeb307d96ad2dd74d6724482f0b3d26d1edcf7

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypitui-0.2.2.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.2.2-py3-none-any.whl.

File metadata

  • Download URL: pypitui-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 62.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.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 d1a50d61e22241518eee7197f501c7db66f1f4cb72abbe1f916f0f1261ea4153
MD5 48a5c9adeab005cee553c96aa2bb063b
BLAKE2b-256 d68697d91b93ef13bf3fd29c07d82d5ea2f63d5e2a359584f3837364ec408fdf

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypitui-0.2.2-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