I have a model that is a little complicated where one field can be one of several other models which looks similar to the following:
'''These are the options'''
class ChatterFilter(Record, serializer='json'):
counts:int
time:int
init_state:str
new_state:str
stale_time:int
comment:str
class LimitFilter(Record, serializer='json'):
lolo:float
low:float
high:float
hihi:float
comment:str
class DitherFilter(Record, serializer='json'):
stale_time:int
init_state:str
new_state:str
comment:str
class FitlerOptions(FieldDescriptor[type]):
''' This class defines the allowable filter types and validates these on initialisation '''
def __init__(self, choices: List[type], **kwargs: Any) -> None:
self.choices = choices
super().__init__(choices=choices, **kwargs)
def validate(self, value: type) -> Iterable[ValidationError]:
if type(value) not in self.choices:
yield self.validation_error(
f'{self.field} must be one of {self.choices}, received:\t{value}=>{type(value)}')
class Filter(Record, serializer='json', validation=True):
filter: type = FitlerOptions([ChatterFilter, LimitFilter, DitherFilter, type(None)])
initiated:str=None
end:str=None
duration:float=None
initiator:str=None
The idea was that we wanted to ensure that the filter was one of the 3 types (or None if there is no filter), so we used this method to create a model to validate the type supplied.
This appears to work really well... until we try to send it to a topic and then read the incoming event and it fails to deserialize the filter from the serialised dictionary and complains that it's a dictionary instead of one of the allowed options with the error log being received: {'counts': 0, 'time': 0, 'init_state': 'NO_ALARM', 'new_state': 'LOLO', 'stale_time': 60, 'comment': 'comment string', '__faust': {'ns': 'models.models.ChatterFilter'}}=><class 'dict'>
It's clear that it's a model and that faust should recognise it, but it doesn't seem to do it by default. I could add a check in the validation and yield a converted version and error on an unsuccessful attempt, but it seems like I shouldn't have to.
So it does indeed work. It's just a matter of setting it up differently so that you specify it to be a list:
class Filter(Record): masks:List[Union[ChatterFilter, LimitFilter, DitherFilter]]=[]
This now works as expected.