Releases: modern-python/modern-di-aiogram
Release list
2.2.0
modern-di-aiogram 2.2.0 — adopt the modern-di integration kit
Maintenance release. No public API change — FromDI, inject (both
modern_di_aiogram and modern_di_aiogram.dialog), setup_di,
fetch_di_container, and the two connection providers keep their signatures
and behavior. Swaps this package's hand-rolled connection-scope lifecycle
and marker resolution for the shared primitives in
modern_di.integrations,
shipped in
modern-di 2.28.0.
Twelfth of 13 planned adapter conversions across the modern-di ecosystem
(after
modern-di-starlette 2.2.0,
modern-di-fastapi 2.10.0,
modern-di-litestar 2.13.0,
modern-di-aiohttp 2.2.0,
modern-di-flask 2.1.0,
modern-di-faststream 2.10.0,
modern-di-typer 2.3.0,
modern-di-grpc 2.1.0,
modern-di-celery 2.1.0,
modern-di-arq 2.1.0,
and
modern-di-taskiq 2.1.0).
aiogram is the kit's documented Layer-1 outlier: its per-update child
container's context is a hand-written multi-provider merge with a hardcoded
scope ({Update: event, TelegramObject: event.event}, two aiogram types
from one event) that no single-provider bind() can derive — so that
literal is kept, and no bind/classify_connection is introduced. Only
the container lifecycle and the marker/resolution seam adopt the kit.
Internal refactors
_DiMiddlewarenow opens/closes the per-update child through
Container's ownasync with(replacing the manualtry/finally: await child.close_async()). The multi-providercontext={...}literal and
bothContextProviderregistrations are unchanged._FromDIis gone;FromDI = integrations.from_di._parse_inject_params
is deleted;injectcomposesintegrations.parse_markers/
integrations.resolve_markers.- The
__modern_di_injected__double-wrap guard is now
integrations.is_injected/integrations.mark_injected(same underlying
attribute — used ininjectandauto_inject's_inject_router). modern_di_aiogram.dialog(the aiogram-dialoginject, which shares
the marker) converts itsparse_markers/resolve_markersusage in the
same change.- The
injectsignature-rewrite machinery (the deliberate non-use of
functools.wraps, driven by aiogram's__wrapped__unwrapping) and
dialog.py's_container_from_callcall-shape lookup are aiogram-specific
glue, kept exactly as-is. - Dead imports removed (
dataclasses, theT_coTypeVar). architecture/dependency-injection.mdpromoted to describe the new
internals.
Packaging
- Bumps the
modern-difloor to>=2.28,<3.
Downstream
No action needed — the public API (FromDI, inject, setup_di,
fetch_di_container, aiogram_update_provider, aiogram_event_provider,
and modern_di_aiogram.dialog.inject) is unchanged. Upgrading only requires
modern-di>=2.28.0.
Internals
- 100% line coverage;
ruff,tyclean across Python 3.10–3.14. Tests use
a fake-tokenBotandaiogram_dialog.test_tools(no external service). - Built via
subagent-driven-development: 5 planned tasks, each with an
independent spec+quality review; a whole-branch review before merge that
verified nobind/classify_connectionwas introduced, theasync with
preserves the old close semantics on both the normal and handler-error
paths, and the double-wrap guard round-trips through the same
__modern_di_injected__attribute.
2.1.0
modern-di-aiogram 2.1.0 — aiogram-dialog support
A backward-compatible minor release. Adds DI for
aiogram-dialog getters and
callbacks as a new submodule of the existing package — not a new package,
since the container lifecycle is already owned by modern-di-aiogram's
middleware.
Feature
modern_di_aiogram.dialog.inject. A dialog-awareinjectfor
aiogram-dialog getters and callbacks — windowgetters,on_start,
on_close,on_click, andon_process_result. It finds the per-update
Scope.REQUESTchild container by the call shape aiogram-dialog uses
(getter: container in**kwargs; callbacks: container at the positional
DialogManager'smiddleware_data) and resolvesFromDIparams the same
way the handlerinjectdoes.- Reuses existing infrastructure. The
setup_dimiddleware, theFromDI
marker, and the per-update child-container key are all imported unchanged
frommodern_di_aiogram.main— no second container, no second lifecycle.
Import viafrom modern_di_aiogram.dialog import inject, FromDI. - No auto-inject for dialogs. Getters/callbacks live on
Window/widget
objects with no router-like registry to walk, so only explicit@injectis
supported (matches Dishka's aiogram-dialog integration).
Packaging
- No new runtime dependency.
dialog.pyimports nothing from
aiogram_dialog— the container lookup is structural.aiogram-dialogis
added to thedevdependency group only, for the test suite. aiogram>=3.2,<4andmodern-di>=2.25,<3are unchanged.
Downstream
No action needed — purely additive; existing handler inject/auto_inject
behavior is untouched.
Internals
- 100% line coverage via
tests/test_dialog.py, driving real dialogs
bot-less withaiogram_dialog.test_tools(BotClient+
MockMessageManager) — no live bot or Telegram API involved. architecture/dependency-injection.mdgained an "aiogram-dialog" section
covering the call-shape lookup and whyfunctools.wrapsis safe there
(unlike the handlerinject).
2.0.0
modern-di-aiogram 2.0.0 — first release
First release of the aiogram integration for modern-di. It wires a
modern-di container into an
aiogram 3.x Dispatcher and resolves dependencies
into handlers, scoped per update. The version starts at 2.0.0 to track the
modern-di 2.x ecosystem alongside the other official integrations.
aiogram has no dependency-injection seam of its own (handlers receive values
from a middleware data dict), so this integration follows modern-di's
middleware + @inject decorator path: an update-level outer middleware owns
the per-update container lifecycle, and an @inject decorator (or
auto_inject=True) resolves FromDI markers.
Feature
setup_di(dispatcher, container, *, auto_inject=False). Stashes the root
container on the dispatcher's workflow-data (read back with
fetch_di_container(dispatcher)), registers the connection providers, wires
the container's lifecycle todispatcher.startup(reopen — so a restart
works) anddispatcher.shutdown(close), and installs an update-level outer
middleware. Returns the container.- Per-update child containers. The middleware builds one
Scope.REQUEST
child container per update, seeded with the aiogramUpdateand its concrete
event (Message,CallbackQuery, …), stashes it in the handlerdata, and
closes it when the update finishes — including on the handler error path. FromDI+@inject. Mark a handler parameter with
Annotated[T, FromDI(provider_or_type)]and decorate the handler with
@inject; the decorator rewrites the handler signature (removing the DI
params so aiogram doesn't try to fill them, adding the container by name) and
resolves each marked parameter from the update's child container.auto_inject=True. Wraps every handler registered before startup with
@injectautomatically, so individual handlers don't need the decorator.aiogram_update_provider/aiogram_event_provider. Connection providers
exposing theUpdateand the concreteTelegramObjectevent at
Scope.REQUESTfor injection into factories.
Packaging
- Requires
aiogram>=3.2,<4andmodern-di>=2.25,<3; Python 3.10–3.14. The
>=3.2floor is the earliest aiogram exposingHandlerObject.params, which
auto_injectrelies on. - Ships
py.typed; zero runtime dependencies beyond aiogram and modern-di. - Resolution stays synchronous by design; only the per-update container builder
and finalizers are async.
Downstream
No action needed — this is a new package.
Internals
- 100% line coverage;
ruff,ty, andeof-fixerclean across Python
3.10–3.14. - Uses the portable planning convention (
planning/) with anarchitecture/
truth home; releases are tag-driven.