jcrist / msgspec

A fast serialization and validation library, with builtin support for JSON, MessagePack, YAML, and TOML
https://jcristharif.com/msgspec/
BSD 3-Clause "New" or "Revised" License
2.01k stars 59 forks source link

Is it possible to have the decoding of union of all subclasses of a struct #656

Open sercant opened 3 months ago

sercant commented 3 months ago

Question

Hello!

I have a very specific use case at hand and I would like to ask if there is a better supported way to achieve what I am trying to do.

What I am trying to achieve;

import typing

import msgspec

class Base(msgspec.Struct, tag=True):
    pass

class A(Base):
    pass

class C(Base):
    other: Base # should be union of subclasses of Base

What works;

import typing

import msgspec

class Base(msgspec.Struct, tag=True):
    pass

class A(Base):
    pass

class C(Base):
    other: "BaseSubType"

BaseSubType = typing.Union[tuple(Base.__subclasses__())]

msgspec.json.decode(
    '{"type":"C","other":{"type":"C","other":{"type":"A"}}}', type=BaseSubType
)

But unfortunately, this has issues when there are multiple files defining the subclass of Base.

What would be probably ideal but does not work;

import typing

import msgspec

BaseSubType = typing.TypeVar("BaseSubType", bound=Base)

class Base(msgspec.Struct, tag=True):
    pass

class A(Base):
    pass

class C(Base, typing.Generic[BaseSubType]):
    other: BaseSubType

msgspec.json.decode(
    '{"type":"C","other":{"type":"C","other":{"type":"A"}}}', type=BaseSubType
)
# ValidationError: Invalid value 'C' - at `$.type`

Thank you in advance.