Creating (rather) generic plugin framework?
bruno at modulix
onurb at xiludom.gro
Wed Nov 16 14:38:09 EST 2005
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/papers/7/pyconHooking.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 'onurb at xiludom.gro'.split('@')])"
More information about the Python-list
mailing list