diff --git a/fastapi/encoders.py b/fastapi/encoders.py index 6f571edb261d7..f64e4b86ea3b4 100644 --- a/fastapi/encoders.py +++ b/fastapi/encoders.py @@ -71,7 +71,14 @@ def jsonable_encoder( sqlalchemy_safe=sqlalchemy_safe, ) if dataclasses.is_dataclass(obj): - return dataclasses.asdict(obj) + obj_dict = dataclasses.asdict(obj) + return jsonable_encoder( + obj_dict, + exclude_none=exclude_none, + exclude_defaults=exclude_defaults, + custom_encoder=custom_encoder, + sqlalchemy_safe=sqlalchemy_safe, + ) if isinstance(obj, Enum): return obj.value if isinstance(obj, PurePath): diff --git a/tests/test_serialize_response_dataclass.py b/tests/test_serialize_response_dataclass.py index e520338ec68f0..1e3bf3b28bcc3 100644 --- a/tests/test_serialize_response_dataclass.py +++ b/tests/test_serialize_response_dataclass.py @@ -1,8 +1,9 @@ +from dataclasses import dataclass +from datetime import datetime from typing import List, Optional from fastapi import FastAPI from fastapi.testclient import TestClient -from pydantic.dataclasses import dataclass app = FastAPI() @@ -10,54 +11,64 @@ @dataclass class Item: name: str + date: datetime price: Optional[float] = None owner_ids: Optional[List[int]] = None @app.get("/items/valid", response_model=Item) def get_valid(): - return {"name": "valid", "price": 1.0} + return {"name": "valid", "date": datetime(2021, 7, 26), "price": 1.0} @app.get("/items/object", response_model=Item) def get_object(): - return Item(name="object", price=1.0, owner_ids=[1, 2, 3]) + return Item( + name="object", date=datetime(2021, 7, 26), price=1.0, owner_ids=[1, 2, 3] + ) @app.get("/items/coerce", response_model=Item) def get_coerce(): - return {"name": "coerce", "price": "1.0"} + return {"name": "coerce", "date": datetime(2021, 7, 26).isoformat(), "price": "1.0"} @app.get("/items/validlist", response_model=List[Item]) def get_validlist(): return [ - {"name": "foo"}, - {"name": "bar", "price": 1.0}, - {"name": "baz", "price": 2.0, "owner_ids": [1, 2, 3]}, + {"name": "foo", "date": datetime(2021, 7, 26)}, + {"name": "bar", "date": datetime(2021, 7, 26), "price": 1.0}, + { + "name": "baz", + "date": datetime(2021, 7, 26), + "price": 2.0, + "owner_ids": [1, 2, 3], + }, ] @app.get("/items/objectlist", response_model=List[Item]) def get_objectlist(): return [ - Item(name="foo"), - Item(name="bar", price=1.0), - Item(name="baz", price=2.0, owner_ids=[1, 2, 3]), + Item(name="foo", date=datetime(2021, 7, 26)), + Item(name="bar", date=datetime(2021, 7, 26), price=1.0), + Item(name="baz", date=datetime(2021, 7, 26), price=2.0, owner_ids=[1, 2, 3]), ] @app.get("/items/no-response-model/object") def get_no_response_model_object(): - return Item(name="object", price=1.0, owner_ids=[1, 2, 3]) + return Item( + name="object", date=datetime(2021, 7, 26), price=1.0, owner_ids=[1, 2, 3] + ) @app.get("/items/no-response-model/objectlist") def get_no_response_model_objectlist(): return [ - Item(name="foo"), - Item(name="bar", price=1.0), - Item(name="baz", price=2.0, owner_ids=[1, 2, 3]), + Item(name="foo", date=datetime(2021, 7, 26)), + Item(name="bar", date=datetime(2021, 7, 26), price=1.0), + Item(name="baz", date=datetime(2021, 7, 26), price=2.0, owner_ids=[1, 2, 3]), ] @@ -67,28 +78,58 @@ def get_no_response_model_objectlist(): def test_valid(): response = client.get("/items/valid") response.raise_for_status() - assert response.json() == {"name": "valid", "price": 1.0, "owner_ids": None} + assert response.json() == { + "name": "valid", + "date": datetime(2021, 7, 26).isoformat(), + "price": 1.0, + "owner_ids": None, + } def test_object(): response = client.get("/items/object") response.raise_for_status() - assert response.json() == {"name": "object", "price": 1.0, "owner_ids": [1, 2, 3]} + assert response.json() == { + "name": "object", + "date": datetime(2021, 7, 26).isoformat(), + "price": 1.0, + "owner_ids": [1, 2, 3], + } def test_coerce(): response = client.get("/items/coerce") response.raise_for_status() - assert response.json() == {"name": "coerce", "price": 1.0, "owner_ids": None} + assert response.json() == { + "name": "coerce", + "date": datetime(2021, 7, 26).isoformat(), + "price": 1.0, + "owner_ids": None, + } def test_validlist(): response = client.get("/items/validlist") response.raise_for_status() assert response.json() == [ - {"name": "foo", "price": None, "owner_ids": None}, - {"name": "bar", "price": 1.0, "owner_ids": None}, - {"name": "baz", "price": 2.0, "owner_ids": [1, 2, 3]}, + { + "name": "foo", + "date": datetime(2021, 7, 26).isoformat(), + "price": None, + "owner_ids": None, + }, + { + "name": "bar", + "date": datetime(2021, 7, 26).isoformat(), + "price": 1.0, + "owner_ids": None, + }, + { + "name": "baz", + "date": datetime(2021, 7, 26).isoformat(), + "price": 2.0, + "owner_ids": [1, 2, 3], + }, ] @@ -96,23 +137,58 @@ def test_objectlist(): response = client.get("/items/objectlist") response.raise_for_status() assert response.json() == [ - {"name": "foo", "price": None, "owner_ids": None}, - {"name": "bar", "price": 1.0, "owner_ids": None}, - {"name": "baz", "price": 2.0, "owner_ids": [1, 2, 3]}, + { + "name": "foo", + "date": datetime(2021, 7, 26).isoformat(), + "price": None, + "owner_ids": None, + }, + { + "name": "bar", + "date": datetime(2021, 7, 26).isoformat(), + "price": 1.0, + "owner_ids": None, + }, + { + "name": "baz", + "date": datetime(2021, 7, 26).isoformat(), + "price": 2.0, + "owner_ids": [1, 2, 3], + }, ] def test_no_response_model_object(): response = client.get("/items/no-response-model/object") response.raise_for_status() - assert response.json() == {"name": "object", "price": 1.0, "owner_ids": [1, 2, 3]} + assert response.json() == { + "name": "object", + "date": datetime(2021, 7, 26).isoformat(), + "price": 1.0, + "owner_ids": [1, 2, 3], + } def test_no_response_model_objectlist(): response = client.get("/items/no-response-model/objectlist") response.raise_for_status() assert response.json() == [ - {"name": "foo", "price": None, "owner_ids": None}, - {"name": "bar", "price": 1.0, "owner_ids": None}, - {"name": "baz", "price": 2.0, "owner_ids": [1, 2, 3]}, + { + "name": "foo", + "date": datetime(2021, 7, 26).isoformat(), + "price": None, + "owner_ids": None, + }, + { + "name": "bar", + "date": datetime(2021, 7, 26).isoformat(), + "price": 1.0, + "owner_ids": None, + }, + { + "name": "baz", + "date": datetime(2021, 7, 26).isoformat(), + "price": 2.0, + "owner_ids": [1, 2, 3], + }, ]