import importlib, json from typing import Any, List class Message(): _USM_AGENT_CODE = "CZDygPSF2HJTLKVIqys1"; _ATTRIBUTES = { # * in name -> optional "id" : str, "sub_ids*" : List[str], "riddle" : "ums.messages.specials.Riddle", "solution*" : "ums.messages.specials.Solution", "data" : "ums.messages.specials.RiddleData", "status" : "ums.messages.specials.RiddleStatus" } _DEFAULTS = { "data" : ("ums.messages.specials", "RiddleData"), "status" : ("ums.messages.specials", "RiddleStatus") } def __init__(self, *args, **kwargs): if len(args) > 0: self.__dict__['items'] = list(args) elif len(kwargs) > 0: self.__dict__['items'] = kwargs else: self.__dict__['items'] = self._DEFAULTS self._check_attr() def __getattr__(self, name: str) -> Any: if 'items' in self.__dict__ and isinstance(self.items, dict) and name in self.items: return self.items[name] def __setattr__(self, name: str, value: Any) -> None: if hasattr(self, name): setattr(self, name, value) elif isinstance(self.items, dict): self.items[name] = value self._check_attr() def _check_attr(self): if isinstance(self._ATTRIBUTES, list): assert isinstance(self.items, list), \ "{} content must be a list and not a dict!".format(self.__class__.__name__) elif isinstance(self._ATTRIBUTES, dict): assert isinstance(self.items, dict), \ "{} content must be a dict and not a list!".format(self.__class__.__name__) for k,v in self._ATTRIBUTES.items(): if not k.endswith('*') and not k in self.items: if k in self._DEFAULTS: if isinstance(self._DEFAULTS[k], tuple): def_class = getattr( importlib.import_module(self._DEFAULTS[k][0]), self._DEFAULTS[k][1] ) self.items[k] = def_class() else: self.items[k] = self._DEFAULTS[k] else: raise ValueError("Message requires field {}, but not set (and no default)!".format(k)) if isinstance(v, str): # a class name pass elif isinstance(v, dict): # a sub structure pass else: # a type pass def _to_json(self): return self.items def to_json(self) -> str: return json.dumps( self._to_json(), indent=2, cls=JSONEncodeHelper, sort_keys=True ) def from_json(json:str): # TODO pass class JSONEncodeHelper(json.JSONEncoder): def default(self, o): if isinstance(o, Message): return o._to_json() return super().default(o)