Skip to content

waku

waku [ๆž  or ใ‚ใ] means framework in Japanese.


CI/CD Downloads PyPI Python version License Docs

uv Ruff mypy - checked basedpyright - checked


Overview

waku is a modern Python framework designed for building scalable, maintainable applications with a focus on clean architecture and developer experience. It's particularly well-suited for:

  • Enterprise applications requiring clear boundaries and maintainability
  • Microservices architectures needing consistent patterns
  • Teams looking for standardized approaches to common problems
  • Projects that value testability and loose coupling

The framework draws inspiration from NestJS and Tramvai, adapting their best ideas to the Python ecosystem. Here's list of some waku key features:

  • ๐Ÿงฉ Modularity: Build applications as a set of loosely coupled modules with clear boundaries, automatic dependency validation, and controlled visibility
  • ๐Ÿ’‰ Powerful Dependency Injection System: Manage dependencies with built-in DI framework-agnostic IoC-container, multiple lifetime scopes, and automatic resolution
  • ๐Ÿ”ง Extensions: Extend waku with custom plugins that can hook into application lifecycle, add new providers, and integrate with external systems
  • ๐Ÿ“Š Lifespan: Automatic manage application and IoC-container lifecycle with built-in hooks and event system
  • โš™๏ธ Command/Query handling (CQRS): Use mediator abstraction heavily inspired by C# MediatR library to handle commands, queries, and events
  • ๐Ÿค Integrations: waku comes with built-in integrations for popular web frameworks like FastAPI or Litestar and allows you to easily create your own integrations with any other frameworks

Motivation

While Python offers excellent web frameworks, they often lack robust architectural patterns for building complex applications. The challenge of managing dependencies and maintaining clean boundaries between components becomes increasingly difficult as applications grow.

waku addresses these challenges through its core concepts:

๐Ÿงฉ Modular Architecture

Break down complex applications into self-contained modules with clear boundaries and responsibilities. Each module encapsulates its own providers, making the codebase more maintainable and easier to understand.

๐Ÿ’‰ Dependency Injection

Manage dependencies explicitly through a powerful DI system that supports different lifetime scopes (singleton, scoped, transient). This enables:

  • ๐Ÿ”„ Loose coupling between components
  • ๐Ÿงช Easier testing through dependency substitution
  • ๐Ÿ“Š Clear dependency graphs
  • โšก Automatic lifecycle management
  • ๐Ÿ› ๏ธ Framework-agnostic dependency resolution

By combining these concepts, waku provides a structured approach to building Python applications that scales from small services to large enterprise systems.

Quick Start

Prerequisites

  • Python 3.11 or higher
  • Basic understanding of dependency injection and modular architecture
  • Familiarity with async/await syntax

Installation

Install the waku package using your preferred tool. We recommend uv for managing project dependencies due to its speed and simplicity.

# Using UV
uv add waku

# Using pip
pip install waku

# Using poetry
poetry add waku

You also need to install some additional dependencies for the DI system to work.

You can explore all available providers in our documentation.

Basic Example

For our example we stick with aioinject as DI provider. Install it directly using your preferred package manager or as extra dependency of waku:

uv add "waku[aioinject]"
import asyncio

from waku import WakuFactory, module
from waku.di import Scoped, Injected, inject
from waku.di.contrib.aioinject import AioinjectDependencyProvider


# Define your providers
class GreetingService:
    async def greet(self, name: str) -> str:
        return f'Hello, {name}!'


# Define a module with your providers
@module(providers=[Scoped(GreetingService)])
class GreetingModule:
    pass


# Define the application composition root module
@module(imports=[GreetingModule])
class AppModule:
    pass


# Define entrypoints
# In a real-world scenario, this could be FastAPI routes, etc.
@inject
async def greet_user(greeting_service: Injected[GreetingService]) -> str:
    return greeting_service.greet('waku')


async def main() -> None:
    # Create application via factory
    application = WakuFactory.create(
        AppModule,
        dependency_provider=AioinjectDependencyProvider(),
    )

    # Run the application
    # In a real-world scenario, this would be run by a framework like FastAPI
    async with application, application.container.context():
        message = await greet_user()
        print(message)  # Output: Hello, waku!


if __name__ == '__main__':
    asyncio.run(main())

For explanations of the code above and more realistic examples, see the Getting Started guide.

Documentation

Explore detailed documentation on our official site.

Key topics include:

Contributing

We'd love your contributions! Check out our Contributing Guide to get started.

Development Setup

Learn how to set up a development environment in the Contributing Guide.