Skip to content

Commit

Permalink
fix: handle basemodel fallback for custom encoders
Browse files Browse the repository at this point in the history
  • Loading branch information
PrettyWood committed Dec 20, 2021
1 parent c532e83 commit 5da5ee0
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 2 deletions.
6 changes: 4 additions & 2 deletions pydantic/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ def json(
exclude_defaults: bool = False,
exclude_none: bool = False,
encoder: Optional[Callable[[Any], Any]] = None,
to_dict: bool = True,
**dumps_kwargs: Any,
) -> str:
"""
Expand All @@ -469,11 +470,12 @@ def json(
exclude_unset = skip_defaults
encoder = cast(Callable[[Any], Any], encoder or self.__json_encoder__)

# We don't directly call `self.dict()`, which does exactly the same thing but
# with `to_dict = True` because we want to keep raw `BaseModel` instances and not as `dict`.
# We don't directly call `self.dict()`, which is does exactly this with `to_dict=True`
# because we want to be able to keep raw `BaseModel` instances and not as `dict`.
# This allows users to write custom JSON encoders for given `BaseModel` classes.
data = dict(
self._iter(
to_dict=to_dict,
by_alias=by_alias,
include=include,
exclude=exclude,
Expand Down
38 changes: 38 additions & 0 deletions tests/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,3 +319,41 @@ class Config:
pumbaa.json() == '{"name": "Pumbaa", "SSN": 234, "birthday": 737424000.0, "phone": 18007267864, "friend": null}'
)
assert timon.json() == '{"name": "Timon", "SSN": 123, "birthday": 738892800.0, "phone": 18002752273, "friend": 234}'


def test_custom_encode_fallback_basemodel():
class MyExoticType:
pass

def custom_encoder(o):
if isinstance(o, MyExoticType):
return 'exo'
raise TypeError('not serialisable')

class Foo(BaseModel):
x: MyExoticType

class Config:
arbitrary_types_allowed = True

class Bar(BaseModel):
foo: Foo

assert Bar(foo=Foo(x=MyExoticType())).json(encoder=custom_encoder) == '{"foo": {"x": "exo"}}'


def test_custom_encode_error():
class MyExoticType:
pass

def custom_encoder(o):
raise TypeError('not serialisable')

class Foo(BaseModel):
x: MyExoticType

class Config:
arbitrary_types_allowed = True

with pytest.raises(TypeError, match='not serialisable'):
Foo(x=MyExoticType()).json(encoder=custom_encoder)

0 comments on commit 5da5ee0

Please sign in to comment.