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. New Snippet! by Antoliny0919 4 days, 20 hours ago
  2. Add Toggle Switch Widget to Django Forms by OgliariNatan 2 months, 3 weeks ago
  3. get_object_or_none by azwdevops 6 months, 2 weeks ago
  4. Mask sensitive data from logger by agusmakmun 8 months, 1 week ago
  5. Template tag - list punctuation for a list of items by shapiromatron 1 year, 10 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.