Atom Feed
Comments Atom Feed


Recent Articles

21/03/2017 15:18
Kubernetes to learn Part 2
21/03/2017 13:53
Kubernetes to learn Part 1
17/07/2016 15:23
AWS ssh known_host sync
11/07/2016 08:42
File integrity and log anomaly auditing Updated (like fcheck/logcheck)
30/05/2016 13:09
Xenial LXC Container on Debian

Glen Pitt-Pladdy :: Blog

Simple Python Plugins

Very often I end up needing an extensible framework that I can slot in new functionality regularly - basically a Plugin framework. I've done this kind of stuff for ages in one form or another for everything from automated infrastructure testing to home automation. This is a very common requirement for a lot more applications.

For Python there are quite a few different modules floating around for doing Plugins, but already baked in there are all the parts you need to do simple Plugins.

I'm going to be sticking to Python 2.7 for this as things have changed in 3.x, and most code kicking around is still 2.7 code.

Basic nuts 'n bolts

The basics of Plugins in everything from C++ to Perl is fairly similar: dynamically load a library/module containing fixed entry points that the loader can call to use the plugin. Often there is some registration process where the Plugin attaches it's self to the appropriate data and event structures in the loading process, or provides metadata for the loader to do that for it. Potentially you also want the ability to unload the Plugin, but that can get more complex.

A typical flow of events in the Loader will be something like:

  1. Scan a directory for Plugins to load or pull the information from some stored config/data
  2. Load the Plugin, using some mechanism of separation (eg. in scripting typically something along the lines of a unique Namespace so names don't conflict)
  3. Execute the registration process / code from some defined entry point
  4. Start using the plugin using defined entry point(s)

Now, what should immediately become obvious here every Plugin needs to have a common structure for interfacing with it, and hence in OO programming inheriting from a template class will likely make a lot of sense and save loads of hassle keeping things manageable.

That's not to say it's absolutely necessary - I have some code which only needs a bit of metadata (set some variables) and maybe a single function for each of a small number of Plugins and creating templates risks introducing complications that could make things less reliable and maintainable for such simple code.

The Code

In Python we will be using the imp module which has two basic functions that are relevant to us. The first step is to locate and gather the data needed to load the module (Plugin). This is done with something like:

info = imp.find_module ( name )

This searches various paths to locate a module matching the name given, and returns the data needed to load it.

Then we need to actually load the module:

plugin = imp.load_module ( name, *info )

Now plugin is a window into the contents of the module.

If there's a variable foo in the module then references that variable. If there's a function bar in the module then executes that function. If there's a class baz then plugin.baz() returns an object of that class.

Provided the entry points (variables, functions, classes) in the module are consistent then there's nothing to stop you loading all the Plugins into an array or dict to be used within the program.

Example Code

I've stuck some example Python Plugin code on GitHub for you to experiment with.

This includes additional code to print out the number of objects at different stages of the process and force garbage collection to ensure we get up-to-date counts. This is interesting since Python doesn't behave entirely like I would expect with this, but maybe someone who understands more about what's going on under the hood can explain.

There is an OO (Class/Object) example with Plugin, and a super-simple non-OO example with Plugin



Are you human? (reduces spam)
Note: Identity details will be stored in a cookie. Posts may not appear immediately