Piou
A CLI tool to build beautiful command-line interfaces with type validation.
Quick Example
from piou import Cli, Option
cli = Cli(description='A CLI tool')
@cli.command(cmd='foo', help='Run foo command')
def foo_main(
bar: int = Option(help='Bar positional argument (required)'),
baz: str = Option('-b', '--baz', help='Baz keyword argument (required)'),
foo: str | None = Option(None, '--foo', help='Foo keyword argument'),
):
"""
A longer description on what the function is doing.
"""
pass
if __name__ == '__main__':
cli.run()
Installation
pip install piou
Or with uv:
uv add piou
Or with conda:
conda install piou -c conda-forge
Raw Formatter
By default, Piou uses Rich for beautiful terminal output. If you prefer plain text output, you can use the raw formatter:
# Force raw output via environment variable
PIOU_FORMATTER=raw python your_cli.py --help
Documentation
Full documentation is available at andarius.github.io/piou.
Features
- FastAPI-like developer experience with type hints
- Custom formatters (Rich-based by default)
- Nested command groups / sub-commands
- Derived options for reusable argument patterns
- Async command support
- Type validation and casting
- Interactive TUI mode with command suggestions and history
- Structured JSON help (
--help-json) for tooling and programmatic CLI discovery
Why Piou?
I could not find a library that provided:
- The same developer experience as FastAPI
- Customization of the interface (to build a CLI similar to Poetry)
- Type validation / casting
Typer is the closest alternative but lacks the possibility to format the output in a custom way using external libraries (like Rich).
Piou provides all these possibilities and lets you define your own Formatter.
Async Commands
Commands can be async functions — piou detects coroutines and runs them automatically, no manual asyncio.run() needed:
from piou import Cli, Option
cli = Cli(description='Async example')
@cli.command(cmd='fetch', help='Fetch data')
async def fetch(url: str = Option(help='URL to fetch')):
import niquests
async with niquests.AsyncSession() as client:
r = await client.get(url)
print(r.status_code)
if __name__ == '__main__':
cli.run()
This works the same way for commands inside command groups.
Interactive TUI Mode
Piou includes an optional interactive TUI (Text User Interface) mode powered by Textual. This provides a rich terminal experience with command suggestions, history, and inline completions.
Installation
pip install piou[tui]
# With auto-reload support for development
pip install piou[tui-reload]
Usage
Enable TUI mode by setting tui=True when creating your CLI:
from piou import Cli, Option
cli = Cli(description='My Interactive CLI', tui=True)
@cli.command(cmd='hello', help='Say hello')
def hello(name: str = Option(..., help='Name to greet')):
print(f'Hello, {name}!')
if __name__ == '__main__':
cli.run()
Or via the --tui flag:
python my_cli.py --tui
Or via the PIOU_TUI=1 environment variable:
PIOU_TUI=1 python my_cli.py
TUI Features
- Command suggestions: Type
/to see available commands with descriptions - Subcommand navigation: Use
:to navigate subcommands (e.g.,/stats:uploads) - Inline completions: See argument placeholders as you type
- Command history: Navigate previous commands with up/down arrows (persisted across sessions)
- Rich output: ANSI colors and formatting preserved in output
- Keyboard shortcuts:
Tab- Confirm selected suggestionUp/Down- Navigate suggestions or historyCtrl+C- Clear input (press twice to exit)Escape- Quit
- Dev mode: Auto-reload commands when source files change (see below)
Dev Mode with Auto-Reload
For faster development iteration, enable dev mode to automatically reload your commands when source files change:
pip install piou[tui-reload]
Then use the --tui-reload flag:
python my_cli.py --tui-reload
Or via environment variable:
PIOU_TUI_DEV=1 python my_cli.py --tui
When enabled, Piou watches your command source files and hot-reloads them on save. You can also toggle reload mode at runtime with the /tui-reload command.
To run custom code after each reload (e.g., refresh cached data), use the @cli.tui_on_reload decorator:
@cli.tui_on_reload
def on_reload():
print('Code reloaded!')
Advanced Example: HTTP Benchmark
The TUI mode supports mounting custom Textual widgets for rich interactive displays. This example benchmarks HTTP libraries with live progress grids:
See examples/http_bench_tui.py for the full implementation using TuiContext and custom widgets.
Development
Running Tests
uv run pytest
Generating Documentation
# Build docs
uv run --group docs mkdocs build
# Serve locally
uv run --group docs mkdocs serve
Generating Screenshots and GIFs
Terminal recordings are created with VHS. Install it first:
# Ubuntu/Debian
sudo apt install vhs ttyd
# macOS
brew install vhs
# Or via Go
go install github.com/charmbracelet/vhs@latest
Then generate recordings from tape files:
vhs docs/static/tui-demo.tape
Tape files are located in docs/static/ and define scripted terminal sessions that produce GIFs.
Release files for piou 0.37.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| piou-0.37.0.tar.gz | 1.7 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| piou-0.37.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.7 MB
Release files / piou-0.37.0.tar.gz
| Download URL | piou-0.37.0.tar.gz |
|---|---|
| Size | 1.7 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bd872f4ccfaa6a16e95c055dcb7b8c55bd2d69ccbd722e728ee2f7508e9d59c2
|
|
BLAKE2b-256 checksum How to use checksums |
3d326def501cfb0de042250544a5277cabe9cfacaf87303b3e43a4fb98b8652a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / piou-0.37.0-py3-none-any.whl
| Download URL | piou-0.37.0-py3-none-any.whl |
|---|---|
| Size | 57.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e28c1be2c055f48eb7ce3bcbc316f76e0e07be82e718130a41f8e6dfe9b8c69f
|
|
BLAKE2b-256 checksum How to use checksums |
85d4b7f6bda3ecc23009e62d1742393f6c20f6295e0d544abdfd38cebcfcdf8a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|