Often, scopes are connected with external events: HTTP requests, messages from a queue, callbacks from a framework. These events can be represented by objects which can be used for dependency creation.
ContextProvider is a provider type that allows injecting context values into dependencies.
This is particularly useful for injecting framework-specific objects like requests, websockets, etc.
ContextProvider makes context data available to other providers in your dependency graph by extracting values from the container's context.
In integrations, some context objects (like fastapi.Request, litestar.WebSocket, etc.) are automatically provided.
from modern_di import Group, Container, Scope, providers
import fastapi
import modern_di_fastapi
def create_request_info(request: fastapi.Request) -> dict[str, str]:
return {
"method": request.method,
"url": str(request.url),
"timestamp": "2023-01-01T00:00:00Z"
}
class Dependencies(Group):
# Factory uses the request from context (automatically provided by the integration)
request_info = providers.Factory(
scope=Scope.REQUEST,
creator=create_request_info,
)
# Create container with context
ALL_GROUPS = [Dependencies]
# Setup DI with your groups
app = fastapi.FastAPI()
container = Container(groups=ALL_GROUPS)
modern_di_fastapi.setup_di(app, container)
# The integration creates a REQUEST-scoped child container per request and
# automatically injects the fastapi.Request into its context. The factory
# is resolved from the child container, not the APP-scope container.You may still need to define ContextProviders manually in cases where you want to inject custom context objects that are not automatically provided by the integration:
from modern_di import Group, Container, Scope, providers
# Custom context type
class CustomContext:
def __init__(self, user_id: str, tenant_id: str) -> None:
self.user_id = user_id
self.tenant_id = tenant_id
def create_user_info(custom_context: CustomContext) -> dict[str, str]:
return {
"user_id": custom_context.user_id,
"tenant_id": custom_context.tenant_id,
}
class Dependencies(Group):
# Manually defined ContextProvider for custom context
custom_context = providers.ContextProvider(scope=Scope.REQUEST, context_type=CustomContext)
# Factory uses the custom context
user_info = providers.Factory(
scope=Scope.REQUEST,
creator=create_user_info,
)
# Provide custom context when building container
container = Container(groups=[Dependencies])
custom_context = CustomContext(user_id="123", tenant_id="abc")
request_container = container.build_child_container(
scope=Scope.REQUEST,
context={CustomContext: custom_context}
)
# Now resolve the factory — it will receive the custom context automatically
user_info = request_container.resolve_provider(Dependencies.user_info)
# {"user_id": "123", "tenant_id": "abc"}