Simple Injection

Finally, dependency injection (DI).

We want our greeting to have punctuation at the end, such as a period or, in the U.S., !!! because we Americans are like puppies.

Everything is the same as in Decorators, Simple Case, we just have different models:

# models.py
from dataclasses import dataclass

from wired.dataclasses import factory


@factory()
@dataclass
class Settings:
    """Store some configuration settings for the app"""

    punctuation: str = '.'


@factory()
@dataclass
class Greeter:
    settings: Settings  # Ask DI to get the configured Settings
    name: str = 'Mary'

    def __call__(self, customer):
        punctuation = self.settings.punctuation
        return f'Hello {customer} my name is {self.name}{punctuation}'
  • We register a dataclass Settings with one field, defaulted to a value of a period

  • Greeter now asks DI to assign the configured Settings to a field…

  • …which is then used in the __call__

So this is DI. What’s actually happening?

wired.dataclasses creates your dataclass instance. When it does, it looks at each field’s type annotation. It uses this type to look in the registry for that configured type, then calls the factory to get an instance. Which it then stores on the field.

This is already useful and powerful. The “callee” and the “caller” have something in between – DI – which can help decouple calling. The callee – the dataclass – can provide instructions for what it wants provided – hence the “inversion of control” expression. Here we are using dataclassses and its field construct as a DSL for object construction.

There’s a lot more to this, as we’ll see in the following sections.

To finish, we change our assert to add the period:

    # Application starts up
    app = App()
    app.scan()

    # Later, a request comes in
    result = process_request(app.registry)
    assert 'Hello Larry my name is Mary.' == result