def test_union(): data = {"node": {"name": "n1", "value": "v1"}} node = from_dict(NodeWithUnion, data, fd_check_types=True) assert isinstance(node.node, SimpleNode) assert node.node.name == "n1" assert node.node.value == "v1" data = {"node": {"name": "n1", "reference": "node-X"}} node = from_dict(NodeWithUnion, data, fd_check_types=True) assert isinstance(node.node, SimpleNode2) assert node.node.name == "n1" assert node.node.reference == "node-X" data = {"node": {"name": "n1", "no_match": "node-X"}} node = from_dict(NodeWithUnion, data) assert isinstance(node.node, dict) assert node.node["name"] == "n1" assert node.node["no_match"] == "node-X" data = {"node": {"name": "n1", "no_match": "node-X"}} with pytest.raises(TypeError) as e: node = from_dict(NodeWithUnion, data, fd_check_types=True) assert str(e.value) == ( 'For "node", expected typing.Union[test_generics_with_dataclasses.SimpleNode, ' 'test_generics_with_dataclasses.SimpleNode2] but found <class \'dict\'>' )
def test_union_works(): @attr.s(auto_attribs=True) class UClass: a: Union[str, int] assert from_dict(UClass, {"a": "hello"}, fd_check_types=True).a == "hello" assert from_dict(UClass, {"a": 22}, fd_check_types=True).a == 22
def test_subscripted_attr_generics_work(): @attr.s(auto_attribs=True) class KDict: a: int b: Optional[str] c: List[int] opt = from_dict(KDict, a=11, b=None, c=[1, 2, 3]) assert opt.a == 11 assert opt.b is None assert opt.c == [1, 2, 3] assert from_dict(KDict, a=11, b="hi", c=[1, 2, 3]).b == "hi"
def test_additional_keys_are_allowed(structures: Structures): my_obj = from_dict(structures.inner_structure, foo=22, bar="Works", additional=[1, 2, 3], fd_global_ns=GLOBALS) assert my_obj.foo == 22 assert my_obj.bar == "Works" if structures.has_dict: assert my_obj.additional == [1, 2, 3]
def test_readme(): customer = from_dict(Customer, input_customer_data) # Structured data is available as attributes since attr.s exposes them like that assert customer.name == "Christopher Lee" # Nested structures are also constructed. List[sub_strucutre] and Dict[key, sub_structure] are supported assert customer.preferences[0].name == "The Hobbit" # Data not defined in the strucutre is inserted into the __dict__ if possible assert customer.__dict__["friend"] == "Mellon"
def test_self_ref_in_optional(): data = {"name": "n1", "next": {"name": "n2", "next": None}} node = from_dict(LinkListNode2, data, fd_check_types=True, fd_global_ns=GLOBALS) assert node.name == "n1" assert node.next.name == "n2"
def test_local_self_ref(): @dataclass class Node: name: str next: 'Node' data = {"name": "n1", "next": {"name": "n2", "next": None}} node = from_dict(Node, data, fd_local_ns=locals()) assert node.name == "n1" assert node.next.name == "n2"
def test_local_self_ref_in_optional(): @dataclass class Node: name: str next: Optional['Node'] data = {"name": "n1", "next": {"name": "n2", "next": None}} node = from_dict(Node, data, fd_check_types=True, fd_local_ns=locals()) assert node.name == "n1" assert node.next.name == "n2"
def test_local_self_ref_in_list(): @dataclass class Node: name: str children: LIST['Node'] data = {"name": "n1", "children": [{"name": "n2", "children": []}]} node = from_dict(Node, data, fd_check_types=True, fd_local_ns=locals()) assert node.name == "n1" assert node.children[0].name == "n2"
def test_union_with_builtin_type(): data = {"node": {"name": "n1", "value": "v1"}} node = from_dict(NodeWithUnionWithBuiltInType, data, fd_check_types=True) assert isinstance(node.node, SimpleNode) assert node.node.name == "n1" assert node.node.value == "v1" data = {"node": "Hello"} node = from_dict(NodeWithUnionWithBuiltInType, data, fd_check_types=True) assert isinstance(node.node, str) assert node.node == "Hello" data = {"node": {"name": "n1", "no_match": "node-X"}} node = from_dict(NodeWithUnionWithBuiltInType, data) assert isinstance(node.node, dict) assert node.node["name"] == "n1" assert node.node["no_match"] == "node-X" data = {"node": {"name": "n1", "no_match": "node-X"}} with pytest.raises(FromDictTypeError) as e: from_dict(NodeWithUnionWithBuiltInType, data, fd_check_types=True) assert str( e.value ) == 'For "node", expected typing.Union[test_generics_with_dataclasses.SimpleNode, str] but found <class \'dict\'>' data = {"node": 123} with pytest.raises(FromDictTypeError) as e: node = from_dict(NodeWithUnionWithBuiltInType, data, fd_check_types=True) assert str( e.value ) == 'For "node", expected typing.Union[test_generics_with_dataclasses.SimpleNode, str] but found <class \'int\'>'
def test_dict_with_substructure(structures: Structures): @attr.s(auto_attribs=True) class SubDict: a: Dict[int, structures.inner_structure] val = { "a": { 11: {"foo": 11, "bar": "Hi"}, 13: {"foo": 13, "bar": "Sup"}, -4: {"foo": -4, "bar": "Ya"}, } } structs = from_dict(SubDict, val, fd_check_types=not structures.does_type_validation) assert all(k == v.foo for k, v in structs.a.items())
def test_packing(structures: Structures): input_dict = { "foo": 22, "baz": { "foo": 42, "bar": "Works :)", } } main_object = from_dict(structures.outer_structure, input_dict, fd_global_ns=GLOBALS) assert main_object.baz.bar == "Works :)" assert isinstance(main_object, structures.outer_structure) assert isinstance(main_object.baz, structures.inner_structure)
def test_list_of_structures_work(structures: Structures): @attr.s(auto_attribs=True) class KList: a: List[structures.inner_structure] val = { "a": [ {"foo": 11, "bar": "Hi"}, {"foo": 13, "bar": "Sup"}, {"foo": -4, "bar": "Ya"}, ] } structs = from_dict(KList, val, fd_check_types=not structures.does_type_validation) assert structs.a[0].foo == 11 assert [el.foo for el in structs.a] == [11, 13, -4] assert [el.bar for el in structs.a] == ["Hi", "Sup", "Ya"]
def test_self_ref_in_dict(): data = { "name": "n1", "children": { "id-123": { "name": "n2", "children": {} }, "id-456": { "name": "n3", "children": {} } } } node = from_dict(DictNode, data, fd_check_types=True, fd_global_ns=GLOBALS) assert node.name == "n1" assert node.children["id-123"].name == "n2" assert node.children["id-456"].name == "n3"
def test_local_self_ref_in_dict(): @dataclass class Node: name: str children: Dict[str, 'Node'] data = { "name": "n1", "children": { "id-123": { "name": "n2", "children": {} }, "id-456": { "name": "n3", "children": {} } } } node = from_dict(Node, data, fd_check_types=True, fd_local_ns=locals()) assert node.name == "n1" assert node.children["id-123"].name == "n2" assert node.children["id-456"].name == "n3"
def test_invalid_type_inherent(structures: Structures): if not structures.does_type_validation: pytest.skip("Structure does not support inherent runtime type checking") with pytest.raises(TypeError) as e: from_dict(structures.inner_structure, {"foo": "wrong", "bar": "right"}, fd_check_types=True)
def test_missing_key_discovered_in_subdict_inherent(structures: Structures): if not structures.does_type_validation: pytest.skip("Structure does not support inherent runtime type checking") with pytest.raises(TypeError): from_dict(structures.outer_structure, {"foo": 22, "baz": {"foo": 42}})
def test_self_ref_in_list(): data = {"name": "n1", "children": [{"name": "n2", "children": []}]} node = from_dict(TreeNode, data, fd_check_types=True, fd_global_ns=GLOBALS) assert node.name == "n1" assert node.children[0].name == "n2"
def test_self_ref(): data = {"name": "n1", "next": {"name": "n2", "next": None}} # Can't type check because next is not optional node = from_dict(LinkListNode, data, fd_global_ns=GLOBALS) assert node.name == "n1" assert node.next.name == "n2"
def test_optional(): data = { "node1": { "name": "n1", "value": "v1" }, "node2": { "name": "n2", "value": "v2" }, "node3": { "name": "n3", "value": "v3" }, } node = from_dict(NodeWithOptional, data, fd_check_types=True) assert node.node1.name == "n1" assert node.node1.value == "v1" assert node.node2.name == "n2" assert node.node2.value == "v2" assert node.node3.name == "n3" assert node.node3.value == "v3" data = { "node1": { "name": "n1", "value": "v1" }, "node2": { "name": "n2", "value": "v2" } } node = from_dict(NodeWithOptional, data, fd_check_types=True) assert node.node1.name == "n1" assert node.node1.value == "v1" assert node.node2.name == "n2" assert node.node2.value == "v2" assert node.node3 == None data = {"node1": {"name": "n1", "value": "v1"}, "node2": None} node = from_dict(NodeWithOptional, data, fd_check_types=True) assert node.node1.name == "n1" assert node.node1.value == "v1" assert node.node2 == None assert node.node3 == None data = { "node1": { "name": "n1", "value": "v1" }, "node2": None, "node3": None } node = from_dict(NodeWithOptional, data, fd_check_types=True) assert node.node1.name == "n1" assert node.node1.value == "v1" assert node.node2 == None assert node.node3 == None data = {"node1": {"name": "n1", "value": "v1"}} with pytest.raises(TypeError) as e: node = from_dict(NodeWithOptional, data, fd_check_types=True) assert "missing 1 required positional argument: 'node2'" in str(e.value)
def test_invalid_type_discovered_in_subdict(structures: Structures): with pytest.raises(FromDictTypeError) as e: from_dict(structures.outer_structure, {"foo": 22, "baz": {"foo": 42, "bar": ["wrong type"]}}, fd_check_types=True, fd_global_ns=GLOBALS) assert str(e.value) == "For \"baz.bar\", expected <class 'str'> but found <class 'list'>"
def test_keyword_style_overwrites_positional(structures: Structures): assert from_dict(structures.inner_structure, {"foo": 42, "bar": "Works :)"}, foo=0, fd_global_ns=GLOBALS).foo == 0
def test_missing_key(structures: Structures): with pytest.raises(TypeError): from_dict(structures.inner_structure, {"foo": 22})
def test_invalid_type_from_dict(structures: Structures): with pytest.raises(FromDictTypeError) as e: from_dict(structures.inner_structure, {"foo": "wrong", "bar": "right"}, fd_check_types=True) assert str(e.value) == "For \"foo\", expected <class 'int'> but found <class 'str'>"
def test_keyword_style(structures: Structures): m = from_dict(structures.outer_structure, foo=22, baz=structures.inner_structure(foo=42, bar="Works :)"), fd_global_ns=GLOBALS) assert m.foo == 22 assert m.baz.foo == 42 assert m.baz.bar == "Works :)"