def test_deserialization_with_yasoo_type_hints(self): @attrs(frozen=True) class Foo: a: int = attrib() l = [[Foo(i) for i in range(5)] for _ in range(5)] l2 = deserialize(serialize(l, type_key=None), obj_type=List_[List_[Foo]]) self.assertIsInstance(l2, list) self.assertIsInstance(l2[0], list) self.assertIsInstance(l2[0][0], Foo) self.assertEqual(l, l2) l = [set(i) for i in l] l2 = deserialize(serialize(l, type_key=None), obj_type=List_[Set_[Foo]]) self.assertIsInstance(l2, list) self.assertIsInstance(l2[0], list) self.assertIsInstance(l2[0][0], Foo) for i1, i2 in zip(l, l2): self.assertEqual(i1, set(i2)) d = dict(enumerate(l)) d2 = deserialize(serialize(d, type_key=None), obj_type=Dict_[int, Set_[Foo]]) self.assertIsInstance(d2, dict) self.assertEqual(d.keys(), d2.keys()) self.assertIsInstance(d2[0], list) self.assertIsInstance(d2[0][0], Foo) for k, v in d.items(): self.assertEqual(v, set(d2[k]))
def test_attr_warning_on_converter_validator_valid(self): @attrs class Foo: bar = attrib(validator=instance_of(int), converter=lambda x: x) with self.assertWarnsRegex(RuntimeWarning, expected_regex='.*converter.*'): serialize(Foo(5))
def test_attr_warning_on_converter(self): @attrs class Foo: bar = attrib(converter=lambda x: x) with self.assertWarnsRegex(RuntimeWarning, expected_regex='.*converter.*'): serialize(Foo(5))
def test_attr_warning_on_dict_without_type_hint_and_no_type_key(self): @attrs class Foo: bar = attrib() f = Foo({1: 5}) with self.assertWarnsRegex(RuntimeWarning, expected_regex='.*no type hint.*'): serialize(f, type_key=None)
def test_attr_warning_on_exception_in_converter(self): @attrs class Foo: bar = attrib(converter=lambda x: 1 / x) f = Foo(5) f.bar = 0 with self.assertWarnsRegex(RuntimeWarning, expected_regex='.*value.*'): serialize(f)
def test_attr_warning_on_converter_validator_valid(self): @attrs class Foo: bar = attrib(validator=instance_of(int), converter=lambda x: x) with self.assertLogs(_logger.name, logging.WARNING) as cm: serialize(Foo(5)) self.assertEqual(1, len(cm.records)) self.assertEqual(logging.WARNING, cm.records[0].levelno)
def test_attr_warning_on_validator_mismatch_with_converter(self): @attrs class Foo: bar = attrib(validator=instance_of(int), converter=lambda x: x) f = Foo(5) f.bar = 'a' with self.assertWarnsRegex(RuntimeWarning, expected_regex='.*validator.*'): serialize(f)
def test_attr_serialization_of_type_info(self): @attrs class Foo: pass s = serialize(Foo(), type_key='__type', fully_qualified_types=False) self.assertEqual(Foo.__name__, s.get('__type')) s = serialize(Foo(), type_key='__type', fully_qualified_types=True) self.assertEqual(f'{Foo.__module__}.{Foo.__name__}', s.get('__type'))
def test_attr_warning_on_dict_with_unsupported_type_hint_and_no_type_key(self): class Unsupported: pass @attrs class Foo: bar = attrib(type=Unsupported) f = Foo({1: 5}) with self.assertWarnsRegex(RuntimeWarning, expected_regex='.*unsupported class.*'): serialize(f, type_key=None)
def test_enum(self): class MyEnum(Enum): FIRST = 1 Second = {'x': 1, 'y': 2} self.assertEqual( MyEnum.FIRST, deserialize(serialize(MyEnum.FIRST, type_key=None), MyEnum)) self.assertEqual( MyEnum.Second, deserialize(serialize(MyEnum.Second, type_key=None), MyEnum))
def test_attr_warning_on_validator_mismatch(self): @attrs class Foo: bar = attrib(validator=instance_of(int)) f = Foo(5) f.bar = 'a' with self.assertLogs(_logger.name, logging.WARNING) as cm: serialize(f) self.assertEqual(1, len(cm.records)) self.assertEqual(logging.WARNING, cm.records[0].levelno)
def test_attr_no_warning_on_dict_with_dict_type_hint_and_no_type_key(self): @attrs class Foo: bar = attrib(type=dict) f = Foo({1: 5}) try: with self.assertWarns(Warning): serialize(f, type_key=None) except AssertionError: return self.fail()
def test_attr_warning_on_exception_in_converter(self): @attrs class Foo: bar = attrib(converter=lambda x: 1 / x) f = Foo(5) f.bar = 0 with self.assertLogs(_logger.name, logging.WARNING) as cm: serialize(f) self.assertEqual(1, len(cm.records)) self.assertEqual(logging.WARNING, cm.records[0].levelno) self.assertIn('value', cm.records[0].msg)
def test_attr_warning_on_validator_mismatch_with_converter(self): @attrs class Foo: bar = attrib(validator=instance_of(int), converter=lambda x: x) f = Foo(5) f.bar = 'a' with self.assertLogs(_logger.name, logging.WARNING) as cm: serialize(f) self.assertEqual(1, len(cm.records)) self.assertEqual(logging.WARNING, cm.records[0].levelno) self.assertTrue('validator' in cm.records[0].msg)
def test_dataclass_no_warning_on_dict_with_dict_type_hint_and_no_type_key( self): @dataclass class Foo: bar: dict f = Foo({1: 5}) try: with self.assertWarns(Warning): serialize(f, type_key=None) except AssertionError: return self.fail()
def test_serialization_temporary_unregister(self): class Foo: pass @serializer_of(Foo) def func(_): return {'foo': 'bar'} with self.assertRaises(TypeError) as e: with unregister_serializers(Foo): serialize(Foo(), type_key=None) self.assertIn('attrs or dataclass classes', e.exception.args[0]) self.assertEquals(func(Foo()), serialize(Foo(), type_key=None))
def test_serializer_registration_including_descendants(self): _dict = {'x': 1} class Foo: pass class Bar(Foo): pass @serializer_of(Foo, include_descendants=True) def foo(f: Foo) -> dict: return _dict self.assertEqual(_dict, serialize(Foo(), type_key=None)) self.assertEqual(_dict, serialize(Bar(), type_key=None))
def test_attr_no_warning_on_validator_mismatch_for_complex_value(self): @attrs class Foo: a = attrib() @attrs class Bar: foo = attrib(validator=instance_of(Foo)) try: with self.assertLogs(_logger.name, logging.WARNING): serialize(Bar(Foo(5))) except AssertionError: return self.fail()
def _check_serialization_of_inner_iterable_of_classes_with_given_type_key( self, iterable_type, type_key): class Foo: pass @serializer def deserialize_foo(_: Foo): return {} size = 5 it = iterable_type(Foo() for _ in range(size)) with warnings.catch_warnings(): warnings.simplefilter("ignore") s = serialize(FooContainer(foo=it), type_key=type_key, fully_qualified_types=False) self.assertIsInstance(s, dict) self.assertIn('foo', s) foo = s['foo'] self.assertIsInstance(foo, list) self.assertEqual(size, len(foo)) if type_key is not None: for d in foo: self.assertEqual({type_key: 'Foo'}, d)
def test_dict_as_value_with_any_type_hint(self): data = {'a': {'b': 1}} serialized = serialize(data, type_key=None) self.assertRaises(ValueError, deserialize, serialized, obj_type=Dict[str, Any])
def test_enum_serialization(self): class Foo(Enum): A = 5 B = 89 s = serialize(Foo.A) self.assertEqual(Foo.A.value, s[ENUM_VALUE_KEY])
def _check_serialization_of_inner_iterable_of_primitives_with_given_type_key( self, iterable_type, preserve_iterable_types, type_key): size = 5 it = iterable_type(range(size)) with warnings.catch_warnings(): warnings.simplefilter("ignore") s = serialize(FooContainer(foo=it), type_key=type_key, fully_qualified_types=False, preserve_iterable_types=preserve_iterable_types) self.assertIsInstance(s, dict) self.assertIn('foo', s) foo = s['foo'] if preserve_iterable_types and iterable_type != list: self.assertIsInstance(foo, dict) if type_key is not None: self.assertEqual(iterable_type.__name__, foo.get(type_key)) foo = foo.get(ITERABLE_VALUE_KEY) self.assertIsInstance(foo, list) self.assertEqual(size, len(foo)) if issubclass(iterable_type, Sequence): self.assertEqual(list(it), list(foo)) else: self.assertEqual(set(it), set(foo))
def test_serializer_registration_datetime_overrides_default(self): _dict = {'x': 1} @serializer_of(datetime) def foo(d: datetime) -> dict: return _dict self.assertEqual(_dict, serialize(datetime.now(), type_key=None))
def test_attrs_with_only_primitives_no_type_hints(self): @attrs class Foo: i = attrib() f = attrib() s = attrib() b = attrib() n = attrib() f = Foo(i=1, f=.5, s='b', b=True, n=None) f2 = deserialize(serialize(f, fully_qualified_types=False), globals=locals()) self.assertIsInstance(f2, Foo) self.assertEqual(f2, f) f2 = deserialize(serialize(f, type_key=None), obj_type=Foo) self.assertIsInstance(f2, Foo) self.assertEqual(f2, f)
def test_all_dataclass_fields_are_serialized(self): @dataclass class Foo: a: Any = None bar: Any = None s = serialize(Foo()) self.assertTrue('a' in s) self.assertTrue('bar' in s)
def test_all_attr_fields_are_serialized(self): @attrs class Foo: a = attrib(default=None) bar = attrib(default=None) s = serialize(Foo()) self.assertTrue('a' in s) self.assertTrue('bar' in s)
def test_serializer_registration_type_hint_forward_ref(self): class Foo: @staticmethod @serializer def func(_: 'Foo'): return {'foo': 'bar'} s = serialize(Foo(), globals=locals()) self.assertEqual(s.get('foo'), 'bar')
def test_stringified_dict_key_types(self): original = {'a': 1, 2: 'b', True: 3} serialized = serialize(original, stringify_dict_keys=True) self.assertIsInstance(serialized, dict) for k in serialized.keys(): self.assertIsInstance(k, str) restored = deserialize(serialized) self.assertEqual(original, restored)
def test_attrs_with_mixed_tuple_of_primitives_and_type_hints(self): @attrs class Foo: a: Tuple[int, str] = attrib() f = Foo((8, 'dfkjh')) f2 = deserialize(serialize(f, type_key=None, fully_qualified_types=False), Foo, globals=locals()) self.assertIsInstance(f2, Foo) self.assertIsInstance(f2.a, Iterable) self.assertEqual(list(f.a), list(f2.a))
def test_attrs_with_list_of_primitives_without_type_hint(self): @attrs class Foo: l = attrib() f = Foo([1, 'a', True, None]) f2 = deserialize(serialize(f, fully_qualified_types=False), globals=locals()) self.assertIsInstance(f2, Foo) self.assertIsInstance(f2.l, list) self.assertEqual(f.l, f2.l)