-
-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow for more complex logic for subclass Discrimnator field matching #184
Comments
At first glance, this is the best way to go. The only difficulty here is what kind of code should be generated when variant_tagger_fn is used. Right now it looks like this: ...
for variant in (*iter_all_subclasses(__main__.ClientEvent), __main__.ClientEvent):
try:
variants_map[variant_tagger_fn(variant)] = variant
except KeyError:
continue
... Important part here is As an alternative, I'd like you to consider creating an explicit @dataclass
class ClientEvent(DataClassDictMixin):
client_ip: str
type: str
class Config:
debug = True
discriminator = Discriminator(field="type", include_subtypes=True)
@dataclass
class ClientUnknownEvent(ClientEvent):
type = "unknown"
@dataclass
class ClientConnectedEvent(ClientEvent):
type = "connected"
@dataclass
class ClientDisconnectedEvent(ClientEvent):
type = "disconnected"
for key, value in (("N/A", ClientUnknownEvent), ('d/c', ClientDisconnectedEvent)):
ClientEvent.__mashumaro_subtype_variants__[key] = value
@dataclass
class AggregatedEvents(DataClassDictMixin):
list: List[ClientEvent]
events = AggregatedEvents.from_dict(
{
"list": [
{"type": "connected", "client_ip": "10.0.0.42"},
{"type": "disconnected", "client_ip": "10.0.0.42"},
{"type": "N/A", "client_ip": "10.0.0.42"},
{"type": "d/c", "client_ip": "10.0.0.42"},
]
}
)
# Produces:
AggregatedEvents(list=[ClientConnectedEvent(client_ip='10.0.0.42', type='connected'), ClientDisconnectedEvent(client_ip='10.0.0.42', type='disconnected'), ClientUnknownEvent(client_ip='10.0.0.42', type='N/A'), ClientDisconnectedEvent(client_ip='10.0.0.42', type='d/c')]) |
btw I had the same case where multiple tag values map to the same class (the tag field is a a literal with multiple possible values). I was thinking about opening a PR to allow |
I've been thinking about it and came to the conclusion that this will not have much of an impact. We iterate over variants and register them only when there is no tag in the registry. I'm going to allow variant_tagger_fn return a list, so that the following code will handle it: variant_tags = variant_tagger_fn(variant)
if type(variant_tags) is list:
for varint_tag in variant_tags:
variants_map[varint_tag] = variant
else:
variants_map[variant_tags] = variant |
Is your feature request related to a problem? Please describe.
In building a deserializer for a large complex configuration file, some subclasses have identical shapes, but it would still be useful to distinguish by a
type
field. Unfortunately, in our situation there are multiple values fortype
that map to the same subclass.Describe the solution you'd like
I haven't dug into the existing code deep enough to know what's feasible, so there are probably a number of possible solutions (or maybe none, I suppose).
The least intrusive I could see would be having
variant_trigger_fn
return alist[str]
instead ofstr
.A more involved solution might be adding an inverse to the
variant_trigger_fn
that takes astr
and returns aclass
.Finally, the workaround below could be improved upon if there was a hook in the base class that could accomplish the same thing.
Describe alternatives you've considered
I have been able to work around this using
__pre_deserialize__
:This works reasonably well (and preserves the original
type
which can be useful). The major downside is that the__pre_deserialize__
method needs to be implemented in each class that makes use ofClientEvent
, and in our situation that ends up being several. It would be more convenient if there was a hook in theClientEvent
base class that could accomplish the same thing.Additional context
I'm just getting started with this library and it's great so far. It's possible I'm missing something and this is already doable. Alternatively, the workaround, well, works, so feel free to close this if this is not a feature you're looking to add. Thanks!
The text was updated successfully, but these errors were encountered: