File size: 2,626 Bytes
550665c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
import re
from abc import ABC, abstractmethod
import json
import dateutil.parser
def _type_to_snake_case(type_):
return re.sub(r'(?<!^)(?=[A-Z])', '_', type_.__name__).lower()
class BaseSerializer(ABC):
type_ = None
def __init__(self, obj):
if isinstance(obj, self.type_):
self.obj = obj
elif isinstance(obj, (str, dict)):
self.obj = self.to_object(obj)
else:
raise TypeError('The "{}" object must be {}, str or dict, not {!r}.'
.format(_type_to_snake_case(self.type_), self.type_.__name__, obj.__class__.__name__))
def get_object(self):
return self.obj
def get_json(self):
return self.to_json(self.obj)
@staticmethod
def _remove_empty_values(data):
return {k: v for k, v in data.items() if v is not None}
@classmethod
def to_json(cls, obj):
cls.ensure_type(obj)
return cls._to_json(obj)
@staticmethod
@abstractmethod
def _to_json(obj):
pass
@classmethod
def to_object(cls, json_):
json_ = cls.ensure_dict(json_)
return cls._to_object(json_)
@staticmethod
@abstractmethod
def _to_object(json_):
pass
@staticmethod
def ensure_dict(json_):
if not isinstance(json_, (str, dict)):
raise TypeError('The json object must be str or dict, not {!r}'.format(json_.__class__.__name__))
if isinstance(json_, str):
return json.loads(json_)
else:
return json_
@classmethod
def ensure_type(cls, obj):
if not isinstance(obj, cls.type_):
raise TypeError('The object must be {}, not {!r}.'.format(cls.type_, obj.__class__.__name__))
def __init_subclass__(cls, **kwargs):
"""Checks that "type_" is defined and that name of the argument in subclasses __init__ method is the name of
the "type_" in lowercase. It ensures that error in __init__ function of BaseSerializer has a correct message.
"""
if cls.type_ is None:
raise AssertionError('Subclass of BaseSerializer has to define class "type_" that is being serialized.')
if cls.__init__.__code__.co_varnames != ('self', _type_to_snake_case(cls.type_)):
raise AssertionError('Argument of the __init__ method has to have a name "{}".'
.format(_type_to_snake_case(cls.type_)))
@staticmethod
def _get_datetime_from_string(s):
return dateutil.parser.parse(s)
|