Introduction#

Antidote works with a Catalog which is a sort of collection of dependencies. Multiple ones can co-exist, but world is used by default. The most common form of a dependency is an instance of a given class

>>> from antidote import injectable, world
>>> @injectable
... class Service:
...    pass
>>> world[Service]
<Service object ...>

By default, injectable() defines a singleton, at most one instance will be created

>>> world[Service] is world[Service]
True

Dependencies can also be injected into a function/method with inject.

>>> from antidote import inject
>>> @inject
... def f(service: Service = inject.me()) -> Service:
...     return service
>>> f()
<Service object ...>
>>> f() is world[Service]
True

Specifying the dependency for each argument can be done in various ways. In the previous example it relied on the type hint. In all cases it’s always explicit, inject won’t guess whether some argument should be injected or not. Here are some of the alternative styles:

from antidote import InjectMe

@inject
def f2(service = inject[Service]):
    ...

@inject(kwargs=dict(service=Service))
def f3(service):
    ...

@inject
def f4(service: InjectMe[Service]):
    ...

All of this can be easily tested either by passing explicitly arguments to override the injection or by overriding globally a dependency with world:

>>> original = world[Service]
>>> x = Service()
>>> x is original  # different object
False
>>> f(x) is x  # overriding injection
True
>>> with world.test.clone() as overrides:
...     overrides[Service] = x  # overriding Service for the whole catalog
...     world[Service] is x, f() is x
(True, True)
>>> world[Service] is original  # outside the test context, nothing has changed.
True