Dependency injection
Wiring dependencies to handlers for extra handling.
Handler factories
Subscribing to a request will create a handler reference. The reference is an
instance of the HandlerReference
class. A handler factory
creates a concrete handler from the reference. The HandlerFactory
protocol defines this contract.
The reference will be to the class or function used in the subscription. Which may or
may not be a handler. The factory tries to coerce these classes and functions into the
Handler
protocol.
Providing dependencies
To perform the business logic a handler represents, it often needs other dependencies.
Banshee has no opinions about on how you manage your dependencies. You can use a custom factory to provide them to handlers any way you like.
import functools
import inspect
import typing
import banshee
T = typing.TypeVar("T")
DEPENDENCIES = {
"user_repository": UserRepository()
}
def kwargs_factory(self, reference: HandlerReference[T]) -> Handler[T]:
expected = inspect.signature(reference.handler).parameters.keys()
kwargs = {k: v for k, v in DEPENDENCIES.items() if k in keys}
return functools.partial(reference.handler, **kwargs)
The above uses values based on argument name. It is a crude example. In production we recommend that you consider using a proper dependency injection framework. See our injector integration for example.
Default behaviour
The SimpleHandlerFactory
is the default used when a factory is not
provided. It will return a function as is, and try to create an instance for class based
handlers.
Reference
- class banshee.HandlerFactory(*args, **kwargs)
Bases:
Protocol
Handler factory protocol.
Returns a concrete handler for the given reference.
- abstract __call__(reference, /)
Get handler.
Returns a concrete handler for the given reference.
- Parameters:
reference (HandlerReference[T]) – reference to a handler
- Returns:
concrete handler instance
- Return type:
Handler[T]
- class banshee.SimpleHandlerFactory(*args, **kwargs)
Bases:
HandlerFactory
Simple handler factory.
This factory assumes that the reference is itself a valid handler, allowing handlers to be directly registered with the registry.
@registry.subscribe_to(GreetCommand) def do_greet(command: GreetCommand): print(f"hello {command.name}!")
- __call__(reference, /)
Get handler.
Returns a concrete handler for the given reference.
- Parameters:
reference (HandlerReference[T]) – reference to a handler
- Returns:
concrete handler instance
- Return type:
Handler[T]