diff --git a/README.md b/README.md index 344f2c9..6d34782 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ | [modern-di-fastapi](https://github.com/modern-python/modern-di-fastapi) | [![Supported versions](https://img.shields.io/pypi/pyversions/modern-di-fastapi.svg)](https://pypi.python.org/pypi/modern-di-fastapi) [![downloads](https://static.pepy.tech/badge/modern-di-fastapi/month)](https://pepy.tech/projects/modern-di-fastapi) | | [modern-di-faststream ](https://github.com/modern-python/modern-di-faststream) | [![Supported versions](https://img.shields.io/pypi/pyversions/modern-di-faststream.svg)](https://pypi.python.org/pypi/modern-di-faststream) [![downloads](https://static.pepy.tech/badge/modern-di-faststream/month)](https://pepy.tech/projects/modern-di-faststream) | | [modern-di-litestar ](https://github.com/modern-python/modern-di-litestar) | [![Supported versions](https://img.shields.io/pypi/pyversions/modern-di-litestar.svg)](https://pypi.python.org/pypi/modern-di-litestar) [![downloads](https://static.pepy.tech/badge/modern-di-litestar/month)](https://pepy.tech/projects/modern-di-litestar) | +| [modern-di-starlette](https://github.com/modern-python/modern-di-starlette) | [![Supported versions](https://img.shields.io/pypi/pyversions/modern-di-starlette.svg)](https://pypi.python.org/pypi/modern-di-starlette) [![downloads](https://static.pepy.tech/badge/modern-di-starlette/month)](https://pepy.tech/projects/modern-di-starlette) | | [modern-di-typer](https://github.com/modern-python/modern-di-typer) | [![Supported versions](https://img.shields.io/pypi/pyversions/modern-di-typer.svg)](https://pypi.python.org/pypi/modern-di-typer) [![downloads](https://static.pepy.tech/badge/modern-di-typer/month)](https://pepy.tech/projects/modern-di-typer) | | [modern-di-pytest](https://github.com/modern-python/modern-di-pytest) | [![Supported versions](https://img.shields.io/pypi/pyversions/modern-di-pytest.svg)](https://pypi.python.org/pypi/modern-di-pytest) [![downloads](https://static.pepy.tech/badge/modern-di-pytest/month)](https://pepy.tech/projects/modern-di-pytest) | @@ -28,7 +29,7 @@ - Scopes and context management - Python 3.10+ support - Fully typed and tested -- Integrations with `FastAPI`, `FastStream`, `LiteStar` and `Typer` +- Integrations with `FastAPI`, `FastStream`, `LiteStar`, `Starlette` and `Typer` - Pytest integration (`modern-di-pytest`) — turns any DI dependency into a pytest fixture ## Install diff --git a/ROADMAP.md b/ROADMAP.md index 18bc579..b1dc126 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -20,7 +20,7 @@ item, or want to build one, please open or comment in Each new entrypoint lets your existing container cover more of your stack: - **Taskiq** — async task queue - **aiogram** — Telegram bots -- **AIOHTTP / Starlette** +- **AIOHTTP** - *Later:* gRPC, Click, Celery ### Developer experience diff --git a/docs/index.md b/docs/index.md index b5cea02..4f52ac9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -9,7 +9,7 @@ Welcome to the `modern-di` documentation! - Scopes and context management - Python 3.10+ support - Fully typed and tested -- Integrations with `FastAPI`, `FastStream`, `LiteStar`, `Typer`, and `pytest` +- Integrations with `FastAPI`, `FastStream`, `LiteStar`, `Starlette`, `Typer`, and `pytest` Reference templates: @@ -42,7 +42,7 @@ For end-to-end patterns drawn from real services, see the [Recipes](recipes/sqla poetry add modern-di ``` -If you want a framework integration, install the matching adapter — e.g. `modern-di-fastapi`, `modern-di-litestar`, `modern-di-faststream`, `modern-di-typer`. For pytest support, install `modern-di-pytest`. +If you want a framework integration, install the matching adapter — e.g. `modern-di-fastapi`, `modern-di-litestar`, `modern-di-faststream`, `modern-di-starlette`, `modern-di-typer`. For pytest support, install `modern-di-pytest`. ## 2. Describe your dependencies @@ -97,6 +97,7 @@ Pick the integration you need: - [FastAPI](integrations/fastapi.md) - [FastStream](integrations/faststream.md) - [LiteStar](integrations/litestar.md) +- [Starlette](integrations/starlette.md) - [Typer](integrations/typer.md) - [Pytest](integrations/pytest.md) diff --git a/docs/integrations/writing-integrations.md b/docs/integrations/writing-integrations.md index 8390ba2..cea3fe9 100644 --- a/docs/integrations/writing-integrations.md +++ b/docs/integrations/writing-integrations.md @@ -192,6 +192,15 @@ Pattern-match your framework to the closest precedent. | `FromDI` bridge | `fastapi.Depends(Dependency(...))` | `faststream.Depends(Dependency(...))` | `Provide(_Dependency(...))` | inert `_FromDI` marker + `inject` | | Child close | `close_async` | `close_async` | `close_async` | `close_sync` | +The **Starlette** integration ([`modern-di-starlette`](starlette.md)) is the +reference for a **middleware + decorator hybrid**: Starlette has no native DI, +so a pure-ASGI middleware owns the child-container lifecycle (like FastStream) +while an `@inject` decorator with an inert `FromDI` marker does resolution (like +Typer). It splits the two responsibilities of the decorator path — the middleware +builds and closes the per-connection child, the decorator only reads it back from +the ASGI scope and resolves. See [Frameworks without native +DI](#frameworks-without-native-di-the-decorator-path). + The **pytest** integration ([`modern-di-pytest`](pytest.md)) is a different shape: it has no app to wire, so instead of `setup_di`/`FromDI` it exposes `modern_di_fixture` (turn one @@ -210,7 +219,11 @@ only what the framework's argument parser binds. There is nowhere to inject. For these, `FromDI` becomes an inert annotation marker and a **decorator** does the work native DI would have. [`modern-di-typer`](typer.md)'s `@inject` is the reference implementation — reach for this shape whenever the framework runs -handlers as plain callables it parses arguments for. +handlers as plain callables it parses arguments for. The decorator can build the +per-call child container itself (Typer), or read one built by middleware +([`modern-di-starlette`](starlette.md) builds it in a pure-ASGI middleware and the +decorator only resolves from it) — the resolution mechanics below are the same +either way. ### How it works diff --git a/docs/introduction/comparison.md b/docs/introduction/comparison.md index 978ee7a..c6d5746 100644 --- a/docs/introduction/comparison.md +++ b/docs/introduction/comparison.md @@ -24,7 +24,7 @@ Reach for a container when one of these is true: the HTTP layer. modern-di's core promise is exactly that: **one typed wiring shared across -FastAPI, Litestar, FastStream, and Typer.** +FastAPI, Litestar, FastStream, Starlette, and Typer.** ## The landscape @@ -34,7 +34,7 @@ FastAPI, Litestar, FastStream, and Typer.** | Scopes | APP→…→STEP (fixed chain) | RUNTIME→…→STEP (+ custom) | lifetimes (Singleton/Factory/Resource) | Singleton / Thread / None | request only | | Resolution | sync (by design) | sync + async | sync + async | sync | async | | First-party pytest plugin | ✅ | ✘ | ✘ | ✘ | n/a | -| Official integrations | 5 (FastAPI, Litestar, FastStream, Typer, pytest) | ~20+ | FastAPI, Flask, … | Flask (1st-party), FastAPI (3rd-party) | n/a | +| Official integrations | 6 (FastAPI, Litestar, FastStream, Starlette, Typer, pytest) | ~20+ | FastAPI, Flask, … | Flask (1st-party), FastAPI (3rd-party) | n/a | | Typed resolution | ✅ | ✅ | partial | ✅ | callable-keyed | | License | MIT | Apache-2.0 | BSD-3 | BSD | — | | Adoption | newest, very active | established, large community | most popular, mature | mature | built into FastAPI |