def test_bad_path_in_mapper(): class Foo(Structure): m = Map s = String i = Integer mapper = { "m": "a.x", "s": FunctionCall(func=lambda x: x, args=['name']), 'i': FunctionCall(func=operator.add, args=['i', 'j']) } with raises(TypeError) as excinfo: deserialize_structure(Foo, { 'a': { 'b': { 'x': 1, 'y': 2 } }, 'name': { 'first': 'Joe', 'last': 'smith' }, 'i': 3, 'j': 4 }, mapper=mapper, keep_undefined=False) assert "m: Got None; Expected a dictionary" in str(excinfo.value)
def test_anyof_field_failure(): data = { 'i': 5, 's': 'test', 'array': [10, 7], 'any': [{ 'name': 'john', 'ssid': '123' }, { 'name': 'paul' }], 'embedded': { 'a1': 8, 'a2': 0.5 }, 'people': [{ 'name': 'john', 'ssid': '123' }], 'simplestruct': { 'name': 'danny' }, 'all': 5, 'enum': 3 } with raises(ValueError) as excinfo: deserialize_structure(Example, data) assert "any: Got [{'name': 'john', 'ssid': '123'}, {'name': 'paul'}]; Does not match any field option" in str( excinfo.value)
def test_invalid_mapper_value(): class Foo(Structure): m = Map s = String i = Integer mapper = { "m": 5, "s": FunctionCall(func=lambda x: x, args=['name']), 'i': FunctionCall(func=operator.add, args=['i', 'j']) } with raises(TypeError) as excinfo: deserialize_structure(Foo, { 'a': { 'b': { 'x': 1, 'y': 2 } }, 'name': { 'first': 'Joe', 'last': 'smith' }, 'i': 3, 'j': 4 }, mapper=mapper, keep_undefined=False) assert "mapper value must be a key in the input or a FunctionCal. Got 5" in str( excinfo.value)
def test_unsupported_nested_field_err(): class UnsupportedStruct(Structure): unsupported = AllOf[Integer, Array] with raises(TypeError) as excinfo: deserialize_structure(UnsupportedStruct, {'unsupported': 1}) assert "unsupported: deserialization of Multifield only supports Number, String and Enum" in str( excinfo.value)
def test_missed_required(all_errors): class Foo(Structure): r: str with raises(Exception) as ex: deserialize_structure(Foo, {}) errs = standard_readable_error_for_typedpy_exception(ex.value) assert errs[0].problem.startswith("missing a required argument: 'r'")
def test_multifield_with_diffrerent_types_no_match(): class Foo(Structure): any = AnyOf[Map, Set[String], String] with raises(ValueError) as excinfo: deserialize_structure(Foo, {'any': [1, 2, 3]}) assert 'any: Got [1, 2, 3]; Does not match any field option' in str( excinfo.value)
def test_map_deserialization_type_err(): class Foo(Structure): map = Map[Integer, SimpleStruct] data = {'map': 5} with raises(TypeError) as excinfo: deserialize_structure(Foo, data) assert 'map: expected a dict' in str(excinfo.value)
def test_allof_wrong_value_err(): class Foo(Structure): bar = AllOf[Integer, Array] with raises(ValueError) as excinfo: deserialize_structure(Foo, {'bar': 1}) assert "bar: Got 1; Does not match <Array>. reason: bar: Got 1; Expected a list, set, or tuple" in str( excinfo.value)
def test_deserialize_tuple_err(): class Foo(Structure): a = Integer t = Tuple[Integer, String] serialized = {'a': 3, 't': [3, 4]} with raises(ValueError) as excinfo: deserialize_structure(Foo, serialized) assert "t_1: Expected a string" in str(excinfo.value)
def test_deserialize_set_err2(): class Foo(Structure): a = Integer t = Set[Integer] serialized = {'a': 3, 't': [1, 'asd']} with raises(ValueError) as excinfo: deserialize_structure(Foo, serialized) assert "t_1: Expected <class 'int'>" in str(excinfo.value)
def test_deserialize_set_err1(): class Foo(Structure): a = Integer t = Set[Integer] serialized = {'a': 3, 't': 4} with raises(ValueError) as excinfo: deserialize_structure(Foo, serialized) assert "t: Got 4; Expected a list, set, or tuple" in str(excinfo.value)
def test_oneof_field_failure2(): class Foo(Structure): a = Integer b = Array[OneOf[String(minLength=3), String(maxLength=5), Integer]] data = {'a': 1, 'b': [1, []]} with raises(ValueError) as excinfo: deserialize_structure(Foo, data) assert "b_1: Got []; Does not match any field option" in str(excinfo.value)
def test_notfield_field_failure(): class Foo(Structure): a = Integer b = Array[NotField[String(minLength=3), String(maxLength=5), Integer]] data = {'a': 1, 'b': [1.4, 'abcd']} with raises(ValueError) as excinfo: deserialize_structure(Foo, data) assert "b_1: Got 'abcd'; Expected not to match any field definition" in str( excinfo.value)
def test_unsupported_field_err(): class UnsupportedField(TypedField): _ty = str class UnsupportedStruct(Structure): unsupported = UnsupportedField with raises(NotImplementedError) as excinfo: deserialize_structure(UnsupportedStruct, {'unsupported': 1}) assert "cannot deserialize field 'unsupported'" in str(excinfo.value)
def test_multifield_with_unsupported_type_err(): source = {'any': 'abc'} class Foo(Structure): any = AnyOf[Map, Set, String] with raises(TypeError) as excinfo: deserialize_structure(Foo, source) assert "any: deserialization of Multifield only supports Number, String and Enum" in str( excinfo.value)
def test_oneof_field_failure1(): class Foo(Structure): a = Integer b = Array[OneOf[String(minLength=3), String(maxLength=5), Integer]] data = {'a': 1, 'b': [1, 'abcd']} with raises(ValueError) as excinfo: deserialize_structure(Foo, data) assert "b_1: Got abcd; Matched more than one field option" in str( excinfo.value)
def test_multifield_with_diffrerent_types(): class Foo(Structure): any = AnyOf[Map, Set, String] assert deserialize_structure(Foo, {'any': 'abc'}).any == 'abc' assert deserialize_structure(Foo, { 'any': { 'abc': 'def' } }).any['abc'] == 'def' assert 'def' in deserialize_structure(Foo, {'any': {'abc', 'def'}}).any
def test_unsupported_field_err(): # This has no information about the type - clearly can't deserialize class UnsupportedField(Field): pass class UnsupportedStruct(Structure): unsupported = UnsupportedField with raises(NotImplementedError) as excinfo: deserialize_structure(UnsupportedStruct, {'unsupported': 1}) assert "unsupported: Got 1; Cannot deserialize value of type UnsupportedField" in str( excinfo.value)
def test_min_items_and_class_reference_err(): class Foo(Structure): a = Integer b = Integer class Bar(Structure): foos = Array(minItems=1, items=Foo) serialized = {'foos': [1]} with raises(ValueError) as excinfo: deserialize_structure(Bar, serialized) assert "foos_0: Expected a dictionary" in str(excinfo.value)
def test_unsupported_type_err(): source = {'bar': 'abc'} class Bar(object): pass WrappedBar = create_typed_field("WrappedBar", Bar) class Foo(Structure): bar = WrappedBar with raises(NotImplementedError) as excinfo: deserialize_structure(Foo, source) assert "cannot deserialize field 'bar' of type WrappedBar" in str( excinfo.value)
def test_map_without_types(): class Foo(Structure): map = Map source = {'map': {'a': 1, 1: 'b'}} foo = deserialize_structure(Foo, source) assert foo.map['a'] == 1
def test_anyof_field_success(): class Foo(Structure): a = Integer b = Array[AnyOf[Person, Float, Array[Person]]] data = { 'a': 1, 'b': [ 1.5, [{ 'name': 'john', 'ssid': '123' }, { 'name': 'john', 'ssid': '456' }], { 'name': 'john', 'ssid': '789' } ], } deserialized = deserialize_structure(Foo, data) expected = Foo( a=1, b=[ 1.5, [Person(name='john', ssid='123'), Person(name='john', ssid='456')], Person(name='john', ssid='789') ]) assert deserialized == expected
def test_mapper_variation_3(): class Foo(Structure): m = Map s = String i = Integer mapper = { "m": "a.b", "s": FunctionCall(func=lambda x: f'the string is {x}'), 'i': FunctionCall(func=lambda x: x * 2) } foo = deserialize_structure(Foo, { 'a': { 'b': { 'x': 1, 'y': 2 } }, 's': 'Joe', 'i': 3 }, mapper=mapper, keep_undefined=False) assert foo == Foo(i=6, m={'x': 1, 'y': 2}, s='the string is Joe')
def test_mapper_variation_2(): class Foo(Structure): m = Map s = String i = Integer mapper = { "m": "a.b", "s": FunctionCall(func=lambda x: f'the string is {x}', args=['name.first']), 'i': FunctionCall(func=operator.add, args=['i', 'j']) } foo = deserialize_structure(Foo, { 'a': { 'b': { 'x': 1, 'y': 2 } }, 'name': { 'first': 'Joe', 'last': 'smith' }, 'i': 3, 'j': 4 }, mapper=mapper, keep_undefined=False) assert foo == Foo(i=7, m={'x': 1, 'y': 2}, s='the string is Joe')
def test_successful_deserialization_with_many_types(): data = { 'i': 5, 's': 'test', 'array': [10, 7], 'embedded': { 'a1': 8, 'a2': 0.5 }, 'simplestruct': { 'name': 'danny' }, 'all': 5, 'enum': 3 } example = deserialize_structure(Example, data) assert example == Example(i=5, s='test', array=[10, 7], embedded={ 'a1': 8, 'a2': 0.5 }, simplestruct=SimpleStruct(name='danny'), all=5, enum=3)
def test_date_alternative_format_serialization(): class Example(Structure): d = DateString(date_format="%Y%m%d") i = Integer e = Example(d="19900530", i=5) assert deserialize_structure(Example, serialize(e)) == e
def test_serializable_deserialize(): class MySerializable(SerializableField): def __init__(self, *args, some_param="xxx", **kwargs): self._some_param = some_param super().__init__(*args, **kwargs) def deserialize(self, value): return { "mykey": "my custom deserialization: {}, {}".format( self._some_param, str(value)) } def serialize(self, value): return 123 class Foo(Structure): d = Array[MySerializable(some_param="abcde")] i = Integer deserialized = deserialize_structure(Foo, { 'd': ["191204", "191205"], 'i': 3 }) assert deserialized == Foo(i=3, d=[{ 'mykey': 'my custom deserialization: abcde, 191204' }, { 'mykey': 'my custom deserialization: abcde, 191205' }]) assert serialize(deserialized) == {'d': [123, 123], 'i': 3}
def test_invalid_type_err2(): data = { 'i': 5, 's': 'test', 'array': [10, 7], 'embedded': { 'a1': 8, 'a2': 0.5 }, 'simplestruct': 2, 'all': 1, 'enum': 3, } with raises(TypeError) as excinfo: deserialize_structure(Example, data) assert "simplestruct: Expected a dictionary" in str(excinfo.value)
def test_deserialize_set(): class Foo(Structure): a = Integer t = Set[Integer] serialized = {'a': 3, 't': [3, 4, 3]} foo = deserialize_structure(Foo, serialized) assert foo.t == {3, 4}
def test_deserialize_deque(): class Example(Structure): d = Deque[Array] original = {'d': [[1, 2], [3, 4]]} deserialized = deserialize_structure(Example, original) assert deserialized == Example(d=deque([[1, 2], [3, 4]])) assert serialize(deserialized) == original