docs(profile): steer newcomers to modern-di, and state the declaration-model edge accurately#48
Merged
Merged
Conversation
…edge that-depends' own README says "if you're starting a new project, consider modern-di", but nothing on the org surfaces said so -- and the two canonical blurbs actively inverted it: modern-di reads "Powerful", that-depends reads "Simple". A newcomer with no other signal picks "simple", i.e. the one we steer away from. Adds a one-line steer above the DI table on profile/README.md and the docs site: modern-di for new projects, that-depends when you need async resolution. Leaves the canonical one-liners untouched, since those are synced across the GitHub description and pyproject on both repos. Also plays modern-di's strongest card in the launch copy. Verified against source, not taken on trust: modern_di defines and exports no DI decorator, while dishka needs @provide on providers and @Inject on every handler. The copy states the limit of the claim too -- FromDI(...) at the FastAPI boundary is still a marker -- so the claim survives the scrutiny an HN thread applies.
bea48eb to
c58f965
Compare
…integrations The previous copy said modern-di "ships no @inject/@provide decorator at all". That was wrong: it generalized from FastAPI and Litestar. Checked all 12 integrations -- @Inject is required in Starlette, Flask, aiohttp, Celery, arq, aiogram and Typer, and only FastAPI, Litestar, FastStream and taskiq are free of it. The universal, defensible difference is narrower: providers are plain class attributes, so there is no @provide anywhere, where dishka requires one on every provider. The @Inject advantage is real but holds in 4 of 11 integrations, not all of them. Copy now states both the claim and its limits, so it survives the scrutiny an HN thread applies -- which is the entire point of the honest framing.
modern-di is not sync-only. The container is an async context manager, async finalizers are supported (there is a dedicated AsyncFinalizerInSyncCloseError pointing at close_async), and async resources -- an aiohttp session, an asyncpg pool -- are constructed in the framework lifespan and injected by type via a ContextProvider, which is a documented recipe. Most of the 13 integrations are async frameworks. What is actually synchronous is the resolve path: container.resolve(X) never awaits. That is the claim the copy should make, and it now does, across all ten places that said "sync-only" or "sync resolution by design". Also drops the advice to use Dishka for async. The ContextProvider recipe is the answer, so the copy points there instead. Dishka is still named honestly as the more established alternative -- we just do not send people to it. Fixes the same misframing in the org-profile and docs-site DI steers added earlier on this branch.
lesnik512
added a commit
that referenced
this pull request
Jul 13, 2026
Two rendering bugs in the DI steer shipped in #48. 1. modern-python.org was serving the literal text '!!! tip "Which one should I use?"' with the body as a raw code block. The admonition extension was never enabled in mkdocs.yml -- the site had no other admonition, so nothing had caught it. mkdocs build --strict passes either way, since a fell-through block is valid markdown, just not the markdown you meant. 2. On the org profile, GitHub renders a single newline as <br>, so the hard-wrapped paragraph broke mid-sentence in 8 places. The rest of profile/README.md avoids this by leaving prose unwrapped. Both surfaces now carry the steer as two blank-line-separated paragraphs, which renders identically under GFM and Python-Markdown with no <br> tricks. Verified: profile renders 4 tables, 0 <br>, 2 <p>; the site renders a real <div class="admonition tip"> with title + 2 paragraphs and no literal '!!!'.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Acts on two findings from the (still unmerged)
research/adoption-strategybranch inmodern-di. One of them did not survive verification — see below.The org profile was inverting your own guidance
that-depends' README says, in its own words: "If you're starting a new project, considermodern-di", and it ships a migration guide pointing that way. But nothing on any org surface said so, and the two canonical blurbs pulled the opposite direction:modern-dithat-dependsA newcomer scanning that table sees "simple" vs "powerful", has no other signal, and a good share will pick simple — the one you steer away from.
Adds a one-line steer above the DI table on
profile/README.mdand the docs site. The canonical one-liners are untouched — they're synced across the GitHub description and pyproject on both repos, so rewriting them is a bigger, separate call.The research's "decorator-free" headline is wrong — corrected
The roadmap (B1) calls "decorator-free, type-annotation DI" modern-di's headline differentiator. It doesn't hold. I checked all 12 integration READMEs:
@provideon providersGroup@injecton handlersrequired in Starlette, Flask, aiohttp, Celery, arq, aiogram, Typer
So the universal, defensible difference is no
@provide, not "decorator-free". The@injectadvantage is real but holds in 4 of 11 integrations, not all of them.The copy now states the claim and its limits — including that
FromDI(Dependencies.user_service)at the FastAPI boundary is still a marker. Shipping the unqualified version would have put a false claim about your own library into a Show HN thread, where the first commenter opensmodern-di-celery's README and finds@inject. The honest framing is the whole credibility play; it only works if it's actually honest.Verification
just check-planning: OK.mkdocs build --strict: clean. All 12 integration READMEs inspected directly for decorator usage.