From f669c91330b10d725fd6cf33a93da83256968234 Mon Sep 17 00:00:00 2001 From: SergioSim Date: Sun, 24 Apr 2022 15:58:13 +0200 Subject: [PATCH] Fix Json strategy serialization failure When generating a pydantic model having nested Json fields with hypothesis, a JSON serialization exception was raised. --- pydantic/_hypothesis_plugin.py | 13 +++++++++++-- tests/test_hypothesis_plugin.py | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/pydantic/_hypothesis_plugin.py b/pydantic/_hypothesis_plugin.py index 890e192ccaf..32ecff550cb 100644 --- a/pydantic/_hypothesis_plugin.py +++ b/pydantic/_hypothesis_plugin.py @@ -27,7 +27,7 @@ import json import math from fractions import Fraction -from typing import Callable, Dict, Type, Union, cast, overload +from typing import Any, Callable, Dict, Type, Union, cast, overload import hypothesis.strategies as st @@ -212,6 +212,15 @@ def inner(f): # type: ignore # Type-to-strategy resolver functions +def is_base_model(cls: Any) -> bool: + """Returns True if the given class is a subclass of the pydantic BaseModel.""" + + try: + return issubclass(cls, pydantic.BaseModel) + except TypeError: + return False + + @resolves(pydantic.JsonWrapper) def resolve_json(cls): # type: ignore[no-untyped-def] try: @@ -223,7 +232,7 @@ def resolve_json(cls): # type: ignore[no-untyped-def] extend=lambda x: st.lists(x) | st.dictionaries(st.text(), x), # type: ignore ) return st.builds( - json.dumps, + cls.inner_type.json if is_base_model(getattr(cls, 'inner_type', None)) else json.dumps, inner, ensure_ascii=st.booleans(), indent=st.none() | st.integers(0, 16), diff --git a/tests/test_hypothesis_plugin.py b/tests/test_hypothesis_plugin.py index 95dc59c979e..4e0ef8d0cc9 100644 --- a/tests/test_hypothesis_plugin.py +++ b/tests/test_hypothesis_plugin.py @@ -67,6 +67,7 @@ class JsonModel(pydantic.BaseModel): json_str: pydantic.Json[str] json_int_or_str: pydantic.Json[typing.Union[int, str]] json_list_of_float: pydantic.Json[typing.List[float]] + json_pydantic_model: pydantic.Json[pydantic.BaseModel] class ConstrainedNumbersModel(pydantic.BaseModel): conintt: pydantic.conint(gt=10, lt=100)