Writing a class-based plugin#
In GeoIPS 2.0, most Python plugins — readers, algorithms, interpolators, colormappers,
output formatters, filename formatters, title formatters, coverage checkers, and more —
are class-based. Each plugin is a Python class that subclasses the base class for its
interface and implements a call() method.
Coming from 1.x module-based plugins?
In GeoIPS 1.x these plugins were module-based: a module with a top-level call()
function and interface/family/name module attributes. In 2.0 they are true classes.
See the module-to-class conversion guide to migrate an
existing plugin.
Anatomy of a plugin#
A class-based plugin:
Subclasses the interface base class (e.g.
BaseAlgorithmPluginfromgeoips.interfaces.class_based.algorithms).Sets three required class attributes:
interface,family, andname.Implements
call(self, ...)with the arguments its family expects.Declares
PLUGIN_CLASS = <YourPluginClass>at the bottom of the module so the plugin registry (pluginify) knows which class in the file is the plugin.
from geoips.interfaces.class_based.algorithms import BaseAlgorithmPlugin
import logging
LOG = logging.getLogger(__name__)
class SingleChannelAlgorithmPlugin(BaseAlgorithmPlugin):
"""Single Channel algorithm plugin class."""
interface = "algorithms"
family = "list_numpy_to_numpy"
name = "single_channel"
def call(self, arrays, output_data_range=None, input_units=None,
output_units=None, min_outbounds="crop", max_outbounds="crop",
norm=False, inverse=False):
"""Apply data range and requested corrections to a single channel product."""
...
return final_array
# Tells pluginify which class in this module is the plugin to register.
PLUGIN_CLASS = SingleChannelAlgorithmPlugin
This example mirrors the real
geoips/plugins/classes/algorithms/single_channel.py.
Required class attributes#
interfaceThe interface the plugin belongs to (e.g.
"algorithms","readers"). Must be a known class-based interface. Usually the interface base class already implies it, but set it explicitly on your plugin.familyThe family name, which determines the plugin’s expected call signature and how GeoIPS converts data into and out of it.
nameThe unique plugin name used to look it up (
algorithms.get_plugin("single_channel")).
The base class validates that all three are non-empty strings and that interface is a
real interface.
The call() method#
call() holds your plugin’s logic. You do not call it directly — the base class
exposes it through __call__ and wraps it with pre/post hooks, so both of these work:
plugin = algorithms.get_plugin("single_channel")
result = plugin(arrays, output_data_range=[-90.0, 30.0]) # module-style call
Under Order-Based Processing and
scripting, plugins are called with the accumulated data tree.
The base class handles converting the DataTree into the native input type your family
expects (e.g. a list of numpy arrays for list_numpy_to_numpy) before call() runs, and
wrapping your return value back into the tree afterward. In most cases you only write
call() and never touch the _pre_call / _post_call hooks.
Where plugins live and how they register#
Class-based plugins live under geoips/plugins/classes/<interface>/<name>.py (or the
equivalent path in your plugin package). Declare PLUGIN_CLASS = <YourPluginClass> at the
bottom of the module so the registry knows which class to register. After adding a plugin,
rebuild the plugin registries so GeoIPS can find it:
geoips config create-registries
Then confirm it is discovered:
geoips list algorithms
geoips describe alg single_channel
See also#
Converting module-based plugins to class-based — migrate a 1.x module-based plugin.
Order-Based Processing (OBP) — how plugins are composed into workflows.
The tutorials under Tutorials walk through building specific plugin types end-to-end.