Created
November 2, 2021 01:15
-
-
Save getjump/53362ec201f3aaa58f0211908977e141 to your computer and use it in GitHub Desktop.
Python Unserializer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""Tests for hello function.""" | |
import pytest | |
from rostelecom_key.unserializer import JsonUnserializer, DatetimeFormat | |
from typing import Optional, List, Union | |
import datetime | |
from enum import Enum | |
import attr | |
@attr.dataclass(eq=True, hash=True) | |
class TestSubObject: | |
data: Optional[str] = None | |
test: Optional[List[int]] = None | |
# test2: list | |
# test4: List[Union[str, int]] | |
@attr.dataclass(eq=True, hash=True) | |
class TestSubObject2: | |
buldiga: bool | |
data: Optional[str] = None | |
# test2: list | |
# test4: List[Union[str, int]] | |
@attr.dataclass(eq=True, hash=True) | |
class TestObjectEnum(Enum): | |
ONE = 1 | |
TWO = 2 | |
# @attr.s(auto_attribs=True, frozen=True, slots=True) | |
@attr.dataclass(eq=True, hash=True) | |
class TestObject: | |
sub: Union[TestSubObject2, TestSubObject] | |
enums: List[TestObjectEnum] | |
created_at: Optional[DatetimeFormat('YYYY-MM-DD[*HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]]')] = None | |
data: Optional[str] = None | |
test: Optional[List[int]] = None | |
# test2: list | |
# test4: List[Union[str, int]] | |
# @pytest.mark.parametrize( | |
# ("name", "expected"), | |
# [ | |
# ("Jeanette", "Hello Jeanette!"), | |
# ("Raven", "Hello Raven!"), | |
# ("Maxine", "Hello Maxine!"), | |
# ("Matteo", "Hello Matteo!"), | |
# ("Destinee", "Hello Destinee!"), | |
# ("Alden", "Hello Alden!"), | |
# ("Mariah", "Hello Mariah!"), | |
# ("Anika", "Hello Anika!"), | |
# ("Isabella", "Hello Isabella!"), | |
# ], | |
# ) | |
def test_hello(): | |
"""Example test with parametrization.""" | |
unserializer = JsonUnserializer() | |
obj = unserializer.unserialize(TestObject, { | |
'sub': { | |
'data': 'test', | |
'buldiga': False | |
}, | |
'created_at': '2021-08-12T02:01:42.743446Z', | |
'enums': [ | |
2, | |
2, | |
1 | |
], | |
'data': 'test', | |
'test': ['1', '2', '3'] | |
}) | |
print(obj.enums[2]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import datetime | |
from typing import Type, List, Union, get_origin, get_args | |
from enum import Enum | |
import inspect | |
import attr | |
class DatetimeFormat: | |
format: str | |
def __init__(self, format: str) -> None: | |
self.format = format | |
class JsonUnserializer: | |
TYPE_CONVERSION_TABLE = { | |
str: str, | |
int: int, | |
bool: bool, | |
list: list | |
} | |
NO_CONVERTO = -1 | |
def __init__(self): | |
pass | |
def unserialize(self, obj: Type, _json: dict): | |
vars_obj = vars(obj) | |
type_instance = {} | |
if '__annotations__' not in vars_obj: | |
raise TypeError(obj) | |
annotations = vars_obj['__annotations__'] | |
if annotations is None: | |
raise TypeError(obj) | |
for key, value in _json.items(): | |
if key not in annotations: | |
break | |
type_name = annotations[key] | |
type_instance[key] = self.convert_types(key, type_name, value) | |
return obj(**type_instance) | |
def nested_convert_types(self, key, type_name, value): | |
print(key, type_name, get_origin(type_name), isinstance(type_name, Enum)) | |
if type_name in self.TYPE_CONVERSION_TABLE: | |
print(key, type_name, 'plain') | |
return self.TYPE_CONVERSION_TABLE[type_name](value) | |
elif get_origin(type_name) is list: | |
return [self.convert_types(key, get_args(type_name)[0], x) for x in value] | |
return self.NO_CONVERTO | |
def convert_types(self, key, type_name, value): | |
result = self.nested_convert_types(key, type_name, value) | |
if result is not self.NO_CONVERTO: | |
return result | |
elif get_origin(type_name) is Union: | |
print(key, type_name, get_origin(type_name), get_args(type_name), value, 'union') | |
for nested_type in get_args(type_name): | |
# try: | |
inner_result = self.convert_types(key, nested_type, value) | |
if inner_result is not self.NO_CONVERTO: | |
return inner_result | |
# except TypeError as e: | |
# print(e) | |
elif inspect.isclass(type_name): | |
if issubclass(type_name, Enum): | |
return type_name(value) | |
elif isinstance(type_name, datetime.datetime): | |
return datetime.datetime.fromisoformat(value) | |
else: | |
return self.unserialize(type_name, value) | |
else: | |
print(type_name, get_origin(type_name), value, 'type_error') | |
raise TypeError(type_name) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment