diff options
Diffstat (limited to 'portato/plugin.py')
-rw-r--r-- | portato/plugin.py | 966 |
1 files changed, 483 insertions, 483 deletions
diff --git a/portato/plugin.py b/portato/plugin.py index befc06d..34004cb 100644 --- a/portato/plugin.py +++ b/portato/plugin.py @@ -29,524 +29,524 @@ from .backend import system from . import plugins as plugin_module class PluginLoadException (Exception): - """ - Exception signaling a failed plugin loading. - """ - pass + """ + Exception signaling a failed plugin loading. + """ + pass class Menu (object): - """ - One single menu entry. + """ + One single menu entry. - :IVariables: + :IVariables: - label : string - The label of the entry. Can have underscores to define the shortcut. + label : string + The label of the entry. Can have underscores to define the shortcut. - call - The function to call, if the entry is clicked. - """ - __slots__ = ("label", "call") + call + The function to call, if the entry is clicked. + """ + __slots__ = ("label", "call") - def __init__ (self, label, call): - self.label = label - self.call = call + def __init__ (self, label, call): + self.label = label + self.call = call class Call (object): - """ - This class represents an object, which is attached to a specified hook. + """ + This class represents an object, which is attached to a specified hook. - :IVariables: + :IVariables: - plugin : `Plugin` - The plugin where this call belongs to. + plugin : `Plugin` + The plugin where this call belongs to. - hook : string - The name of the corresponding hook. + hook : string + The name of the corresponding hook. - call - The function to call. + call + The function to call. - type : string - This is either ``before``, ``after`` or ``override`` and defines the type of the call: + type : string + This is either ``before``, ``after`` or ``override`` and defines the type of the call: - before - access before the original function - override - access *instead of* the original function. **USE THIS ONLY IF YOU KNOW WHAT YOU ARE DOING** - after - access after the original function has been called + before + access before the original function + override + access *instead of* the original function. **USE THIS ONLY IF YOU KNOW WHAT YOU ARE DOING** + after + access after the original function has been called - Default: ``before`` + Default: ``before`` - dep : string - This defines a plugin which should be executed after/before this one. - ``"*"`` means all and ``"-*"`` means none. - """ - __slots__ = ("plugin", "hook", "call", "type", "dep") + dep : string + This defines a plugin which should be executed after/before this one. + ``"*"`` means all and ``"-*"`` means none. + """ + __slots__ = ("plugin", "hook", "call", "type", "dep") - def __init__ (self, plugin, hook, call, type = "before", dep = None): - self.plugin = plugin - self.hook = hook - self.call = call - self.type = type - self.dep = dep + def __init__ (self, plugin, hook, call, type = "before", dep = None): + self.plugin = plugin + self.hook = hook + self.call = call + self.type = type + self.dep = dep class Hook (object): - """ - Representing a hook with all the `Call` s for the different types. - """ - - __slots__ = ("before", "override", "after") + """ + Representing a hook with all the `Call` s for the different types. + """ + + __slots__ = ("before", "override", "after") - def __init__ (self): - self.before = [] - self.override = None - self.after = [] + def __init__ (self): + self.before = [] + self.override = None + self.after = [] class Plugin (object): - """ - This is the main plugin object. It is used where ever a plugin is wanted, and it is the one, which needs to be subclassed by plugin authors. - - :CVariables: - - STAT_DISABLED : status - Status: Disabled. - - STAT_TEMP_ENABLED : status - Status: Enabled for this session only. - - STAT_ENABLED : status - Status: Enabled. - - STAT_TEMP_DISABLED : status - Status: Disabled for this session only. - - STAT_HARD_DISABLED : status - Status: Forced disabled by program (i.e. because of errors in the plugin). - """ - - (STAT_DISABLED, STAT_TEMP_ENABLED, STAT_ENABLED, STAT_TEMP_DISABLED) = range(4) - STAT_HARD_DISABLED = -1 - - def __init__ (self, disable = False): - """ - :param disable: Forcefully disable the plugin - :type disable: bool - """ - self.__menus = [] #: List of `Menu` - self.__calls = [] #: List of `Call` - self._unresolved_deps = False #: Does this plugin has unresolved dependencies? - - self.status = self.STAT_ENABLED #: The status of this plugin - - if disable: - self.status = self.STAT_HARD_DISABLED - - def _init (self): - """ - Method called from outside to init the extension parts of this plugin. - If the current status is `STAT_HARD_DISABLED` or there are unresolved dependencies, the init process is not started. - """ - - for d in self.deps: - if not system.find_packages(d, pkgSet=system.SET_INSTALLED, with_version = False): - self._unresolved_deps = True - break - - if self.status != self.STAT_HARD_DISABLED and not self._unresolved_deps: - self.init() - - def init (self): - """ - This method is called by `_init` and should be overriden by the plugin author. - - :precond: No unresolved deps and the status is not `STAT_HARD_DISABLED`. - """ - pass - - @property - def author (self): - """ - Returns the plugin's author. - The author is given by the ``__author__`` variable. - - :rtype: string - """ - return getattr(self, "__author__", "") - - @property - def description (self): - """ - Returns the description of this plugin. - It is given by either a ``__description__`` variable or by the normal class docstring. - - :rtype: string - """ - if hasattr(self, "__description__"): - return self.__description__ - else: - doc = getattr(self, "__doc__", "") - - if not doc or doc == Plugin.__doc__: - return "" - else: - return doc - - @property - def name (self): - """ - The name of the plugin. If no ``__name__`` variable is given, the class name is taken. - - :rtype: string - """ - return getattr(self, "__name__", self.__class__.__name__) - - @property - def menus (self): - """ - Returns an iterator over the menus for this plugin. - - :rtype: iter<`Menu`> - """ - return iter(self.__menus) - - @property - def calls (self): - """ - Returns an iterator over the registered calls for this plugin. - - :rtype: iter<`Call`> - """ - return iter(self.__calls) - - @property - def deps (self): - """ - Returns an iterator of the dependencies or ``[]`` if there are none. - The dependencies are given in the ``__dependency__`` variable. - - :rtype: [] or iter<string> - """ - if hasattr(self, "__dependency__"): - return iter(self.__dependency__) - else: - return [] - - @property - def enabled (self): - """ - Returns ``True`` if the plugin is enabled. - - :rtype: boolean - :see: `status` - """ - return (self.status in (self.STAT_ENABLED, self.STAT_TEMP_ENABLED)) - - def add_menu (self, label, callable): - """ - Adds a new menu item for this plugin. - - :see: `Menu` - """ - self.__menus.append(Menu(label, callable)) - - def add_call (self, hook, callable, type = "before", dep = None): - """ - Adds a new call for this plugin. - - :see: `Call` - """ - self.__calls.append(Call(self, hook, callable, type, dep)) + """ + This is the main plugin object. It is used where ever a plugin is wanted, and it is the one, which needs to be subclassed by plugin authors. + + :CVariables: + + STAT_DISABLED : status + Status: Disabled. + + STAT_TEMP_ENABLED : status + Status: Enabled for this session only. + + STAT_ENABLED : status + Status: Enabled. + + STAT_TEMP_DISABLED : status + Status: Disabled for this session only. + + STAT_HARD_DISABLED : status + Status: Forced disabled by program (i.e. because of errors in the plugin). + """ + + (STAT_DISABLED, STAT_TEMP_ENABLED, STAT_ENABLED, STAT_TEMP_DISABLED) = range(4) + STAT_HARD_DISABLED = -1 + + def __init__ (self, disable = False): + """ + :param disable: Forcefully disable the plugin + :type disable: bool + """ + self.__menus = [] #: List of `Menu` + self.__calls = [] #: List of `Call` + self._unresolved_deps = False #: Does this plugin has unresolved dependencies? + + self.status = self.STAT_ENABLED #: The status of this plugin + + if disable: + self.status = self.STAT_HARD_DISABLED + + def _init (self): + """ + Method called from outside to init the extension parts of this plugin. + If the current status is `STAT_HARD_DISABLED` or there are unresolved dependencies, the init process is not started. + """ + + for d in self.deps: + if not system.find_packages(d, pkgSet=system.SET_INSTALLED, with_version = False): + self._unresolved_deps = True + break + + if self.status != self.STAT_HARD_DISABLED and not self._unresolved_deps: + self.init() + + def init (self): + """ + This method is called by `_init` and should be overriden by the plugin author. + + :precond: No unresolved deps and the status is not `STAT_HARD_DISABLED`. + """ + pass + + @property + def author (self): + """ + Returns the plugin's author. + The author is given by the ``__author__`` variable. + + :rtype: string + """ + return getattr(self, "__author__", "") + + @property + def description (self): + """ + Returns the description of this plugin. + It is given by either a ``__description__`` variable or by the normal class docstring. + + :rtype: string + """ + if hasattr(self, "__description__"): + return self.__description__ + else: + doc = getattr(self, "__doc__", "") + + if not doc or doc == Plugin.__doc__: + return "" + else: + return doc + + @property + def name (self): + """ + The name of the plugin. If no ``__name__`` variable is given, the class name is taken. + + :rtype: string + """ + return getattr(self, "__name__", self.__class__.__name__) + + @property + def menus (self): + """ + Returns an iterator over the menus for this plugin. + + :rtype: iter<`Menu`> + """ + return iter(self.__menus) + + @property + def calls (self): + """ + Returns an iterator over the registered calls for this plugin. + + :rtype: iter<`Call`> + """ + return iter(self.__calls) + + @property + def deps (self): + """ + Returns an iterator of the dependencies or ``[]`` if there are none. + The dependencies are given in the ``__dependency__`` variable. + + :rtype: [] or iter<string> + """ + if hasattr(self, "__dependency__"): + return iter(self.__dependency__) + else: + return [] + + @property + def enabled (self): + """ + Returns ``True`` if the plugin is enabled. + + :rtype: boolean + :see: `status` + """ + return (self.status in (self.STAT_ENABLED, self.STAT_TEMP_ENABLED)) + + def add_menu (self, label, callable): + """ + Adds a new menu item for this plugin. + + :see: `Menu` + """ + self.__menus.append(Menu(label, callable)) + + def add_call (self, hook, callable, type = "before", dep = None): + """ + Adds a new call for this plugin. + + :see: `Call` + """ + self.__calls.append(Call(self, hook, callable, type, dep)) class PluginQueue (object): - """ - Class managing and loading the plugins. - - :IVariables: - - plugins : `Plugin` [] - The list of managed plugins. - - hooks : string -> `Hook` - For each hook name map to a `Hook` object holding the corresponding `Call` objects. - """ - - def __init__ (self): - """ - Constructor. - """ - - self.plugins = [] - self.hooks = defaultdict(Hook) - - def get_plugins (self, list_disabled = True): - """ - Returns the plugins. - - :param list_disabled: Also list disabled plugins. - :type list_disabled: boolean - - :rtype: iter<`Plugin`> - """ - return (x for x in self.plugins if (x.enabled or list_disabled)) - - def load (self): - """ - Load the plugins. - - This method scans the `portato.constants.PLUGIN_DIR` for python modules and tries to load them. If the modules are real plugins, - they have called `register` and thus the plugins are added. - """ - - # look them up - plugins = [] - for f in os.listdir(PLUGIN_DIR): - path = osp.join(PLUGIN_DIR, f) - if osp.isdir(path): - if osp.isfile(osp.join(path, "__init__.py")): - plugins.append(f) - else: - debug("'%s' is not a plugin: __init__.py missing", path) - else: - if f.endswith(".py"): - plugins.append(f[:-3]) - elif f.endswith(".pyc") or f.endswith(".pyo"): - pass # ignore .pyc and .pyo - else: - debug("'%s' is not a plugin: not a .py file", path) - - # some magic ... - plugin_module.__path__.insert(0, PLUGIN_DIR.rstrip("/")) # make the plugins loadable as "portato.plugins.name" - # add Plugin and register to the builtins, so the plugins always have the correct version :) - plugin_module.__builtins__["Plugin"] = Plugin - plugin_module.__builtins__["register"] = register - - for p in plugins: # import them - try: - exec "from portato.plugins import %s" % p in {} - except PluginLoadException, e: - error(_("Loading plugin '%(plugin)s' failed: %(error)s"), {"plugin" : p, "error" : e.message}) - except: - tb = traceback.format_exc() - error(_("Loading plugin '%(plugin)s' failed: %(error)s"), {"plugin" : p, "error" : tb}) - - self._organize() - - def add (self, plugin, disable = False): - """ - Adds a plugin to the internal list. - - :Parameters: - - plugin : `Plugin` - ``Plugin`` subclass or instance to add. If a class is passed, it is instantiated. - - disable : boolean - Disable the plugin. - - :raise PluginLoadException: passed plugin is not of class `Plugin` - """ - - if callable(plugin) and Plugin in plugin.__bases__: - p = plugin(disable = disable) # need an instance and not the class - elif isinstance(plugin, Plugin): - p = plugin - if disable: - p.status = p.STAT_HARD_DISABLED - else: - raise PluginLoadException, "Is neither a subclass nor an instance of Plugin." - - p._init() - - self.plugins.append(p) - - if p.status == p.STAT_HARD_DISABLED: - msg = _("Plugin is disabled!") - elif p._unresolved_deps: - msg = _("Plugin has unresolved dependencies - disabled!") - else: - msg = "" - - info("%s %s", _("Plugin '%s' loaded.") % p.name, msg) - - def hook (self, hook, *hargs, **hkwargs): - """ - The decorator to use in the program. - All parameters except ``hook`` are passed to plugins. - - :param hook: the name of the hook - :type hook: string - """ - - def hook_decorator (func): - """ - The real decorator. - """ - h = self.hooks[hook] - - active = Hook() - - # remove disabled - for type in ("before", "after"): - calls = getattr(h, type) - aCalls = getattr(active, type) - for call in calls: - if call.plugin.enabled: - aCalls.append(call) - - if h.override and h.override.plugin.enabled: - active.override = h.override - - @wraps(func) - def wrapper (*args, **kwargs): - ret = None - - # before - for call in active.before: - debug("Accessing hook '%(hook)s' of plugin '%(plugin)s' (before).", {"hook" : hook, "plugin": call.plugin.name}) - call.call(*hargs, **hkwargs) - - if active.override: # override - info(_("Overriding hook '%(hook)s' with plugin '%(plugin)s'."), {"hook": hook, "plugin": active.override.plugin.name}) - ret = active.override.call(*hargs, **hkwargs) - else: # normal - ret = func(*args, **kwargs) - - # after - for call in active.after: - debug("Accessing hook '%(hook)s' of plugin '%(plugin)s' (after).", {"hook": hook, "plugin": call.plugin.name}) - call.call(*hargs, **hkwargs) - - return ret - - return wrapper - - return hook_decorator - - def _organize (self): - """ - Organizes the lists of `Call` in a way, that all dependencies are fullfilled. - """ - unresolved_before = defaultdict(list) - unresolved_after = defaultdict(list) - star_before = defaultdict(Hook) # should be _before_ all other - star_after = defaultdict(Hook) # should be _after_ all other - - for plugin in self.plugins: # plugins - for call in plugin.calls: # hooks in plugin - if call.type == "before": - if call.dep is None: # no dependency -> straight add - self.hooks[call.hook].before.append(call) - elif call.dep == "*": - self.hooks[call.hook].before.insert(0, call) - elif call.dep == "-*": - star_before[call.hook].append(call) - else: - named = [x.plugin.name for x in self.hooks[call.hook].before] - if call.dep in named: - self.hooks[call.hook].before.insert(named.index(call.dep), call) - else: - unresolved_before[call.hook].append(call) - - elif call.type == "after": - if call.dep is None: # no dependency -> straight add - self.hooks[call.hook].after.append(call) - elif call.dep == "*": - star_after[call.hook].append(call) - elif call.dep == "-*": - self.hooks[call.hook].after.insert(0, call) - else: - named = [x.plugin.name for x in self.hooks[call.hook].after] - if call.dep in named: - self.hooks[call.hook].after.insert(named.index(call.dep)+1, call) - else: - unresolved_after[call.hook].append(call) - - # type = "override" - elif call.type == "override": - if self.hooks[call.hook].override: - warning(_("For hook '%(hook)s' an override is already defined by plugin '%(plugin)s'!"), {"hook": call.hook, "plugin": self.hooks[call.hook].override.plugin.name}) - warning(_("It is now replaced by the one from plugin '%s'!"), call.plugin.name) - - self.hooks[call.hook].override = call - continue - - self._resolve_unresolved(unresolved_before, unresolved_after) - - for hook, calls in star_before.iteritems(): - self.hooks[hook].before.extend(calls) # append the list - - for hook, calls in star_after.iteritems(): - self.hooks[hook].after.extend(calls) # append the list - - - def _resolve_unresolved (self, before, after): - def resolve(hook, list, type, add): - if not list: - return - - callList = getattr(self.hooks[hook], type) - named = [x.plugin.name for x in callList] - - while list and named: - newNamed = [] # use newNamed, so in each iteration only the plugins inserted last are searched - for call in list[:]: - if call.dep in named: - callList.insert(named.index(call.dep)+add, call) - list.remove(call) - newNamed.append(call.plugin.name) - - named = newNamed - - for l in list: - callList.append(l) - info(_("Dependant '%(dep)s' for '%(hook)s' in plugin '%(plugin)s' not found! Adding nevertheless."), {"hook": hook, "plugin": l.plugin.name, "dep": l.dep}) - - for hook in before: - resolve(hook, before[hook], "before", 0) - - for hook in after: - resolve(hook, after[hook], "after", 1) + """ + Class managing and loading the plugins. + + :IVariables: + + plugins : `Plugin` [] + The list of managed plugins. + + hooks : string -> `Hook` + For each hook name map to a `Hook` object holding the corresponding `Call` objects. + """ + + def __init__ (self): + """ + Constructor. + """ + + self.plugins = [] + self.hooks = defaultdict(Hook) + + def get_plugins (self, list_disabled = True): + """ + Returns the plugins. + + :param list_disabled: Also list disabled plugins. + :type list_disabled: boolean + + :rtype: iter<`Plugin`> + """ + return (x for x in self.plugins if (x.enabled or list_disabled)) + + def load (self): + """ + Load the plugins. + + This method scans the `portato.constants.PLUGIN_DIR` for python modules and tries to load them. If the modules are real plugins, + they have called `register` and thus the plugins are added. + """ + + # look them up + plugins = [] + for f in os.listdir(PLUGIN_DIR): + path = osp.join(PLUGIN_DIR, f) + if osp.isdir(path): + if osp.isfile(osp.join(path, "__init__.py")): + plugins.append(f) + else: + debug("'%s' is not a plugin: __init__.py missing", path) + else: + if f.endswith(".py"): + plugins.append(f[:-3]) + elif f.endswith(".pyc") or f.endswith(".pyo"): + pass # ignore .pyc and .pyo + else: + debug("'%s' is not a plugin: not a .py file", path) + + # some magic ... + plugin_module.__path__.insert(0, PLUGIN_DIR.rstrip("/")) # make the plugins loadable as "portato.plugins.name" + # add Plugin and register to the builtins, so the plugins always have the correct version :) + plugin_module.__builtins__["Plugin"] = Plugin + plugin_module.__builtins__["register"] = register + + for p in plugins: # import them + try: + exec "from portato.plugins import %s" % p in {} + except PluginLoadException, e: + error(_("Loading plugin '%(plugin)s' failed: %(error)s"), {"plugin" : p, "error" : e.message}) + except: + tb = traceback.format_exc() + error(_("Loading plugin '%(plugin)s' failed: %(error)s"), {"plugin" : p, "error" : tb}) + + self._organize() + + def add (self, plugin, disable = False): + """ + Adds a plugin to the internal list. + + :Parameters: + + plugin : `Plugin` + ``Plugin`` subclass or instance to add. If a class is passed, it is instantiated. + + disable : boolean + Disable the plugin. + + :raise PluginLoadException: passed plugin is not of class `Plugin` + """ + + if callable(plugin) and Plugin in plugin.__bases__: + p = plugin(disable = disable) # need an instance and not the class + elif isinstance(plugin, Plugin): + p = plugin + if disable: + p.status = p.STAT_HARD_DISABLED + else: + raise PluginLoadException, "Is neither a subclass nor an instance of Plugin." + + p._init() + + self.plugins.append(p) + + if p.status == p.STAT_HARD_DISABLED: + msg = _("Plugin is disabled!") + elif p._unresolved_deps: + msg = _("Plugin has unresolved dependencies - disabled!") + else: + msg = "" + + info("%s %s", _("Plugin '%s' loaded.") % p.name, msg) + + def hook (self, hook, *hargs, **hkwargs): + """ + The decorator to use in the program. + All parameters except ``hook`` are passed to plugins. + + :param hook: the name of the hook + :type hook: string + """ + + def hook_decorator (func): + """ + The real decorator. + """ + h = self.hooks[hook] + + active = Hook() + + # remove disabled + for type in ("before", "after"): + calls = getattr(h, type) + aCalls = getattr(active, type) + for call in calls: + if call.plugin.enabled: + aCalls.append(call) + + if h.override and h.override.plugin.enabled: + active.override = h.override + + @wraps(func) + def wrapper (*args, **kwargs): + ret = None + + # before + for call in active.before: + debug("Accessing hook '%(hook)s' of plugin '%(plugin)s' (before).", {"hook" : hook, "plugin": call.plugin.name}) + call.call(*hargs, **hkwargs) + + if active.override: # override + info(_("Overriding hook '%(hook)s' with plugin '%(plugin)s'."), {"hook": hook, "plugin": active.override.plugin.name}) + ret = active.override.call(*hargs, **hkwargs) + else: # normal + ret = func(*args, **kwargs) + + # after + for call in active.after: + debug("Accessing hook '%(hook)s' of plugin '%(plugin)s' (after).", {"hook": hook, "plugin": call.plugin.name}) + call.call(*hargs, **hkwargs) + + return ret + + return wrapper + + return hook_decorator + + def _organize (self): + """ + Organizes the lists of `Call` in a way, that all dependencies are fullfilled. + """ + unresolved_before = defaultdict(list) + unresolved_after = defaultdict(list) + star_before = defaultdict(Hook) # should be _before_ all other + star_after = defaultdict(Hook) # should be _after_ all other + + for plugin in self.plugins: # plugins + for call in plugin.calls: # hooks in plugin + if call.type == "before": + if call.dep is None: # no dependency -> straight add + self.hooks[call.hook].before.append(call) + elif call.dep == "*": + self.hooks[call.hook].before.insert(0, call) + elif call.dep == "-*": + star_before[call.hook].append(call) + else: + named = [x.plugin.name for x in self.hooks[call.hook].before] + if call.dep in named: + self.hooks[call.hook].before.insert(named.index(call.dep), call) + else: + unresolved_before[call.hook].append(call) + + elif call.type == "after": + if call.dep is None: # no dependency -> straight add + self.hooks[call.hook].after.append(call) + elif call.dep == "*": + star_after[call.hook].append(call) + elif call.dep == "-*": + self.hooks[call.hook].after.insert(0, call) + else: + named = [x.plugin.name for x in self.hooks[call.hook].after] + if call.dep in named: + self.hooks[call.hook].after.insert(named.index(call.dep)+1, call) + else: + unresolved_after[call.hook].append(call) + + # type = "override" + elif call.type == "override": + if self.hooks[call.hook].override: + warning(_("For hook '%(hook)s' an override is already defined by plugin '%(plugin)s'!"), {"hook": call.hook, "plugin": self.hooks[call.hook].override.plugin.name}) + warning(_("It is now replaced by the one from plugin '%s'!"), call.plugin.name) + + self.hooks[call.hook].override = call + continue + + self._resolve_unresolved(unresolved_before, unresolved_after) + + for hook, calls in star_before.iteritems(): + self.hooks[hook].before.extend(calls) # append the list + + for hook, calls in star_after.iteritems(): + self.hooks[hook].after.extend(calls) # append the list + + + def _resolve_unresolved (self, before, after): + def resolve(hook, list, type, add): + if not list: + return + + callList = getattr(self.hooks[hook], type) + named = [x.plugin.name for x in callList] + + while list and named: + newNamed = [] # use newNamed, so in each iteration only the plugins inserted last are searched + for call in list[:]: + if call.dep in named: + callList.insert(named.index(call.dep)+add, call) + list.remove(call) + newNamed.append(call.plugin.name) + + named = newNamed + + for l in list: + callList.append(l) + info(_("Dependant '%(dep)s' for '%(hook)s' in plugin '%(plugin)s' not found! Adding nevertheless."), {"hook": hook, "plugin": l.plugin.name, "dep": l.dep}) + + for hook in before: + resolve(hook, before[hook], "before", 0) + + for hook in after: + resolve(hook, after[hook], "after", 1) __plugins = None def load_plugins(): - """ - Loads the plugins. - """ - - global __plugins - if __plugins is None: - __plugins = PluginQueue() - __plugins.load() - + """ + Loads the plugins. + """ + + global __plugins + if __plugins is None: + __plugins = PluginQueue() + __plugins.load() + def get_plugin_queue(): - """ - Returns the actual `PluginQueue`. If it is ``None``, they are not being loaded yet. + """ + Returns the actual `PluginQueue`. If it is ``None``, they are not being loaded yet. - :rtype: `PluginQueue` or ``None``""" - return __plugins + :rtype: `PluginQueue` or ``None``""" + return __plugins def hook(hook, *args, **kwargs): - """ - Shortcut to `PluginQueue.hook`. If no `PluginQueue` is loaded, this does nothing. - """ - if __plugins is None: - def pseudo_decorator(f): - return f - return pseudo_decorator - else: - return __plugins.hook(hook, *args, **kwargs) + """ + Shortcut to `PluginQueue.hook`. If no `PluginQueue` is loaded, this does nothing. + """ + if __plugins is None: + def pseudo_decorator(f): + return f + return pseudo_decorator + else: + return __plugins.hook(hook, *args, **kwargs) def register (plugin, disable = False): - """ - Registers a plugin. + """ + Registers a plugin. - :see: `PluginQueue.add` - """ - if __plugins is not None: - __plugins.add(plugin, disable) + :see: `PluginQueue.add` + """ + if __plugins is not None: + __plugins.add(plugin, disable) |