Plugins are used by groundwork to load specific functions into a groundwork application.

In most cases a plugin should have a functional focus, like providing some documentation about signals or providing some commands to the user to handle specific tasks on data.

A plugin can be activated and deactivated during runtime. And it can be loaded from python packages or from own code.

The following rules apply for each groundwork plugin.

  • A plugin contains code, documentation and tests.
  • A plugin provides routines for activation and deactivation during runtime.
  • A plugin inherits directly or indirectly from GwBasePattern.

During development of a plugin, patterns can be used to extend its functionality or grant access to specific objects, like a database engine to perform database actions.


The registration of a plugin must happen by using the application:

from groundwork import App

my_app = App()

For more information please read Plugin registration of the chapter Application.

Activation and Deactivation

Plugins can be activated and deactivated during runtime. There are two ways of doing this:

  • By the activate()/ deactivate() function, accessible by my_app.plugins.activate() or my_app.plugins.deactivate().
  • By the activation/deactivation function of the plugin itself, accessible by my_plugin.activate() or my_plugin.deactivate().

For a code example, please take a look into Plugin activation and Plugin deactivation of the application documentation.

Development of own plugins

To start the development of own plugins, simply create a new class and inherit from GwBasePattern:

from groundwork.patterns import GwBasePattern

class MyPlugin(GwBasePattern):
    def __init__(self, app, **kwargs): = "My Plugin"
        super().__init__(app, **kwargs)

    def activate(self): pass

    def deactivate(self): pass


It is very important to call the __init__ routine of parent classes. Otherwise they can’t deliver functions and objects, which you may need. Also no signals are registered, which inform interested functions when your plugin gets activated or deactivated. So no automatic cleanup would happen, like erasing all registered commands of your plugin.

Also make sure that your __init__ can handle app as the first argument and additional, optional keyword arguments.

Provided variables

The groundwork GwBasePattern creates the following variables for your plugin and makes them directly available:

  • self.path: The absolute path of the python-file, which contains your plugin (directory + file name)
  • self.dir: The absolute directory, which contains your plugin (directory only)
  • self.file: The name of the file, which contains your plugin (file name only)
  • self.version: An initial version (0.0.1), if this was not set by your plugin during initialisation
  • True, if the plugin got activated.
  • self.needed_plugins: Empty tuple, if it was not set by your plugin during initialisation

Using signals and receivers

You are free to add signals or connect receivers to them:

from groundwork.patterns import GwBasePattern

class MyPlugin(GwBasePattern):
    def __init__(self, app, **kwargs): = "My Plugin"
        super().__init__(app, **kwargs)

    def activate(self):
        self.signals.register(signal="My signal",
                              description="Informing about something")

        self.signals.connect(receiver="My signal receiver",
                             signal="My signal",
                             description="Doing some fancy stuff")

    def fancy_stuff(plugin, **kwargs):
        print("FANCY STUFF!!! " * 50)

For more details about signals, please read Signals and Receivers.


Each plugin sends automatically signals when it gets activated or deactivated. The used signals are: plugin_activate_pre, plugin_activate_post, plugin_deactivate_pre and plugin_deactivate_post.

Please see Signals and Receivers for more information.

Using patterns

Patterns can be used to extend your plugin with new functions and objects.

groundwork itself provides 6 patterns:

You can load multiple patterns into your plugin:

from groundwork.patterns import GwCommandsPattern, GwDocumentsPattern, GwSharedObjectsPattern

# GwBasePattern is no longer needed, because the used patterns already inherit from it.
class MyPlugin(GwCommandsPattern, GwDocumentsPattern, GwSharedObjectsPattern):
    def __init__(self, app, **kwargs): = "My Plugin"
        super().__init__(app, **kwargs)

    def activate(self):

For more information about these patterns, please read the related chapters: Commands, Documents, Recipes, Shared Objects and Threads.


Each plugin has its own logger, which name is the name of the plugin. It is accessible via self.log inside a plugin class:

from groundwork.patterns import GwBasePattern

class MyPlugin(GwBasePattern):
    def __init__(self, app, **kwargs): = "My Plugin"
        super().__init__(app, **kwargs)"Initialisation done for %s" %

    def activate(self):
        self.log.debug("Starting activation")"Activation done")

For each logger, and therefore for each plugin, it is possible to register handlers to monitor specific plugins and log messages in detail.

For instance: Store all messages of “My Plugin” inside a file called “my_plugin.log”. All other messages go to “app.log”.

For details how to configure groundworks logging, please see logging configuration.

Plugin dependencies

A plugin can have dependencies to other plugins and it needs to be sure that these plugins are activated in the current app.

Therefore a plugin can specify the names of needed plugins and groundwork cares about their activation:

from groundwork.patterns import GwBasePattern

class MyPlugin(GwBasePattern):
    def __init__(self, app, **kwargs): = "My Plugin"
        self.needed_plugins = ("AnotherPlugin", "AndAnotherPlugin")
        super().__init__(app, **kwargs)

During plugin activation, groundwork does the following:

  • Read in self.needed_plugins
  • For each plugin name
    • Check, if a plugin with this name exists in app.plugins (objects/instantiated plugins)
      • If yes: activate it instantly (if not done yet)
      • If no: check for plugin classes with this name in app.plugin.classes (classes, not instantiated)
        • If yes: Instantiate and activate it
        • If not: Throw error