Hooks¶
Hooks can be used to modify FunDI’s injection process on specific dependencies. All hooks must be synchronous functions as they should work both in asynchronous and synchronous scopes.
Graph hook¶
Graph hook is a hook that is called when dependency is added to dependency graph. This may be useful to modify dependency cache key depending on the dependant’s parameter info.
Graph hook function is called with two positional arguments:
CallableInfo— information about the dependency that is about to be added to a graphParameter— information about the parameter the dependency is about to be linked to
Graph hook should modify the CallableInfo passed to it. It may return anything, but returned value would not be used.
Here is an example:
from fundi import with_hooks, from_
from fundi import FromType, Parameter, scan
# Graph hook will be called only at the addition of the dependency to the dependant's parameters
@with_hooks(graph=lambda info, parameter: info.key.add(parameter.name, parameter.annotation))
def dependency(param: FromType[Parameter]):
print(param.name) # name of the parameter being injected to
print(param.annotation) # expected type of the parameter
def dependant(_: None = from_(dependency)): ...
ci_dependant = scan(dependant)
dependant_dependency = ci_dependant.named_parameters["_"].from_
assert dependant_dependency is not None
assert dependant_dependency.key._items == [ # pyright: ignore[reportPrivateUsage]
dependency,
"_",
None,
]
ci_dependency = scan(dependency)
assert ci_dependency.key._items == [dependency] # pyright: ignore[reportPrivateUsage]
Scope hook¶
Scope hook is called when dependency is about to be injected. This hook should be used to produce dependency specific scope values.
Scope hook function is called with two positional arguments:
scope— string based dictionary. Hook should mutate it, to change dependency scopeCallableInfo— information about the dependency that is about to be injected
As in graph hook the returned value of the scope hook would not be used.
Scope hook example:
from fundi import scan, Scope
from fundi import inject, with_hooks
# Scope hook will be called before the injection
@with_hooks(scope=lambda scope, ci: scope.update(name="Kuyugama") if "name" not in scope else None)
def dependency(name: str):
print(f"dependency({name=!r})")
inject(Scope(), scan(dependency))
Combining hooks¶
It is possible to combine multiple hooks together using the fundi.util.combine_hooks().
This function will call all hooks with the same parameters and produce nothing.