from abc import ABCMeta, abstractmethod import json from website_generator.utils import Registry class ActionMetaclass(ABCMeta): def __new__(cls, name, *args, **kwargs): newclass = ABCMeta.__new__(cls, name, *args, **kwargs) if name != 'Action': register(newclass) return newclass class Action(metaclass=ActionMetaclass): def __init__(self, **params): for name, value in params.items(): setattr(self, name, value) @abstractmethod def __call__(self): pass class ActionRegistry(Registry): def check_key(self, key): assert isinstance(key, str), 'Action type must be a string.' def check_value(self, value): assert callable(value), 'Action must be a callable.' def register(self, key, value=None): """ Register a generator action. May be used a register(action) if the action has a defined type (using the action.type attribute), or as register(type, action) or register(action, type) to set a custom type. """ if value: try: # Try register(type, action) return super().register(key, value) except (KeyError, ValueError): # Try register(action, type) try: return super().register(value, key) except (KeyError, ValueError): pass raise if not getattr(key, 'type', None): raise KeyError( 'Action does not have a type. ' 'Set the type attribute or use register(type, action)' ) return super().register(key.type, key) registry = ActionRegistry() register = registry.register unregister = registry.unregister class DebugAction(Action): """ A simple action that prints its execution context, for debugging purposes. """ type = 'debug' def __call__(self): def _default(obj): if hasattr(obj, '__dict__'): return vars(obj) try: return dict(obj) except Exception: return str(obj) print(json.dumps(vars(self), default=_default, indent=4))