Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't use frozen native dataclass #4763

Closed
9 tasks done
dimaqq opened this issue Apr 5, 2022 · 12 comments
Closed
9 tasks done

Can't use frozen native dataclass #4763

dimaqq opened this issue Apr 5, 2022 · 12 comments
Labels
question Question or problem question-migrate

Comments

@dimaqq
Copy link
Contributor

dimaqq commented Apr 5, 2022

First Check

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar issue and didn't find it.
  • I searched the FastAPI documentation, with the integrated search.
  • I already searched in Google "How to X in FastAPI" and didn't find any information.
  • I already read and followed all the tutorial in the docs and didn't find an answer.
  • I already checked if it is not related to FastAPI but to Pydantic.
  • I already checked if it is not related to FastAPI but to Swagger UI.
  • I already checked if it is not related to FastAPI but to ReDoc.

Commit to Help

  • I commit to help with one of those options 👆

Example Code

from dataclasses import dataclass
from fastapi import FastAPI

app = FastAPI()

@dataclass(frozen=True)
class Mod:
    foo: str


@app.get("/", response_model=Mod)
async def get_mod():
    return {"foo": "bar"}

Description

ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/home/dima/.cache/pypoetry/virtualenvs/mre-frozen-dataclass-3kNYbFrL-py3.11/lib/python3.8/site-packages/uvicorn/protocols/http/h11_impl.py", line 366, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "/home/dima/.cache/pypoetry/virtualenvs/mre-frozen-dataclass-3kNYbFrL-py3.11/lib/python3.8/site-packages/uvicorn/middleware/proxy_headers.py", line 75, in __call__
    return await self.app(scope, receive, send)
  File "/home/dima/.cache/pypoetry/virtualenvs/mre-frozen-dataclass-3kNYbFrL-py3.11/lib/python3.8/site-packages/fastapi/applications.py", line 261, in __call__
    await super().__call__(scope, receive, send)
  File "/home/dima/.cache/pypoetry/virtualenvs/mre-frozen-dataclass-3kNYbFrL-py3.11/lib/python3.8/site-packages/starlette/applications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/home/dima/.cache/pypoetry/virtualenvs/mre-frozen-dataclass-3kNYbFrL-py3.11/lib/python3.8/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc
  File "/home/dima/.cache/pypoetry/virtualenvs/mre-frozen-dataclass-3kNYbFrL-py3.11/lib/python3.8/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "/home/dima/.cache/pypoetry/virtualenvs/mre-frozen-dataclass-3kNYbFrL-py3.11/lib/python3.8/site-packages/starlette/exceptions.py", line 82, in __call__
    raise exc
  File "/home/dima/.cache/pypoetry/virtualenvs/mre-frozen-dataclass-3kNYbFrL-py3.11/lib/python3.8/site-packages/starlette/exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "/home/dima/.cache/pypoetry/virtualenvs/mre-frozen-dataclass-3kNYbFrL-py3.11/lib/python3.8/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/home/dima/.cache/pypoetry/virtualenvs/mre-frozen-dataclass-3kNYbFrL-py3.11/lib/python3.8/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/home/dima/.cache/pypoetry/virtualenvs/mre-frozen-dataclass-3kNYbFrL-py3.11/lib/python3.8/site-packages/starlette/routing.py", line 656, in __call__
    await route.handle(scope, receive, send)
  File "/home/dima/.cache/pypoetry/virtualenvs/mre-frozen-dataclass-3kNYbFrL-py3.11/lib/python3.8/site-packages/starlette/routing.py", line 259, in handle
    await self.app(scope, receive, send)
  File "/home/dima/.cache/pypoetry/virtualenvs/mre-frozen-dataclass-3kNYbFrL-py3.11/lib/python3.8/site-packages/starlette/routing.py", line 61, in app
    response = await func(request)
  File "/home/dima/.cache/pypoetry/virtualenvs/mre-frozen-dataclass-3kNYbFrL-py3.11/lib/python3.8/site-packages/fastapi/applications.py", line 216, in openapi
    return JSONResponse(self.openapi())
  File "/home/dima/.cache/pypoetry/virtualenvs/mre-frozen-dataclass-3kNYbFrL-py3.11/lib/python3.8/site-packages/fastapi/applications.py", line 191, in openapi
    self.openapi_schema = get_openapi(
  File "/home/dima/.cache/pypoetry/virtualenvs/mre-frozen-dataclass-3kNYbFrL-py3.11/lib/python3.8/site-packages/fastapi/openapi/utils.py", line 412, in get_openapi
    flat_models = get_flat_models_from_routes(routes)
  File "/home/dima/.cache/pypoetry/virtualenvs/mre-frozen-dataclass-3kNYbFrL-py3.11/lib/python3.8/site-packages/fastapi/openapi/utils.py", line 377, in get_flat_models_from_routes
    flat_models = callback_flat_models | get_flat_models_from_fields(
  File "pydantic/schema.py", line 448, in pydantic.schema.get_flat_models_from_fields
  File "pydantic/schema.py", line 421, in pydantic.schema.get_flat_models_from_field
  File "pydantic/dataclasses.py", line 255, in pydantic.dataclasses.dataclass
  File "pydantic/dataclasses.py", line 250, in pydantic.dataclasses.dataclass.wrap
  File "pydantic/dataclasses.py", line 159, in pydantic.dataclasses._process_class
  File "/usr/lib/python3.8/dataclasses.py", line 1019, in dataclass
    return wrap(cls)
  File "/usr/lib/python3.8/dataclasses.py", line 1011, in wrap
    return _process_class(cls, init, repr, eq, order, unsafe_hash, frozen)
  File "/usr/lib/python3.8/dataclasses.py", line 891, in _process_class
    raise TypeError('cannot inherit non-frozen dataclass from a '
TypeError: cannot inherit non-frozen dataclass from a frozen one

Operating System

Linux

Operating System Details

Linux

FastAPI Version

0.75.1

Python Version

3.10, 3.11

Additional Context

pydantic 1.9.0

Workarounds:

  1. remove frozen=True, or
  2. from pyndatic.dataclasses impotr dataclass -- the pydantic version works.

It could be a bug in pydantic for all I know, or even a limitation, in which case fastapi docs need to be updated.

@dimaqq dimaqq added the question Question or problem label Apr 5, 2022
@jonatasoli
Copy link

In this case I think the response_model statement expect a pydantic object and not a dataclass.

@dimaqq
Copy link
Contributor Author

dimaqq commented Apr 19, 2022

Note that dataclasses.dataclass can be used if they are not frozen.
My gut tells me that pydantic attempts to convert my dataclass into their kind in order to generate the schema and/or to validators, in which case this is not a FastAPI problem per se.

If this is indeed a limitation, let's note this in FastAPI docs 🙏🏿

@jonatasoli
Copy link

Why in your case, use a dataclass instead of a pydantic object?

@dimaqq
Copy link
Contributor Author

dimaqq commented May 2, 2022

A couple of reasons, though perhaps neither is super important:

  1. simplicity, if I can use stdlib dataclass, why not?
  2. exporting data in a shape that's defined in a 3p package

@dimaqq
Copy link
Contributor Author

dimaqq commented May 2, 2022

I wonder if pydantic/pydantic#3469 is related.
Conceivably, generating the OpenAPI schema for the entire API could use a BaseModel somewhere in pydantic 🤔

@dimaqq
Copy link
Contributor Author

dimaqq commented May 2, 2022

Or maybe this: pydantic/pydantic#2555

@dimaqq
Copy link
Contributor Author

dimaqq commented May 2, 2022

Or this? pydantic/pydantic#2065

@jonatasoli
Copy link

It looks like something would be more related to pydantic than actually fastapi from the data examples.

@dimaqq
Copy link
Contributor Author

dimaqq commented May 2, 2022

Indeed it is. All I'm proposing is for FastAPI to document this limitation for the time being.

@dimaqq
Copy link
Contributor Author

dimaqq commented May 2, 2022

OT: looks like my issue comments are breaking GHA:

github.GithubException.RateLimitExceededException: 403 {"message": "API rate limit exceeded for installation ID 3370073.", "documentation_url": "https://docs.github.com/rest/overview/resources-in-the-rest-api#rate-limiting"}
https://github.com/tiangolo/fastapi/runs/6257027940?check_suite_focus=true

@haf
Copy link

haf commented May 3, 2022

It seems to be specific to something fastapi might do when it converts normal dataclasses to pydantic dataclasses?

@haf
Copy link

haf commented May 18, 2022

pydantic/pydantic#2557

Repository owner locked and limited conversation to collaborators Feb 28, 2023
@tiangolo tiangolo converted this issue into discussion #8457 Feb 28, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
question Question or problem question-migrate
Projects
None yet
Development

No branches or pull requests

4 participants