diff --git a/force_bdss/core_mco_driver.py b/force_bdss/core_mco_driver.py index 36e045012769998c8b65c9d4d1246bbd1188272a..6e17888318c33eccb96aea5d8ebe6ca0d013dfa9 100644 --- a/force_bdss/core_mco_driver.py +++ b/force_bdss/core_mco_driver.py @@ -1,6 +1,7 @@ from __future__ import print_function import sys +import logging from traits.api import on_trait_change, Instance, List @@ -31,6 +32,17 @@ class CoreMCODriver(BaseCoreDriver): def application_started(self): self.mco.run(self.workflow.mco) + @on_trait_change("application:stopping") + def application_stopping(self): + for listener in self.listeners: + try: + listener.finalize(None) + except Exception as e: + logging.error( + "Failed to finalize " + "listener {}: {}".format( + listener.__class__.__name__, str(e))) + def _mco_default(self): try: workflow = self.workflow @@ -51,8 +63,15 @@ class CoreMCODriver(BaseCoreDriver): listeners = [] for factory in self.factory_registry.notification_listener_factories: - listener = factory.create_listener() - listener.init_persistent_state(None) - listeners.append(listener) + try: + listener = factory.create_listener() + listener.initialize(None) + except Exception as e: + logging.error( + "Failed to create or initialize " + "listener with id {}: {}".format( + factory.id, str(e))) + else: + listeners.append(listener) return listeners 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 index 6efc45a1000c92596c8619c7e0bdfbd88ea4279a..dbd0ed794b4558dc7306d0a88aa3825859646cb9 100644 --- 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 @@ -10,5 +10,8 @@ class DummyNotificationListener(BaseNotificationListener): elif isinstance(event, MCOProgressEvent): print(event.__class__.__name__, event.input, event.output) - def init_persistent_state(self, model): + def initialize(self, model): print("Initializing persistent state") + + def finalize(self, model): + print("Finalizing persistent state") diff --git a/force_bdss/core_plugins/dummy/ui_notification/ui_notification.py b/force_bdss/core_plugins/dummy/ui_notification/ui_notification.py index 48cb2af35aa093dc71d0143fe6ec47d5f3b6dbff..c8fe9353fd4f1fe8b5a84037f3357d70a9968512 100644 --- a/force_bdss/core_plugins/dummy/ui_notification/ui_notification.py +++ b/force_bdss/core_plugins/dummy/ui_notification/ui_notification.py @@ -41,7 +41,7 @@ class UINotification(BaseNotificationListener): self._msg_cache.append(msg) self._pub_socket.send(msg) - def init_persistent_state(self, model): + def initialize(self, model): self._context = zmq.Context() self._pub_socket = self._context.socket(zmq.PUB) self._pub_socket.bind("tcp://*:12345") @@ -62,3 +62,9 @@ class UINotification(BaseNotificationListener): return None return ("EVENT\n{}".format(data)).encode("utf-8") + + def finalize(self, model): + self._context.destroy() + self._pub_socket = None + self._rep_socket = None + self._context = None diff --git a/force_bdss/notification_listeners/base_notification_listener.py b/force_bdss/notification_listeners/base_notification_listener.py index a43d4f2a3db11a6594213a9e31f4022a5037db98..64b8243ae001ac658365da2e0aae298027fb98e8 100644 --- a/force_bdss/notification_listeners/base_notification_listener.py +++ b/force_bdss/notification_listeners/base_notification_listener.py @@ -24,9 +24,33 @@ class BaseNotificationListener(ABCHasStrictTraits): self.factory = factory super(BaseNotificationListener, self).__init__(*args, **kwargs) + def initialize(self, model): + """ + Method used to initialize persistent state of the listener using + information from the model. + + Reimplement it in your Notification Listener to perform special + initialization of state that survives across deliver() invocations, + such as setting up a connection, or opening a file. + """ + + def finalize(self, model): + """ + Method used to finalize state of the listener. + + Reimplement it in your Notification Listener to perform special + finalization of state that survives across deliver() invocations, + such as closing a connection, or closing a file. + """ + @abc.abstractmethod - def deliver(self, model, message): - pass + def deliver(self, model, event): + """Delivers the event to the recipient - def init_persistent_state(self, model): - pass + Parameters + ---------- + model: + The model + event: MCOEvent + The event to notify. + """ diff --git a/force_bdss/notification_listeners/base_notification_listener_factory.py b/force_bdss/notification_listeners/base_notification_listener_factory.py index ffbe464c746df3cf2ba443895a7a4ed5b7169415..08e2b59f90f2518d99445ffd09568e23e1b84045 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, Any +from traits.api import ABCHasStrictTraits, Instance, String, provides from envisage.plugin import Plugin from .i_notification_listener_factory import INotificationListenerFactory @@ -8,14 +8,19 @@ from .i_notification_listener_factory import INotificationListenerFactory @provides(INotificationListenerFactory) class BaseNotificationListenerFactory(ABCHasStrictTraits): + """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() + #: Name of the factory. User friendly for UI name = String() + #: A reference to the containing plugin plugin = Instance(Plugin) - persistent_state = Any() - def __init__(self, plugin, *args, **kwargs): """Initializes the instance. @@ -29,8 +34,17 @@ class BaseNotificationListenerFactory(ABCHasStrictTraits): @abc.abstractmethod def create_listener(self): - """""" + """ + Creates an instance of the listener. + """ @abc.abstractmethod def create_model(self, model_data=None): - """""" + """ + Creates an instance of the model. + + Parameters + ---------- + model_data: dict + Data to use to fill the model. + """ diff --git a/force_bdss/notification_listeners/i_notification_listener_factory.py b/force_bdss/notification_listeners/i_notification_listener_factory.py index a269f8cceae1448fac211e5c5dab9cfc2236af23..c4240d80500dfe343c5ae01216bca4588d2f1ea0 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, Any +from traits.api import Interface, String, Instance from envisage.plugin import Plugin @@ -6,7 +6,7 @@ class INotificationListenerFactory(Interface): """Envisage required interface for the BaseNotificationListenerFactory. You should not need to use this directly. - Refer to the BaseNotifier for documentation. + Refer to the BaseNotificationListenerFactory for documentation. """ id = String() @@ -14,13 +14,8 @@ class INotificationListenerFactory(Interface): plugin = Instance(Plugin) - persistent_state = Any - def create_listener(self): """""" def create_model(self, model_data=None): """""" - - def init_persistent_state(self): - pass