Sayer
Fast. Scalable. Elegant. Command the CLI like a boss. 🧙♂️
Documentation: https://sayer.dymmond.com 📚
Source Code: https://github.com/dymmond/sayer
The official supported version is always the latest released.
🤔 What is Sayer?
Sayer is a modern, async-native Python CLI framework built for developers who want more:
- More structure.
- More power.
- More expressiveness.
Less boilerplate. Less headache. Less "why doesn't this just work?".
Designed to scale from weekend scripts to enterprise-grade CLI suites — with a touch of magic.
📦 Installation
Using pip:
pip install sayer
Or with uv (blazing fast):
uv pip install sayer
🧩 Features
- ✅ Fully async support out-of-the-box
- ✅ Param metadata via
Option(...),Argument(...),Env(...)— inspired by the best - ✅ Declarative CLI building with decorators
- ✅ Built-in middleware system (yes, for CLI!)
- ✅ Shared app state and lifecycle management
- ✅ Terminal-rich output via
rich - ✅ Easy testing with
SayerTestClient - ✅ Flexible help and docs rendering
- ✅ Clean project scaffolding, sensible defaults
- ✅ 100% type annotated.
🔥 Why Sayer?
| Feature | Sayer | Notes |
|---|---|---|
| Async Support | ✅ Yes | Truly async from top to bottom |
| Param Metadata | ✅ Yes | With rich options, env vars, etc. |
| Middleware Support | ✅ Yes | Per-command, app-wide, scoped |
| Lifecycle Hooks | ✅ Yes | on_startup, on_shutdown |
| State Management | ✅ Yes | Like a Flask g but better |
| Testability | ✅ Yes | CLI client for unit tests |
| Output Styling | ✅ Yes | Built-in rich integration |
| Based on Modern Tools | ✅ Hatch + UV | Modern dev setup from day 1 |
| Full Typing | ✅ Yes | Ty + Ruff compliant |
| Fun to Use? | 🕺 Extremely | Let the code dance with you |
🚀 Getting Started
Create your first CLI app:
from sayer import Sayer, Option
app = Sayer()
@app.command()
def hello(name: str = Option(..., help="Your name")):
"""Say hello to someone"""
print(f"Hello, {name}!")
if __name__ == "__main__":
app()
Run it:
$ python app.py hello --name Ada
Hello, Ada!
🧪 Testing
hatch run test:test
Or with pytest:
pytest -v
📚 Documentation
Full docs available at: https://sayer.dymmond.com
You'll find:
- Full API reference
- Command examples
- Parameter deep dives
- Middleware patterns
- Configuration strategies
- ... and some fun easter eggs 🐣
Metadata
Release files for sayer 0.8.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| sayer-0.8.1.tar.gz | 69.7 kB | Without provenance | Details for sayer-0.8.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| sayer-0.8.1-py3-none-any.whl | Python 3 | none | any | Details for sayer-0.8.1-py3-none-any.whl |
Total release size: 155.0 kB
Release files / sayer-0.8.1.tar.gz
| Download URL | sayer-0.8.1.tar.gz |
|---|---|
| Size | 69.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
77c6c822f5cf9559f6978c394eaf4bea42eebb20d44691412a5a264ce4e28813
|
|
BLAKE2b-256 checksum How to use checksums |
e3781e5ce98759948450bfb69e81c7abfc9a85e31879cc010d9aa3a189f021d6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
Hatch/1.18.1 {"ci":true,"cpu":"x86_64","distro":{"id":"noble","libc":{"lib":"glibc","version":"2.39"},"name":"Ubuntu","version":"24.04"},"implementation":{"name":"CPython","version":"3.12.15"},"installer":{"name":"hatch","version":"1.18.1"},"openssl_version":"OpenSSL 3.0.13 30 Jan 2024","python":"3.12.15","system":{"name":"Linux","release":"7.0.0-1017-azure"}} HTTPX2/2.16.0
|
Release files / sayer-0.8.1-py3-none-any.whl
| Download URL | sayer-0.8.1-py3-none-any.whl |
|---|---|
| Size | 85.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
06b661063e5a68b12c6e166d86f8fe75cfc1d512ca21bb7d84e3153ef195d960
|
|
BLAKE2b-256 checksum How to use checksums |
42f0b60fc261eb90b38480a2e9d915fe57c0c8067fde50bd41dfeb6d738dd6aa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
Hatch/1.18.1 {"ci":true,"cpu":"x86_64","distro":{"id":"noble","libc":{"lib":"glibc","version":"2.39"},"name":"Ubuntu","version":"24.04"},"implementation":{"name":"CPython","version":"3.12.15"},"installer":{"name":"hatch","version":"1.18.1"},"openssl_version":"OpenSSL 3.0.13 30 Jan 2024","python":"3.12.15","system":{"name":"Linux","release":"7.0.0-1017-azure"}} HTTPX2/2.16.0
|
Security for sayer 0.8.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.