stop (ab)using __subclasses__ isntead interrogating the imported plugin modules for a predefined list of the plugin classes they contain, and always instantiate them when they are imported. Add a test plugin only useful for doctest

This commit is contained in:
Chris Jones 2009-12-17 13:51:55 +00:00
parent 9029e519f9
commit 01bb454d90
3 changed files with 29 additions and 11 deletions

View File

@ -4,11 +4,18 @@
"""plugin.py - Base plugin system """plugin.py - Base plugin system
>>> registry = PluginRegistry() >>> registry = PluginRegistry()
>>> registry.instances
{}
>>> registry.load_plugins() >>> registry.load_plugins()
>>> registry.get_plugins_by_capability('test') >>> plugins = registry.get_plugins_by_capability('test')
[<testplugin.TestPlugin object at ...>] >>> len(plugins)
1
>>> plugins[0] #doctest: +ELLIPSIS
<testplugin.TestPlugin object at 0x...>
>>> registry.get_plugins_by_capability('this_should_not_ever_exist') >>> registry.get_plugins_by_capability('this_should_not_ever_exist')
[] []
>>> plugins[0].do_test()
'TestPluginWin'
""" """
@ -50,12 +57,16 @@ class PluginRegistry(borg.Borg):
sys.path.insert(0, self.path) sys.path.insert(0, self.path)
files = os.listdir(self.path) files = os.listdir(self.path)
for plugin in files: for plugin in files:
if os.path.isfile(os.path.join(self.path, plugin)) and \ pluginpath = os.path.join(self.path, plugin)
plugin[-3:] == '.py': if os.path.isfile(pluginpath) and plugin[-3:] == '.py':
dbg('PluginRegistry::load_plugins: Importing plugin %s' % dbg('PluginRegistry::load_plugins: Importing plugin %s' %
plugin) plugin)
try: try:
__import__(plugin[:-3], None, None, ['']) module = __import__(plugin[:-3], None, None, [''])
for item in getattr(module, 'available'):
if item not in self.instances:
func = getattr(module, item)
self.instances[item] = func()
except Exception as e: except Exception as e:
err('PluginRegistry::load_plugins: Importing plugin %s \ err('PluginRegistry::load_plugins: Importing plugin %s \
failed: %s' % (plugin, e)) failed: %s' % (plugin, e))
@ -64,17 +75,19 @@ failed: %s' % (plugin, e))
"""Return a list of plugins with a particular capability""" """Return a list of plugins with a particular capability"""
result = [] result = []
dbg('PluginRegistry::get_plugins_by_capability: searching %d plugins \ dbg('PluginRegistry::get_plugins_by_capability: searching %d plugins \
for %s' % (len(Plugin.__subclasses__()), capability)) for %s' % (len(self.instances), capability))
for plugin in Plugin.__subclasses__(): for plugin in self.instances:
if capability in plugin.capabilities: if capability in self.instances[plugin].capabilities:
if not plugin in self.instances:
self.instances[plugin] = plugin()
result.append(self.instances[plugin]) result.append(self.instances[plugin])
return result return result
def get_all_plugins(self):
"""Return all plugins"""
return(self.instances)
if __name__ == '__main__': if __name__ == '__main__':
import doctest import doctest
sys.path.insert(0, 'plugins') sys.path.insert(0, 'plugins')
import testplugin
(failed, attempted) = doctest.testmod() (failed, attempted) = doctest.testmod()
print "%d/%d tests failed" % (failed, attempted) print "%d/%d tests failed" % (failed, attempted)

View File

@ -1,5 +1,8 @@
import plugin import plugin
# available must contain a list of all the classes that you want exposed
available = ['TestPlugin']
class TestPlugin(plugin.Plugin): class TestPlugin(plugin.Plugin):
capabilities = ['test'] capabilities = ['test']

View File

@ -1,5 +1,7 @@
import plugin import plugin
available = ['LaunchpadURLHandler']
class LaunchpadURLHandler(plugin.Plugin): class LaunchpadURLHandler(plugin.Plugin):
capabilities = ['url_handler'] capabilities = ['url_handler']