Decorators, Simple Case

Note

Decorators depend on the venusian package being installed.

Our previous example didn’t do Dependency Injection (DI) which makes it pretty boring. But it saved us from writing a factory function. Let’s rewrite it to see how decorators can also save us the register_dataclass registration step. Still no DI.

As before, we have an application with a registry. Let’s add a method that looks for our wired.dataclasses decorators, using venusian:

# app.py
from dataclasses import dataclass, field
from venusian import Scanner

from wired import ServiceRegistry

from . import models


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

    def scan(self):
        # Look for decorators
        scanner = Scanner(registry=self.registry)
        scanner.scan(models)

Our Greeter dataclass can now register itself as a wired factory, using a decorator:

# models.py
from dataclasses import dataclass

from wired.dataclasses import factory


@factory()
@dataclass
class Greeter:
    name: str = 'Mary'

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

We no longer need the call to the register_dataclass, which needed the registry and the target class. The decorator knows the registry, knows the class being decorated, and can call register_dataclass. Simple!

Our request processing is exactly the same as the previous step:

# 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

Putting it all together: make an app, scan for decorators, and process requests:

    # 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