import datetime import json from enum import Enum, IntEnum from api.utils.common import string_to_bytes, bytes_to_string class BaseType: def to_dict(self): return dict([(k.lstrip("_"), v) for k, v in self.__dict__.items()]) def to_dict_with_type(self): def _dict(obj): module = None if issubclass(obj.__class__, BaseType): data = {} for attr, v in obj.__dict__.items(): k = attr.lstrip("_") data[k] = _dict(v) module = obj.__module__ elif isinstance(obj, (list, tuple)): data = [] for i, vv in enumerate(obj): data.append(_dict(vv)) elif isinstance(obj, dict): data = {} for _k, vv in obj.items(): data[_k] = _dict(vv) else: data = obj return {"type": obj.__class__.__name__, "data": data, "module": module} return _dict(self) class CustomJSONEncoder(json.JSONEncoder): def __init__(self, **kwargs): self._with_type = kwargs.pop("with_type", False) super().__init__(**kwargs) def default(self, obj): if isinstance(obj, datetime.datetime): return obj.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(obj, datetime.date): return obj.strftime('%Y-%m-%d') elif isinstance(obj, datetime.timedelta): return str(obj) elif issubclass(type(obj), Enum) or issubclass(type(obj), IntEnum): return obj.value elif isinstance(obj, set): return list(obj) elif issubclass(type(obj), BaseType): if not self._with_type: return obj.to_dict() else: return obj.to_dict_with_type() elif isinstance(obj, type): return obj.__name__ else: return json.JSONEncoder.default(self, obj) def json_dumps(src, byte=False, indent=None, with_type=False): dest = json.dumps( src, indent=indent, cls=CustomJSONEncoder, with_type=with_type) if byte: dest = string_to_bytes(dest) return dest def json_loads(src, object_hook=None, object_pairs_hook=None): if isinstance(src, bytes): src = bytes_to_string(src) return json.loads(src, object_hook=object_hook, object_pairs_hook=object_pairs_hook)