Migration Guide: Upgrading to modern-di 2.x¶
modern-di 2.x merges the container classes, moves providers to keyword-only arguments, removes four provider types in favor of Factory, and drops async resolution. Breaking changes, once:
-
AsyncContainer/SyncContainer→Container(single class, both sync and async operations):# Before (1.x) from modern_di import AsyncContainer, SyncContainer async_container = AsyncContainer(groups=ALL_GROUPS) async_container.enter() # After (2.x) from modern_di import Container container = Container(groups=ALL_GROUPS, validate=True) # no explicit enter() needed container.close_sync() # or: await container.close_async()with/async with container.build_child_container(...)still works for automatic cleanup;close_sync()/close_async()are also available for manual lifecycle control. The framework integration packages were updated with matching new APIs. -
Provider constructor arguments became keyword-only.
# Before (1.x) factory = providers.Factory(Scope.REQUEST, MyClass, arg1="value1") # After (2.x) factory = providers.Factory(MyClass, scope=Scope.REQUEST, kwargs={"arg1": "value1"})Since 2.27, the subject argument (
creator/context_type/source_type) is accepted positionally again; all other parameters remain keyword-only. -
Singleton,Resource,Dict,Listremoved — all four map ontoFactory:# Before (1.x) singleton = providers.Singleton(Scope.APP, create_singleton) resource = providers.Resource(Scope.REQUEST, create_resource) # After (2.x) singleton = providers.Factory(create_singleton, scope=Scope.APP, cache=True) resource = providers.Factory( create_resource, scope=Scope.REQUEST, cache=providers.CacheSettings(finalizer=lambda r: r.close()), )Dict/Listhave no provider equivalent — write a plain creator function that returns the collection and wrap it in aFactory.clear_cachedefaults toTrue(oldResourcesemantics: finalizer runs on close, instance rebuilt on next resolve); setclear_cache=Falseonly when the same object must survive a close→reopen cycle. -
Resolution is sync-only — no more
sync_prefix, noawaiton resolution (async finalizers are still supported viaCacheSettings(finalizer=async_fn)andawait container.close_async()): -
.castremoved — wiring is by type instead:1.x 2.x dep=other_provider.cast(a provider dependency)Drop the argument — annotate the creator parameter with the dependency's type. value=settings.host(a static value)Pass it in kwargs={"value": ...}.a request/context value Register a ContextProviderfor that type (see Context).