Skip to content
Snippets Groups Projects
Commit 8ad0a7de authored by Stefano Borini's avatar Stefano Borini
Browse files

Changed infrastructure for plugin and factories

parent 5d19c7b4
No related branches found
No related tags found
1 merge request!130Safer plugin import - 2
from .base_extension_plugin import BaseExtensionPlugin # noqa
from .ids import factory_id, mco_parameter_id # noqa
from .ids import plugin_id # noqa
from .core.data_value import DataValue # noqa
from .core.workflow import Workflow # noqa
......
......@@ -28,11 +28,7 @@ class BaseExtensionPlugin(Plugin):
in your plugin, and reimplement the methods as from example::
class MyPlugin(BaseExtensionPlugin):
def get_producer(self):
return "enthought"
def get_identifier(self):
return "myplugin"
id = plugin_id("enthought", "plugin_name", 0)
def get_factory_classes(self):
return [
......@@ -86,26 +82,8 @@ class BaseExtensionPlugin(Plugin):
_logger = Instance(logging.Logger)
def __init__(self, *args, **kwargs):
broken = False
error = ""
if "id" not in kwargs:
try:
id_ = plugin_id(self.get_producer(), self.get_identifier())
except Exception as e:
self._logger.exception(e)
error = traceback.format_exc()
broken = True
else:
kwargs["id"] = id_
super(BaseExtensionPlugin, self).__init__(*args, **kwargs)
if broken:
self.broken = True
self.error = error
return
try:
self.factory_classes = self.get_factory_classes()
self.mco_factories[:] = [
......@@ -133,25 +111,6 @@ class BaseExtensionPlugin(Plugin):
self.notification_listener_factories[:] = []
self.ui_hooks_factories[:] = []
def get_producer(self):
"""Must be reimplemented to return a string with the name of the
company producing this plugin. Examples are "enthought", "itwm" etc.
"""
raise NotImplementedError(
"get_producer was not implemented in plugin {}".format(
self.__class__))
def get_identifier(self):
"""Must return a string with the name of the plugin the producer
is releasing. The name must be unique and is responsibility of
the producer to guarantee this name is not conflicting with
another already existing plugin
"""
raise NotImplementedError(
"get_identifier was not implemented in plugin {}".format(
self.__class__))
def get_factory_classes(self):
"""Must return a list of factory classes that this plugin exports.
"""
......
import logging
from traits.api import ABCHasStrictTraits, provides, String, Instance, Type
from traits.api import ABCHasStrictTraits, provides, Str, Instance, Type
from envisage.plugin import Plugin
from force_bdss.data_sources.base_data_source import BaseDataSource
from force_bdss.data_sources.base_data_source_model import BaseDataSourceModel
from force_bdss.data_sources.i_data_source_factory import IDataSourceFactory
from force_bdss.ids import factory_id
log = logging.getLogger(__name__)
......@@ -13,15 +14,30 @@ log = logging.getLogger(__name__)
class BaseDataSourceFactory(ABCHasStrictTraits):
"""Base class for DataSource factories. Reimplement this class to
create your own DataSource.
You must reimplement the following methods as from example::
class MyDataSourceFactory(BaseDataSourceFactory)
def get_data_source_class(self):
return MyDataSource
def get_data_source_model(self):
return MyDataSourceModel
def get_name(self):
return "My data source"
def get_identifier(self):
return "my_data_source"
"""
# NOTE: changes to this class must be ported also to the IDataSourceFactory
#: Unique identifier that identifies the factory uniquely in the
#: universe of factories. Create one with the function factory_id()
id = String()
id = Str()
#: A human readable name of the factory. Spaces allowed
name = String()
name = Str()
#: The data source to be instantiated. Define this to your DataSource
data_source_class = Type(BaseDataSource)
......@@ -39,6 +55,43 @@ class BaseDataSourceFactory(ABCHasStrictTraits):
self.plugin = plugin
super(BaseDataSourceFactory, self).__init__(*args, **kwargs)
self.data_source_class = self.get_data_source_class()
self.model_class = self.get_model_class()
self.name = self.get_name()
identifier = self.get_identifier()
self.id = factory_id(self.plugin.id, identifier)
def get_data_source_class(self):
"""Must be reimplemented to return the DataSource class.
"""
raise NotImplementedError(
"get_data_source_class was not implemented in factory {}".format(
self.__class__))
def get_model_class(self):
"""Must be reimplemented to return the DataSourceModel class.
"""
raise NotImplementedError(
"get_model_class was not implemented in factory {}".format(
self.__class__))
def get_name(self):
"""Must be reimplemented to return a user-visible name of the
data source.
"""
raise NotImplementedError(
"get_name was not implemented in factory {}".format(
self.__class__))
def get_identifier(self):
"""Must be reimplemented to return a unique string identifying
the factory. The provider is responsible to guarantee this identifier
to be unique across the plugin data sources.
"""
raise NotImplementedError(
"get_name was not implemented in factory {}".format(
self.__class__))
def create_data_source(self):
"""Factory method.
Must return the factory-specific BaseDataSource instance.
......
......@@ -17,57 +17,69 @@ class ExtensionPointID:
UI_HOOKS_FACTORIES = 'force.bdss.ui_hooks.factories'
def factory_id(producer, identifier):
def factory_id(plugin_id, identifier):
"""Creates an id for the factory.
Parameters
----------
producer: str
the company or research institute unique identifier (e.g. "enthought")
plugin_id: str
the id of the plugin that contains this factory
identifier: str
A unique identifier for the factory. The producer has authority and
A unique identifier for the factory. The identifier should be unique
control over the uniqueness of this identifier.
Returns
-------
str: an identifier to be used in the factory.
"""
return _string_id(producer, "factory", identifier)
return _string_id(plugin_id, "factory", identifier)
def mco_parameter_id(producer, mco_identifier, parameter_identifier):
def mco_parameter_id(mco_factory_id, parameter_identifier):
"""Creates an ID for an MCO parameter, so that it can be identified
uniquely."""
return _string_id(producer,
"factory",
mco_identifier,
"parameter",
parameter_identifier)
return _string_id(mco_factory_id, "parameter", parameter_identifier)
def plugin_id(producer, identifier):
def plugin_id(producer, identifier, version):
"""Creates an ID for the plugins. These must be defined, otherwise
the envisage system will complain (but not break)
Parameters
----------
producer: str
A unique string identifying the producer (company/research institute)
of the plugin (e.g. "enthought", "itwm")
identifier: str
A string identifying the plugin. It must be unique within the context
of the producer, who is responsible to guarantee that plugin names
are unique
version: int
A version number for the plugin.
"""
return _string_id(producer, "plugin", identifier)
if not isinstance(version, int) or version < 0:
raise ValueError("version must be a non negative integer")
return _string_id("force",
"bdss",
producer,
"plugin",
identifier,
"v{}".format(version))
def _string_id(*args):
"""Creates an id for a generic entity.
"""Creates an id for a generic entity, by concatenating the given args
with dots.
Parameters
----------
entity_namespace: str
A namespace for the entity we want to address (e.g. "factory")
producer: str
the company or research institute unique identifier (e.g. "enthought")
identifier: str
A unique identifier for the factory. The producer has authority and
control over the uniqueness of this identifier.
*args: str
The strings to concatenate
Returns
-------
str: an identifier to be used in the factory.
str: an identifier to be used.
"""
def is_valid(entry):
return (
......@@ -79,4 +91,4 @@ def _string_id(*args):
raise ValueError("One or more of the specified parameters was "
"invalid: {}".format(str(args)))
return ".".join(["force", "bdss"]+list(args))
return ".".join(list(args))
import logging
from traits.api import ABCHasStrictTraits, String, provides, Instance, Type
from traits.api import ABCHasStrictTraits, Str, provides, Instance, Type
from envisage.plugin import Plugin
from force_bdss.ids import factory_id
from force_bdss.mco.base_mco import BaseMCO
from force_bdss.mco.base_mco_communicator import BaseMCOCommunicator
from force_bdss.mco.base_mco_model import BaseMCOModel
......@@ -18,10 +19,10 @@ class BaseMCOFactory(ABCHasStrictTraits):
# in the IMultiCriteriaOptimizerFactory interface class.
#: A unique ID produced with the factory_id() routine.
id = String()
id = Str()
#: A user friendly name of the factory. Spaces allowed.
name = String()
name = Str()
#: The optimizer class to instantiate. Define this to your MCO class.
optimizer_class = Type(BaseMCO)
......@@ -39,6 +40,38 @@ class BaseMCOFactory(ABCHasStrictTraits):
self.plugin = plugin
super(BaseMCOFactory, self).__init__(*args, **kwargs)
self.name = self.get_name()
self.optimizer_class = self.get_optimizer_class()
self.model_class = self.get_model_class()
self.communicator_class = self.get_communicator_class()
identifier = self.get_identifier()
self.id = factory_id(self.plugin.id, identifier)
def get_optimizer_class(self):
raise NotImplementedError(
"get_optimizer_class was not implemented in factory {}".format(
self.__class__))
def get_model_class(self):
raise NotImplementedError(
"get_model_class was not implemented in factory {}".format(
self.__class__))
def get_communicator_class(self):
raise NotImplementedError(
"get_communicator_class was not implemented in factory {}".format(
self.__class__))
def get_identifier(self):
raise NotImplementedError(
"get_identifier was not implemented in factory {}".format(
self.__class__))
def get_name(self):
raise NotImplementedError(
"get_name was not implemented in factory {}".format(
self.__class__))
def create_optimizer(self):
"""Factory method.
Creates the optimizer with the given application
......
from traits.api import HasStrictTraits, String, Type, Instance
from traits.api import HasStrictTraits, Str, Type, Instance
from force_bdss.ids import mco_parameter_id
class BaseMCOParameterFactory(HasStrictTraits):
......@@ -14,23 +16,49 @@ class BaseMCOParameterFactory(HasStrictTraits):
mco_factory = Instance('force_bdss.mco.base_mco_factory.BaseMCOFactory')
#: A unique string identifying the parameter
id = String()
id = Str()
#: A user friendly name (for the UI)
name = String("Undefined parameter")
name = Str("Undefined parameter")
#: A long description of the parameter
description = String("Undefined parameter")
description = Str("Undefined parameter")
# The model class to instantiate when create_model is called.
model_class = Type(
"force_bdss.mco.parameters.base_mco_parameter.BaseMCOParameter"
)
def get_identifier(self):
raise NotImplementedError(
"get_identifier was not implemented in factory {}".format(
self.__class__))
def get_name(self):
raise NotImplementedError(
"get_name was not implemented in factory {}".format(
self.__class__))
def get_description(self):
raise NotImplementedError(
"get_description was not implemented in factory {}".format(
self.__class__))
def get_model_class(self):
raise NotImplementedError(
"get_model_class was not implemented in factory {}".format(
self.__class__))
def __init__(self, mco_factory, *args, **kwargs):
self.mco_factory = mco_factory
super(BaseMCOParameterFactory, self).__init__(*args, **kwargs)
self.name = self.get_name()
self.description = self.get_description()
self.model_class = self.get_model_class()
identifier = self.get_identifier()
self.id = mco_parameter_id(self.mco_factory.id, identifier)
def create_model(self, data_values=None):
"""Creates the instance of the model class and returns it.
You should not reimplement this, as the default is generally ok.
......
import logging
from traits.api import (
ABCHasStrictTraits, Instance, String, provides, Type, Bool
HasStrictTraits, Instance, Str, provides, Type, Bool
)
from envisage.plugin import Plugin
from force_bdss.ids import factory_id
from force_bdss.notification_listeners.base_notification_listener import \
BaseNotificationListener
from force_bdss.notification_listeners.base_notification_listener_model \
......@@ -15,16 +16,16 @@ log = logging.getLogger(__name__)
@provides(INotificationListenerFactory)
class BaseNotificationListenerFactory(ABCHasStrictTraits):
class BaseNotificationListenerFactory(HasStrictTraits):
"""Base class for notification listeners.
Notification listeners are extensions that receive event notifications
from the MCO and perform an associated action.
"""
#: identifier of the factory
id = String()
id = Str()
#: Name of the factory. User friendly for UI
name = String()
name = Str()
#: If the factor should be visible in the UI. Set to false to make it
#: invisible. This is normally useful for notification systems that are
......@@ -53,6 +54,32 @@ class BaseNotificationListenerFactory(ABCHasStrictTraits):
self.plugin = plugin
super(BaseNotificationListenerFactory, self).__init__(*args, **kwargs)
self.listener_class = self.get_listener_class()
self.model_class = self.get_model_class()
self.name = self.get_name()
identifier = self.get_identifier()
self.id = factory_id(self.plugin.id, identifier)
def get_listener_class(self):
raise NotImplementedError(
"get_listener_class was not implemented in factory {}".format(
self.__class__))
def get_model_class(self):
raise NotImplementedError(
"get_model_class was not implemented in factory {}".format(
self.__class__))
def get_identifier(self):
raise NotImplementedError(
"get_identifier was not implemented in factory {}".format(
self.__class__))
def get_name(self):
raise NotImplementedError(
"get_name was not implemented in factory {}".format(
self.__class__))
def create_listener(self):
"""
Creates an instance of the listener.
......
......@@ -2,6 +2,7 @@ import logging
from traits.api import ABCHasStrictTraits, Instance, String, provides, Type
from envisage.plugin import Plugin
from force_bdss.ids import factory_id
from force_bdss.ui_hooks.base_ui_hooks_manager import BaseUIHooksManager
from .i_ui_hooks_factory import IUIHooksFactory
......@@ -38,6 +39,27 @@ class BaseUIHooksFactory(ABCHasStrictTraits):
self.plugin = plugin
super(BaseUIHooksFactory, self).__init__(*args, **kwargs)
self.ui_hooks_manager_class = self.get_ui_hooks_manager_class()
self.name = self.get_name()
identifier = self.get_identifier()
self.id = factory_id(self.plugin.id, identifier)
def get_ui_hooks_manager_class(self):
raise NotImplementedError(
"get_ui_hooks_manager_class was not implemented "
"in factory {}".format(
self.__class__))
def get_name(self):
raise NotImplementedError(
"get_name was not implemented in factory {}".format(
self.__class__))
def get_identifier(self):
raise NotImplementedError(
"get_identifier was not implemented in factory {}".format(
self.__class__))
def create_ui_hooks_manager(self):
"""Creates an instance of the hook manager.
The hooks manager contains a set of methods that are applicable in
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment