Tutorial 3: State, Middleware, and Testing¶
This tutorial adds production-grade behavior: shared state, middleware hooks, and tests.
Step 1. Add shared state¶
Inject it into commands:
Step 2. Register middleware¶
from sayer.middleware import register
def before(name, args):
print(f"[before] {name} -> {args}")
def after(name, args, result):
print(f"[after] {name} -> {result}")
register("audit", before=[before], after=[after])
@app.command(middleware=["audit"])
def ping():
return "pong"
Step 3. Add tests¶
from sayer.testing import SayerTestClient
def test_ping():
client = SayerTestClient(app=app)
result = client.invoke(["ping"], with_return_value=True)
assert result.exit_code == 0
assert result.return_value == "pong"
Step 4. Validate behavior¶
What changed¶
Stateprovides shared, injected context.- Middleware adds cross-cutting behavior.
SayerTestClientvalidates output and return values.