diff --git a/planning/releases/2.2.0.md b/planning/releases/2.2.0.md new file mode 100644 index 0000000..43e8c0c --- /dev/null +++ b/planning/releases/2.2.0.md @@ -0,0 +1,76 @@ +# 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`](https://github.com/modern-python/modern-di/blob/main/architecture/integration-kit.md), +shipped in +[modern-di 2.28.0](https://github.com/modern-python/modern-di/releases/tag/2.28.0). +Twelfth of 13 planned adapter conversions across the `modern-di` ecosystem +(after +[`modern-di-starlette` 2.2.0](https://github.com/modern-python/modern-di-starlette/releases/tag/2.2.0), +[`modern-di-fastapi` 2.10.0](https://github.com/modern-python/modern-di-fastapi/releases/tag/2.10.0), +[`modern-di-litestar` 2.13.0](https://github.com/modern-python/modern-di-litestar/releases/tag/2.13.0), +[`modern-di-aiohttp` 2.2.0](https://github.com/modern-python/modern-di-aiohttp/releases/tag/2.2.0), +[`modern-di-flask` 2.1.0](https://github.com/modern-python/modern-di-flask/releases/tag/2.1.0), +[`modern-di-faststream` 2.10.0](https://github.com/modern-python/modern-di-faststream/releases/tag/2.10.0), +[`modern-di-typer` 2.3.0](https://github.com/modern-python/modern-di-typer/releases/tag/2.3.0), +[`modern-di-grpc` 2.1.0](https://github.com/modern-python/modern-di-grpc/releases/tag/2.1.0), +[`modern-di-celery` 2.1.0](https://github.com/modern-python/modern-di-celery/releases/tag/2.1.0), +[`modern-di-arq` 2.1.0](https://github.com/modern-python/modern-di-arq/releases/tag/2.1.0), +and +[`modern-di-taskiq` 2.1.0](https://github.com/modern-python/modern-di-taskiq/releases/tag/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.