Generic types

You can use dishka with TypeVars and Generic-classes.

Note

Though generics are supported, there are some limitations:

  • You cannot use TypeVar bounded to a Generic type.

  • Generic-decorators are only applied to concrete factories or factories with more narrow TypeVars.

Creating objects with @provide

You can create generic factories, use type[T] to access resolved value of TypeVar. TypeVar can have bound or constraints, which are checked. For example, here we have a factory providing instances of generic class A. Note that A[int] and A[bool] are different types and cached separately.

from typing import Generic, TypeVar

from dishka import make_container, Provider, provide, Scope

T = TypeVar("T", bound=int)


class A(Generic[T]):
    pass


class MyProvider(Provider):
    @provide(scope=Scope.APP)
    def make_a(self, t: type[T]) -> A[T]:
        print("Requested type", t)
        return A()


container = make_container(MyProvider())
container.get(A[int])  # printed: Requested type <class 'int'>
container.get(A[bool])  # printed: Requested type <class 'bool'>
container.get(A[str])  # NoFactoryError

Decorating objects with @decorate

You can also make Generic decorator. Here it is used to decorate any type.

from collections.abc import Iterator
from typing import TypeVar

from dishka import make_container, Provider, provide, Scope, decorate

T = TypeVar("T")


class MyProvider(Provider):
    scope = Scope.APP

    @provide
    def make_int(self) -> int:
        return 1

    @provide
    def make_str(self) -> str:
        return "hello"

    @decorate
    def log(self, a: T, t: type[T]) -> Iterator[T]:
        print("Requested", t, "with value", a)
        yield a
        print("Requested release", a)


container = make_container(MyProvider())
container.get(int)  # Requested <class 'int'> with value 1
container.get(str)  # Requested <class 'str'> with value hello
container.close()
# Requested release object hello
# Requested release object 1