Getting started¶
Install¶
termopy needs Python 3.12 or later, and a POSIX terminal.
Its only dependency is Rich, which it uses to measure glyph widths correctly and to draw Rich renderables into a view. Rich's heavy parts (Pygments, markdown-it) are lazily imported, so importing termopy costs about 20 ms.
Your first app¶
from termopy import UI, Style, View, run
from termopy.events import Event, Key, KeyPress
def app(ui: UI) -> View:
name, set_name = ui.state("world")
def keys(event: Event) -> bool:
if isinstance(event, KeyPress) and event.key is Key.BACKSPACE:
set_name(name[:-1])
return True
if isinstance(event, KeyPress) and isinstance(event.key, str):
set_name(name + event.key)
return True
return False
ui.on_event(keys)
return View.vcat([
View.text(f"Hello, {name}!", Style(bold=True, fg=ui.theme.mauve)),
View.text(""),
View.text("Type to change it. Ctrl-C to quit.", Style(fg=ui.theme.subtext0)),
]).center(within=ui.size)
if __name__ == "__main__":
run(app)
Three things are happening.
ui.state("world") asks for a value that survives re-renders, and gets back the value
and a setter. Calling the setter marks the frame dirty, so app runs again.
ui.on_event subscribes to input for this frame. Returning True consumes the event so
nothing behind it sees it.
The return value is a View: an immutable grid of styled cells. View.vcat stacks,
center positions. Nothing was mutated and nothing was drawn; run takes care of that.
Running it¶
Ctrl-C quits. run puts the terminal in raw mode on the alternate screen and restores
it on the way out, including if your app raises.
Testing it¶
The same function, without a terminal:
from termopy.events import KeyPress
from termopy.testing import render, to_text
from termopy.view import Size
def test_typing_changes_the_greeting():
view = render(app, size=Size(40, 10), events=[KeyPress("!")])
assert "Hello, world!!" in to_text(view)
render runs the app, feeds it the events, and returns the final View. to_text
throws away the styling and gives you the characters. The thing under test is a
function, so you call it, with no pilot and no async harness to set up.
See Testing for asserting on colours, geometry and timers.
What to read next¶
The guide covers each piece in turn. If you would rather read code,
examples/ in the repository has about twenty small programs, one per idea, and
porting/ has two complete applications.