question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[BUG] Generic pydantic model causes inconsistent OpenAPI spec generation

See original GitHub issue

Describe the bug I am wrapping my responses in a generic model like below (full code in toggle section).

class Response(GenericModel, Generic[DataT]):
    """Wrapper for responses"""
    data: Optional[DataT]

I see two issues:

  • The /docs endpoint renders things differently for a contained list or a contained single element.
  • PyCharm warns on type mismatch according to the annotations

I am wondering if I am using the GenericModel in a wrong way or if there is a bug?

Click to toggle
from typing import TypeVar, Generic, Optional, List

import uvicorn
from fastapi import FastAPI
from pydantic import BaseModel
from pydantic.generics import GenericModel

DataT = TypeVar('DataT')


class Response(GenericModel, Generic[DataT]):
    """Wrapper for responses"""
    data: Optional[DataT]


class ProjectOut(BaseModel):
    """Project model (out)"""
    id: int


app = FastAPI()

out = ProjectOut(id=1)


@app.get(
    '/projects/{item_id}',
    response_model=Response[ProjectOut]
)
def get_single() -> Response[ProjectOut]:
    return Response[ProjectOut](data=out)


@app.get(
    '/projects',
    response_model=Response[List[ProjectOut]])
def get_projects() -> Response[List[ProjectOut]]:
    return Response[List[ProjectOut]](data=[out])


if __name__ == '__main__':
    uvicorn.run(
        f"{__name__}:app",
        host='0.0.0.0',
        port=8888,
        reload=True,
        debug=True,
        log_level='info')

To Reproduce

Expected behavior

  • The list response is shown as Response[List[ProjectOut]]
  • I see no warnings in PyCharm when I am using annotations correctly.

Screenshots

Screenshot 2019-10-25 08 34 07 Screenshot 2019-10-25 08 33 07

Environment:

  • OS: macOS
  • FastAPI Version: 0.42
  • Python version: 3.7.4

Additional context Add any other context about the problem here.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

15reactions
fhesselcommented, Dec 2, 2021

@KiraPC – I just stumbled upon the same issue as you and Google led me here, so I’ll write down the solution to that:

Instead of deriving your PaginationModel from pydantic.BaseModel you have to use pydantic.generics.GenericModel, so the following gives you the expected result:

from pydantic import BaseModel
from pydantic.generics import GenericModel

Model = TypeVar("Model", bound=BaseModel)

class PaginationModel(GenericModel, Generic[Model]):
    index: int
    size: int
    total: int
    items: List[Model]
1reaction
KiraPCcommented, Dec 1, 2021

Hello everyone.

I have a similar issue to the one presented here.

Basically I’m using a pydantic BaseModel to represent the Pagination response. This class extends generic with a TypeVar.

T = TypeVar("T")


class PaginationModel(BaseModel, Generic[T]):
    total: int = Field(description="Total number of elements on DB")
    index: int = Field(description="The current page index")
    size: int = Field(description="The size of the page")
    results: List[T]

Then I use as Generic input the object that should be in the results list

class MyMockModel(BaseModel):
    foo: int
    bar: int

Then use it as route response model

def get_foo_bar(response_model=PaginationModel[MyMockModel]):
     ...

When I print the openapi spec, I expect to have something like

{
    "total": 0,
    "index": 0,
    "size": 20,
    "result": [
        {
            "foo": 0,
            "bar": 0
        }
    ]
}

but what actually I get is

{
   "foo": 0,
   "bar": 0
}

I’m doing somethings wrong, or it is a bug?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Changelog - pydantic
support generic models with discriminated union, #3551 by @PrettyWood ... refactor schema generation to be compatible with JSON Schema and OpenAPI specs, ...
Read more >
pydantic [python-library] - Occam :: Details
Fast and extensible, pydantic plays nicely with your linters/IDE/brain. Define how data should be in pure, canonical Python 3.6+; validate it with pydantic....
Read more >
datamodel-code-generator - GitHub Pages
This code generator creates pydantic model from an openapi file and others.
Read more >
pydantic - Bountysource
Bug. Output of python -c "import pydantic.utils; ... One of my model's fields is a Callable and I would like to call .json()...
Read more >
pydantic — pydantic v0.28 documentation
use of recursive pydantic models, typing 's List and Dict etc. and ... pydantic would try to validate the default None which would...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found