linkd.solver¶
- class AutoInjecting(func: Callable[..., Awaitable[t.Any]], self_: t.Any = None, _dependency_func: DependencyResolverFunctionT | None = None)[source]¶
Wrapper for a callable that implements dependency injection. When called, resolves the required dependencies and calls the original callable. Supports both synchronous and asynchronous functions, however this cannot be called synchronously - synchronous functions will need to be awaited.
You should generally never have to instantiate this yourself - you should instead use one of the decorators that applies this to the target automatically.
See also
- class DependencyInjectionManager[source]¶
Class which contains dependency injection functionality.
- async close() None[source]¶
Close the default dependency injection context. This must be called if you wish the teardown functions for any dependencies registered for the default registry to be called.
- Returns:
- contextual(context: context_.Context, /, *contexts: context_.Context) Callable[[AsyncFnT], AsyncFnT][source]¶
Convenience decorator that enters the given DI context(s) for the decorated function. The requested contexts will be entered IN ORDER, and so in most cases the first one should be
ROOT.- Parameters:
context – The first context to enter.
*contexts – Additional contexts to enter.
Note
If a context would already be available and this decorator is used, the contexts will be reapplied. For example, if you are in a request handler with the REQUEST context enabled, and a function decorated with this - @manager.contextual(Contexts.ROOT, Contexts.REQUEST) - is called, the REQUEST context will be re-entered and will not have access to any of the dependencies already instantiated in the previous instance of the context.
Example
manager = linkd.DependencyInjectionManager() ... @manager.contextual(Contexts.ROOT, Contexts.REQUEST) @linkd.injected async def foo(bar: Bar) -> Baz: ...
- enter_context(context: context_.Context = 'linkd.contexts.default', /) AsyncIterator[Container][source]¶
Context manager that ensures a dependency injection context is available for the nested operations.
- Parameters:
context – The context to enter. If a container for the given context already exists, it will be returned and a new container will not be created.
- Yields:
Container– The container that has been entered.
Example
# Enter a specific context ('manager' is your DependencyInjectionManager instance) async with manager.enter_context(linkd.Contexts.ROOT): await some_function_that_needs_dependencies()
Note
If you want to enter multiple contexts - i.e. a command context that requires the default context to be available first - you should call this once for each context that is needed.
async with ( manager.enter_context(linkd.Contexts.ROOT), manager.enter_context(SOME_COMMAND_CONTEXT) ): ...
- inject(func: AsyncFnT) AsyncFnT[source]¶
- inject(func: Callable[P, R]) Callable[P, Coroutine[t.Any, t.Any, R]]
Decorator that enables dependency injection on the decorated function. If dependency injection has been disabled globally then this function does nothing and simply returns the object that was passed in.
- Parameters:
func – The function to enable dependency injection for.
- Returns:
The function with dependency injection enabled, or the same function if DI has been disabled globally.
Warning
Dependency injection relies on a context being available when the function is called. Refer to library documentation for which flows will have a dependency injection context set-up for you automatically. Otherwise, you will have to set up the context yourself using the helper context manager
enter_context().
- INJECTED: Final[Any] = <linkd.Marker: 'INJECTED'>¶
Flag value used to explicitly mark that a function parameter should be dependency-injected.
This exists to stop type checkers complaining that function arguments are not provided when calling dependency-injection enabled functions.
Example
@linkd.inject async def foo(bar: SomeClass = linkd.INJECTED) -> None: ... # Type-checker shouldn't error that a parameter is missing await foo()