A cell-buffer terminal UI framework
Project description
painted
One library. Print to TUI. One dependency.
from painted import show
show({"cpu": 67, "mem": 82, "disk": 45})
TTY gets a styled bar chart. Pipe gets plain text. --json gets JSON.
Same data, same function — the stack figures out the rest.
Enter anywhere
Every entry point uses the same building blocks. Pick the one that fits your problem — you never hand over control, and there's no cliff between them.
Print styled output
Replace print() one call at a time. Auto-detects TTY — no ANSI garbage in pipes.
from painted import Block, Style, print_block
block = Block.text("deploy OK", Style(fg="green", bold=True))
print_block(block)
Compose
Blocks are immutable rectangles. Compose them with functions — no widget tree, no DOM.
from painted import border, join_vertical, pad, ROUNDED
header = Block.text(" api-gateway ", Style(bold=True, reverse=True))
status = join_vertical(
Block.text(" replicas: 2/3 ready", Style(fg="yellow")),
Block.text(" /health: 200 12ms", Style(fg="green")),
)
card = border(join_vertical(header, status), chars=ROUNDED)
print_block(card)
CLI harness
One render function, three output modes. Pipe gets static, TTY gets live updates,
-i gets full interactive.
from painted import run_cli, CliContext, Block
def render(ctx: CliContext, data: dict) -> Block:
# your render logic — returns a Block
...
def fetch() -> dict:
return {"status": "ok", "replicas": 3}
run_cli(sys.argv[1:], render=render, fetch=fetch)
myapp # auto-detect
myapp -q # quiet (zoom 0)
myapp -v # verbose (zoom 2)
myapp -i # interactive TUI
myapp --json # JSON output
myapp | grep ok # plain text, no ANSI
Full TUI
Alt screen, keyboard input, async render loop, diff-flush. Subclass Surface,
override render() and on_key().
import asyncio
from painted import Block, Style, border
from painted.tui import Surface
class MyApp(Surface):
def render(self):
block = Block.text("Hello!", Style(fg="green"))
border(block, title="Demo").paint(self._buf)
def on_key(self, key: str):
if key == "q":
self.quit()
asyncio.run(MyApp().run())
Install
pip install painted
One dependency: wcwidth (wide character display width).
API
Primitives
| Export | Purpose |
|---|---|
Cell / Style |
Atomic display unit (char + style, frozen) |
Span / Line |
Styled text with display-width awareness |
Block |
Immutable rectangle of cells for composition |
Composition
| Export | Purpose |
|---|---|
join_horizontal / join_vertical |
Combine Blocks |
pad / border / truncate |
Transform Blocks |
BorderChars |
ROUNDED, HEAVY, DOUBLE, LIGHT, ASCII presets |
Display
| Export | Purpose |
|---|---|
show(data) |
Zero-config display with auto-detection |
print_block(block) |
Print a Block to stdout (TTY-aware) |
run_cli(args, render=, fetch=) |
CLI harness with zoom/mode/format |
Views (painted.views)
| Export | Purpose |
|---|---|
shape_lens |
Auto-dispatch for exploration (numeric → chart, hierarchical → tree) |
tree_lens / chart_lens |
Explicit tree and chart strategies |
list_view / table / text_input |
Stateful interactive components |
spinner / progress_bar / sparkline |
Animation and data viz |
TUI (painted.tui)
| Export | Purpose |
|---|---|
Surface |
Alt screen, keyboard, resize, diff-flush render loop |
Layer |
Modal stack: Stay / Pop / Push / Quit |
Buffer / BufferView |
2D cell grid with region clipping |
Aesthetic
| Export | Purpose |
|---|---|
Palette |
5 semantic Style roles (success, warning, error, accent, muted) |
IconSet |
Glyph vocabulary with ASCII fallback |
License
MIT
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file painted-0.1.1.tar.gz.
File metadata
- Download URL: painted-0.1.1.tar.gz
- Upload date:
- Size: 7.5 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ee32fe9a66654551fd0b8008414b1de0cab6edb2609530de0f427f6432261cdd
|
|
| MD5 |
db6980825da6c62875183505dd858fc7
|
|
| BLAKE2b-256 |
d01858d535fe0c535a06b32b2dc8fd41f1065e1a671ea542c545a1e333baa7db
|
Provenance
The following attestation bundles were made for painted-0.1.1.tar.gz:
Publisher:
release.yml on kgruel/painted
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
painted-0.1.1.tar.gz -
Subject digest:
ee32fe9a66654551fd0b8008414b1de0cab6edb2609530de0f427f6432261cdd - Sigstore transparency entry: 1088533364
- Sigstore integration time:
-
Permalink:
kgruel/painted@af761db80abe373a00d6b3a52c2425d6a627350c -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/kgruel
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@af761db80abe373a00d6b3a52c2425d6a627350c -
Trigger Event:
release
-
Statement type:
File details
Details for the file painted-0.1.1-py3-none-any.whl.
File metadata
- Download URL: painted-0.1.1-py3-none-any.whl
- Upload date:
- Size: 101.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e70f8cd73b42f8a3a0bf01b86851d59acccfd17a257ebfa42987e038fc0c84b5
|
|
| MD5 |
ff0ea5ce4ca17acfa3f1a3f3986c3ab8
|
|
| BLAKE2b-256 |
bcfffa31efd4d0e963d31fe8524636a2bae41bc14d01cb48f96ad026d961ec8f
|
Provenance
The following attestation bundles were made for painted-0.1.1-py3-none-any.whl:
Publisher:
release.yml on kgruel/painted
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
painted-0.1.1-py3-none-any.whl -
Subject digest:
e70f8cd73b42f8a3a0bf01b86851d59acccfd17a257ebfa42987e038fc0c84b5 - Sigstore transparency entry: 1088533406
- Sigstore integration time:
-
Permalink:
kgruel/painted@af761db80abe373a00d6b3a52c2425d6a627350c -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/kgruel
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@af761db80abe373a00d6b3a52c2425d6a627350c -
Trigger Event:
release
-
Statement type: