Plugin Framework

 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. Method Caching by bryanhelmig 2 years, 9 months ago
  2. HTTP (basic) auth enabled (new-style) syndication framework feed class by hupf 3 years, 4 months ago
  3. SectionedForm by marinho 5 years, 10 months ago
  4. Using descriptors for lazy attribute caching by djypsy 6 years, 8 months ago
  5. EasyFeed class by limodou 7 years, 1 month 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 !!

#

(Forgotten your password?)