pgjones / quart-schema

Quart-Schema is a Quart extension that provides schema validation and auto-generated API documentation.
MIT License
76 stars 24 forks source link

convert_model_result breaks on receiving GenericBaseModel as result #58

Closed joeblackwaslike closed 3 months ago

joeblackwaslike commented 12 months ago

It's common to use Generics to reuse a wrapper schema to enclose many different payload schemas existing on the data attribute. This is what I'm currently doing but when I do that, make_response raises an exception when I hit the endpoint.

TypeError: The response value type (GenericResponseWrapper[LinkAccountResponse]) is not valid

It would seem after a little exploration of the code, the problem lies here: https://github.com/pgjones/quart-schema/blob/a2171e82cf20ae070c5471e4ae353a2cb3e55846/src/quart_schema/extension.py#L335C18-L335C18

elif isinstance(value, BaseModel):

should instead be

elif isinstance(value, (BaseModel, GenericModel)):

with the additional import

from pydantic.generics import GenericModel

For test case purposes I use the following model for the envelope "(any model for the actual response schema):

DataT = TypeVar("DataT")

class GenericResponseWrapper(GenericModel, Generic[DataT]):
    """Generic response wrapper using actual generics."""

    error_code: str = ""
    status: str = ""
    message: str = ""
    data: DataT = Field(default_factory=dict)

    @validator("status")
    def set_status_by_error_code(cls, v, values):
        error_code = values.get("error_code")
        if error_code:
            return "failed"
        return "ok"

I use the following style type hint for the view:

GenericResponseWrapper[DataResponseModel]

and return from the view like so

return GenericResponseWrapper[DataResponseModel](
    data=DataResponseModel(
        x=x,
        y=y,
    ),
)
pgjones commented 3 months ago

I think you need to switch to using Pydantic 2 and BaseModel, as per https://docs.pydantic.dev/2.7/concepts/models/#generic-models. Please reopen if this doesn't work.