msgspec
msgspec copied to clipboard
Better enum support
Description
I would like to suggest allowing enums to be passed in literals and to the tag
kwarg in msgspec.Struct
s.
Thanks for opening this. Can you please add minimal complete examples of code you'd want to work that hits each of these issues?
Hello, just chiming in here.
Allowing enum values in literals is useful for making specialised versions of a struct. e.g. I have something like this at the moment
class InteractionCallbackType(IntEnum):
PONG = 1
CHANNEL_MESSAGE_WITH_SOURCE = 4
class InteractionResponse(msgspec.Struct, kw_only=True):
type: InteractionCallbackType
data: Optional[Any]
class PongInteractionResponse(InteractionResponse, kw_only=True):
type: Literal[1] = 1
data: None = None
class InteractionMessage(msgspec.Struct):
content: str
flags: int
class MessageInteractionResponse(InteractionResponse, kw_only=True):
type: Literal[4] = 4
data: InteractionMessage
where PongInteractionResponse
and MessageInteractionResponse
are specialised versions of InteractionResponse
with literal values for the type
field.
It would be nice for MessageInteractionResponse
to be defined like this instead, using the enum value:
class MessageInteractionResponse(InteractionResponse, kw_only=True):
type: Literal[InteractionCallbackType.CHANNEL_MESSAGE_WITH_SOURCE] = InteractionCallbackType.CHANNEL_MESSAGE_WITH_SOURCE
data: InteractionMessage
Sorry for responding so late, but here you go.
Enums in Literals
auburnsummer convered it pretty well, but I want to add onto it. The ideal solution would be:
class SomeEnum(Enum):
video = 1
audio = 2
class VideoPayload(msgspec.Struct):
type: Literal[SomeEnum.video]
The reason I think this should be supported is because you have to put the enum's value in the literal, which could change. Technically you could do this:
Literal[SomeEnum.video.value]
Though, typecheckers dislike it:
Type arguments for "Literal" must be None, a literal value (int, bool, str, or bytes), or an enum valuePylance
Enums in the tag
kwarg
This one is a little petty, but I just want to remove the need to pass SomeEnum.video.value
to the tag
kwarg opposed to SomeEnum.video
. The ideal solution would be:
class SomeEnum(Enum):
audio = 2
tts = 3
class TTSPayload(msgspec.Struct, tag=SomeEnum.tts):
text: str
speed: int
class AudioPayload(msgspec.Struct, tag=SomeEnum.audio):
url: str
Rather than
class SomeEnum(Enum):
audio = 2
tts = 3
class TTSPayload(msgspec.Struct, tag=SomeEnum.tts.value):
text: str
speed: int
class AudioPayload(msgspec.Struct, tag=SomeEnum.audio.value):
url: str
I'd also benefit from enum members in Literals. Somewhat useful for reused flags that not all flags are valid for all fields, comes up with a few external APIs I've had to deal with.
On the typing side, Literals may include slightly more than msgspec currently allows, that being
literal ints, byte and unicode strings, bools, Enum values and None
If this is something you're willing to accept into msgspec, I can make time to PR support for it, but I understand that there may be reasons not to fully support all of the things typing does without first considering the implications of it on serialization and potential ambiguities.