from abc import abstractmethod class ConfigLoadBaseException(Exception): def __init__(self, msg, node, inner=None) -> None: super().__init__(msg) self.__msg = msg self.__node = node self.__inner = inner def __str__(self) -> str: return super().__str__() class ConfigLoadException(ConfigLoadBaseException): def __init__(self, msg, node = None, inner=None) -> None: super().__init__(msg, node, inner) class ConfigTypeCheckError(ConfigLoadBaseException): def __init__(self, msg, node, inner=None) -> None: super().__init__(msg, node, inner) class ConfigIOProvider: def __init__(self) -> None: pass @abstractmethod def export(self, env, config_dict): pass @abstractmethod def save(self, env, config_dict): pass @abstractmethod def load(self, env): pass class TypeProviderBase: def __init__(self, type) -> None: self._type = type @abstractmethod def check(self, val): return True @abstractmethod def serialise(self, val): pass @abstractmethod def deserialise(self, val): pass @abstractmethod def parse_input(self, input_str): pass @abstractmethod def to_input(self, val): pass def allow_none(self): return False @staticmethod def typedef_matched(typedef): return False @abstractmethod def __str__(self) -> str: pass class Renderable: def __init__(self) -> None: pass @abstractmethod def render(self, rctx): pass class RenderContext: def __init__(self) -> None: pass @abstractmethod def add_expandable(self, label, node, on_expand_cb): pass @abstractmethod def add_field(self, label, node): pass class InteractiveRenderer(RenderContext): def __init__(self) -> None: super().__init__() @abstractmethod def render_loop(self): pass class LConfigBuiltin: def __init__(self, f, is_contextual, rename=None, caller_type=[]): self.name = f.__name__ if not rename else rename self.__f = f self.__contextual = is_contextual self.__caller_type = caller_type def __call__(self, env, *args, **kwds): if not self.__contextual: return self.__f(env, *args, **kwds) caller = env.callframe_at(0) f_name = self.__f.__name__ if not caller: raise ConfigLoadException( f"contextual function '{f_name}' can not be called contextless", None ) if self.__caller_type and not any([isinstance(caller, x) for x in self.__caller_type]): raise ConfigLoadException( f"caller of '{f_name}' ({caller}) must have type of any {self.__caller_type}", caller ) return self.__f(env, caller, *args, **kwds) def contextual(name=None, caller_type=[]): def wrapper(func): return LConfigBuiltin(func, True, name, caller_type) return wrapper def builtin(name=None): def wrapper(func): return LConfigBuiltin(func, False, name) return wrapper