Skip to content

Releases: modern-python/modern-di-aiogram

2.2.0

Choose a tag to compare

@github-actions github-actions released this 13 Jul 21:51
10b1d68

modern-di-aiogram 2.2.0 — adopt the modern-di integration kit

Maintenance release. No public API changeFromDI, 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

  • _DiMiddleware now opens/closes the per-update child through
    Container's own async with
    (replacing the manual try/finally: await child.close_async()). The multi-provider context={...} literal and
    both ContextProvider registrations are unchanged.
  • _FromDI is gone; FromDI = integrations.from_di. _parse_inject_params
    is deleted; inject composes integrations.parse_markers/
    integrations.resolve_markers.
  • The __modern_di_injected__ double-wrap guard is now
    integrations.is_injected/integrations.mark_injected
    (same underlying
    attribute — used in inject and auto_inject's _inject_router).
  • modern_di_aiogram.dialog (the aiogram-dialog inject, which shares
    the marker) converts its parse_markers/resolve_markers usage in the
    same change.
  • The inject signature-rewrite machinery (the deliberate non-use of
    functools.wraps, driven by aiogram's __wrapped__ unwrapping) and
    dialog.py's _container_from_call call-shape lookup are aiogram-specific
    glue, kept exactly as-is.
  • Dead imports removed (dataclasses, the T_co TypeVar).
  • architecture/dependency-injection.md promoted to describe the new
    internals.

Packaging

  • Bumps the modern-di floor 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, ty clean across Python 3.10–3.14. Tests use
    a fake-token Bot and aiogram_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 no bind/classify_connection was introduced, the async 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

Choose a tag to compare

@github-actions github-actions released this 12 Jul 09:24
05cb060

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-aware inject for
    aiogram-dialog getters and callbacks — window getters, on_start,
    on_close, on_click, and on_process_result. It finds the per-update
    Scope.REQUEST child container by the call shape aiogram-dialog uses
    (getter: container in **kwargs; callbacks: container at the positional
    DialogManager's middleware_data) and resolves FromDI params the same
    way the handler inject does.
  • Reuses existing infrastructure. The setup_di middleware, the FromDI
    marker, and the per-update child-container key are all imported unchanged
    from modern_di_aiogram.main — no second container, no second lifecycle.
    Import via from 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 @inject is
    supported (matches Dishka's aiogram-dialog integration).

Packaging

  • No new runtime dependency. dialog.py imports nothing from
    aiogram_dialog — the container lookup is structural. aiogram-dialog is
    added to the dev dependency group only, for the test suite.
  • aiogram>=3.2,<4 and modern-di>=2.25,<3 are 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 with aiogram_dialog.test_tools (BotClient +
    MockMessageManager) — no live bot or Telegram API involved.
  • architecture/dependency-injection.md gained an "aiogram-dialog" section
    covering the call-shape lookup and why functools.wraps is safe there
    (unlike the handler inject).

2.0.0

Choose a tag to compare

@github-actions github-actions released this 10 Jul 08:32
0123502

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 to dispatcher.startup (reopen — so a restart
    works) and dispatcher.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 aiogram Update and its concrete
    event (Message, CallbackQuery, …), stashes it in the handler data, 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
    @inject automatically, so individual handlers don't need the decorator.
  • aiogram_update_provider / aiogram_event_provider. Connection providers
    exposing the Update and the concrete TelegramObject event at
    Scope.REQUEST for injection into factories.

Packaging

  • Requires aiogram>=3.2,<4 and modern-di>=2.25,<3; Python 3.10–3.14. The
    >=3.2 floor is the earliest aiogram exposing HandlerObject.params, which
    auto_inject relies 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, and eof-fixer clean across Python
    3.10–3.14.
  • Uses the portable planning convention (planning/) with an architecture/
    truth home; releases are tag-driven.