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

Uploaded Python 3

File details

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

File metadata

  • Download URL: pypitui-0.2.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.2.0.tar.gz
Algorithm Hash digest
SHA256 2fda817c5973be46a1347f08f689938e0a450febeef2641aebfbd3bb91fbaf6c
MD5 3ab8e594e14615e2119d9de192fff21d
BLAKE2b-256 9688b2d74de03ca63107620fbeb5a0212cdce3e4d01d260e46d9890c34befad6

See more details on using hashes here.

Provenance

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

File metadata

  • Download URL: pypitui-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 59.9 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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a5b103b3a8b2317b9514baf3bf5b93b1ada7a53e0abb7a452a52a92e3810ad92
MD5 59d513afda18dc0573bbf9206bc682d1
BLAKE2b-256 a6a07ecc5d7995bddf4f369b9b60c0a94854f64d7a87ce006aa74760e97c5f91

See more details on using hashes here.

Provenance

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