Skip to content

Instantly share code, notes, and snippets.

@getjump
Created November 2, 2021 01:15
Show Gist options
  • Save getjump/53362ec201f3aaa58f0211908977e141 to your computer and use it in GitHub Desktop.
Save getjump/53362ec201f3aaa58f0211908977e141 to your computer and use it in GitHub Desktop.
Python Unserializer
"""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])
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