1from functools import wraps
2
3
4class _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
47plugin_manager = _PluginManager()