Login

Plugin Framework

Author:
Gulopine
Posted:
January 10, 2008
Language:
Python
Version:
.96
Tags:
plugins
Score:
16 (after 16 ratings)

This is a very basic -- yet fully functional -- framework for producing a loosely coupled plugin architecture. Full details of its use can be found on my blog, but the basics are listed below.

Defining a mount point for plugins

class ActionProvider:
    __metaclass__ = PluginMount

Implementing plugins

class Insert(ActionProvider):
    def perform(self):
        # Do stuff here

class Update(ActionProvider):
    def perform(self):
        # Do stuff here

Utilizing plugins

for action in ActionProvider.plugins:
    action.perform()

Yes, it really is that simple.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class PluginMount(type):
    def __init__(cls, name, bases, attrs):
        if not hasattr(cls, 'plugins'):
            # This branch only executes when processing the mount point itself.
            # So, since this is a new plugin type, not an implementation, this
            # class shouldn't be registered as a plugin. Instead, it sets up a
            # list where plugins can be registered later.
            cls.plugins = []
        else:
            # This must be a plugin implementation, which should be registered.
            # Simply appending it to the list is all that's needed to keep
            # track of it later.
            cls.plugins.append(cls)

More like this

Comments

jezdez (on January 22, 2009):
<p>This is just unbelievable awesome. Great snippet and weblog post!</p>

#

mattjvincent (on August 26, 2010):
<p>Help...</p> <p>I received this error:</p> <pre>TypeError: unbound method perform() must be called with Insert instance as first argument (got nothing instead) </pre> <p>Here is the code....</p> <pre>class PluginMount(type): def __init__(cls, name, bases, attrs): if not hasattr(cls, 'plugins'): cls.plugins = [] else: cls.plugins.append(cls) class ActionProvider(object): __metaclass__ = PluginMount class Insert(ActionProvider): def perform(self): print 'Insert' class Update(ActionProvider): def perform(self): print 'Update' if __name__ == '__main__': for action in ActionProvider.plugins: action.perform() </pre>

#

ffsffd (on April 27, 2011):
<p>This is a little late, but just informational for everyone else.</p> <p>The poster above me encountered the error because action (which is a class), is not being instantiated first.</p> <p>So the fix is: if name == 'main': for action in ActionProvider.plugins: action().perform()</p> <p>Really simple. :) And this idea really rocks.</p>

#

ffsffd (on April 27, 2011):
<p>Oops, here's the code again, correctly formatted.</p> <pre>if __name__ == '__main__': for action in ActionProvider.plugins: action().perform() </pre>

#

eagleamon (on August 1, 2012):
<p>Hi, really nice and neat solution. Just a thing, I don't see a way to do this if your plugins are defined in different module files without having to look for them somewhere. Just an example:</p> <p>main.py plugins/ metaclass.py plugin.py init.py plugin1.py plugin2.py etc..</p> <p>and in init.py: all = [p for p in glob.glob(....)...]</p> <p>which quite destroy the benefit not to look for anything. Am I missing something ?</p> <p>Thanks for the idea anyway !!</p>

#

Please login first before commenting.