472,325 Members | 1,400 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,325 software developers and data experts.

Creating (rather) generic plugin framework?

Hi,

My idea is to create a system working as follows: each module knows
path to plugin directory, and that directory contains modules which
may add hooks to some points in the code.

Inspired by http://www.python.org/pycon/2005/pap...onHooking.html

I would create a class like this:

class Printer:

def printit(self, msg):
stuff = self.beforePrintHook(msg)
if stuff:
msg = stuff
print msg
self.afterPrintHook(msg)

def beforePrintHook(self, msg): pass
def afterPrintHook(self, msg): pass

Now, in the spirit of py.test, I'd like API to be practically no API at all :)
moreover, deploying a plugin must consist simply of adding appropriate file to
plugins directory, nothing more, and removing it would uninstall it. The
plugin should be able to somehow result in all future invocations to
Printer.printit() call hooks specified in the plugin. Now, the plugin module
for class above /might/ be along the following lines (I'm thinking of stuff
here, so I don't know yet what would be the most appropriate way):

### a very simple plugin which uppercases all data fed to it.

extensions = {'Printer': 'PrinterHook'}

class PrinterHook:

def beforePrintHook(self, msg):
return msg.upper()
def afterPrintHook(self, msg):
print "Called afterPrintHook with msg %s" % msg
Now, I have a very rude (I think) implementation which has two methods, first
the one that loads plugin modules:

def find_plugins():
mods = [mod for mod in os.listdir(PLUGIN_DIR) if mod.endswith('.py')]

# for each module in plugin dir, import the module and setup hooks. Hooks
# must have equal method names in plugin module as in the original class.
for mod in mods:
name = os.path.splitext(mod)[0]
fobj, fpath, desc = imp.find_module(os.path.join(PLUGIN_DIR, name))
module = imp.load_module(name, fobj, fpath, desc)
set_hooks(module)

....then the other that is responsible for setting up hooks

def set_hooks(mod):
# mod.extensions has "base" class names as keys, (hook, priority) as
# values
for k, hook in mod.extensions.items():
# get class object
hook_cls = mod.__dict__[hook]

try:
base = globals()[k]
except KeyError:
print "No such class to insert hooks to:", k
else:
for item in base.__dict__:
if item.endswith('Hook'):
# Override original (no-op) hook method
# uhh.. kludgety kludge
base.__dict__[item] = hook_cls.__dict__[item]

now, my plugindemo.py just does as follows:

find_plugins()
p = Printer()
p.printit('Hello, world!')

which prints

$ python2.4 plugindemo.py
HELLO, WORLD!
Called afterPrintHook with msg HELLO, WORLD!

But hey, this has many downsides. First off, mechanism doesn't support
arbitrary namespaces. Here, class identifier in the plugin must be as it is
seen from the module which calls the plugin (not a problem for me, but could
be more elegant; probably a mapping between logical class identifiers and
actual class names, hmm?). Second, if one wants to use many hooks (with
priority for conflicts), it is not possible now; set_hooks always overrides
potentially existing hooks. And probably many other problems that are not
obvious to me, but for the simple purpose I have in mind, it seems to work.

This is the first plugin system in Python I'm writing, so I can be a way off
the correct path..
Nov 22 '05 #1
2 2625
Edvard Majakari wrote:
Hi,

My idea is to create a system working as follows: each module knows
path to plugin directory, and that directory contains modules which
may add hooks to some points in the code.

Inspired by http://www.python.org/pycon/2005/pap...onHooking.html

I would create a class like this:

class Printer:

def printit(self, msg):
stuff = self.beforePrintHook(msg)
if stuff:
msg = stuff
print msg
self.afterPrintHook(msg)

def beforePrintHook(self, msg): pass
def afterPrintHook(self, msg): pass

Now, in the spirit of py.test, I'd like API to be practically no API at all :)
moreover, deploying a plugin must consist simply of adding appropriate file to
plugins directory, nothing more, and removing it would uninstall it. The
plugin should be able to somehow result in all future invocations to
Printer.printit() call hooks specified in the plugin. Now, the plugin module
for class above /might/ be along the following lines (I'm thinking of stuff
here, so I don't know yet what would be the most appropriate way):

### a very simple plugin which uppercases all data fed to it.

extensions = {'Printer': 'PrinterHook'}

class PrinterHook:

def beforePrintHook(self, msg):
return msg.upper()
def afterPrintHook(self, msg):
print "Called afterPrintHook with msg %s" % msg
Now, I have a very rude (I think) implementation which has two methods, first
the one that loads plugin modules:

(snip code)

But hey, this has many downsides. First off, mechanism doesn't support
arbitrary namespaces. Here, class identifier in the plugin must be as it is
seen from the module which calls the plugin (not a problem for me, but could
be more elegant; probably a mapping between logical class identifiers and
actual class names, hmm?). Second, if one wants to use many hooks (with
priority for conflicts), it is not possible now; set_hooks always overrides
potentially existing hooks. And probably many other problems that are not
obvious to me, but for the simple purpose I have in mind, it seems to work.
Just a couple of ideas:
- using decorators for plugin hooks ? ie:

import hooks

class Whatever(anything):
@hooks.hook(for='Printer.beforePrintHook',priority =42)
def my_function_with_a_long_name(self, *args, **kw):
pass

The decorator would take care of "registering" the hook where relevant,
ie, storing it in a class attribute of the hooked class ?

which leads to:

- in the hooked class, use a dict class attribute for hooks:

from hooks import run_hooks

class Printer
# will be filled (and could even be created)
# by the @hook decorator
_hooks = {}

def print(self, msg):
# run_hooks will take care of selecting appropriate
# hooks (by looking up the class attribute _hooks)
# and running'em in order
msg = run_hooks(self, 'Printer.beforePrintHook', msg)
print msg
run_hooks(self, 'Printer.afterPrintHook', msg)

My 2 cents... I don't even know if this can be implemented (but I don't
see why it couldn't).
This is the first plugin system in Python I'm writing, so I can be a way off
the correct path..


<aol>

--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Nov 22 '05 #2
Edvard Majakari wrote:
Hi,

My idea is to create a system working as follows: each module knows
path to plugin directory, and that directory contains modules which
may add hooks to some points in the code.

Inspired by http://www.python.org/pycon/2005/pap...onHooking.html

I would create a class like this:

class Printer:

def printit(self, msg):
stuff = self.beforePrintHook(msg)
if stuff:
msg = stuff
print msg
self.afterPrintHook(msg)

def beforePrintHook(self, msg): pass
def afterPrintHook(self, msg): pass

Now, in the spirit of py.test, I'd like API to be practically no API at all :)
moreover, deploying a plugin must consist simply of adding appropriate file to
plugins directory, nothing more, and removing it would uninstall it. The
plugin should be able to somehow result in all future invocations to
Printer.printit() call hooks specified in the plugin. Now, the plugin module
for class above /might/ be along the following lines (I'm thinking of stuff
here, so I don't know yet what would be the most appropriate way):

### a very simple plugin which uppercases all data fed to it.

extensions = {'Printer': 'PrinterHook'}

class PrinterHook:

def beforePrintHook(self, msg):
return msg.upper()
def afterPrintHook(self, msg):
print "Called afterPrintHook with msg %s" % msg
Now, I have a very rude (I think) implementation which has two methods, first
the one that loads plugin modules:

(snip code)

But hey, this has many downsides. First off, mechanism doesn't support
arbitrary namespaces. Here, class identifier in the plugin must be as it is
seen from the module which calls the plugin (not a problem for me, but could
be more elegant; probably a mapping between logical class identifiers and
actual class names, hmm?). Second, if one wants to use many hooks (with
priority for conflicts), it is not possible now; set_hooks always overrides
potentially existing hooks. And probably many other problems that are not
obvious to me, but for the simple purpose I have in mind, it seems to work.
Just a couple of ideas:
- using decorators for plugin hooks ? ie:

import hooks

class Whatever(anything):
@hooks.hook(for='Printer.beforePrintHook',priority =42)
def my_function_with_a_long_name(self, *args, **kw):
pass

The decorator would take care of "registering" the hook where relevant,
ie, storing it in a class attribute of the hooked class ?

which leads to:

- in the hooked class, use a dict class attribute for hooks:

from hooks import run_hooks

class Printer
# will be filled (and could even be created)
# by the @hook decorator
_hooks = {}

def print(self, msg):
# run_hooks will take care of selecting appropriate
# hooks (by looking up the class attribute _hooks)
# and running'em in order
msg = run_hooks(self, 'Printer.beforePrintHook', msg)
print msg
run_hooks(self, 'Printer.afterPrintHook', msg)

My 2 cents... I don't even know if this can be implemented (but I don't
see why it couldn't).
This is the first plugin system in Python I'm writing, so I can be a way off
the correct path..


<aol>

--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Nov 22 '05 #3

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Simon Roses Femerling | last post by:
Dear pythonnians :) Hopeful somebody can help me about implementing plugin support. I'm working on a python/wxpython app that needs plugin...
2
by: Chua Wen Ching | last post by:
Hi there, I had some doubts on creatings plugins. As most example on the internet shows how to write plugins onto a plugin host which is...
2
by: Joe_Black | last post by:
Hi all, I want to create an MDI app that allows reporting on XML data files downloaded from the equipment that we manufacture, this MDI app will...
0
by: Edvard Majakari | last post by:
Hi, My idea is to create a system working as follows: each module knows path to plugin directory, and that directory contains modules which may...
2
by: Ron | last post by:
Hello, I'm attempting to develop a plugin framework for an application that I'm working on. I wish to develop something in which all plugins...
12
by: Mats Lycken | last post by:
Hi, I'm creating a CMS that I would like to be plug-in based with different plugins handling different kinds of content. What I really want is to...
16
by: tshad | last post by:
This is a little complicated to explain but I have some web services on a machine that work great. The problem is that I have run into a...
0
by: Zeya | last post by:
Situation: Using C#, ASP.Net Requirement: 1. ASP.net application with virtual hosting service. 2. Requires a service that will run every...
0
by: gerdhub | last post by:
I develop an application that uses a plugin interface, that the hosting application as well as the plugins implement. Each plugin is loaded via: ...
0
by: tammygombez | last post by:
Hey fellow JavaFX developers, I'm currently working on a project that involves using a ComboBox in JavaFX, and I've run into a bit of an issue....
0
by: concettolabs | last post by:
In today's business world, businesses are increasingly turning to PowerApps to develop custom business applications. PowerApps is a powerful tool...
0
by: teenabhardwaj | last post by:
How would one discover a valid source for learning news, comfort, and help for engineering designs? Covering through piles of books takes a lot of...
0
by: Kemmylinns12 | last post by:
Blockchain technology has emerged as a transformative force in the business world, offering unprecedented opportunities for innovation and...
0
by: Naresh1 | last post by:
What is WebLogic Admin Training? WebLogic Admin Training is a specialized program designed to equip individuals with the skills and knowledge...
0
jalbright99669
by: jalbright99669 | last post by:
Am having a bit of a time with URL Rewrite. I need to incorporate http to https redirect with a reverse proxy. I have the URL Rewrite rules made...
0
by: antdb | last post by:
Ⅰ. Advantage of AntDB: hyper-convergence + streaming processing engine In the overall architecture, a new "hyper-convergence" concept was...
0
by: Matthew3360 | last post by:
Hi there. I have been struggling to find out how to use a variable as my location in my header redirect function. Here is my code. ...
0
by: AndyPSV | last post by:
HOW CAN I CREATE AN AI with an .executable file that would suck all files in the folder and on my computerHOW CAN I CREATE AN AI with an .executable...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.