I have written a simple system to load plugins from files in Python 2.7, and I'd like to see if any of it can be improved upon.
vedo.py
from __future__ import absolute_import
import os.path
import inspect
from vedo.event_emitter import EventEmitter
from vedo import VedoPlugin
def _get_module_name(directory, filename):
return '{0}.{1}'.format(os.path.basename(directory), filename)
def _is_plugin_class(plugin_class):
return (inspect.isclass(plugin_class) and
issubclass(plugin_class, VedoPlugin) and
plugin_class != VedoPlugin)
class Vedo(EventEmitter):
def __init__(self, plugin_directory):
self._plugin_directory = plugin_directory
self._plugins = []
@property
def plugin_directory(self):
return self._plugin_directory
@property
def plugins(self):
return self._plugins
def load_module(self, module):
plugin_classes = [c for c in module.__dict__.values() if
_is_plugin_class(c)]
for plugin_class in plugin_classes:
self.plugins.append(plugin_class(self))
def load_file(self, name):
try:
plugin_module = _get_module_name(self._plugin_directory, name)
namespace = __import__(plugin_module)
except ImportError:
return
self.load_module(getattr(namespace, name))
Each plugin must inherit from VedoPlugin
, and is loaded by the Vedo
class.
Here's an example plugin:
plugins/first.py
class MyFirstPlugin(VedoPlugin):
def __init__(self, vedo):
super(MyFirstPlugin, self).__init__(vedo)
And a quick example of how to use Vedo:
vedo = Vedo("./plugins")
vedo.load_file("first")
vedo.plugins[0] # This is an instance of `MyFirstPlugin'
Here's some things I'm not too fond of, but I'm not sure what I can do about them:
- Should the private functions in the top of
vedo.py
be moved inside theVedo
class? - Should
load_module
be private? It's only really going to be used when loading files. - Is there a way to get around the ugliness that is the plugin
__init__
function? Every single plugin will need to have that constructor, which I'm not too happy about.