From 57719b8c0cf1f525e3329caa05269530301f9003 Mon Sep 17 00:00:00 2001 From: Stefano Borini <sborini@enthought.com> Date: Tue, 8 Aug 2017 17:53:30 +0100 Subject: [PATCH] Working implementation --- force_bdss/api.py | 5 +++ force_bdss/base_extension_plugin.py | 8 +++-- force_bdss/core_mco_driver.py | 34 ++++++++++++++++--- .../dummy/dummy_dakota/dakota_optimizer.py | 4 +++ .../__init__.py | 0 .../dummy_notification_listener.py | 6 ++++ .../dummy_notification_listener_factory.py | 23 +++++++++++++ .../dummy_notification_listener_model.py | 7 ++++ force_bdss/core_plugins/dummy/dummy_plugin.py | 5 ++- .../gui_notification_listener_factory.py | 0 .../base_notification_listener.py | 29 ++++++++++++++++ .../base_notification_listener_factory.py | 20 +++++++++-- .../base_notification_listener_model.py | 22 ++++++++++++ .../i_notification_listener_factory.py | 9 +++-- 14 files changed, 160 insertions(+), 12 deletions(-) rename force_bdss/core_plugins/dummy/{ui_notification_listener => dummy_notification_listener}/__init__.py (100%) create mode 100644 force_bdss/core_plugins/dummy/dummy_notification_listener/dummy_notification_listener.py create mode 100644 force_bdss/core_plugins/dummy/dummy_notification_listener/dummy_notification_listener_factory.py create mode 100644 force_bdss/core_plugins/dummy/dummy_notification_listener/dummy_notification_listener_model.py delete mode 100644 force_bdss/core_plugins/dummy/gui_notification_listener/gui_notification_listener_factory.py create mode 100644 force_bdss/notification_listeners/base_notification_listener.py create mode 100644 force_bdss/notification_listeners/base_notification_listener_model.py diff --git a/force_bdss/api.py b/force_bdss/api.py index 129f5cc..1713d4f 100644 --- a/force_bdss/api.py +++ b/force_bdss/api.py @@ -20,3 +20,8 @@ from .mco.i_mco_factory import IMCOFactory # noqa from .mco.parameters.base_mco_parameter_factory import BaseMCOParameterFactory # noqa from .mco.parameters.base_mco_parameter import BaseMCOParameter # noqa + +from .notification_listeners.i_notification_listener_factory import INotificationListenerFactory # noqa +from .notification_listeners.base_notification_listener import BaseNotificationListener # noqa +from .notification_listeners.base_notification_listener_factory import BaseNotificationListenerFactory # noqa +from .notification_listeners.base_notification_listener_model import BaseNotificationListenerModel # noqa diff --git a/force_bdss/base_extension_plugin.py b/force_bdss/base_extension_plugin.py index 8954d00..692b9fa 100644 --- a/force_bdss/base_extension_plugin.py +++ b/force_bdss/base_extension_plugin.py @@ -1,6 +1,8 @@ from envisage.plugin import Plugin from traits.trait_types import List +from .notification_listeners.i_notification_listener_factory import \ + INotificationListenerFactory from .ids import ExtensionPointID from .data_sources.i_data_source_factory import IDataSourceFactory from .kpi.i_kpi_calculator_factory import IKPICalculatorFactory @@ -40,7 +42,7 @@ class BaseExtensionPlugin(Plugin): contributes_to=ExtensionPointID.KPI_CALCULATOR_FACTORIES ) - notifier_factory = List( - INotifierFactory, - contributes_to=ExtensionPointID.NOTIFIER_FACTORIES + notification_listener_factories = List( + INotificationListenerFactory, + contributes_to=ExtensionPointID.NOTIFICATION_LISTENER_FACTORIES ) diff --git a/force_bdss/core_mco_driver.py b/force_bdss/core_mco_driver.py index 729f569..d140f06 100644 --- a/force_bdss/core_mco_driver.py +++ b/force_bdss/core_mco_driver.py @@ -2,9 +2,11 @@ from __future__ import print_function import sys -from traits.api import on_trait_change, Instance +from traits.api import on_trait_change, Instance, List from force_bdss.mco.base_mco import BaseMCO +from force_bdss.notification_listeners.base_notification_listener import \ + BaseNotificationListener from .ids import plugin_id from .base_core_driver import BaseCoreDriver from .io.workflow_reader import ( @@ -23,10 +25,13 @@ class CoreMCODriver(BaseCoreDriver): mco = Instance(BaseMCO, allow_none=True) - listeners = Instance(BaseNotificationListener) + listeners = List(Instance(BaseNotificationListener)) @on_trait_change("application:started") def application_started(self): + self.mco.run(self.workflow.mco) + + def _mco_default(self): try: workflow = self.workflow except (InvalidVersionException, InvalidFileException) as e: @@ -35,5 +40,26 @@ class CoreMCODriver(BaseCoreDriver): mco_model = workflow.mco mco_factory = mco_model.factory - mco = mco_factory.create_optimizer() - mco.run(mco_model) + return mco_factory.create_optimizer() + + @on_trait_change("mco:started,mco:finished,mco:progress") + def _handle_mco_event(self, object, name, old, new): + if name == "started": + self._deliver_to_listeners("MCO_STARTED") + elif name == "finished": + self._deliver_to_listeners("MCO_FINISHED") + elif name == "progress": + self._deliver_to_listeners("MCO_PROGRESS") + + def _deliver_to_listeners(self, message): + for listener in self.listeners: + listener.deliver(None, message) + + def _listeners_default(self): + listeners = [] + + print(self.factory_registry.notification_listener_factories) + for factory in self.factory_registry.notification_listener_factories: + listeners.append(factory.create_listener()) + + return listeners diff --git a/force_bdss/core_plugins/dummy/dummy_dakota/dakota_optimizer.py b/force_bdss/core_plugins/dummy/dummy_dakota/dakota_optimizer.py index 5b1291a..d97c414 100644 --- a/force_bdss/core_plugins/dummy/dummy_dakota/dakota_optimizer.py +++ b/force_bdss/core_plugins/dummy/dummy_dakota/dakota_optimizer.py @@ -16,6 +16,7 @@ def rotated_range(start, stop, starting_value): class DummyDakotaOptimizer(BaseMCO): def run(self, model): + self.started = True parameters = model.parameters values = [] @@ -42,3 +43,6 @@ class DummyDakotaOptimizer(BaseMCO): " ".join([str(v) for v in value]).encode("utf-8")) print("{}: {}".format(" ".join([str(v) for v in value]), out[0].decode("utf-8"))) + self.progress = True + + self.finished = True diff --git a/force_bdss/core_plugins/dummy/ui_notification_listener/__init__.py b/force_bdss/core_plugins/dummy/dummy_notification_listener/__init__.py similarity index 100% rename from force_bdss/core_plugins/dummy/ui_notification_listener/__init__.py rename to force_bdss/core_plugins/dummy/dummy_notification_listener/__init__.py diff --git a/force_bdss/core_plugins/dummy/dummy_notification_listener/dummy_notification_listener.py b/force_bdss/core_plugins/dummy/dummy_notification_listener/dummy_notification_listener.py new file mode 100644 index 0000000..bfa1a10 --- /dev/null +++ b/force_bdss/core_plugins/dummy/dummy_notification_listener/dummy_notification_listener.py @@ -0,0 +1,6 @@ +from force_bdss.api import BaseNotificationListener + + +class DummyNotificationListener(BaseNotificationListener): + def deliver(self, model, message): + print(message) diff --git a/force_bdss/core_plugins/dummy/dummy_notification_listener/dummy_notification_listener_factory.py b/force_bdss/core_plugins/dummy/dummy_notification_listener/dummy_notification_listener_factory.py new file mode 100644 index 0000000..74d6b38 --- /dev/null +++ b/force_bdss/core_plugins/dummy/dummy_notification_listener/dummy_notification_listener_factory.py @@ -0,0 +1,23 @@ +from traits.api import String + +from force_bdss.ids import factory_id +from force_bdss.notification_listeners.base_notification_listener_factory \ + import \ + BaseNotificationListenerFactory +from .dummy_notification_listener import DummyNotificationListener +from .dummy_notification_listener_model import DummyNotificationListenerModel + + +class DummyNotificationListenerFactory(BaseNotificationListenerFactory): + id = String(factory_id("enthought", "dummy_notification_listener")) + + name = String("Dummy Notification Listener") + + def create_model(self, model_data=None): + if model_data is None: + model_data = {} + + return DummyNotificationListenerModel(self, **model_data) + + def create_listener(self): + return DummyNotificationListener(self) diff --git a/force_bdss/core_plugins/dummy/dummy_notification_listener/dummy_notification_listener_model.py b/force_bdss/core_plugins/dummy/dummy_notification_listener/dummy_notification_listener_model.py new file mode 100644 index 0000000..78443c4 --- /dev/null +++ b/force_bdss/core_plugins/dummy/dummy_notification_listener/dummy_notification_listener_model.py @@ -0,0 +1,7 @@ +from force_bdss.notification_listeners.base_notification_listener_model \ + import \ + BaseNotificationListenerModel + + +class DummyNotificationListenerModel(BaseNotificationListenerModel): + pass diff --git a/force_bdss/core_plugins/dummy/dummy_plugin.py b/force_bdss/core_plugins/dummy/dummy_plugin.py index 1ff6590..bc64438 100644 --- a/force_bdss/core_plugins/dummy/dummy_plugin.py +++ b/force_bdss/core_plugins/dummy/dummy_plugin.py @@ -1,4 +1,7 @@ from force_bdss.api import BaseExtensionPlugin, plugin_id +from force_bdss.core_plugins.dummy.dummy_notification_listener\ + .dummy_notification_listener_factory import \ + DummyNotificationListenerFactory from .csv_extractor.csv_extractor_factory import CSVExtractorFactory from .kpi_adder.kpi_adder_factory import KPIAdderFactory from .dummy_dakota.dakota_factory import DummyDakotaFactory @@ -23,4 +26,4 @@ class DummyPlugin(BaseExtensionPlugin): KPIAdderFactory(self)] def _notification_listener_factories_default(self): - return [GUINotificationListenerFactory()] + return [DummyNotificationListenerFactory(self)] diff --git a/force_bdss/core_plugins/dummy/gui_notification_listener/gui_notification_listener_factory.py b/force_bdss/core_plugins/dummy/gui_notification_listener/gui_notification_listener_factory.py deleted file mode 100644 index e69de29..0000000 diff --git a/force_bdss/notification_listeners/base_notification_listener.py b/force_bdss/notification_listeners/base_notification_listener.py new file mode 100644 index 0000000..32293b3 --- /dev/null +++ b/force_bdss/notification_listeners/base_notification_listener.py @@ -0,0 +1,29 @@ +import abc + +from traits.api import ABCHasStrictTraits, Instance + +from .i_notification_listener_factory import INotificationListenerFactory + + +class BaseNotificationListener(ABCHasStrictTraits): + """Base class for the Multi Criteria Optimizer. + + Inherit this class for your MCO implementation + """ + #: A reference to the factory + factory = Instance(INotificationListenerFactory) + + def __init__(self, factory, *args, **kwargs): + """Initializes the MCO. + + Parameters + ---------- + factory: BaseMCOFactory + The factory this BaseMCO belongs to + """ + self.factory = factory + super(BaseNotificationListener, self).__init__(*args, **kwargs) + + @abc.abstractmethod + def deliver(self, model, message): + pass diff --git a/force_bdss/notification_listeners/base_notification_listener_factory.py b/force_bdss/notification_listeners/base_notification_listener_factory.py index 58d4d08..18389a3 100644 --- a/force_bdss/notification_listeners/base_notification_listener_factory.py +++ b/force_bdss/notification_listeners/base_notification_listener_factory.py @@ -1,6 +1,6 @@ import abc -from traits.api import ABCHasStrictTraits, Instance, String, provides +from traits.api import ABCHasStrictTraits, Instance, String, provides, Any from envisage.plugin import Plugin from .i_notification_listener_factory import INotificationListenerFactory @@ -14,10 +14,26 @@ class BaseNotificationListenerFactory(ABCHasStrictTraits): plugin = Instance(Plugin) + persistent_state = Any() + + def __init__(self, plugin, *args, **kwargs): + """Initializes the instance. + + Parameters + ---------- + plugin: Plugin + The plugin that holds this factory. + """ + self.plugin = plugin + super(BaseNotificationListenerFactory, self).__init__(*args, **kwargs) + @abc.abstractmethod - def create_object(self): + def create_listener(self): """""" @abc.abstractmethod def create_model(self, model_data=None): """""" + + def init_persistent_state(self): + pass diff --git a/force_bdss/notification_listeners/base_notification_listener_model.py b/force_bdss/notification_listeners/base_notification_listener_model.py new file mode 100644 index 0000000..821a650 --- /dev/null +++ b/force_bdss/notification_listeners/base_notification_listener_model.py @@ -0,0 +1,22 @@ +from traits.api import ABCHasStrictTraits, Instance + +from force_bdss.notification_listeners.i_notification_listener_factory import \ + INotificationListenerFactory + + +class BaseNotificationListenerModel(ABCHasStrictTraits): + """Base class for the specific MCO models. + This model will also provide, through traits/traitsui magic the View + that will appear in the workflow manager UI. + + In your definition, your specific model must reimplement this class. + """ + #: A reference to the creating factory, so that we can + #: retrieve it as the originating factory. + factory = Instance(INotificationListenerFactory, + visible=False, + transient=True) + + def __init__(self, factory, *args, **kwargs): + self.factory = factory + super(BaseNotificationListenerModel, self).__init__(*args, **kwargs) diff --git a/force_bdss/notification_listeners/i_notification_listener_factory.py b/force_bdss/notification_listeners/i_notification_listener_factory.py index 6a2c1e5..a269f8c 100644 --- a/force_bdss/notification_listeners/i_notification_listener_factory.py +++ b/force_bdss/notification_listeners/i_notification_listener_factory.py @@ -1,4 +1,4 @@ -from traits.api import Interface, String, Instance +from traits.api import Interface, String, Instance, Any from envisage.plugin import Plugin @@ -14,8 +14,13 @@ class INotificationListenerFactory(Interface): plugin = Instance(Plugin) - def create_object(self): + persistent_state = Any + + def create_listener(self): """""" def create_model(self, model_data=None): """""" + + def init_persistent_state(self): + pass -- GitLab