PyFly
Async Python. From request to domain.
An async Python application framework with typed dependency injection, HTTP controllers, persistence, CQRS, and orchestration. Build APIs and server-rendered web applications with explicit application boundaries.
- Python 3.12+
- Async / await
- Starlette or FastAPI
The building blocks,
explained.
Explore what this implementation provides, with a direct path to the code behind each capability.
- Typed dependency injection
Declare application services and let PyFly resolve constructor dependencies from type hints. Named beans, qualifiers, and ordered collections make multiple implementations explicit.
Explore this capability- Async HTTP controllers
Map async controller methods to HTTP routes and connect them to injected services. The web layer can expose OpenAPI alongside the application.
Explore this capability- Native HTML and forms
Render Jinja templates and bind typed form models, with escaping, validation, upload limits, and CSRF handling. Keep web applications inside the same application model as your APIs.
Explore this capability- Async persistence and transaction boundaries
Work through SQLAlchemy-backed repositories and explicit async transaction boundaries. Configure propagation and rollback behavior around application operations.
Explore this capability- Commands, queries, and handlers
Keep HTTP endpoints thin by dispatching application commands and queries to dedicated handlers. The command pipeline supports validation, authorization, correlation, event publication, and metrics.
Explore this capability- Saga orchestration
Coordinate multi-step operations and invoke compensation when a step fails. Saga execution exposes state-persistence and event hooks for the surrounding application.
Explore this capability
From the source
See the ideas
in real code.
Verbatim Lumen sample read handler, including its real imports: the injected repository loads a wallet and maps it to its public DTO.
View the complete sourcefrom lumen.core.mappers.wallet_mapper import entity_to_dto
from lumen.core.services.wallets.get_wallet_query import GetWallet
from lumen.interfaces.dtos.v1.wallet_dto import WalletDto
from lumen.models.repositories.wallet_repository import WalletRepository
from pyfly.container import service
from pyfly.cqrs import QueryHandler, query_handler
@query_handler
@service
class GetWalletHandler(QueryHandler[GetWallet, WalletDto | None]):
def __init__(self, repository: WalletRepository) -> None:
super().__init__()
self._repository = repository
async def do_handle(self, query: GetWallet) -> WalletDto | None: # type: ignore[override]
entity = await self._repository.find_by_id(query.wallet_id)
return entity_to_dto(entity) if entity is not None else None
Follow a wallet from request to balance.
Lumen is the companion wallet and ledger application. Follow its real controller, command handler, and repository to see how the layers work together.
Receive the request
WalletController binds and validates the request body, then sends an OpenWallet command. The HTTP boundary stays focused on input and the response.
Apply the business operation
OpenWalletHandler creates the wallet aggregate and saves it through the repository. Its async transaction boundary commits successful work and rolls back failures.
Read the balance
Follow the query bus to GetBalance, then explore the sample tests that open, deposit into, and withdraw from a wallet. The application-context test uses an isolated SQLite database.

Learn by building
PyFly by Example
Event-Driven Python Microservices with the Firefly Framework
Build the Lumen wallet and ledger service through dependency injection, HTTP APIs, persistence, CQRS, events, and orchestration. A separate web application appendix covers native HTML and forms.
English and Spanish · PDF and EPUB · v26.09.07
Keep exploring.
Follow the projects and references connected to PyFly.
