You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently, the only way to deserialise such classes is to use Union type or write your own code that would select a class depending on some value. Such approaches can be found in the related issue:
We can make it so that it can be done without writing boilerplate code by users. It will also be very useful to get Event2 instance from Event as follows:
event2=Event.from_json('{"event_type": 2, ...}')
Using discriminated unions instead of simple Union[A, B] we can also get a huge performance boost.
Describe the solution you'd like
There is such a thing as discriminated unions. This is what we need. We can introduce a new entity called "Discriminator" which will be used to describe the class selection rules.
@dataclassclassEvent(DataClassDictMixin): # we have a common parent class
...
@dataclassclassEvent1(Event):
event_type: Literal[1] =1
...
@dataclassclassEvent2(Event):
event_type: Literal[2] =2
...
@dataclassclassMessage(DataClassDictMixin):
# using the parent class hereevent: Annotated[Event, Discriminator(field="event_type", include_subclasses=True)]
event2_msg=Message.from_dict({"event": {"event_type": 2, ...}})) # <- Event2 will be used for event@dataclassclassEvent3(Event): # a new event declared after the Messageevent_type: Literal[3] =3
...
event3_msg=Message.from_dict({"event": {"event_type": 3, ...}})) # <- Event3 will be used for event
Using discriminator with unions
Deserialization of Unions will be much faster because there will be no traversal of all classes and an attempt to deserialize each of them.
@dataclassclassEvent1(DataClassDictMixin):
event_type: Literal[1] =1
...
@dataclassclassEvent2(DataClassDictMixin):
event_type: Literal[2] =2
...
@dataclassclassMessage(DataClassDictMixin):
# no common parent classes here, using Unionevent: Annotated[Union[Event1, Event2], Discriminator(field="event_type")]
event2_msg=Message.from_dict({"event": {"event_type": 2, ...}}) # <- Event2 will be used for event
Using discriminator inside a parent class config
@dataclassclassEvent(DataClassDictMixin):
classConfig:
# using discriminator in a parent classdiscriminator=Discriminator(field="event_type", include_subclasses=True)
@dataclassclassEvent1(Event):
event_type: Literal[1] =1
...
@dataclassclassEvent2(Event):
event_type: Literal[2] =2
...
event2=Event.from_dict({"event_type": 2, ...}) # Event2 instance will be returned@dataclassclassMessage(DataClassDictMixin):
event: Event# using the parent class hereevent2_msg=Message.from_dict({"event": {"event_type": 2, ...}}) # <- Event2 will be used for event@dataclassclassEvent3(Event): # a new event declared after the Messageevent_type: Literal[3] =3
...
event3=Event.from_dict({"event_type": 3, ...}) # <- Event3 instance will be returnedevent3_msg=Message.from_dict({"event": {"event_type": 3, ...}}) # <- Event3 will be used for event
Using discriminator with unions and subclasses
@dataclassclassEvent(DataClassDictMixin):
...
@dataclassclassClientEvent(Event):
...
@dataclassclassServerEvent(Event):
...
@dataclassclassSystemEvent(Event):
...
@dataclassclassClientEvent1(ClientEvent):
code: Literal["client_event_1"] ="client_event_1"
...
@dataclassclassServerEvent1(ServerEvent):
code: Literal["server_event_1"] ="server_event_1"
...
@dataclassclassSystemEvent1(SystemEvent):
code: Literal["system_event_1"] ="system_event_1"
...
@dataclassclassMessage(DataClassDictMixin):
event: Annotated[Union[ClientEvent, ServerEvent], Discriminator(field="code", include_subclasses=True)]
# ServerEvent1 will be used for event:server_event1_msg=Message.from_dict({"event": {"code": "server_event_1", ...}}))
# Wrong event code will produce an error:Message.from_dict({"event": {"code": "system_event_1", ...}})
Additional context
For a discriminator value we could use the following class attributes:
without annotations: code = 42
annotated as ClassVar: code: ClassVar[int] = 42
annotated as Final: code: Final[int] = 42
annotated as Literal: code: Literal[42] = 42
Enum value: code: ClientEvent = ClientEvent.FOO
The text was updated successfully, but these errors were encountered:
Is your feature request related to a problem? Please describe.
There are situations when you have multiple subclasses that are distinguishable by a specific field like "type" or "code":
Currently, the only way to deserialise such classes is to use
Union
type or write your own code that would select a class depending on some value. Such approaches can be found in the related issue:We can make it so that it can be done without writing boilerplate code by users. It will also be very useful to get
Event2
instance fromEvent
as follows:Using discriminated unions instead of simple
Union[A, B]
we can also get a huge performance boost.Describe the solution you'd like
There is such a thing as discriminated unions. This is what we need. We can introduce a new entity called "Discriminator" which will be used to describe the class selection rules.
Using discriminator with subclasses
Using discriminator with unions
Deserialization of Unions will be much faster because there will be no traversal of all classes and an attempt to deserialize each of them.
Using discriminator inside a parent class config
Using discriminator with unions and subclasses
Additional context
For a discriminator value we could use the following class attributes:
code = 42
code: ClassVar[int] = 42
code: Final[int] = 42
code: Literal[42] = 42
code: ClientEvent = ClientEvent.FOO
The text was updated successfully, but these errors were encountered: