This form of dependency injection works by injecting values for keyword arguments during callback execution based on the linked client. This is the main form of dependency injection implemented by Alluka.
Declaring a function's injected dependencies#
There are two styles for declaring a function's injected dependencies in Alluka:
def callback( foo: Foo = alluka.inject(type=Foo) bar: BarResult = alluka.inject(callback=bar_callback) ) -> None: ...
Assigning the result of alluka.inject to a parameter's default will declare it as requiring an injected type or callback.
async def callback( foo: Foo = alluka.inject() ) -> None: ...
callback is passed to alluka.inject then a type dependency will be inferred from the parameter's annotation.
The type-hint will need to resolvable/accessible at runtime in the callback's module for it to be inferred (so it can't be hidden behind a typing.TYPE_CHECKING only import or using a type or operation that isn't implemented in the current python version).
typing.Annotated style type-hint descriptors may be used to declare the injected dependencies for a function.
def callback( foo: typing.Annotated[Foo, alluka.inject(type=Foo)], bar: typing.Annotated[BarResult, alluka.inject(callback=bar_callback)] ) -> None: ...
Where passing the default descriptors returned by alluka.inject to typing.Annotated lets you declare the type or callback dependency for an argument without effecting non-DI calls to the function (by leaving these parameters required).
async def callback( foo: alluka.Injected[Foo] ) -> None: ...
Calling functions with dependency injection#
client: alluka.Client async def callback( argument: int, /, injected: alluka.Injected[Foo], keyword_arg: str, ) -> int: ... ... result = await client.call_with_async_di(callback, 123, keyword_arg="ok")
To execute a function with async dependency injection alluka.abc.Client.call_with_async_di should be called with the function and any positional or keyword arguments to pass through alongside the the injected arguments.
While both sync and async functions may be executed with
call_with_async_di, you'll always have to await
call_with_async_di to get the result of the call.
client: alluka.Client def callback( argument: int, /, injected: alluka.Injected[Foo], keyword_arg: str, ) -> int: ... ... result = client.call_with_di(callback, 123, keyword_arg="ok")
To execute a function with purely sync dependency injection alluka.abc.Client.call_with_di can be used with similar semantics to
call_with_async_di for passed through arguments but this comes with the limitation that only sync functions may be used and any dependency on async callback dependencies will lead to alluka.SyncOnlyError being raised.
def foo(ctx: alluka.Inject[alluka.abc.Context]) -> None: result = ctx.call_with_di(other_callback, 542, keyword_arg="meow")
async def bar(ctx: alluka.Inject[alluka.abc.Context]) -> None: result = await ctx.call_with_async_di(other_callback, 123, keyword_arg="ok")
Using the client#
Adding type dependencies#
client = ( alluka.Client() .set_type_dependency(TypeA, type_a_impl) .set_type_dependencu(TypeB, type_b_impl) )
For a type dependency to work, the linked client will have to have an implementation loaded for it. While right now the only way to load type dependencies is with the lower-level alluka.abc.Client.set_type_dependency method, more approaches and helpers will be added in the future as Alluka is further developed.
Overriding callback dependencies#
client = alluka.Client().set_callback_override(callback, other_callback)
While (unlike type dependencies) callback dependencies can work on their own without being explicitly declared on the client unless they're relying on a type dependency themselves, they can still be overridden on a client level using alluka.abc.Client.set_callback_override.
Generally speaking you should only ever override an injected callback with a callback which returns a compatible type but their signatures do not need to match and async callbacks can be overridden with sync with vice versa also working (although the latter will prevent callbacks from being used in an async context).