Repository navigation
4.2.0
4.2.0 lets several apps share one container, rejects async creators where they are declared, and makes validate() and several error messages more accurate. Resolving a chain of factories is about 22% faster. Python 3.11 or newer is required, and modern-di still has no runtime dependencies.
Changes that can affect existing code
Factory(async_fn)raisesAsyncCreatorError(#680). It is raised from theFactory(...)call, for anasync deffunction or method, afunctools.partialaround one, and an instance withasync def __call__. Before, the declaration was accepted andresolve()returned an un-awaited coroutine. Build async resources in the framework's lifespan instead; see Async resources via lifespan.validate()checks reference-only providers (#686). A provider withbound_type=None, or withskip_creator_parsing=Trueand nobound_type, used to be checked only when a typed provider depended on it. A broken one now failsvalidate()withValidationFailedErrorinstead of failing on first resolve.ResolutionStep.scopecan beNone(#693). An alias step whose source is not registered has no known scope. Error chains draw it as?. Code that reads.dependency_path[i].scopeorCircularDependencyError.steps[i].scopemust handleNone.- Error message text changed for
InvalidChildScopeError(#682),DuplicateProviderTypeError(#688) andAliasSourceNotRegisteredError(#692). Code that matches the old text must change.
Fixed
- Registering the same provider object more than once, for example from two groups, registers it once instead of raising
DuplicateProviderTypeError. This also lets several apps share one container: callingsetup_dion a second app with the same container no longer raises in the starlette, fastapi, aiohttp, litestar, flask, faststream, aiogram and taskiq integrations. The container is not reference-counted, so whichever app stops first closes it for the others; give it one owner, or use one container per app when apps stop independently. See Sharing a container. (#681) - A creator whose parameter types are only on its
__signature__, such as a Pydantic model or a msgspecStruct, is now wired. Before, resolving it raisedArgumentResolutionError, and a function creator also lost its return type and was left out of by-type registration. (#685) - A provider whose bound type is a falsy class, for example one whose metaclass defines
__len__returning 0, is registered by type and named correctly in errors. (#687) repr(alias)no longer reports a scope the alias doesn't have, and "did you mean" hints show an alias's effective scope. (#683)
Improvements
DuplicateProviderTypeErrornames each provider by its group attribute and call site, such asDependencies.first: Factory (myapp.deps:12), so two factories with the same creator are told apart. (#688)AliasSourceNotRegisteredErrornames the reference-only provider when the source type is only served withbound_type=None, and says how to fix it. (#692)InvalidChildScopeErrorstates the value rule instead of listing no scopes when the parent is the deepest built-in scope. (#682)
Performance
- Each factory gets its own copy of its resolver code, so CPython's call-site caches stop missing between factories. A six-deep chain resolves 22% faster and a ten-wide one 22% faster. The first resolve of a cold container is about 35% slower, about 6 µs. (#694)
CacheItemis a plain slotted class. A request cycle is about 7% faster and closing a container with finalizers about 11% faster. (#690)
Docs
- Most pages were reworked, including the lifecycle, factories, recipes, troubleshooting and integration pages (#651 to #675).
- New recipe: Sharing a container, with
manage_lifespan=Falseand one owner (#700, #702, #703). - The integration pages describe each plugin's current shutdown order: the root opens before user startup code and closes after user shutdown code (#704, #705, #706).
- Every docs page runs in the test suite against the released integration packages (#654, #658).
What's Changed
- docs: point integration scope-hierarchy links at the scope table by @lesnik512 in #651
- test: run the writing-integrations examples in test-docs by @lesnik512 in #652
- docs: rework the lifecycle page: finalizer forms, close order, and which integrations close the root by @lesnik512 in #653
- docs: say every release from 2.15.0 on has a curated body by @lesnik512 in #655
- test: run the framework integration pages against their packages by @lesnik512 in #654
- docs: rework the factories page: kwargs errors, the skip-parsing warning, and the validate() gap by @lesnik512 in #657
- test: run every docs page in the integration env and drop the last skip markers by @lesnik512 in #658
- docs: declare Litestar handler dependencies with NamedDependency by @lesnik512 in #660
- docs: rework the providers: context, container, alias, advanced api pages by @lesnik512 in #661
- docs: rework the pytest and writing an integration pages by @lesnik512 in #662
- docs: rework the wiring, alias, group and kwargs troubleshooting pages by @lesnik512 in #663
- docs: rework the errors catalog and the scope, container and lifecycle troubleshooting pages by @lesnik512 in #664
- docs: rework the web integrations pages by @lesnik512 in #665
- docs: rework the migration guides and dev pages by @lesnik512 in #666
- docs: rework the task, bot, rpc and cli integrations pages by @lesnik512 in #667
- docs: rework the recipes pages by @lesnik512 in #668
- docs: fix cross-page follow-ups from the docs rework by @lesnik512 in #675
- fix: make _DependencyChainError._message abstract for ty 0.0.87 by @lesnik512 in #677
- fix: drop ty ignore that ty 0.0.88 reports as unused by @lesnik512 in #679
- fix: reject an async creator when a Factory is declared by @lesnik512 in #680
- fix: register a repeated provider object once instead of raising by @lesnik512 in #681
- fix: state the value rule in InvalidChildScopeError instead of an empty list by @lesnik512 in #682
- fix: validate() checks reference-only providers by @lesnik512 in #686
- fix: stop Alias repr from reporting a scope it does not have by @lesnik512 in #683
- fix: name each provider in DuplicateProviderTypeError by its group attribute and call site by @lesnik512 in #688
- fix: wire parameters typed only on the creator's signature by @lesnik512 in #685
- fix: register and name a provider whose bound type is falsy by @lesnik512 in #687
- docs: state that close does not wait for other threads and a finalizer runs at most once by @lesnik512 in #689
- perf: build CacheItem as a plain slotted class by @lesnik512 in #690
- fix: name the reference-only provider when an alias source is unbound by @lesnik512 in #692
- fix: draw an unknown step scope as ? in error chains by @lesnik512 in #693
- docs: document the Litestar, Flask and Celery integration fixes by @lesnik512 in #684
- ci: list the installed modern-di packages before the integration docs run by @lesnik512 in #695
- perf: give each factory its own copy of its shape's resolver code by @lesnik512 in #694
- docs: align README and quickstart with the integration and pytest pages by @lesnik512 in #696
- docs: document the aiogram, aiohttp, Starlette, gRPC, FastStream, Typer, pytest and FastAPI integration fixes by @lesnik512 in #697
- docs: call modern-di-pytest an integration and note mounted apps in writing-integrations by @lesnik512 in #698
- docs: mounted apps with middleware are found since starlette 4.1.1 and fastapi 4.0.2 by @lesnik512 in #699
- docs: warn that apps sharing a root container close it for each other by @lesnik512 in #700
- docs: share a container with manage_lifespan=False and one owner by @lesnik512 in #702
- docs: FastStream start() and stop() skip the app lifespan by @lesnik512 in #703
- docs: update integration pages for the new shutdown order by @lesnik512 in #704
- docs: update aiogram, celery, flask and grpc pages for shutdown changes by @lesnik512 in #705
- docs: flask streaming fixed in 4.2.1, aiogram webhook handlers outlive shutdown by @lesnik512 in #706
Full Changelog: 4.1.0...4.2.0