Lagom Dependency Injection
Lagom is a dependency injection container designed to give you 'just enough' help with building your dependencies. It emphasizes type-based auto-wiring with strong Mypy integration and minimal changes to existing code. It currently supports Python 3.7+ and is actively maintained with frequent releases.
Common errors
-
lagom.exceptions.TypeOnlyAvailableAsAwaitable: Unable to construct type <YourType> as it is only available as an async.Try requesting Awaitable[<YourType>] instead.
cause You are trying to resolve an asynchronous dependency directly as its concrete type (<YourType>) instead of wrapping it in `typing.Awaitable` and awaiting the result.fixIf your dependency `MyAsyncDep` is defined by an `async def` constructor, you must request it as `my_dep = await container[Awaitable[MyAsyncDep]]`. -
lagom.exceptions.UnresolvableType: Unable to construct dependency of type <YourType> The constructor probably has some unresolvable dependencies
cause Lagom could not determine how to construct `YourType` or one of its sub-dependencies. This can happen due to missing type hints, abstract types without concrete bindings, or unconfigured dependencies.fixEnsure all constructor arguments have explicit type hints. If `YourType` is an abstract base class, provide a concrete implementation using `container[YourAbstractType] = YourConcreteClass`. For complex types, define a factory function: `container[YourType] = lambda c: YourType(c[DependencyA], c[DependencyB])`. -
lagom.exceptions.RecursiveDefinitionError: When trying to build dependency of type '<YourType>' python hit a recursion limit. This could indicate a circular definition somewhere.
cause There is a circular dependency in your application's object graph (e.g., A depends on B, and B depends on A), causing infinite recursion during dependency resolution.fixIdentify and break the circular dependency. This often involves introducing an interface, a factory function, or restructuring your classes to decouple their direct dependencies.
Warnings
- breaking Lagom versions 2.0.0 dropped formal support for Python 3.6, and 2.7.0 dropped formal support for Python 3.8. Using these versions on unsupported Python runtimes may lead to unexpected behavior or compilation issues.
- gotcha Asynchronous dependencies defined with `async def` must be requested from the container as `Awaitable[YourType]` and then awaited. Attempting to directly resolve `YourType` will result in an error or an unawaited `Awaitable` object.
- gotcha When using Lagom's FastAPI integration, versions prior to 1.7.1 and between 2.4.2 and 2.7.5 had a bug where only the last defined request-level singleton would be correctly applied. This could lead to incorrect instances being injected for other request-scoped dependencies.
Install
-
pip install lagom
Imports
- Container
from lagom import Container
- injectable
from lagom import injectable
- dependency_definition
from lagom import dependency_definition
- Awaitable
from lagom import Awaitable
from typing import Awaitable
Quickstart
from lagom import Container, injectable
class Config:
def __init__(self, api_key: str):
self.api_key = api_key
class HttpClient:
def __init__(self, config: Config):
self.config = config
class MyService:
def __init__(self, http_client: HttpClient):
self.http_client = http_client
# Create a container
container = Container()
# Configure a dependency (e.g., from environment variables)
# In a real app, this might come from os.environ.get or a settings file
container[Config] = lambda: Config(api_key=os.environ.get('MY_API_KEY', 'default_api_key'))
# Lagom will auto-wire HttpClient and MyService based on type hints
service = container[MyService]
print(f"Service created with API Key: {service.http_client.config.api_key}")
# Example with function binding
from lagom.decorators import bind_to_container
@bind_to_container(container)
def process_request(service: MyService, request_data: dict):
print(f"Processing request with API Key: {service.http_client.config.api_key}")
return {"status": "ok", "data": request_data}
process_request(request_data={"id": 123})