fix serialization as a whole for list/dict/Base containing custom items to serialize (#1984)
This commit is contained in:
parent
d1d5812602
commit
df09c716c6
@ -30,7 +30,9 @@ class Base(pydantic.BaseModel):
|
|||||||
Returns:
|
Returns:
|
||||||
The object as a json string.
|
The object as a json string.
|
||||||
"""
|
"""
|
||||||
return self.__config__.json_dumps(self.dict(), default=list)
|
from reflex.utils.serializers import serialize
|
||||||
|
|
||||||
|
return self.__config__.json_dumps(self.dict(), default=serialize)
|
||||||
|
|
||||||
def set(self, **kwargs):
|
def set(self, **kwargs):
|
||||||
"""Set multiple fields and return the object.
|
"""Set multiple fields and return the object.
|
||||||
|
@ -597,7 +597,7 @@ def json_dumps(obj: Any) -> str:
|
|||||||
Returns:
|
Returns:
|
||||||
A string
|
A string
|
||||||
"""
|
"""
|
||||||
return json.dumps(obj, ensure_ascii=False, default=list)
|
return json.dumps(obj, ensure_ascii=False, default=serialize)
|
||||||
|
|
||||||
|
|
||||||
def unwrap_vars(value: str) -> str:
|
def unwrap_vars(value: str) -> str:
|
||||||
|
@ -93,7 +93,7 @@ def get_serializer(type_: Type) -> Serializer | None:
|
|||||||
return serializer
|
return serializer
|
||||||
|
|
||||||
# If the type is not registered, check if it is a subclass of a registered type.
|
# If the type is not registered, check if it is a subclass of a registered type.
|
||||||
for registered_type, serializer in SERIALIZERS.items():
|
for registered_type, serializer in reversed(SERIALIZERS.items()):
|
||||||
if types._issubclass(type_, registered_type):
|
if types._issubclass(type_, registered_type):
|
||||||
return serializer
|
return serializer
|
||||||
|
|
||||||
@ -127,18 +127,31 @@ def serialize_str(value: str) -> str:
|
|||||||
|
|
||||||
|
|
||||||
@serializer
|
@serializer
|
||||||
def serialize_primitive(value: Union[bool, int, float, Base, None]) -> str:
|
def serialize_primitive(value: Union[bool, int, float, None]) -> str:
|
||||||
"""Serialize a primitive type.
|
"""Serialize a primitive type.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
value: The number to serialize.
|
value: The number/bool/None to serialize.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The serialized number.
|
The serialized number/bool/None.
|
||||||
"""
|
"""
|
||||||
return format.json_dumps(value)
|
return format.json_dumps(value)
|
||||||
|
|
||||||
|
|
||||||
|
@serializer
|
||||||
|
def serialize_base(value: Base) -> str:
|
||||||
|
"""Serialize a Base instance.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value : The Base to serialize.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The serialized Base.
|
||||||
|
"""
|
||||||
|
return value.json()
|
||||||
|
|
||||||
|
|
||||||
@serializer
|
@serializer
|
||||||
def serialize_list(value: Union[List, Tuple, Set]) -> str:
|
def serialize_list(value: Union[List, Tuple, Set]) -> str:
|
||||||
"""Serialize a list to a JSON string.
|
"""Serialize a list to a JSON string.
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import datetime
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@ -604,6 +605,14 @@ def test_format_library_name(input: str, output: str):
|
|||||||
([1, 2, 3], "[1, 2, 3]"),
|
([1, 2, 3], "[1, 2, 3]"),
|
||||||
({}, "{}"),
|
({}, "{}"),
|
||||||
({"k1": False, "k2": True}, '{"k1": false, "k2": true}'),
|
({"k1": False, "k2": True}, '{"k1": false, "k2": true}'),
|
||||||
|
(
|
||||||
|
[datetime.timedelta(1, 1, 1), datetime.timedelta(1, 1, 2)],
|
||||||
|
'["1 day, 0:00:01.000001", "1 day, 0:00:01.000002"]',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
{"key1": datetime.timedelta(1, 1, 1), "key2": datetime.timedelta(1, 1, 2)},
|
||||||
|
'{"key1": "1 day, 0:00:01.000001", "key2": "1 day, 0:00:01.000002"}',
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_json_dumps(input, output):
|
def test_json_dumps(input, output):
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
from enum import Enum
|
||||||
from typing import Any, Dict, List, Type
|
from typing import Any, Dict, List, Type
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from reflex.base import Base
|
||||||
from reflex.utils import serializers
|
from reflex.utils import serializers
|
||||||
from reflex.vars import Var
|
from reflex.vars import Var
|
||||||
|
|
||||||
@ -93,6 +95,31 @@ def test_add_serializer():
|
|||||||
assert not serializers.has_serializer(Foo)
|
assert not serializers.has_serializer(Foo)
|
||||||
|
|
||||||
|
|
||||||
|
class StrEnum(str, Enum):
|
||||||
|
"""An enum also inheriting from str."""
|
||||||
|
|
||||||
|
FOO = "foo"
|
||||||
|
BAR = "bar"
|
||||||
|
|
||||||
|
|
||||||
|
class EnumWithPrefix(Enum):
|
||||||
|
"""An enum with a serializer adding a prefix."""
|
||||||
|
|
||||||
|
FOO = "foo"
|
||||||
|
BAR = "bar"
|
||||||
|
|
||||||
|
|
||||||
|
@serializers.serializer
|
||||||
|
def serialize_EnumWithPrefix(enum: EnumWithPrefix) -> str:
|
||||||
|
return "prefix_" + enum.value
|
||||||
|
|
||||||
|
|
||||||
|
class BaseSubclass(Base):
|
||||||
|
"""A class inheriting from Base for testing."""
|
||||||
|
|
||||||
|
ts: datetime.timedelta = datetime.timedelta(1, 1, 1)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"value,expected",
|
"value,expected",
|
||||||
[
|
[
|
||||||
@ -104,6 +131,23 @@ def test_add_serializer():
|
|||||||
(None, "null"),
|
(None, "null"),
|
||||||
([1, 2, 3], "[1, 2, 3]"),
|
([1, 2, 3], "[1, 2, 3]"),
|
||||||
([1, "2", 3.0], '[1, "2", 3.0]'),
|
([1, "2", 3.0], '[1, "2", 3.0]'),
|
||||||
|
([{"key": 1}, {"key": 2}], '[{"key": 1}, {"key": 2}]'),
|
||||||
|
(StrEnum.FOO, "foo"),
|
||||||
|
([StrEnum.FOO, StrEnum.BAR], '["foo", "bar"]'),
|
||||||
|
(
|
||||||
|
{"key1": [1, 2, 3], "key2": [StrEnum.FOO, StrEnum.BAR]},
|
||||||
|
'{"key1": [1, 2, 3], "key2": ["foo", "bar"]}',
|
||||||
|
),
|
||||||
|
(EnumWithPrefix.FOO, "prefix_foo"),
|
||||||
|
([EnumWithPrefix.FOO, EnumWithPrefix.BAR], '["prefix_foo", "prefix_bar"]'),
|
||||||
|
(
|
||||||
|
{"key1": EnumWithPrefix.FOO, "key2": EnumWithPrefix.BAR},
|
||||||
|
'{"key1": "prefix_foo", "key2": "prefix_bar"}',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
BaseSubclass(ts=datetime.timedelta(1, 1, 1)),
|
||||||
|
'{"ts": "1 day, 0:00:01.000001"}',
|
||||||
|
),
|
||||||
(
|
(
|
||||||
[1, Var.create_safe("hi"), Var.create_safe("bye", _var_is_local=False)],
|
[1, Var.create_safe("hi"), Var.create_safe("bye", _var_is_local=False)],
|
||||||
'[1, "hi", bye]',
|
'[1, "hi", bye]',
|
||||||
@ -121,6 +165,10 @@ def test_add_serializer():
|
|||||||
(datetime.date(2021, 1, 1), "2021-01-01"),
|
(datetime.date(2021, 1, 1), "2021-01-01"),
|
||||||
(datetime.time(1, 1, 1, 1), "01:01:01.000001"),
|
(datetime.time(1, 1, 1, 1), "01:01:01.000001"),
|
||||||
(datetime.timedelta(1, 1, 1), "1 day, 0:00:01.000001"),
|
(datetime.timedelta(1, 1, 1), "1 day, 0:00:01.000001"),
|
||||||
|
(
|
||||||
|
[datetime.timedelta(1, 1, 1), datetime.timedelta(1, 1, 2)],
|
||||||
|
'["1 day, 0:00:01.000001", "1 day, 0:00:01.000002"]',
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_serialize(value: Any, expected: str):
|
def test_serialize(value: Any, expected: str):
|
||||||
|
Loading…
Reference in New Issue
Block a user