Skip to content

Commit 96b1df2

Browse files
authored
Merge pull request #565 from yukinarit/fix-de-internal-tagging
Fix deserialization when internal tagging is used for non dataclass
2 parents d87205b + 3604f7b commit 96b1df2

File tree

4 files changed

+31
-4
lines changed

4 files changed

+31
-4
lines changed

serde/compat.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ def typename(typ: Any, with_typing_module: bool = False) -> str:
214214
args = type_args(typ)
215215
if not args:
216216
raise TypeError("Literal type requires at least one literal argument")
217-
return f'Literal[{", ".join(str(e) for e in args)}]'
217+
return f'Literal[{", ".join(stringify_literal(e) for e in args)}]'
218218
elif typ is Any:
219219
return f"{mod}Any"
220220
elif is_ellipsis(typ):
@@ -236,6 +236,13 @@ def typename(typ: Any, with_typing_module: bool = False) -> str:
236236
raise SerdeError(f"Could not get a type name from: {typ}")
237237

238238

239+
def stringify_literal(v: Any) -> str:
240+
if isinstance(v, str):
241+
return f"'{v}'"
242+
else:
243+
return str(v)
244+
245+
239246
def type_args(typ: Any) -> tuple[type[Any], ...]:
240247
"""
241248
Wrapper to suppress type error for accessing private members.

serde/de.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import jinja2
1414
from collections.abc import Callable, Sequence, Iterable
1515
from beartype import beartype, BeartypeConf
16+
from beartype.door import is_bearable
1617
from beartype.roar import BeartypeCallHintParamViolation
1718
from dataclasses import dataclass, is_dataclass
1819
from typing import overload, TypeVar, Generic, Any, Optional, Union, Literal
@@ -263,6 +264,7 @@ def wrap(cls: type[T]) -> type[T]:
263264
g["_get_by_aliases"] = _get_by_aliases
264265
g["class_deserializers"] = class_deserializers
265266
g["BeartypeCallHintParamViolation"] = BeartypeCallHintParamViolation
267+
g["is_bearable"] = is_bearable
266268
if deserializer:
267269
g["serde_legacy_custom_class_deserializer"] = functools.partial(
268270
serde_legacy_custom_class_deserializer, custom=deserializer
@@ -1158,9 +1160,11 @@ def {{func}}(cls=cls, maybe_generic=None, maybe_generic_type_vars=None, data=Non
11581160
if not isinstance(fake_dict["fake_key"], {{typename(t)}}):
11591161
raise Exception("Not a type of {{typename(t)}}")
11601162
{% endif %}
1161-
return {{rvalue(arg(t))}}
1163+
res = {{rvalue(arg(t))}}
1164+
ensure(is_bearable(res, {{typename(t)}}), "object is not of type '{{typename(t)}}'")
1165+
return res
11621166
except Exception as e:
1163-
errors.append(f' Failed to deserialize into {{typename(t)}}: {e}')
1167+
errors.append(f" Failed to deserialize into {{typename(t)}}: {e}")
11641168
{% endfor %}
11651169
raise SerdeError("Can not deserialize " + repr(data) + " of type " + \
11661170
typename(type(data)) + " into {{union_name}}.\\nReasons:\\n" + "\\n".join(errors))

tests/test_compat.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ class Foo(Generic[T]):
8383
assert typename(dict[str, Foo]) == "dict[str, Foo]" # type: ignore
8484
assert typename(set) == "set"
8585
assert typename(set[int]) == "set[int]"
86-
assert typename(Literal[1, True, "Hey"]) == "Literal[1, True, Hey]"
86+
assert typename(Literal[1, True, "Hey"]) == "Literal[1, True, 'Hey']"
8787

8888

8989
def test_iter_types() -> None:

tests/test_union.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,3 +822,19 @@ class Foo:
822822
s = '{"a":"1","b":{"Expr":{"expr":"2"}},"c":"3"}'
823823
assert s == to_json(f)
824824
assert f == from_json(Foo, s)
825+
826+
827+
def test_union_internal_tagging_for_non_dataclass() -> None:
828+
@serde
829+
class Bar:
830+
a: int
831+
832+
@serde(tagging=InternalTagging("type"))
833+
class Foo:
834+
x: Union[list[int], Bar]
835+
836+
f = Foo(Bar(1))
837+
assert f == from_json(Foo, to_json(f))
838+
839+
f = Foo([10])
840+
assert f == from_json(Foo, to_json(f))

0 commit comments

Comments
 (0)