I am working on a project whose main design guiding principle is extensibility.
I implemented a plugin system by defining a metaclass that register - with a class method - the class name of any plugin that gets loaded (each type of plugin inherit from a specific class defined in the core code, as there are different types of plugins in the application). Basically this means that a developer will have to define his class as
class PieChart(ChartPluginAncestor):
# Duck typing:
# Implement compulsory methods for Plugins
# extending Chart functionality
and the main program will know of his presence because PieChart
will be included in the list of registered plugins available at ChartPluginAncestor.plugins
.
Being the mounting method a class method, all plugins get registered when their class code is loaded into memory (so even before an object of that class is instantiated).
The system works good enough™ for me (although I am always open to suggestions on how to improve the architecture!) but I am now wondering what would be the best way to manage the plugin files (i.e. where and how the files containing the plugins should be stored).
So far I am using - for developing purposes - a package that I called "plugins". I put all my *.py files containing plugins classes in the package directory, and I simply issue import plugins
in the main.py file, for all the plugins to get mounted properly.
EDIT: Jeff pointed out in the comments that import plugins
the classes contained in the various modules of the packages won't be readily available (I did not realise this as I was - for debugging purposes - importing each class separately with from plugins.myAI import AI
).
However this system is only good while I am developing and testing the code, as:
- Plugins might come with their own unittests, and I do not want to load those in memory.
- All plugins are currently loaded into memory, but indeed there are certain plugins which are alternative versions of the same feature, so you really just need to know that you can switch between the two, but you want to load into memory just the one you picked from the config pane.
- At some point, I will want to have a double location for installing plugins: a system-wide location (for example somewhere under
/usr/local/bin/
) and a user-specific one (for example somewhere under/home/<user>/.myprogram/
).
So my questions are really - perhaps - three:
- Plugin container: what is the most sensible choice for my goal? single files? packages? a simple directory of .py files?)
- Recognise the presence of plugins without necessarily loading (importing) them: what is a smart way to use Python introspection to do so?
- Placing plugins in two different locations: is there a standard way / best practice (under gnu/linux, at least) to do that?
Thank you in advance for your time and guidance!