Canary Framework 0.6
A typed, decorator-driven async framework for Service, Router, and Module applications.
中文 · Documentation · Changelog
Install
pip install canary-framework
Requires Python 3.12+.
The model
- Service owns lifecycle, dependency injection, and domain logic. It is not an ASGI app.
- Router is the smallest runnable HTTP application. Keep small endpoint logic inline; extract reusable or non-HTTP-tested logic into Services.
- Module explicitly composes
children, creates dependency scopes, and recursively aggregates descendant Routers. - A runtime root must be initialized with
await app.init()before it is served. ASGI lifespan performs startup and shutdown only; it never initializes. on_initprepares structural state. Event-loop-bound long-lived resources belong inon_startup; release them inon_shutdown.- Configuration is root/Module context, not a dependency-injected Service. One root config owns OpenAPI metadata, security schemes, and documentation paths.
Quick start
import asyncio
import uvicorn
from canary_framework import get, router
from canary_framework.core import RouterBase
@router(prefix="/hello", tags=("Hello",))
class HelloRouter(RouterBase):
@get("")
async def hello(self) -> dict[str, str]:
return {"message": "Hello, Canary!"}
async def setup() -> HelloRouter:
app = HelloRouter()
await app.init()
return app
application = asyncio.run(setup())
uvicorn.run(application, lifespan="on")
Open http://127.0.0.1:8000/hello, /docs, /redoc, or /openapi.json.
Composition and transitive DI
from canary_framework import get, module, router, service
from canary_framework.core import ModuleBase, RouterBase, ServiceBase
@service()
class Greeting(ServiceBase):
def message(self, name: str) -> str:
return f"Hello, {name}!"
@router(prefix="/api")
class ApiRouter(RouterBase):
greeting: Greeting
@get("/hello/{name}")
async def hello(self, name: str) -> dict[str, str]:
return {"message": self.greeting.message(name)}
@module(children=(ApiRouter,))
class App(ModuleBase):
pass
Greeting is discovered transitively through ApiRouter; the Module lists only explicit composition nodes. Promote a shared Service to a common parent Module when sibling scopes must reuse one instance.
HTTP and OpenAPI
Use top-level @get, @post, @put, @delete, and @patch. Paths may contain path templates (/{item_id}) and query templates (/search?q={query}). Endpoint metadata supports request/response models, status codes, tags, summaries, descriptions, deprecation, operation IDs, and additional responses.
Nested Module and Router prefixes, tags, and security requirements propagate deterministically. The runtime root compiles one route table and one OpenAPI document. Route, documentation-path, operation-ID, security-scheme, and schema-name conflicts fail during initialization.
Examples
Ten runnable examples are in examples/, progressing from a standalone Router through nested scopes, validation, OpenAPI, and a layered application. 04_module_aggregation.py demonstrates recursive route aggregation.
Breaking release
0.6.0 has no 0.5.x compatibility layer. See What's New for the migration table.
License
Apache-2.0.
Release files for canary-framework 0.6.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 | |
|---|---|---|---|
| canary_framework-0.6.1.tar.gz | 85.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| canary_framework-0.6.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 124.0 kB
Release files / canary_framework-0.6.1.tar.gz
| Download URL | canary_framework-0.6.1.tar.gz |
|---|---|
| Size | 85.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4e9d2b1af84d3ef88208c72549f6b4f516191f2ca0d2cb9d2d07d60dbbb1e445
|
|
BLAKE2b-256 checksum How to use checksums |
e0ea5b9df0ce0d2efee3e314bd515641a829ddbd64ccd16b5a1c44c1c774c746
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 31, 2026.
Transparency logRelease files / canary_framework-0.6.1-py3-none-any.whl
| Download URL | canary_framework-0.6.1-py3-none-any.whl |
|---|---|
| Size | 39.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e625cd346cf73ace283243a760b8d2c228780f4def782ab7c9aea9dd8dee1489
|
|
BLAKE2b-256 checksum How to use checksums |
cd42be0aaad84711ea44fcf4870a972c66f3dbdc8c5de7bc5dfdd78d25fbf8cb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 31, 2026.
Transparency log