Handle loading plugins on demand.

Plugins that are referenced as dependencies, but have not been
registered now will be imported. Newer plugins should register
themselves automatically, but older style plugins will be
explicitly registered after import.
This commit is contained in:
Lance Stout 2012-03-12 09:43:24 -07:00
parent 9d645ad5cd
commit f8f2b541db
3 changed files with 46 additions and 33 deletions

View file

@ -32,7 +32,7 @@ from sleekxmpp.xmlstream.matcher import MatchXPath
from sleekxmpp.xmlstream.handler import Callback from sleekxmpp.xmlstream.handler import Callback
from sleekxmpp.features import * from sleekxmpp.features import *
from sleekxmpp.plugins import PluginManager, register_plugin from sleekxmpp.plugins import PluginManager, register_plugin, load_plugin
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -218,34 +218,7 @@ class BaseXMPP(XMLStream):
pconfig = self.plugin_config.get(plugin, {}) pconfig = self.plugin_config.get(plugin, {})
if not self.plugin.registered(plugin): if not self.plugin.registered(plugin):
# Use old-style plugin load_plugin(plugin, module)
try:
#Import the given module that contains the plugin.
if not module:
try:
module = sleekxmpp.plugins
module = __import__(
str("%s.%s" % (module.__name__, plugin)),
globals(), locals(), [str(plugin)])
except ImportError:
module = sleekxmpp.features
module = __import__(
str("%s.%s" % (module.__name__, plugin)),
globals(), locals(), [str(plugin)])
if isinstance(module, str):
# We probably want to load a module from outside
# the sleekxmpp package, so leave out the globals().
module = __import__(module, fromlist=[plugin])
plugin_class = getattr(module, plugin)
if not hasattr(plugin_class, 'name'):
plugin_class.name = plugin
register_plugin(plugin_class, name=plugin)
except:
log.exception("Unable to load plugin: %s", plugin)
return
self.plugin.enable(plugin, pconfig) self.plugin.enable(plugin, pconfig)
def register_plugins(self): def register_plugins(self):

View file

@ -6,8 +6,9 @@
See the file LICENSE for copying permission. See the file LICENSE for copying permission.
""" """
from sleekxmpp.plugins.base import PluginManager, PluginNotFound, \ from sleekxmpp.plugins.base import PluginManager, PluginNotFound, BasePlugin
BasePlugin, register_plugin from sleekxmpp.plugins.base import register_plugin, load_plugin
__all__ = [ __all__ = [
# Non-standard # Non-standard

View file

@ -33,6 +33,10 @@ PLUGIN_DEPENDENTS = {}
REGISTRY_LOCK = threading.RLock() REGISTRY_LOCK = threading.RLock()
class PluginNotFound(Exception):
"""Raised if an unknown plugin is accessed."""
def register_plugin(impl, name=None): def register_plugin(impl, name=None):
"""Add a new plugin implementation to the registry. """Add a new plugin implementation to the registry.
@ -56,8 +60,40 @@ def register_plugin(impl, name=None):
PLUGIN_DEPENDENTS[dep].add(name) PLUGIN_DEPENDENTS[dep].add(name)
class PluginNotFound(Exception): def load_plugin(name, module=None):
"""Raised if an unknown plugin is accessed.""" """Find and import a plugin module so that it can be registered.
This function is called to import plugins that have selected for
enabling, but no matching registered plugin has been found.
:param str name: The name of the plugin. It is expected that
plugins are in packages matching their name,
even though the plugin class name does not
have to match.
:param str module: The name of the base module to search
for the plugin.
"""
try:
if not module:
try:
module = 'sleekxmpp.plugins.%s' % name
mod = __import__(module, fromlist=[str(name)])
except:
module = 'sleekxmpp.features.%s' % name
mod = __import__(module, fromlist=[str(name)])
else:
mod = __import__(module, fromlist=[str(name)])
# Add older style plugins to the registry.
if hasattr(mod, name):
plugin = getattr(mod, name)
if not hasattr(plugin, 'name'):
plugin.name = name
register_plugin(plugin, name)
else:
log.debug("%s does not have %s", mod, name)
except:
log.exception("Unable to load plugin: %s", name)
class PluginManager(object): class PluginManager(object):
@ -105,6 +141,9 @@ class PluginManager(object):
if name not in self._enabled: if name not in self._enabled:
enabled.add(name) enabled.add(name)
self._enabled.add(name) self._enabled.add(name)
if not self.registered(name):
load_plugin(name)
plugin_class = PLUGIN_REGISTRY.get(name, None) plugin_class = PLUGIN_REGISTRY.get(name, None)
if not plugin_class: if not plugin_class:
raise PluginNotFound(name) raise PluginNotFound(name)