yasoo
Advanced tools
+126
-123
| Metadata-Version: 2.1 | ||
| Name: yasoo | ||
| Version: 0.9.4 | ||
| Version: 0.10.0 | ||
| Summary: Yet another serializer of objects | ||
@@ -8,124 +8,2 @@ Home-page: https://github.com/drorvinkler/yasoo | ||
| License: MIT | ||
| Description: # `yasoo`: Serialize the Data You Have | ||
| [](https://travis-ci.com/github/drorvinkler/yasoo) | ||
| [](https://codecov.io/gh/drorvinkler/yasoo) | ||
| [](https://opensource.org/licenses/MIT) | ||
| [](https://github.com/psf/black) | ||
| A python serializer of `attrs` and `dataclass` objects that doesn't rely on type hints. | ||
| ## Why yasoo | ||
| `yasoo` adds type data to the serialized data, so deserialization doesn't need to rely on type hints. | ||
| Moreover, if you have a field that can contain multiple types of values, or a field which contains some specific implementation of an abstract class, `yasoo` has no problem with that. | ||
| For example, this code works fine: | ||
| ``` | ||
| from attr import attrs, attrib | ||
| from yasoo import serialize, deserialize | ||
| @attrs | ||
| class Foo: | ||
| a = attrib() | ||
| @attrs | ||
| class Bar: | ||
| foo: Foo = attrib() | ||
| serialized = serialize(Bar(foo=5)) | ||
| assert(deserialize(serialized).foo == 5) | ||
| ``` | ||
| ## Usage | ||
| ### Basic Usage | ||
| For simple objects, use: | ||
| ``` | ||
| from yasoo import serialize, deserialize | ||
| with open(path, 'w') as f: | ||
| json.dump(serialize(obj), f) | ||
| with open(path) as f: | ||
| obj = deserizlie(json.load(f)) | ||
| ``` | ||
| ### Advanced Usage | ||
| #### Deserializing Collections of Objects | ||
| You can deserialize collections of objects: | ||
| ``` | ||
| from attr import attrs, attrib | ||
| from yasoo import serialize, deserialize | ||
| from yasoo.typing import List_ | ||
| @attrs | ||
| class Foo: | ||
| a = attrib() | ||
| foos = [Foo(a=i) for i in range(5)] | ||
| serialized = serialize(foos) | ||
| de_foos = deserialize(serialized, obj_type=List_[Foo]) | ||
| assert de_foos == foos | ||
| ``` | ||
| Notice that passing the object type as `List[Foo]` won't give you the type | ||
| of `de_foos`, but using `yasoo.typing.List_` will fix this. | ||
| #### Custom (De)Serializers | ||
| For objects that need custom serialization/deserialization, you can register your own methods: | ||
| ``` | ||
| from attr import attrs, attrib, asdict | ||
| from yasoo import serialize, deserialize, serializer, deserializer | ||
| @attrs | ||
| class Foo: | ||
| bar = attrib(converter=lambda x: x * 2) | ||
| def set_foobar(self, foobar): | ||
| self.foobar = foobar | ||
| @serializer | ||
| def serialize(self: 'Foo'): | ||
| result = asdict(self) | ||
| if hasattr(self, 'foobar'): | ||
| result['foobar'] = self.foobar | ||
| return result | ||
| @staticmethod | ||
| @deserializer | ||
| def deserialize(data: dict) -> 'Foo': | ||
| foo = Foo(data['bar'] / 2) | ||
| if 'foobar' in data: | ||
| foo.set_foobar(data['foobar']) | ||
| return foo | ||
| ``` | ||
| Notice that registering custom methods with forward reference (i.e. `'Foo'` instead of `Foo`) requires passing the `globals` parameter to `serialize`/`deserialize`, e.g. | ||
| ``` | ||
| serialize(obj, globals=globals()) | ||
| ``` | ||
| #### Using Type Hints | ||
| If you want to avoid having the `__type` key in your serialized data, you can set the `type_key` parameter to `None` when calling `serialize`. | ||
| For this to work all fields in the serialized class that are not json-serializable should have a type hint. | ||
| #### Serializing Sequences | ||
| By default all sequences found in the data will be converted to `list` in the serialization process. | ||
| If you want to be able to deserialize them back to anything other than a list, set the `preserve_iterable_types` parameter to `True` when calling `serialize`. | ||
| Note: setting the `preserve_iterable_types` parameter to `True` will cause all iterables that are not `list` to be serialized as dictionaries with their type saved under the `type_key`. | ||
| #### Multiple Serialization Methods For The Same Type | ||
| If you want to define a custom serialization method for a type for a specific use case, without affecting the default serializer, you can create another instance of `Serializer` and register the method on that instance. For example: | ||
| ``` | ||
| from yasoo import Serializer, serializer, serialize | ||
| @serializer | ||
| def serialize_foo(foo: Foo): | ||
| return {'bar': foo.bar} | ||
| my_serializer = Serializer() | ||
| @my_serializer.register() | ||
| def serialize_foo_another_way(foo: Foo): | ||
| return {'bar': foo.bar * 2} | ||
| serialize(Foo(bar=5)) # returns {'bar': 5, '__type': 'Foo'} | ||
| my_serializer.serialize(Foo(bar=5)) # returns {'bar': 10, '__type': 'Foo'} | ||
| ``` | ||
| Platform: UNKNOWN | ||
@@ -137,1 +15,126 @@ Classifier: Programming Language :: Python :: 3 | ||
| Description-Content-Type: text/markdown | ||
| License-File: LICENSE | ||
| # `yasoo`: Serialize the Data You Have | ||
| [](https://travis-ci.com/github/drorvinkler/yasoo) | ||
| [](https://codecov.io/gh/drorvinkler/yasoo) | ||
| [](https://opensource.org/licenses/MIT) | ||
| [](https://github.com/psf/black) | ||
| A python serializer of `attrs` and `dataclass` objects that doesn't rely on type hints. | ||
| ## Why yasoo | ||
| `yasoo` adds type data to the serialized data, so deserialization doesn't need to rely on type hints. | ||
| Moreover, if you have a field that can contain multiple types of values, or a field which contains some specific implementation of an abstract class, `yasoo` has no problem with that. | ||
| For example, this code works fine: | ||
| ``` | ||
| from attr import attrs, attrib | ||
| from yasoo import serialize, deserialize | ||
| @attrs | ||
| class Foo: | ||
| a = attrib() | ||
| @attrs | ||
| class Bar: | ||
| foo: Foo = attrib() | ||
| serialized = serialize(Bar(foo=5)) | ||
| assert(deserialize(serialized).foo == 5) | ||
| ``` | ||
| ## Usage | ||
| ### Basic Usage | ||
| For simple objects, use: | ||
| ``` | ||
| from yasoo import serialize, deserialize | ||
| with open(path, 'w') as f: | ||
| json.dump(serialize(obj), f) | ||
| with open(path) as f: | ||
| obj = deserizlie(json.load(f)) | ||
| ``` | ||
| ### Advanced Usage | ||
| #### Deserializing Collections of Objects | ||
| You can deserialize collections of objects: | ||
| ``` | ||
| from attr import attrs, attrib | ||
| from yasoo import serialize, deserialize | ||
| from yasoo.typing import List_ | ||
| @attrs | ||
| class Foo: | ||
| a = attrib() | ||
| foos = [Foo(a=i) for i in range(5)] | ||
| serialized = serialize(foos) | ||
| de_foos = deserialize(serialized, obj_type=List_[Foo]) | ||
| assert de_foos == foos | ||
| ``` | ||
| Notice that passing the object type as `List[Foo]` won't give you the type | ||
| of `de_foos`, but using `yasoo.typing.List_` will fix this. | ||
| #### Custom (De)Serializers | ||
| For objects that need custom serialization/deserialization, you can register your own methods: | ||
| ``` | ||
| from attr import attrs, attrib, asdict | ||
| from yasoo import serialize, deserialize, serializer, deserializer | ||
| @attrs | ||
| class Foo: | ||
| bar = attrib(converter=lambda x: x * 2) | ||
| def set_foobar(self, foobar): | ||
| self.foobar = foobar | ||
| @serializer | ||
| def serialize(self: 'Foo'): | ||
| result = asdict(self) | ||
| if hasattr(self, 'foobar'): | ||
| result['foobar'] = self.foobar | ||
| return result | ||
| @staticmethod | ||
| @deserializer | ||
| def deserialize(data: dict) -> 'Foo': | ||
| foo = Foo(data['bar'] / 2) | ||
| if 'foobar' in data: | ||
| foo.set_foobar(data['foobar']) | ||
| return foo | ||
| ``` | ||
| Notice that registering custom methods with forward reference (i.e. `'Foo'` instead of `Foo`) requires passing the `globals` parameter to `serialize`/`deserialize`, e.g. | ||
| ``` | ||
| serialize(obj, globals=globals()) | ||
| ``` | ||
| #### Using Type Hints | ||
| If you want to avoid having the `__type` key in your serialized data, you can set the `type_key` parameter to `None` when calling `serialize`. | ||
| For this to work all fields in the serialized class that are not json-serializable should have a type hint. | ||
| #### Serializing Sequences | ||
| By default all sequences found in the data will be converted to `list` in the serialization process. | ||
| If you want to be able to deserialize them back to anything other than a list, set the `preserve_iterable_types` parameter to `True` when calling `serialize`. | ||
| Note: setting the `preserve_iterable_types` parameter to `True` will cause all iterables that are not `list` to be serialized as dictionaries with their type saved under the `type_key`. | ||
| #### Multiple Serialization Methods For The Same Type | ||
| If you want to define a custom serialization method for a type for a specific use case, without affecting the default serializer, you can create another instance of `Serializer` and register the method on that instance. For example: | ||
| ``` | ||
| from yasoo import Serializer, serializer, serialize | ||
| @serializer | ||
| def serialize_foo(foo: Foo): | ||
| return {'bar': foo.bar} | ||
| my_serializer = Serializer() | ||
| @my_serializer.register() | ||
| def serialize_foo_another_way(foo: Foo): | ||
| return {'bar': foo.bar * 2} | ||
| serialize(Foo(bar=5)) # returns {'bar': 5, '__type': 'Foo'} | ||
| my_serializer.serialize(Foo(bar=5)) # returns {'bar': 10, '__type': 'Foo'} | ||
| ``` | ||
+1
-1
@@ -9,3 +9,3 @@ import setuptools | ||
| name="yasoo", | ||
| version="0.9.4", | ||
| version="0.10.0", | ||
| author="Dror A. Vinkler", | ||
@@ -12,0 +12,0 @@ description="Yet another serializer of objects", |
+126
-123
| Metadata-Version: 2.1 | ||
| Name: yasoo | ||
| Version: 0.9.4 | ||
| Version: 0.10.0 | ||
| Summary: Yet another serializer of objects | ||
@@ -8,124 +8,2 @@ Home-page: https://github.com/drorvinkler/yasoo | ||
| License: MIT | ||
| Description: # `yasoo`: Serialize the Data You Have | ||
| [](https://travis-ci.com/github/drorvinkler/yasoo) | ||
| [](https://codecov.io/gh/drorvinkler/yasoo) | ||
| [](https://opensource.org/licenses/MIT) | ||
| [](https://github.com/psf/black) | ||
| A python serializer of `attrs` and `dataclass` objects that doesn't rely on type hints. | ||
| ## Why yasoo | ||
| `yasoo` adds type data to the serialized data, so deserialization doesn't need to rely on type hints. | ||
| Moreover, if you have a field that can contain multiple types of values, or a field which contains some specific implementation of an abstract class, `yasoo` has no problem with that. | ||
| For example, this code works fine: | ||
| ``` | ||
| from attr import attrs, attrib | ||
| from yasoo import serialize, deserialize | ||
| @attrs | ||
| class Foo: | ||
| a = attrib() | ||
| @attrs | ||
| class Bar: | ||
| foo: Foo = attrib() | ||
| serialized = serialize(Bar(foo=5)) | ||
| assert(deserialize(serialized).foo == 5) | ||
| ``` | ||
| ## Usage | ||
| ### Basic Usage | ||
| For simple objects, use: | ||
| ``` | ||
| from yasoo import serialize, deserialize | ||
| with open(path, 'w') as f: | ||
| json.dump(serialize(obj), f) | ||
| with open(path) as f: | ||
| obj = deserizlie(json.load(f)) | ||
| ``` | ||
| ### Advanced Usage | ||
| #### Deserializing Collections of Objects | ||
| You can deserialize collections of objects: | ||
| ``` | ||
| from attr import attrs, attrib | ||
| from yasoo import serialize, deserialize | ||
| from yasoo.typing import List_ | ||
| @attrs | ||
| class Foo: | ||
| a = attrib() | ||
| foos = [Foo(a=i) for i in range(5)] | ||
| serialized = serialize(foos) | ||
| de_foos = deserialize(serialized, obj_type=List_[Foo]) | ||
| assert de_foos == foos | ||
| ``` | ||
| Notice that passing the object type as `List[Foo]` won't give you the type | ||
| of `de_foos`, but using `yasoo.typing.List_` will fix this. | ||
| #### Custom (De)Serializers | ||
| For objects that need custom serialization/deserialization, you can register your own methods: | ||
| ``` | ||
| from attr import attrs, attrib, asdict | ||
| from yasoo import serialize, deserialize, serializer, deserializer | ||
| @attrs | ||
| class Foo: | ||
| bar = attrib(converter=lambda x: x * 2) | ||
| def set_foobar(self, foobar): | ||
| self.foobar = foobar | ||
| @serializer | ||
| def serialize(self: 'Foo'): | ||
| result = asdict(self) | ||
| if hasattr(self, 'foobar'): | ||
| result['foobar'] = self.foobar | ||
| return result | ||
| @staticmethod | ||
| @deserializer | ||
| def deserialize(data: dict) -> 'Foo': | ||
| foo = Foo(data['bar'] / 2) | ||
| if 'foobar' in data: | ||
| foo.set_foobar(data['foobar']) | ||
| return foo | ||
| ``` | ||
| Notice that registering custom methods with forward reference (i.e. `'Foo'` instead of `Foo`) requires passing the `globals` parameter to `serialize`/`deserialize`, e.g. | ||
| ``` | ||
| serialize(obj, globals=globals()) | ||
| ``` | ||
| #### Using Type Hints | ||
| If you want to avoid having the `__type` key in your serialized data, you can set the `type_key` parameter to `None` when calling `serialize`. | ||
| For this to work all fields in the serialized class that are not json-serializable should have a type hint. | ||
| #### Serializing Sequences | ||
| By default all sequences found in the data will be converted to `list` in the serialization process. | ||
| If you want to be able to deserialize them back to anything other than a list, set the `preserve_iterable_types` parameter to `True` when calling `serialize`. | ||
| Note: setting the `preserve_iterable_types` parameter to `True` will cause all iterables that are not `list` to be serialized as dictionaries with their type saved under the `type_key`. | ||
| #### Multiple Serialization Methods For The Same Type | ||
| If you want to define a custom serialization method for a type for a specific use case, without affecting the default serializer, you can create another instance of `Serializer` and register the method on that instance. For example: | ||
| ``` | ||
| from yasoo import Serializer, serializer, serialize | ||
| @serializer | ||
| def serialize_foo(foo: Foo): | ||
| return {'bar': foo.bar} | ||
| my_serializer = Serializer() | ||
| @my_serializer.register() | ||
| def serialize_foo_another_way(foo: Foo): | ||
| return {'bar': foo.bar * 2} | ||
| serialize(Foo(bar=5)) # returns {'bar': 5, '__type': 'Foo'} | ||
| my_serializer.serialize(Foo(bar=5)) # returns {'bar': 10, '__type': 'Foo'} | ||
| ``` | ||
| Platform: UNKNOWN | ||
@@ -137,1 +15,126 @@ Classifier: Programming Language :: Python :: 3 | ||
| Description-Content-Type: text/markdown | ||
| License-File: LICENSE | ||
| # `yasoo`: Serialize the Data You Have | ||
| [](https://travis-ci.com/github/drorvinkler/yasoo) | ||
| [](https://codecov.io/gh/drorvinkler/yasoo) | ||
| [](https://opensource.org/licenses/MIT) | ||
| [](https://github.com/psf/black) | ||
| A python serializer of `attrs` and `dataclass` objects that doesn't rely on type hints. | ||
| ## Why yasoo | ||
| `yasoo` adds type data to the serialized data, so deserialization doesn't need to rely on type hints. | ||
| Moreover, if you have a field that can contain multiple types of values, or a field which contains some specific implementation of an abstract class, `yasoo` has no problem with that. | ||
| For example, this code works fine: | ||
| ``` | ||
| from attr import attrs, attrib | ||
| from yasoo import serialize, deserialize | ||
| @attrs | ||
| class Foo: | ||
| a = attrib() | ||
| @attrs | ||
| class Bar: | ||
| foo: Foo = attrib() | ||
| serialized = serialize(Bar(foo=5)) | ||
| assert(deserialize(serialized).foo == 5) | ||
| ``` | ||
| ## Usage | ||
| ### Basic Usage | ||
| For simple objects, use: | ||
| ``` | ||
| from yasoo import serialize, deserialize | ||
| with open(path, 'w') as f: | ||
| json.dump(serialize(obj), f) | ||
| with open(path) as f: | ||
| obj = deserizlie(json.load(f)) | ||
| ``` | ||
| ### Advanced Usage | ||
| #### Deserializing Collections of Objects | ||
| You can deserialize collections of objects: | ||
| ``` | ||
| from attr import attrs, attrib | ||
| from yasoo import serialize, deserialize | ||
| from yasoo.typing import List_ | ||
| @attrs | ||
| class Foo: | ||
| a = attrib() | ||
| foos = [Foo(a=i) for i in range(5)] | ||
| serialized = serialize(foos) | ||
| de_foos = deserialize(serialized, obj_type=List_[Foo]) | ||
| assert de_foos == foos | ||
| ``` | ||
| Notice that passing the object type as `List[Foo]` won't give you the type | ||
| of `de_foos`, but using `yasoo.typing.List_` will fix this. | ||
| #### Custom (De)Serializers | ||
| For objects that need custom serialization/deserialization, you can register your own methods: | ||
| ``` | ||
| from attr import attrs, attrib, asdict | ||
| from yasoo import serialize, deserialize, serializer, deserializer | ||
| @attrs | ||
| class Foo: | ||
| bar = attrib(converter=lambda x: x * 2) | ||
| def set_foobar(self, foobar): | ||
| self.foobar = foobar | ||
| @serializer | ||
| def serialize(self: 'Foo'): | ||
| result = asdict(self) | ||
| if hasattr(self, 'foobar'): | ||
| result['foobar'] = self.foobar | ||
| return result | ||
| @staticmethod | ||
| @deserializer | ||
| def deserialize(data: dict) -> 'Foo': | ||
| foo = Foo(data['bar'] / 2) | ||
| if 'foobar' in data: | ||
| foo.set_foobar(data['foobar']) | ||
| return foo | ||
| ``` | ||
| Notice that registering custom methods with forward reference (i.e. `'Foo'` instead of `Foo`) requires passing the `globals` parameter to `serialize`/`deserialize`, e.g. | ||
| ``` | ||
| serialize(obj, globals=globals()) | ||
| ``` | ||
| #### Using Type Hints | ||
| If you want to avoid having the `__type` key in your serialized data, you can set the `type_key` parameter to `None` when calling `serialize`. | ||
| For this to work all fields in the serialized class that are not json-serializable should have a type hint. | ||
| #### Serializing Sequences | ||
| By default all sequences found in the data will be converted to `list` in the serialization process. | ||
| If you want to be able to deserialize them back to anything other than a list, set the `preserve_iterable_types` parameter to `True` when calling `serialize`. | ||
| Note: setting the `preserve_iterable_types` parameter to `True` will cause all iterables that are not `list` to be serialized as dictionaries with their type saved under the `type_key`. | ||
| #### Multiple Serialization Methods For The Same Type | ||
| If you want to define a custom serialization method for a type for a specific use case, without affecting the default serializer, you can create another instance of `Serializer` and register the method on that instance. For example: | ||
| ``` | ||
| from yasoo import Serializer, serializer, serialize | ||
| @serializer | ||
| def serialize_foo(foo: Foo): | ||
| return {'bar': foo.bar} | ||
| my_serializer = Serializer() | ||
| @my_serializer.register() | ||
| def serialize_foo_another_way(foo: Foo): | ||
| return {'bar': foo.bar * 2} | ||
| serialize(Foo(bar=5)) # returns {'bar': 5, '__type': 'Foo'} | ||
| my_serializer.serialize(Foo(bar=5)) # returns {'bar': 10, '__type': 'Foo'} | ||
| ``` | ||
@@ -8,2 +8,3 @@ from .deserialization import Deserializer | ||
| serializer_of = _default_serializer.register | ||
| unregister_serializers = _default_serializer.unregister | ||
@@ -14,1 +15,2 @@ _default_deserializer = Deserializer() | ||
| deserializer_of = _default_deserializer.register | ||
| unregister_deserializers = _default_deserializer.unregister |
| import json | ||
| from contextlib import contextmanager | ||
| from datetime import datetime | ||
@@ -50,3 +51,3 @@ from enum import Enum | ||
| self, | ||
| type_to_register: Optional[Union[Type, str]] = None, | ||
| type_to_register: Optional[Union[Type[T], str]] = None, | ||
| include_descendants: bool = False, | ||
@@ -65,3 +66,3 @@ ): | ||
| def registration_method( | ||
| deserialization_method: Union[Callable[[Dict[str, Any]], Any], staticmethod] | ||
| deserialization_method: Union[Callable[[Dict[str, Any]], T], staticmethod] | ||
| ): | ||
@@ -79,2 +80,21 @@ method = normalize_method(deserialization_method) | ||
| @contextmanager | ||
| def unregister(self, *types: Type[T]): | ||
| """ | ||
| Temporarily unregisters registered deserializers, so ``deserialize`` will use the default deserialization | ||
| algorithm. | ||
| :param types: The types to deserialize using the default algorithm. | ||
| :return: | ||
| """ | ||
| types_funcs = [ | ||
| (type_, self._custom_deserializers.pop(type_, None)) for type_ in types | ||
| ] | ||
| try: | ||
| yield | ||
| finally: | ||
| for type_, func in types_funcs: | ||
| if func is not None: | ||
| self._custom_deserializers[type_] = func | ||
| @overload | ||
@@ -86,2 +106,3 @@ def deserialize( | ||
| type_key: Optional[str] = "__type", | ||
| allow_extra_fields: bool = False, | ||
| globals: Optional[Dict[str, Any]] = None, | ||
@@ -96,2 +117,3 @@ ) -> T: | ||
| type_key: Optional[str] = "__type", | ||
| allow_extra_fields: bool = False, | ||
| globals: Optional[Dict[str, Any]] = None, | ||
@@ -107,2 +129,4 @@ ) -> T: | ||
| Can be ``None`` if this key was omitted during serialization and deserialization should rely on type hints. | ||
| :param allow_extra_fields: Whether to throw an exception if the data contains fields that are not in the type | ||
| definition, or just ignore them. | ||
| :param globals: A dictionary from type name to type, most easily acquired using the built-in ``globals()`` | ||
@@ -116,3 +140,5 @@ function. | ||
| return self._deserialize(data, obj_type, type_key, globals or {}) | ||
| return self._deserialize( | ||
| data, obj_type, type_key, allow_extra_fields, globals or {} | ||
| ) | ||
@@ -124,2 +150,3 @@ def _deserialize( | ||
| type_key: Optional[str], | ||
| allow_extra_fields: bool, | ||
| external_globals: Dict[str, Any], | ||
@@ -134,3 +161,4 @@ ): | ||
| return [ | ||
| self._deserialize(d, t, type_key, all_globals) for t, d in list_types | ||
| self._deserialize(d, t, type_key, allow_extra_fields, all_globals) | ||
| for t, d in list_types | ||
| ] | ||
@@ -167,9 +195,18 @@ | ||
| return self._load_mapping( | ||
| data, real_type, generic_args, type_key, all_globals | ||
| data, | ||
| real_type, | ||
| generic_args, | ||
| type_key, | ||
| allow_extra_fields, | ||
| all_globals, | ||
| ) | ||
| elif issubclass(real_type, Iterable): | ||
| # If we got here it means data is not a list, so obj_type came from the data itself and is safe to use | ||
| return self._load_iterable(data, obj_type, type_key, all_globals) | ||
| return self._load_iterable( | ||
| data, obj_type, type_key, allow_extra_fields, all_globals | ||
| ) | ||
| elif real_type != obj_type: | ||
| return self._deserialize(data, real_type, type_key, external_globals) | ||
| return self._deserialize( | ||
| data, real_type, type_key, allow_extra_fields, external_globals | ||
| ) | ||
| else: | ||
@@ -179,7 +216,7 @@ raise | ||
| self._check_for_missing_fields(data, fields, obj_type) | ||
| self._check_for_extraneous_fields(data, fields, obj_type) | ||
| self._load_inner_fields(data, fields, type_key, all_globals) | ||
| self._check_for_extraneous_fields(data, fields, obj_type, allow_extra_fields) | ||
| self._load_inner_fields(data, fields, type_key, allow_extra_fields, all_globals) | ||
| if obj_type is DictWithSerializedKeys: | ||
| return self._load_dict_with_serialized_keys( | ||
| obj_type(**data), key_type, type_key, all_globals | ||
| obj_type(**data), key_type, type_key, allow_extra_fields, all_globals | ||
| ) | ||
@@ -189,6 +226,13 @@ return obj_type(**data) | ||
| def _load_dict_with_serialized_keys( | ||
| self, obj: DictWithSerializedKeys, key_type, type_key, all_globals | ||
| self, | ||
| obj: DictWithSerializedKeys, | ||
| key_type, | ||
| type_key, | ||
| allow_extra_fields, | ||
| all_globals, | ||
| ): | ||
| data = { | ||
| self._deserialize(json.loads(k), key_type, type_key, all_globals): v | ||
| self._deserialize( | ||
| json.loads(k), key_type, type_key, allow_extra_fields, all_globals | ||
| ): v | ||
| for k, v in obj.data.items() | ||
@@ -200,3 +244,9 @@ } | ||
| def _load_mapping( | ||
| self, data: Mapping, obj_type, generic_args, type_key, all_globals | ||
| self, | ||
| data: Mapping, | ||
| obj_type, | ||
| generic_args, | ||
| type_key, | ||
| allow_extra_fields, | ||
| all_globals, | ||
| ): | ||
@@ -206,3 +256,5 @@ val_type = generic_args[1] if len(generic_args) > 1 else None | ||
| { | ||
| k: self._deserialize(v, val_type, type_key, all_globals) | ||
| k: self._deserialize( | ||
| v, val_type, type_key, allow_extra_fields, all_globals | ||
| ) | ||
| for k, v in data.items() | ||
@@ -212,13 +264,15 @@ } | ||
| def _load_iterable(self, data, obj_type, type_key, all_globals): | ||
| def _load_iterable(self, data, obj_type, type_key, allow_extra_fields, all_globals): | ||
| return obj_type( | ||
| self._deserialize(i, None, type_key, all_globals) | ||
| self._deserialize(i, None, type_key, allow_extra_fields, all_globals) | ||
| for i in data[ITERABLE_VALUE_KEY] | ||
| ) | ||
| def _load_inner_fields(self, data, fields, type_key, all_globals): | ||
| def _load_inner_fields( | ||
| self, data, fields, type_key, allow_extra_fields, all_globals | ||
| ): | ||
| for key, value in data.items(): | ||
| field = fields[key] | ||
| data[key] = self._deserialize( | ||
| value, field.field_type, type_key, all_globals | ||
| value, field.field_type, type_key, allow_extra_fields, all_globals | ||
| ) | ||
@@ -258,5 +312,5 @@ | ||
| @staticmethod | ||
| def _check_for_extraneous_fields(data, fields, obj_type): | ||
| def _check_for_extraneous_fields(data, fields, obj_type, allow_extra_fields): | ||
| extraneous = set(data.keys()).difference(fields) | ||
| if extraneous: | ||
| if extraneous and not allow_extra_fields: | ||
| extraneous_str = '", "'.join(extraneous) | ||
@@ -267,2 +321,4 @@ raise ValueError( | ||
| ) | ||
| for e in extraneous: | ||
| data.pop(e) | ||
@@ -290,3 +346,3 @@ @staticmethod | ||
| all_globals: Dict[str, Any], | ||
| ) -> Type: | ||
| ) -> type: | ||
| if type_key in data: | ||
@@ -293,0 +349,0 @@ return Deserializer._get_type(data[type_key], all_globals) |
| import json | ||
| import warnings | ||
| from contextlib import contextmanager | ||
| from datetime import datetime | ||
| from enum import Enum | ||
| from inspect import signature | ||
| from typing import Dict, Any, Union, Mapping, Iterable, Callable, Type, Optional | ||
| from typing import Dict, Any, Union, Mapping, Iterable, Callable, Optional | ||
@@ -32,3 +33,3 @@ from yasoo.default_customs import serialize_type, serialize_datetime | ||
| def register( | ||
| self, type_to_register: Optional[Type] = None, include_descendants: bool = False | ||
| self, type_to_register: Optional[type] = None, include_descendants: bool = False | ||
| ): | ||
@@ -59,2 +60,22 @@ """ | ||
| @contextmanager | ||
| def unregister(self, *types: type): | ||
| """ | ||
| Temporarily unregisters registered serializers, so ``serialize`` will use the default serialization | ||
| algorithm. | ||
| :param types: The types to serialize using the default algorithm. | ||
| :return: | ||
| """ | ||
| types_funcs = [ | ||
| (type_, self._custom_serializers.pop(type_, None)) for type_ in types | ||
| ] | ||
| try: | ||
| yield | ||
| finally: | ||
| for type_, func in types_funcs: | ||
| if func is not None: | ||
| self._custom_serializers[type_] = func | ||
| pass | ||
| def serialize( | ||
@@ -61,0 +82,0 @@ self, |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
52705
1.22%966
8.42%