new new plugin architecture suggestion

Suggestions and discussion of future versions
Post Reply
jorge.vargas
Member
Member
Posts: 14
Joined: Wed Jun 27, 2007 8:50 pm

new new plugin architecture suggestion

Post by jorge.vargas »

Hi I have been playing around with the plugin arch and I'll like to propose an enhancement, please note this is based on having setuptools manage the plugins, although that only counts for discoverability and metadata so those places could be replaced.

currently you need to supply 3 groups of information
1. module level package info (plugin_name,autho,etc.)
2. module level package functions (deluge_init, enable)
3. object level plugin control (unload,update)

I want to reorganize this information in hooks
on_install
on_uninstall
on_create
on_update
on_unload
on_configure
and so on.

after that you will have a Plugin class which will probably be instantiated in on_create and be keep as a module variable for unload/configure,etc. What I like about this is that your plugin code is totally independent of the API, for example on_create will pass in the core and the interface but if you have a plugin that doesn't make use of the interface just ignore it when creating ur plugin instance.

also all the metadata will be read from the egg-info dir since this is a python package
tarka
Member
Member
Posts: 22
Joined: Sat Jun 09, 2007 6:49 am

Re: new new plugin architecture suggestion

Post by tarka »

Cool! I'm the one that did the initial plugins-are-modules conversion, but I agree it needs a cleaner architecture and API. The hooks you propose look good.

One issue with the current api is that that the core needs to explicitly check whether a hook exists before calling it. One method I've used in the past to remove this is to use GTK-style signalling (ie. observer pattern). What you have is a base class like this:

Code: Select all

import sys, os, string, weakref

class SignalEmitter(object):
    """Base class for linking named signals to functions.
       Initialised with a list of signals this class will emit."""
    def __init__(self, signals):
        self._signals = {}
        for sig in signals:
            self._signals[sig] = []

    def addSignal(self, sig):
        if sig not in self._signals:
            self._signals[sig] = []

    def addReceiver(self, sig, receiver, pri=50):        
        """Add a signal receiver, throws KeyError if not available."""
        self._signals[sig].append((pri, receiver))
        self._signals[sig].sort()

    def emitsig(self, signal, **kwargs):
        """Emit a signal with keyword arguments.  The emitting object
           will be added if the function has the 'magic' keyword
           'emitter'. Throws KeyError if signal not registered."""
        for func in self._signals[signal]:
            func = func[1]
            if 'emitter' in func.func_code.co_names:
                func(emitter=self, **kwargs)
            else:
                func(**kwargs)
The deluge core then inherits from this and registers the signals it can emit:

Code: Select all

class Manager(SignalEmitter):
    ....
    def __init__(self, ....):
        SignalEmitter.__init__(self, ['on_update', 'on_plugin_init', ...])
The plugins are passed the core as part of the initial inspection, so they can then subscribe to these signals:

Code: Select all

class MyPlugin:
    def __init__(self, core):
        core.addReceiver('on_update', self.update)
You can even set a priority to ensure plugins are serviced in a given order.

I've been meaning to start on this at some point but I've been tied up with other things. Feel free to use this code though :)
Post Reply