1 from functools import wraps 2 3 4 class _PluginManager: 5 def __init__(self): 6 self._registered_plugins = [] 7 self._cached_base_callbacks = {} 8 self._built_functions = {} 9 10 def register(self, *plugins): 11 """ 12 Makes it possible to register your plugin. 13 """ 14 self._registered_plugins.extend(plugins) 15 self._build_functions() 16 17 def decorate(self, name=None): 18 def decorator(callback): 19 @wraps(callback) 20 def wrapper(*args, **kwargs): 21 return built_functions[public_name](*args, **kwargs) 22 23 public_name = name or callback.__name__ 24 25 assert public_name not in self._built_functions 26 built_functions = self._built_functions 27 built_functions[public_name] = callback 28 self._cached_base_callbacks[public_name] = callback 29 30 return wrapper 31 32 return decorator 33 34 def _build_functions(self): 35 for name, callback in self._cached_base_callbacks.items(): 36 for plugin in reversed(self._registered_plugins): 37 # Need to reverse so the first plugin is run first. 38 try: 39 func = getattr(plugin, name) 40 except AttributeError: 41 pass 42 else: 43 callback = func(callback) 44 self._built_functions[name] = callback 45 46 47 plugin_manager = _PluginManager() 48