Simple Construction

Before looking at injection, let’s take a look at how dataclasses get registered. We’ll use a very simple example: a Greeter that greets people, for example in a grocery store.

First, imagine we have a nice, boring Greeter:

# models.py
from dataclasses import dataclass


@dataclass
class Greeter:
    name: str = 'Mary'

    def __call__(self, customer):
        return f'Hello {customer} my name is {self.name}'

Since this is a wired application, we need an application with a registry. Dataclasses are fun, let’s use them for our application:

# app.py
from dataclasses import dataclass, field

from wired import ServiceRegistry


@dataclass
class App:
    registry: ServiceRegistry = field(default_factory=ServiceRegistry)

During startup, we create the app (and thus registry) and then start configuring our stuff. For example, here is a configuration step:

# configure.py
from wired import ServiceRegistry
from wired.dataclasses import register_dataclass

from .models import Greeter


def register(registry: ServiceRegistry):
    register_dataclass(registry, Greeter)

If we were using wired directly, we would have to define a factory function and register it:

# NO LONGER NEED THIS, wired.dataclasses makes a factory
def greeter_factory(container):
    greeter = Greeter()
    return greeter

registry.register_factory(greeter_factory, Greeter)

But with wired.dataclasses, no factory function is needed, as wired.dataclasses makes a factory for you

The application is now finished starting up. Later on, it’s time to process a “request”. Here’s a function that can do so:

# request.py
from .models import Greeter


def process_request(registry):
    # Each request gets its own container
    container = registry.create_container()

    # Do the work unique to this request and return result
    greeter: Greeter = container.get(Greeter)
    greeting = greeter('Larry')

    return greeting

Now let’s put all these pieces together: models, application, configuration, and request processing:

    # Application starts up, imports App and configure
    app = App()
    configure.register(app.registry)

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

This was a very simple example: the Greeter needed nothing from its environment because the only field had a default value. Thus, the only parts of “DI” used were construction of the dataclass instance.