Login

Plugin Framework

Author:
Gulopine
Posted:
January 10, 2008
Language:
Python
Version:
.96
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

  1. Template tag - list punctuation for a list of items by shapiromatron 2 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 2 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 9 months, 2 weeks ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 10 months, 1 week ago
  5. Help text hyperlinks by sa2812 11 months ago

Comments

jezdez (on January 22, 2009):

This is just unbelievable awesome. Great snippet and weblog post!

#

mattjvincent (on August 26, 2010):

Help...

I received this error:

TypeError: unbound method perform() must be called with Insert instance as first argument (got nothing instead)

Here is the code....

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()

#

ffsffd (on April 27, 2011):

This is a little late, but just informational for everyone else.

The poster above me encountered the error because action (which is a class), is not being instantiated first.

So the fix is: if name == 'main': for action in ActionProvider.plugins: action().perform()

Really simple. :) And this idea really rocks.

#

ffsffd (on April 27, 2011):

Oops, here's the code again, correctly formatted.

if __name__ == '__main__':
    for action in ActionProvider.plugins:
        action().perform()

#

eagleamon (on August 1, 2012):

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:

main.py plugins/ metaclass.py plugin.py init.py plugin1.py plugin2.py etc..

and in init.py: all = [p for p in glob.glob(....)...]

which quite destroy the benefit not to look for anything. Am I missing something ?

Thanks for the idea anyway !!

#

Please login first before commenting.