Overrides with for_
and context
We have a Greeter
that is used whenever our app asks for a Greeter
.
But maybe we want a second kind of Greeter
, used in a certain context.
For example, if we ask for a Greeter
but the context is FrenchCustomer
, get a FrenchGreeter
.
Stated differently, we want:
To register a
FrenchGreeter
…To be used “for”
Greeter
……when
context is ``FrenchCustomer
Our models are now richer. We add Customer
, FrenchCustomer
, and FrenchGreeter
:
1# models.py
2from dataclasses import dataclass
3
4from wired.dataclasses import factory
5
6
7@factory()
8@dataclass
9class Settings:
10 """Store some configuration settings for the app"""
11
12 punctuation: str = '.'
13
14
15@dataclass
16class Customer:
17 """A basic customer"""
18
19 name: str = 'Larry'
20
21
22@dataclass
23class FrenchCustomer:
24 """A certain kind of customer"""
25
26 name: str = 'Anne'
27
28
29@factory()
30@dataclass
31class Greeter:
32 """A basic greeter"""
33
34 settings: Settings
35 name: str = 'Mary'
36
37 def __call__(self, customer):
38 punctuation = self.settings.punctuation
39 return f'Hello {customer} my name is {self.name}{punctuation}'
40
41
42@factory(for_=Greeter, context=FrenchCustomer)
43@dataclass
44class FrenchGreeter:
45 """A greeter to use when the customer (context) is French"""
46
47 settings: Settings
48 name: str = 'Henri'
49
50 def __call__(self, customer):
51 punctuation = self.settings.punctuation
52 return f'Salut {customer} je m\'apelle {self.name}{punctuation}'
What’s important here is this line:
@factory(for_=Greeter, context=FrenchCustomer)
This registers a dataclass to be used as the Greeter
for the case when the context
is a FrenchCustomer
.
Let’s change our scenario to process two requests, meaning two customers.
In the first request the customer is a Customer
.
In the second, the customer is a FrenchCustomer
.
In both cases, we make a container for the request that sets the container’s context to the customer instance.
# request.py
from .models import Customer, FrenchCustomer, Greeter
def process_request(registry):
# Handle two requests: first a regular Customer and then a
# FrenchCustomer. In both cases:
# - Make a request, meaning a container
# - Make a customer instance matching that request
# - Stash the customer in the container as the context
# Handle a regular customer by setting the container's context
# to an instance of Customer
regular_customer = Customer()
container = registry.create_container(context=regular_customer)
greeter = container.get(Greeter)
greeting = greeter(regular_customer.name)
# Handle a French customer by making a container with
# a "context" that is a FrenchCustomer
french_customer = FrenchCustomer()
container = registry.create_container(context=french_customer)
french_greeter = container.get(Greeter)
french_greeting = french_greeter(french_customer.name)
return greeting, french_greeting
To finish, we change our assert
to test two cases:
# Application starts up
app = App()
app.scan()
# Later, a request comes in
results = process_request(app.registry)
assert 'Hello Larry my name is Mary.' == results[0]
assert 'Salut Anne je m\'apelle Henri.' == results[1]
With this, whenever the system asks for a Greeter
, if the container’s current context is a FrenchCustomer
, they’ll get FrenchGreeter
instead of a plain Greeter
.