Building a plugin architecture with Python

Problem statement

Given a broad category of devices that share similar functionality and a communication interface with indecent protocols, in this case let’s call them inverters (for a solar system). These inverters can provide us with power readings for input (solar and or battery), output (to mains/load) and device information/status e.t.c that we can access though some text based. Say for example to change from hybrid mode (solar and grid) to just offline mode (solar and battery only).

Fundamental plugin concepts

A common plugin system typically needs to define some form of contract/s that the plugins can extend and the core application can use as an abstraction layer for communication, this could be in the form of a package with some abstract classes. Typically the application would using the following steps/phases to interact with the plugins:

Discovery

This is the mechanism by which a running application can find out which plugins it has at its disposal. To “discover” a plugin, one has to look in certain places, and also know what to look for.

Registration

This is the mechanism by which a plugin tells an application — “I’m here, ready to do work”. Admittedly, registration usually has a large overlap with discovery.

Application Hooks

Hooks are also called “mount points” or “extension points”. These are the places where the plugin can “attach” itself to the application, signalling that it wants to know about certain events and participate in the flow. The exact nature of hooks is very much dependent on the application.

Exposing application API to plugins

To make plugins truly powerful and versatile, the application needs to give them access to itself, by means of exposing an API the plugins can use.

Code examples

Discovery

Let us create a few contracts that all plugins will implement/extend, one contract will be used for registering a plugin when it is loaded/registered (will go into more detail later) and the other defines the behaviour of the plugin (what it can do and the information we can expect to get):

The references models can be found here, these are just data classes for demonstration purposes

Registration

In the sample project all our plugins will be placed in a plugins directory, this is to simulate a case where a plugins are downloaded and kept.

Sample plugin directory structure which can be found here
plugin.yaml configuration file for the sample plugin
sample.py the main sample plugin file which can be found here
PluginUseCase discover and load/hook plugins

Application hooks and exposing the API

Plugins are loaded through __search_for_plugins at this point
Plugin instance creation and invocation
Application core module which can be found here

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Maxwell Mapako

Maxwell Mapako

Freelancer and open source developer, growing my skills one byte a time :)