Browse Source

Fix jsonable_encoder custom encoders for Pydantic models

pull/15124/head
letmetry-oss 4 months ago
parent
commit
20e0abbeab
  1. 6
      fastapi/encoders.py
  2. 19
      tests/test_jsonable_encoder.py

6
fastapi/encoders.py

@ -224,8 +224,11 @@ def jsonable_encoder(
if exclude is not None and not isinstance(exclude, (set, dict)): if exclude is not None and not isinstance(exclude, (set, dict)):
exclude = set(exclude) # type: ignore[assignment] # ty: ignore[unused-ignore-comment] exclude = set(exclude) # type: ignore[assignment] # ty: ignore[unused-ignore-comment]
if isinstance(obj, BaseModel): if isinstance(obj, BaseModel):
model_dump_mode: str = "json"
if custom_encoder:
model_dump_mode = "python"
obj_dict = obj.model_dump( obj_dict = obj.model_dump(
mode="json", mode=model_dump_mode,
include=include, include=include,
exclude=exclude, exclude=exclude,
by_alias=by_alias, by_alias=by_alias,
@ -237,6 +240,7 @@ def jsonable_encoder(
obj_dict, obj_dict,
exclude_none=exclude_none, exclude_none=exclude_none,
exclude_defaults=exclude_defaults, exclude_defaults=exclude_defaults,
custom_encoder=custom_encoder,
sqlalchemy_safe=sqlalchemy_safe, sqlalchemy_safe=sqlalchemy_safe,
) )
if dataclasses.is_dataclass(obj): if dataclasses.is_dataclass(obj):

19
tests/test_jsonable_encoder.py

@ -225,6 +225,25 @@ def test_custom_encoders():
assert encoded_instance2["dt_field"] == instance["dt_field"].isoformat() assert encoded_instance2["dt_field"] == instance["dt_field"].isoformat()
def test_custom_encoders_for_pydantic_model_arbitrary_type():
class CustomType:
def __init__(self, value: str):
self.value = value
class ModelWithCustomType(BaseModel):
custom: CustomType
model_config = {"arbitrary_types_allowed": True}
instance = ModelWithCustomType(custom=CustomType("encoded"))
encoded_instance = jsonable_encoder(
instance,
custom_encoder={CustomType: lambda o: {"value": o.value}},
)
assert encoded_instance == {"custom": {"value": "encoded"}}
def test_custom_enum_encoders(): def test_custom_enum_encoders():
def custom_enum_encoder(v: Enum): def custom_enum_encoder(v: Enum):
return v.value.lower() return v.value.lower()

Loading…
Cancel
Save