1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
|
from typing import Union
import pytest
from attrs import define
from cattrs.converters import BaseConverter, Converter
from ._compat import is_py310_plus
@pytest.mark.parametrize("cls", (BaseConverter, Converter))
def test_custom_union_toplevel_roundtrip(cls: type[BaseConverter]):
"""
Test custom code union handling.
We override union unstructuring to add the class type, and union structuring
to use the class type.
"""
c = cls()
@define
class A:
a: int
@define
class B:
a: int
c.register_unstructure_hook(
Union[A, B], lambda o: {"_type": o.__class__.__name__, **c.unstructure(o)}
)
c.register_structure_hook(
Union[A, B], lambda o, t: c.structure(o, A if o["_type"] == "A" else B)
)
inst = B(1)
unstructured = c.unstructure(inst, unstructure_as=Union[A, B])
assert unstructured["_type"] == "B"
assert c.structure(unstructured, Union[A, B]) == inst
@pytest.mark.skipif(not is_py310_plus, reason="3.10 union syntax")
@pytest.mark.parametrize("cls", (BaseConverter, Converter))
def test_310_custom_union_toplevel_roundtrip(cls: type[BaseConverter]):
"""
Test custom code union handling.
We override union unstructuring to add the class type, and union structuring
to use the class type.
"""
c = cls()
@define
class A:
a: int
@define
class B:
a: int
c.register_unstructure_hook(
A | B, lambda o: {"_type": o.__class__.__name__, **c.unstructure(o)}
)
c.register_structure_hook(
A | B, lambda o, t: c.structure(o, A if o["_type"] == "A" else B)
)
inst = B(1)
unstructured = c.unstructure(inst, unstructure_as=A | B)
assert unstructured["_type"] == "B"
assert c.structure(unstructured, A | B) == inst
@pytest.mark.parametrize("cls", (BaseConverter, Converter))
def test_custom_union_clsfield_roundtrip(cls: type[BaseConverter]):
"""
Test custom code union handling.
We override union unstructuring to add the class type, and union structuring
to use the class type.
"""
c = cls()
@define
class A:
a: int
@define
class B:
a: int
@define
class C:
f: Union[A, B]
c.register_unstructure_hook(
Union[A, B], lambda o: {"_type": o.__class__.__name__, **c.unstructure(o)}
)
c.register_structure_hook(
Union[A, B], lambda o, t: c.structure(o, A if o["_type"] == "A" else B)
)
inst = C(A(1))
unstructured = c.unstructure(inst)
assert unstructured["f"]["_type"] == "A"
assert c.structure(unstructured, C) == inst
|