Skip to content

Support several dataclasses in a union #982

@sobolevn

Description

@sobolevn

Description

Currently msgspec has a very noticable limitation: it cannot convert an object with a field defined as a union of two dataclasses. Which is very common. For example:

>>> import msgspec
>>> import dataclasses
>>> @dataclasses.dataclass
... class User:
...     username: str
...     
>>> @dataclasses.dataclass
... class Reference:
...     instance_id: int
...     
>>> @dataclasses.dataclass
... class Project:
...     author: User | Reference
...     
>>> msgspec.convert({'author': {'username': 'example'}}, Project)
Traceback (most recent call last):
  File "<python-input-5>", line 1, in <module>
    msgspec.convert({'author': {'username': 'example'}}, Project)
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: Type unions may not contain more than one dataclass or attrs type - type `__main__.User | __main__.Reference` is not supported

pydantic does not have such a limitation. It works for this case.
I would love to have the same feature in msgspec.

See https://docs.pydantic.dev/2.2/usage/types/unions/

Real use-case

We in django-modern-rest have a lot of cases where unions are very specific. For example, in our OpenAPI integration. https://github.com/wemake-services/django-modern-rest/blob/04632fcc87ddb5d067ec22effec6d93bc07ba3b8/dmr/openapi/objects/schema.py#L33

We cannot model it any other way, because:

  1. We need them to be dataclasses, so both msgspec and pydantic will understand it
  2. We can't remove the union type, because this is how the OpenAPI spec defines this field

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions