Skip to content

Plugin Architecture for flopy #1470

@jlarsen-usgs

Description

@jlarsen-usgs

Hello,

Following the discussion about investigating a plugin architecture for modflowapi packages I've done a little bit of research into how python plugins work and created a simple example to dynamically search for and load plugins in an existing python package. In essence, this would allow user developed modflowapi packages to be installed seperately, but be discoverable and useable by flopy.

The first step is to create a standardized entry point naming convention for the existing python package (i.e. flopy). This could be something like flopy.plugin or flopy.package.plugin. The entry point name will be used to search the python installations to see if they include this "entry point".

After that we can create a module, such as plugins.py in this example, that programatically search entry points and then import them into the existing software package when plugins.py is imported. For this code example I use test_plugins.plugin for the entry point:

import sys

if sys.version_info < (3, 10):
    from importlib_metadata import entry_points
else:
    from importlib.metadata import entry_points

this_module = sys.modules[__name__]
eps = entry_points(group="test_plugins.plugin")
installed_plugins = {}
for ep in eps:
    _x = ep.load()
    setattr(this_module, ep.name, _x())
    installed_plugins[ep.name] = _x()

Once this script exists, a plugin developer can create code as a seperate installable python package for distribution, wrap it with a simple function, add an [options.entry_points] record to their setup.cfg file, and specify that it is a test_plugins.plugin entry point. Example plugin code and setup.cfg entry.

class FancyHelloWord():
    def __init__(self):
        self.str = "@@!! Hello World !!@@"

    def display(self):
        print(self.str)


def plugin():
    return FancyHelloWord
[options.entry_points]
test_plugins.plugin =
    FancyHelloWorld = src.plugin:plugin

Finally, the user will be able to call the new plugin features from the plugins.py module in the existing software. Example:

from main_plugin_arch import plugins


fhw = plugins.FancyHelloWorld()
fhw.display()

print(plugins.installed_plugins)

I put together a full working example with instructions that can be found at https://github.com/jlarsen-usgs/plugin_example.git

Any thoughts or ideas on this @langevin-usgs @jdhughes-usgs @spaulins-usgs? Feel free to mention others that would be interested in this discussion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions