Skip to content
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

Add deque to serialization when Sequence is used as type hinting in V2 #7797

Closed
4 of 13 tasks
XCanG opened this issue Oct 11, 2023 · 2 comments · Fixed by #9128
Closed
4 of 13 tasks

Add deque to serialization when Sequence is used as type hinting in V2 #7797

XCanG opened this issue Oct 11, 2023 · 2 comments · Fixed by #9128
Assignees

Comments

@XCanG
Copy link

XCanG commented Oct 11, 2023

Initial Checks

  • I have searched Google & GitHub for similar requests and couldn't find anything
  • I have read and followed the docs and still think this feature is missing

Description

It seems like Pydantic V1 had this support, but it was missed on Pydantic V2.

I using Pydantic with project on FastAPI.

In my case I'm working with fast stream of data, so I had to use deque. As for the type hinting I using Sequence[MyModel]
however Pydantic cannot recognize deque as valid Sequence type, even if it is if you check with isinstance(my_deque, Sequence) -> True

When it trying to serialize, it throw error:

Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/cors.py", line 83, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/usr/local/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__
    raise e
  File "/usr/local/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 718, in __call__
    await route.handle(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 66, in app
    response = await func(request)
               ^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 291, in app
    content = await serialize_response(
              ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 159, in serialize_response
    return field.serialize(
           ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/fastapi/_compat.py", line 141, in serialize
    return self._type_adapter.dump_python(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pydantic/type_adapter.py", line 266, in dump_python
    return self.serializer.to_python(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
pydantic_core._pydantic_core.PydanticSerializationError: Unable to serialize unknown type: <class 'collections.deque'>

Project running in Docker with requirements.txt:

fastapi[all]==0.100.*
pydantic[email]==2.4.*
uvicorn[standard]==0.23.*

(not related requirements are omitted)

2.4.2 is current version

Affected Components

@sydney-runkle
Copy link
Member

Hi @XCanG,

Thanks for filing this feature request. Could you attach the code that raised the above error? Thanks!

@sydney-runkle sydney-runkle self-assigned this Oct 11, 2023
@sydney-runkle sydney-runkle added the awaiting author response awaiting response from issue opener label Oct 11, 2023
@XCanG
Copy link
Author

XCanG commented Oct 12, 2023

I thought it was self explanatory, but since it get down to this, there is minimal example with 2 cases:

"""
fastapi[all]==0.100.*
pydantic[email]==2.4.*
uvicorn[standard]==0.23.*
"""

from collections import deque
from collections.abc import Sequence

from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from pydantic import BaseModel


class TestSubmodel(BaseModel):
    id: int
    name: str


class TestModel(BaseModel):
    id: int
    objects: Sequence[TestSubmodel]


app = FastAPI(debug=True)

model = TestModel(
    id=1,
    objects=deque([
        TestSubmodel(id=1, name="test 1"),
        TestSubmodel(id=2, name="test 2"),
    ]))


@app.get("/")
async def index() -> HTMLResponse:
    """Index page"""

    return HTMLResponse("""
        <a href="/docs">Swagger docs</a><br />
        <a href="/test1">Test model with deque attribute (error)</a><br />
        <a href="/test1_fixed">Test model with deque attribute (fixed)</a><br />
        <a href="/test2">Test deque Sequence (error)</a><br />
        <a href="/test2_fixed">Test deque Sequence (fixed)</a>
    """)


@app.get("/test1")
async def get_model() -> TestModel:
    """Return TestModel with deque as Sequence (error)"""

    print(model)

    return model


@app.get("/test1_fixed")
async def get_model_fixed() -> TestModel:
    """Return TestModel with deque as Sequence (fixed)"""

    model_copy = model.model_copy()
    model_copy.objects = list(model_copy.objects)

    print(model_copy)

    return model_copy


@app.get("/test2")
async def get_model_sequence() -> Sequence[TestSubmodel]:
    """Return deque sequence of TestSubmodel (error)"""

    print(model.objects)

    return model.objects


@app.get("/test2_fixed")
async def get_model_sequence_fixed() -> Sequence[TestSubmodel]:
    """Return deque sequence of TestSubmodel (fixed)"""

    submodel = list(model.objects)

    print(submodel)

    return submodel


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, port=80)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants