Lightweight decorator-driven Python async service framework with dependency injection
Project description
Canary Framework
Lightweight Python Async Service Framework — Decorator-Driven, Zero Boilerplate
Canary Framework is a decorator-driven async service framework for Python. Core philosophy: Services are the smallest unit, modules compose services, and modules themselves are services.
Core Features
- Decorator-Driven — Use
@service,@module,@routerdecorators, zero inheritance required - Topological Startup — Kahn's algorithm ensures dependencies start first
- Dependency Injection —
deps=[DBService]auto-injected asself.db_service - Lifecycle Management —
@after_config/@after_init/@before_startup/@before_shutdownhooks - ASGI Compatible — Built on Starlette, works with uvicorn and other ASGI servers
- Modular Architecture — Hierarchical composition with nested modules
- OpenAPI Support — Auto-generated Swagger UI and ReDoc documentation
Design Principles
- Decorator-Driven — Code is configuration, no complex setup required
- Async-First — Built on async/await for high performance
- Explicit Dependencies — Clear dependency declarations for better understanding and testing
- Convention Over Configuration — Auto-injection, auto-mounting
- Composability — Build complex systems through module composition
Installation
pip install canary-framework
Quick Start
from canary_framework import module, service, router, get, post, after_config
@service(name="database")
class DatabaseService:
def __init__(self):
self.connection = None
@after_config
async def connect(self):
self.connection = "connected"
print("Database connected")
@service(name="user_service", deps=[DatabaseService])
class UserService:
async def get_user(self, user_id):
return {"id": user_id, "name": "User"}
@router(name="api", prefix="/api", deps=[UserService])
class ApiRouter:
@get("/users/{user_id}")
async def get_user(self, request):
user_id = request.path_params["user_id"]
return await self.user_service.get_user(int(user_id))
@post("/users")
async def create_user(self, request):
data = await request.json()
return {"id": 1, **data}, 201
@module(name="app", services=[DatabaseService, UserService, ApiRouter])
class AppModule:
pass
# Run with uvicorn
# uvicorn main:AppModule --host 0.0.0.0 --port 8000 --reload
Web Example with OpenAPI
from canary_framework import module, router, get, post
from pydantic import BaseModel, Field
class UserRequest(BaseModel):
name: str = Field(description="User name")
email: str = Field(description="User email")
class UserResponse(BaseModel):
id: int = Field(description="User ID")
name: str = Field(description="User name")
email: str = Field(description="User email")
@router(name="users", prefix="/users", tags=["Users"])
class UsersRouter:
@get("/", summary="List users", description="Get all users")
async def list_users(self, request):
return {"users": []}
@post("/",
summary="Create user",
description="Create a new user",
request_model=UserRequest,
response_model=UserResponse)
async def create_user(self, request, user: UserRequest):
return {"id": 1, **user.model_dump()}, 201
@module(name="app", services=[UsersRouter])
class AppModule:
pass
OpenAPI Documentation
Access automatically generated documentation:
- Swagger UI:
http://localhost:8000/docs - ReDoc:
http://localhost:8000/redoc - OpenAPI JSON:
http://localhost:8000/openapi.json
Documentation
📖 Complete documentation: Canary Framework Docs
Documentation Structure
- Quickstart — Build a complete application from scratch
- Services — Service definition, dependency injection, lifecycle
- Modules — Module composition, hierarchical structure
- Web Routing — Routing, HTTP methods, request handling
- Dependency Injection — DI system, topological sorting, registry
- Lifecycle — Lifecycle hooks, best practices
- Core Concepts — Design principles, architecture, internals
- API Reference — Complete API documentation
Architecture
src/canary_framework/
├── common/ # Shared types, enums, exceptions
│ ├── errors.py # Framework exceptions
│ ├── markers.py # Metadata markers and accessors
│ └── types.py # Data classes and type aliases
├── core/ # Core base classes
│ ├── module.py # ModuleBase - module orchestration
│ ├── service.py # ServiceBase - lifecycle management
│ └── router.py # RouterBase - ASGI routing
├── decorators/ # Decorator implementations
│ ├── module.py # @module decorator
│ ├── service.py # @service decorator
│ ├── router.py # @router, @get/@post/... decorators
│ └── lifecycle.py # @after_config, @after_init, etc.
└── engine/ # Core engine components
├── registry.py # Registry - service registration
├── injector.py # Dependency injection, topological sort
├── hooks.py # Lifecycle hook discovery
├── openapi.py # OpenAPI schema generation
├── utils.py # Helper utilities
└── logging.py # Logging utilities
Lifecycle Flow
AppModule.configure()
├── Collect all services
├── Build dependency graph
├── Topological sort (Kahn's algorithm)
├── Instantiate services
├── Inject dependencies
└── Call configure() + @after_config hooks on each service
AppModule.init()
└── Call init() + @after_init hooks on each service
AppModule.startup()
└── Call startup() + @before_startup hooks on each service
AppModule.shutdown()
└── Call shutdown() + @before_shutdown hooks in reverse order
Testing
# Run all tests
pytest
# Run unit tests
pytest tests/unit/
# Run integration tests
pytest tests/integration/
Community
- 💬 Discussions
- 🐛 Issues
- 📖 Docs
Contributing
See CONTRIBUTING.md.
License
Apache 2.0 · Copyright 2026 Zhang Wenbo (Canary)
Project details
Release history Release notifications | RSS feed
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 canary_framework-0.4.6.tar.gz.
File metadata
- Download URL: canary_framework-0.4.6.tar.gz
- Upload date:
- Size: 77.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
de7755b107c6c72a7b1b4b58ba3911be1c9d504d89729e99fbf253a709bb9ef0
|
|
| MD5 |
2366f55e1dda877c179522249768b0e1
|
|
| BLAKE2b-256 |
01dbb095d23754ae12a6040977d481101cc72f64ef642ed45b4ad014809d5536
|
Provenance
The following attestation bundles were made for canary_framework-0.4.6.tar.gz:
Publisher:
publish.yml on HotcocoaCanary/Canary-Framework
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
canary_framework-0.4.6.tar.gz -
Subject digest:
de7755b107c6c72a7b1b4b58ba3911be1c9d504d89729e99fbf253a709bb9ef0 - Sigstore transparency entry: 1710052983
- Sigstore integration time:
-
Permalink:
HotcocoaCanary/Canary-Framework@91330eadfa4c903c8a68d1451f4a26cd030e1f09 -
Branch / Tag:
refs/heads/releases/v0.4.6 - Owner: https://github.com/HotcocoaCanary
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@91330eadfa4c903c8a68d1451f4a26cd030e1f09 -
Trigger Event:
push
-
Statement type:
File details
Details for the file canary_framework-0.4.6-py3-none-any.whl.
File metadata
- Download URL: canary_framework-0.4.6-py3-none-any.whl
- Upload date:
- Size: 40.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e8c137ee55630dabedee00383625521610df40a4275d2b8ffb4bc71369a196fb
|
|
| MD5 |
ae8ce73ab772cf8b30d6dca6a7e76a25
|
|
| BLAKE2b-256 |
40362989f204a5dd0f77a4b1c9b6088aa8efb67cd13cdf201d24686d971b9eeb
|
Provenance
The following attestation bundles were made for canary_framework-0.4.6-py3-none-any.whl:
Publisher:
publish.yml on HotcocoaCanary/Canary-Framework
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
canary_framework-0.4.6-py3-none-any.whl -
Subject digest:
e8c137ee55630dabedee00383625521610df40a4275d2b8ffb4bc71369a196fb - Sigstore transparency entry: 1710053027
- Sigstore integration time:
-
Permalink:
HotcocoaCanary/Canary-Framework@91330eadfa4c903c8a68d1451f4a26cd030e1f09 -
Branch / Tag:
refs/heads/releases/v0.4.6 - Owner: https://github.com/HotcocoaCanary
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@91330eadfa4c903c8a68d1451f4a26cd030e1f09 -
Trigger Event:
push
-
Statement type: