Modern DI¶
Welcome to the modern-di documentation!
modern-di is a Python dependency injection framework which supports the following:
- Automatic dependencies graph based on type annotations
- Also, explicit dependencies are allowed where needed
- Scopes and context management
- Python 3.10+ support
- Fully typed and tested
- Integrations with
FastAPI,FastStream,LiteStar,Typer, andpytest
Usage examples:
- with LiteStar - litestar-sqlalchemy-template
- with FastAPI - fastapi-sqlalchemy-template
Quickstart¶
1. Install modern-di using your favorite tool:¶
If you need only modern-di without integrations:
If you need to integrate with fastapi or litestar, then install modern-di-fastapi or modern-di-litestar accordingly.
2. Describe resources and classes:¶
import dataclasses
import logging
import typing
logger = logging.getLogger(__name__)
def create_singleton() -> str:
return "some string"
@dataclasses.dataclass(kw_only=True, slots=True, frozen=True)
class SimpleFactory:
dep1: str
dep2: int
@dataclasses.dataclass(kw_only=True, slots=True, frozen=True)
class DependentFactory:
simple_factory: SimpleFactory
singleton: str
3. Describe dependencies groups¶
from modern_di import Group, Scope, providers
class Dependencies(Group):
singleton = providers.Factory(
scope=Scope.APP, # scope is APP by default, can be missing
creator=create_singleton,
cache_settings=providers.CacheSettings()
)
# relation between dependent_factory and simple_factory will be defined based on type annotations
simple_factory = providers.Factory(
scope=Scope.REQUEST,
creator=SimpleFactory,
kwargs={"dep1": "text", "dep2": 123}
)
dependent_factory = providers.Factory(
scope=Scope.REQUEST,
creator=DependentFactory,
)
4.1. Integrate with your framework¶
For now there are integrations for the following frameworks:
4.2. Or use modern-di without integrations¶
Create a container and resolve dependencies in your code
from modern_di import Container, Scope
ALL_GROUPS = [Dependencies]
# Initialize container of app scope
# Pass validate=True to detect circular dependencies at startup
container = Container(groups=ALL_GROUPS, validate=True)
# Resolve provider
instance1 = container.resolve_provider(Dependencies.singleton)
# You can also resolve by type if you've registered groups
instance2 = container.resolve(str) # resolves the singleton
# Create container of request scope
with container.build_child_container(scope=Scope.REQUEST) as request_container:
# Resolve factories of request scope
instance3 = request_container.resolve_provider(Dependencies.simple_factory)
instance4 = request_container.resolve_provider(Dependencies.dependent_factory)
# Use your instances...
# Finalizers run automatically on `with` exit. In async code, use
# `async with container.build_child_container(...) as request_container:` instead.