3.2. Creating a Plugin¶
All plugin classes must
- Inherit from
force_bdss.api.BaseExtensionPlugin
from force_bdss.api import BaseExtensionPlugin, plugin_id
VERSION = 0
class ExamplePlugin(BaseExtensionPlugin):
"""This is an example of the plugin system for the BDSS."""
- Implement a
id
class member, that must be set to the result of calling the functionplugin_id()
id = plugin_id("enthought", "example", VERSION)
The three arguments determine the unique name of the extension point
- Implement the methods
get_name()
,get_version()
andget_description()
to return appropriate values. Theget_version()
method in particular should return the same value as in the id (in this case zero). It is advised to extract this value in a global, module level constant
def get_name(self):
return "Enthought example"
def get_description(self):
return "An example plugin from Enthought"
def get_version(self):
return VERSION
- Implement a method
get_factory_classes()
returning a list of all the classes (NOT the instances) of the entities you want to export.
def get_factory_classes(self):
return [
ExampleDataSourceFactory,
ExampleMCOFactory,
ExampleNotificationListenerFactory,
ExampleUIHooksFactory,
]
3.2.1. Install the Plugin¶
In order for the BDSS to recognize the plugin, it must be installed as a package in the deployed
environment (force-py36
). This can be performed using pip
and an appropriate setup.py
file,
that employs the setuptools
package. Additional documentation describing package building using setuptools
can be found here.
The plugin is declared as an extension to the force_bdss
by having it defined as the setup
command
entry_points
keyword argument, under the namespace force.bdss.extensions
. You have to specify a path to the
plugin class (in this case ExamplePlugin
), as given below. The name (before the '='
) of the plugin is irrelevant, but to avoid confusion,
try to use the name of the module. For example
entry_points={
"force.bdss.extensions": [
"enthought_example = "
"enthought_example.example_plugin:ExamplePlugin",
]
}
A basic example setup.py
file is therefore shown below
from setuptools import setup, find_packages
VERSION = 0
setup(
name="enthought_example",
version=VERSION,
entry_points={
"force.bdss.extensions": [
"enthought_example = "
"enthought_example.example_plugin:ExamplePlugin",
]
},
# Automatically looks for file directories containing __init__.py files
# to be included in package
packages=find_packages(),
)
Running the following command line instruction from the same directory as setup.py
will then install
the package in the deployed environment
edm run -e force-py36 -- pip install -e .
3.2.2. Advanced Plugins¶
Additionally, a plugin can also define one or more custom visualization classes for the
GUI application force-wfmanager
, typically to either display data or
provide a tailor-made UI for a specific user.
In which case, the plugin class
must inherit from force_bdss.api.ServiceOfferExtensionPlugin
, which is a child class of BaseExtensionPlugin
. Any UI subclasses
can then be made discoverable by force-wfmanager
using the Envisage
ServiceOffer
protocol through the get_service_offer_factories
method
def get_service_offer_factories(self):
"""A method returning a list user-made objects to be provided by this
plugin as envisage ServiceOffer objects. Each item in the outer list is
a tuple containing an Interface trait to be used as the ServiceOffer
protocol and an inner list of subclass factories to be instantiated
from said protocol.
Returns
-------
service_offer_factories: list of tuples
List of objects to load, where each tuple takes the form
(Interface, [HasTraits1, HasTraits2..]), defining a Traits
Interface subclass and a list of HasTraits subclasses to be
instantiated as an envisage ServiceOffer.
"""
Make sure to import the module containing the UI classes from inside
get_service_offer_factories
: this ensures that running BDSS without a GUI
application doesn’t import the graphical stack.
There are currently two types of custom UI object that may be contributed by a
plugin: IBasePlot
and IContributedUI
. These interfaces represent requirements
for any UI feature that can be used to display MCO data or a present a simplified
workflow builder respectively.
Also, multiple types of plugin contributed UI objects can be imported in the same method. For instance
from force_bdss.api import ServiceOfferExtensionPlugin
class ExamplePlugin(ServiceOfferExtensionPlugin):
"""This is another example of the plugin system for the BDSS."""
def get_service_offer_factories(self):
from force_wfmanager.ui import IBasePlot, IContributedUI
from .example_custom_uis import PlotUI, ExperimentUI, AnalysisUI
return [
(IBasePlot, [PlotUI]),
(IContributedUI, [ExperimentUI, AnalysisUI])
]
These plugins are installed in the same way as described previously, but are only accessible when
running the force_wfmanager
GUI.