Repository: yukinarit/pyserde

Issue:
Incorrect deserialization when deserializing a Union[list, object]
Code to reproduce: 

```python
import serde
from dataclasses import dataclass

@serde.serde
@dataclass
class A:
    a: int

@serde.serde(tagging=serde.InternalTagging('type'))
@dataclass
class B:
    x: list[int] | A

o = B(x=A(a=1))
serde.json.from_json(B, serde.json.to_json(o))
```

Expect:
`B(x=A(a=1))`

Output:
`B(x=['a', 'type'])`



Discussion:

Patch:
diff --git a/serde/compat.py b/serde/compat.py
index 2b3ccb9..77b15bf 100644
--- a/serde/compat.py
+++ b/serde/compat.py
@@ -214,7 +214,7 @@ def typename(typ: Any, with_typing_module: bool = False) -> str:
         args = type_args(typ)
         if not args:
             raise TypeError("Literal type requires at least one literal argument")
-        return f'Literal[{", ".join(str(e) for e in args)}]'
+        return f'Literal[{", ".join(stringify_literal(e) for e in args)}]'
     elif typ is Any:
         return f"{mod}Any"
     elif is_ellipsis(typ):
@@ -236,6 +236,13 @@ def typename(typ: Any, with_typing_module: bool = False) -> str:
                 raise SerdeError(f"Could not get a type name from: {typ}")
 
 
+def stringify_literal(v: Any) -> str:
+    if isinstance(v, str):
+        return f"'{v}'"
+    else:
+        return str(v)
+
+
 def type_args(typ: Any) -> tuple[type[Any], ...]:
     """
     Wrapper to suppress type error for accessing private members.
diff --git a/serde/de.py b/serde/de.py
index e51458c..6356bfd 100644
--- a/serde/de.py
+++ b/serde/de.py
@@ -13,6 +13,7 @@ import typing
 import jinja2
 from collections.abc import Callable, Sequence, Iterable
 from beartype import beartype, BeartypeConf
+from beartype.door import is_bearable
 from beartype.roar import BeartypeCallHintParamViolation
 from dataclasses import dataclass, is_dataclass
 from typing import overload, TypeVar, Generic, Any, Optional, Union, Literal
@@ -263,6 +264,7 @@ def deserialize(
         g["_get_by_aliases"] = _get_by_aliases
         g["class_deserializers"] = class_deserializers
         g["BeartypeCallHintParamViolation"] = BeartypeCallHintParamViolation
+        g["is_bearable"] = is_bearable
         if deserializer:
             g["serde_legacy_custom_class_deserializer"] = functools.partial(
                 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
     if not isinstance(fake_dict["fake_key"], {{typename(t)}}):
         raise Exception("Not a type of {{typename(t)}}")
     {% endif %}
-    return {{rvalue(arg(t))}}
+    res = {{rvalue(arg(t))}}
+    ensure(is_bearable(res, {{typename(t)}}), "object is not of type '{{typename(t)}}'")
+    return res
   except Exception as e:
-    errors.append(f' Failed to deserialize into {{typename(t)}}: {e}')
+    errors.append(f" Failed to deserialize into {{typename(t)}}: {e}")
   {% endfor %}
   raise SerdeError("Can not deserialize " + repr(data) + " of type " + \
           typename(type(data)) + " into {{union_name}}.\\nReasons:\\n" + "\\n".join(errors))


Test patch:
diff --git a/tests/test_compat.py b/tests/test_compat.py
index a1fd888..265f197 100644
--- a/tests/test_compat.py
+++ b/tests/test_compat.py
@@ -83,7 +83,7 @@ def test_typename() -> None:
     assert typename(dict[str, Foo]) == "dict[str, Foo]"  # type: ignore
     assert typename(set) == "set"
     assert typename(set[int]) == "set[int]"
-    assert typename(Literal[1, True, "Hey"]) == "Literal[1, True, Hey]"
+    assert typename(Literal[1, True, "Hey"]) == "Literal[1, True, 'Hey']"
 
 
 def test_iter_types() -> None:
diff --git a/tests/test_union.py b/tests/test_union.py
index 75fa80d..04edf35 100644
--- a/tests/test_union.py
+++ b/tests/test_union.py
@@ -822,3 +822,19 @@ def test_union_with_different_ordering() -> None:
     s = '{"a":"1","b":{"Expr":{"expr":"2"}},"c":"3"}'
     assert s == to_json(f)
     assert f == from_json(Foo, s)
+
+
+def test_union_internal_tagging_for_non_dataclass() -> None:
+    @serde
+    class Bar:
+        a: int
+
+    @serde(tagging=InternalTagging("type"))
+    class Foo:
+        x: Union[list[int], Bar]
+
+    f = Foo(Bar(1))
+    assert f == from_json(Foo, to_json(f))
+
+    f = Foo([10])
+    assert f == from_json(Foo, to_json(f))