msgspec icon indicating copy to clipboard operation
msgspec copied to clipboard

Support Literal[bool]

Open peku33 opened this issue 6 months ago • 4 comments

Description

Many APIs use something like {"success": true, data: ...}.

It will be really nice to be able to validate such boolean field against constant value when deserializing:

from typing import Literal

import msgspec


class ResponseData(msgspec.Struct):
    pass


class Response(msgspec.Struct):
    success: Literal[True]
    data: ResponseData


response = msgspec.convert(
    {
        "success": True,
        "data": {},
    },
    Response,
)

At the moment this raises:

TypeError: Literal may only contain None/integers/strings - typing.Literal[True] is not supported

Thank you 👍

peku33 avatar Jun 24 '25 12:06 peku33

why not just use bool directly?

class Response(msgspec.Struct):
    success: bool
    data: ResponseData

EDIT: I don't really see the point in using a literal for a boolean; perhaps there's a reason for when an API always sets a response to True, but then again using bool should be more than enough

jacopoabramo avatar Jun 24 '25 13:06 jacopoabramo

Using post-init-processing could help here https://jcristharif.com/msgspec/structs.html#post-init-processing

class Response(msgspec.Struct):
    success: bool
    data: ResponseData
    def __post_init__(self):
        if self.success is not True:
            raise ValueError("Expected success==true")

jack-mcivor avatar Jun 24 '25 16:06 jack-mcivor

And if success is False, you'd rather get a validation error from msgspec? I'd find that misleading

rafalkrupinski avatar Jun 24 '25 17:06 rafalkrupinski

I'm coming straight from pydantic v2, in which I was able to model api response like this:

class ApiResponseOk(BaseModel):
    success: Literal[True]
    data: SomeDataModel

class ApiResponseError(BaseModel):
    success: Literal[False]
    errors: list[ApiResponseErrorItem]

ApiResponse = RootModel[ApiResponseOk | ApiResponseError]

I understand that msgspec does not allow to create union types, like in pydantic.

And if success is False, you'd rather get a validation error from msgspec? I'd find that misleading

If i receive error response I will then get "data field not found" error from msgspec, which is even worse then something like "expected success to be True, but is False".

I assumed this would be easy, as we already have string and numeric literals.

peku33 avatar Jun 24 '25 18:06 peku33