def test_mapper_in_list(): class Foo(Structure): a = String i = Integer class Bar(Structure): wrapped = Array[Foo] mapper = {'wrapped._mapper': {'a': 'aaa', 'i': 'iii'}, 'wrapped': 'other'} deserializer = Deserializer(target_class=Bar, mapper=mapper) deserialized = deserializer.deserialize( { 'other': [{ 'aaa': 'string1', 'iii': 1 }, { 'aaa': 'string2', 'iii': 2 }] }, keep_undefined=False) assert deserialized == Bar( wrapped=[Foo(a='string1', i=1), Foo(a='string2', i=2)])
def test_mapper_in_embedded_structure(): class Foo(Structure): a = String i = Integer s = StructureReference(st=String, arr=Array) mapper = { 'a': 'aaa', 'i': 'iii', 's._mapper': { "arr": FunctionCall(func=lambda x: x * 2, args=['xxx']) } } deserializer = Deserializer(target_class=Foo, mapper=mapper) deserialized = deserializer.deserialize( { 'aaa': 'string', 'iii': 1, 's': { 'st': 'string', 'xxx': [1, 2, 3] } }, keep_undefined=False) assert deserialized == Foo(a='string', i=1, s={ 'st': 'string', 'arr': [1, 2, 3, 1, 2, 3] })
def test_valid_deserializer(): 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']) } deserializer = Deserializer(target_class=Foo, mapper=mapper) foo = deserializer.deserialize( { 'a': { 'b': { 'x': 1, 'y': 2 } }, 'name': { 'first': 'Joe', 'last': 'smith' }, 'i': 3, 'j': 4 }, keep_undefined=False) assert foo == Foo(i=7, m={'x': 1, 'y': 2}, s='the string is Joe')
def transform_foo_to_bar(foo: Foo) -> Bar: mapper = { 'i': FunctionCall(func=lambda f: [int(f)], args=['i']), 'f': FunctionCall(func=lambda x: str(x), args=['f']) } deserializer = Deserializer(Bar, {'numbers': 'i', 's': 'f'}) serializer = Serializer(source=foo, mapper=mapper) return deserializer.deserialize(serializer.serialize(), keep_undefined=False)
def test_deserializer_no_mapper(): class Foo(Structure): m = Map s = String i = Integer deserializer = Deserializer(target_class=Foo) foo = deserializer.deserialize({'m': {'x': 1}, 's': 'abc', 'i': 9999}) assert foo.i == 9999
def test_ignore_node_should_not_work_on_required_fields(): class Foo(Structure): a = Integer s = String i = Integer _required = ["s"] _ignore_none = True with raises(TypeError) as excinfo: Deserializer(target_class=Foo).deserialize({ "s": None, "a": None, "i": 1 }) assert "s: Got None; Expected a string" in str(excinfo.value) assert Deserializer(target_class=Foo).deserialize({ "s": "x", "a": None, "i": 1 }).a is None
def test_convert_camel_case2(): class Foo(Structure): first_name: String last_name: String age_years: PositiveInt _additionalProperties = False input_dict = {"first_name": "joe", "last_name": "smith", "ageYears": 5} res = Deserializer(target_class=Foo, camel_case_convert=True).deserialize(input_dict) assert res == Foo(first_name="joe", last_name="smith", age_years=5)
def test_enum_deserialization_converts_to_enum(): class Values(enum.Enum): ABC = enum.auto() DEF = enum.auto() GHI = enum.auto() class Example(Structure): arr = Array[Enum[Values]] deserialized = Deserializer(target_class=Example).deserialize( {'arr': ['GHI', 'DEF', 'ABC']}) assert deserialized.arr == [Values.GHI, Values.DEF, Values.ABC]
def test_pickle_with_map_without_any_type_definition(): class Bar(Structure): m = Map() a = Integer original = Bar(a=3, m={'abc': Bar(a=2, m={"x": "xx"}), 'bcd': 2}) serialized = serialize(original) unpickeled = pickle.loads(pickle.dumps(serialized)) deserialized = Deserializer(target_class=Bar).deserialize(unpickeled) # there is no info on the fact that deserialized.m['abc'] should be converted to a Bar instance, so # we convert it to a simple dict, to make it straight forward to compare original.m['abc'] = Serializer(original.m['abc']).serialize() assert deserialized == original
def test_deserialize_with_deep_mapper_camel_case(): class Foo(Structure): a_b = String i = Integer class Bar(Structure): foo_bar = Foo array_nums = Array class Example(Structure): bar = Bar number = Integer mapper = { 'bar._mapper': { 'fooBar._mapper': { "i": FunctionCall(func=lambda x: x * 2) } } } deserializer = Deserializer(target_class=Example, mapper=mapper, camel_case_convert=True) deserialized = deserializer.deserialize( { "number": 1, "bar": { "fooBar": { "aB": "string", "i": 10 }, "arrayNums": [1, 2] } }, keep_undefined=False) assert deserialized == Example(number=1, bar=Bar(foo_bar=Foo(a_b="string", i=20), array_nums=[1, 2]))
def test_deserialize_with_deep_mapper(): class Foo(Structure): a = String i = Integer class Bar(Structure): foo = Foo array = Array class Example(Structure): bar = Bar number = Integer mapper = { 'bar._mapper': { 'foo._mapper': { "i": FunctionCall(func=lambda x: x * 2) } } } deserializer = Deserializer(target_class=Example, mapper=mapper) deserialized = deserializer.deserialize( { "number": 1, "bar": { "foo": { "a": "string", "i": 10 }, "array": [1, 2] } }, keep_undefined=False) assert deserialized == Example(number=1, bar=Bar(foo=Foo(a="string", i=20), array=[1, 2]))
def test_invalid_deserializer(): class Foo(Structure): m = Map s = String i = Integer mapper = { "xyz": "a.b", "s": FunctionCall(func=lambda x: f'the string is {x}', args=['name.first']), 'i': FunctionCall(func=operator.add, args=['i', 'j']) } with raises(ValueError) as excinfo: Deserializer(target_class=Foo, mapper=mapper) assert "Invalid key in mapper for class Foo: xyz. Keys must be one of the class fields" in str( excinfo.value)