Python framework for backends that grow
Project description
waku [枠 or わく] means framework in Japanese.
Python makes it easy to build a backend. waku makes it easy to keep growing one.
As your project scales, problems creep in: services import each other freely, swapping a database means editing dozens of files, and nobody can tell which module depends on what. waku gives you modules with explicit boundaries, type-safe DI powered by dishka, and integrated CQRS and event sourcing — so your codebase stays manageable as it scales.
[!TIP] Check out the full documentation and our examples to get started.
The Problem
Python has no built-in way to enforce component boundaries. Packages don't control visibility, imports aren't validated, and nothing stops module A from reaching into the internals of module B. As a project grows, what started as clean separation quietly becomes a web of implicit dependencies — where testing requires the whole system, onboarding means reading everything, and changing one module risks breaking three others.
What waku gives you
Structure
- 🧩 Package by component: Each module is a self-contained unit with its own providers. Explicit imports and exports control what crosses boundaries — validated at startup, not discovered in production.
- 💉 Dependency inversion: Define interfaces in your application core, bind adapters in infrastructure modules. Swap a database, a cache, or an API client by changing one provider — powered by dishka.
- 🔌 One core, any entrypoint:
Build your module tree once with
WakuFactory. Plug it into FastAPI, Litestar, FastStream, Aiogram, CLI, or workers — same logic everywhere.
Capabilities
- 📨 Messaging: DI alone doesn't decouple components — you need events. The message bus dispatches commands, queries, and events so components never reference each other directly. Pipeline behaviors handle cross-cutting concerns.
- 📜 Event sourcing: Aggregates, projections, snapshots, upcasting, and the decider pattern with built-in SQLAlchemy adapters.
- 🧪 Testing:
Override any provider in tests with
override(), or spin up a minimal app withcreate_test_app(). - 🧰 Lifecycle & extensions: Hook into startup, shutdown, and module initialization. Add validation, logging, or custom behaviors — decoupled from your business logic.
Quick Start
Installation
uv add waku
Minimal Example
Define a service, register it in a module, and resolve it from the container:
import asyncio
from waku import WakuFactory, module
from waku.di import scoped
class GreetingService:
async def greet(self, name: str) -> str:
return f'Hello, {name}!'
@module(providers=[scoped(GreetingService)])
class GreetingModule:
pass
@module(imports=[GreetingModule])
class AppModule:
pass
async def main() -> None:
app = WakuFactory(AppModule).create()
async with app, app.container() as c:
svc = await c.get(GreetingService)
print(await svc.greet('waku'))
if __name__ == '__main__':
asyncio.run(main())
Module Boundaries in Action
Modules control visibility. InfrastructureModule exports ILogger — UserModule imports it. Dependencies are explicit, not implicit:
import asyncio
from typing import Protocol
from waku import WakuFactory, module
from waku.di import scoped, singleton
class ILogger(Protocol):
async def log(self, message: str) -> None: ...
class ConsoleLogger(ILogger):
async def log(self, message: str) -> None:
print(f'[LOG] {message}')
class UserService:
def __init__(self, logger: ILogger) -> None:
self.logger = logger
async def create_user(self, username: str) -> str:
user_id = f'user_{username}'
await self.logger.log(f'Created user: {username}')
return user_id
@module(
providers=[singleton(ILogger, ConsoleLogger)],
exports=[ILogger],
)
class InfrastructureModule:
pass
@module(
imports=[InfrastructureModule],
providers=[scoped(UserService)],
)
class UserModule:
pass
@module(imports=[UserModule])
class AppModule:
pass
async def main() -> None:
app = WakuFactory(AppModule).create()
async with app, app.container() as c:
user_service = await c.get(UserService)
user_id = await user_service.create_user('alice')
print(f'Created user with ID: {user_id}')
if __name__ == '__main__':
asyncio.run(main())
Next steps
- Learn about module imports and exports
- Try different provider scopes
- Add Messaging for clean command handling
- Connect with your favorite framework
- Browse the examples directory for inspiration
Documentation
- Getting Started
- Module System
- Providers
- Extensions
- Messaging
- Event Sourcing
- API Reference
- dishka Documentation
- DeepWiki
Contributing
Top contributors
Roadmap
- Create logo
- Improve inner architecture
- Improve documentation
- Add new and improve existing validation rules
- Provide example projects for common architectures
Support
License
This project is licensed under the terms of the MIT License.
Acknowledgements
- dishka – Dependency Injection framework powering
wakuIoC container. - NestJS – Inspiration for modular architecture and design patterns.
- Wolverine (C#) – Inspiration for messaging, transport model, and pipeline architecture.
- Marten (C#) – Inspiration for event sourcing, projections, and document store design.
- Emmett – Functional-first event sourcing patterns.
- Eventuous – Event store interface design.
- Jérémie Chassaing – Decider pattern formalization.
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 waku-0.43.0.tar.gz.
File metadata
- Download URL: waku-0.43.0.tar.gz
- Upload date:
- Size: 65.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eefc015daa6dbf36d160b97c54b29ccc9b56fbfc0bc00efc5d315d3e0cd6269a
|
|
| MD5 |
d2feda0bb28537c8ed8e4d0666e1ffea
|
|
| BLAKE2b-256 |
c658055cd6d3089c27985d09b461f0b095e51b476261a98b11279ff9d045f1e7
|
Provenance
The following attestation bundles were made for waku-0.43.0.tar.gz:
Publisher:
release.yml on waku-py/waku
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
waku-0.43.0.tar.gz -
Subject digest:
eefc015daa6dbf36d160b97c54b29ccc9b56fbfc0bc00efc5d315d3e0cd6269a - Sigstore transparency entry: 1190772225
- Sigstore integration time:
-
Permalink:
waku-py/waku@9eb54051f79229504e35e827b01b26d2222b907a -
Branch / Tag:
refs/heads/master - Owner: https://github.com/waku-py
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9eb54051f79229504e35e827b01b26d2222b907a -
Trigger Event:
push
-
Statement type:
File details
Details for the file waku-0.43.0-py3-none-any.whl.
File metadata
- Download URL: waku-0.43.0-py3-none-any.whl
- Upload date:
- Size: 116.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8890fcb6f93dfc3c09a6f06388a66d72d5e22adc72d9b098c819c6a3b41096d5
|
|
| MD5 |
e006c3030c58844dd42dfdac2921cf56
|
|
| BLAKE2b-256 |
47e8869837b65ef2ac73bccbd2676f40fd3be417bde5bb84e7603db0b1303590
|
Provenance
The following attestation bundles were made for waku-0.43.0-py3-none-any.whl:
Publisher:
release.yml on waku-py/waku
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
waku-0.43.0-py3-none-any.whl -
Subject digest:
8890fcb6f93dfc3c09a6f06388a66d72d5e22adc72d9b098c819c6a3b41096d5 - Sigstore transparency entry: 1190772245
- Sigstore integration time:
-
Permalink:
waku-py/waku@9eb54051f79229504e35e827b01b26d2222b907a -
Branch / Tag:
refs/heads/master - Owner: https://github.com/waku-py
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9eb54051f79229504e35e827b01b26d2222b907a -
Trigger Event:
push
-
Statement type: