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

Reports error in case of failed initialization of factory

parent e9a7fc37
No related branches found
No related tags found
1 merge request!129Safer plugin import
This commit is part of merge request !129. Comments created here will be created in the context of that merge request.
import logging
import traceback
from envisage.plugin import Plugin from envisage.plugin import Plugin
from traits.trait_types import List from traits.api import List, Unicode, Bool, Type, Either
from force_bdss.data_sources.base_data_source_factory import \
BaseDataSourceFactory
from force_bdss.mco.base_mco_factory import BaseMCOFactory
from force_bdss.notification_listeners.base_notification_listener_factory \
import \
BaseNotificationListenerFactory
from force_bdss.ui_hooks.base_ui_hooks_factory import BaseUIHooksFactory
from .notification_listeners.i_notification_listener_factory import \ from .notification_listeners.i_notification_listener_factory import \
INotificationListenerFactory INotificationListenerFactory
from .ids import ExtensionPointID from .ids import ExtensionPointID
...@@ -9,20 +19,40 @@ from .mco.i_mco_factory import IMCOFactory ...@@ -9,20 +19,40 @@ from .mco.i_mco_factory import IMCOFactory
from .ui_hooks.i_ui_hooks_factory import IUIHooksFactory from .ui_hooks.i_ui_hooks_factory import IUIHooksFactory
logger = logging.getLogger(__name__)
class BaseExtensionPlugin(Plugin): class BaseExtensionPlugin(Plugin):
"""Base class for extension plugins, that is, plugins that are """Base class for extension plugins, that is, plugins that are
provided by external contributors. provided by external contributors.
It provides a set of slots to be populated that end up contributing It provides a set of slots to be populated that end up contributing
to the application extension points. To use the class, simply inherit it to the application extension points. To use the class, simply inherit it
in your plugin, and then define the trait default initializer for the in your plugin, and then fill the factory_classes trait with the classes
specific trait you want to populate. For example:: you want to export. For example::
class MyPlugin(BaseExtensionPlugin): class MyPlugin(BaseExtensionPlugin):
def _data_source_factories_default(self): id = plugin_id("enthought", "myplugin")
return [MyDataSourceFactory1(),
MyDataSourceFactory2()] factory_classes = [
MyDataSourceFactory1,
MyDataSourceFactory2
]
""" """
#: Reports if the plugin loaded its factories successfully or not.
broken = Bool(False)
#: The error that have been generated by the instantiations.
error = Unicode()
#: A list of all the factory classes to export.
factory_classes = List(
Either(Type(BaseDataSourceFactory),
Type(BaseMCOFactory),
Type(BaseNotificationListenerFactory),
Type(BaseUIHooksFactory)
)
)
#: A list of available Multi Criteria Optimizers this plugin exports. #: A list of available Multi Criteria Optimizers this plugin exports.
mco_factories = List( mco_factories = List(
...@@ -36,12 +66,46 @@ class BaseExtensionPlugin(Plugin): ...@@ -36,12 +66,46 @@ class BaseExtensionPlugin(Plugin):
contributes_to=ExtensionPointID.DATA_SOURCE_FACTORIES contributes_to=ExtensionPointID.DATA_SOURCE_FACTORIES
) )
#: A list of the available notification listeners this plugin exports
notification_listener_factories = List( notification_listener_factories = List(
INotificationListenerFactory, INotificationListenerFactory,
contributes_to=ExtensionPointID.NOTIFICATION_LISTENER_FACTORIES contributes_to=ExtensionPointID.NOTIFICATION_LISTENER_FACTORIES
) )
#: A list of the available ui hooks this plugin exports
ui_hooks_factories = List( ui_hooks_factories = List(
IUIHooksFactory, IUIHooksFactory,
contributes_to=ExtensionPointID.UI_HOOKS_FACTORIES contributes_to=ExtensionPointID.UI_HOOKS_FACTORIES
) )
def _data_source_factories_default(self):
return self._instantiate_factories(BaseDataSourceFactory)
def _mco_factories_default(self):
return self._instantiate_factories(BaseMCOFactory)
def _notification_listener_factories_default(self):
return self._instantiate_factories(BaseNotificationListenerFactory)
def _ui_hooks_factories_default(self):
return self._instantiate_factories(BaseUIHooksFactory)
def _instantiate_factories(self, type_):
if self.broken:
logger.error(
"Skipping instantiation of {} due to previous errors.".format(
type_.__name__))
return []
try:
return [
factory(self)
for factory in self._factory_by_type(type_)
]
except Exception as e:
self.broken = True
self.error = traceback.format_exc()
logger.exception(e)
def _factory_by_type(self, type_):
return [cls for cls in self.factory_classes if issubclass(cls, type_)]
from force_bdss.base_extension_plugin import BaseExtensionPlugin
from force_bdss.ids import plugin_id
from force_bdss.tests.probe_classes.data_source import ProbeDataSourceFactory
from force_bdss.tests.probe_classes.mco import ProbeMCOFactory
from force_bdss.tests.probe_classes.notification_listener import \
ProbeNotificationListenerFactory
from force_bdss.tests.probe_classes.ui_hooks import ProbeUIHooksFactory
class ProbeExtensionPlugin(BaseExtensionPlugin):
id = plugin_id("enthought", "test")
factory_classes = [
ProbeDataSourceFactory,
ProbeMCOFactory,
ProbeNotificationListenerFactory,
ProbeUIHooksFactory,
]
import unittest
from force_bdss.tests.probe_classes.probe_extension_plugin import \
ProbeExtensionPlugin
try:
import mock
except ImportError:
from unittest import mock
class TestBaseExtensionPlugin(unittest.TestCase):
def test_basic_init(self):
plugin = ProbeExtensionPlugin()
self.assertEqual(len(plugin.data_source_factories), 1)
self.assertEqual(len(plugin.notification_listener_factories), 1)
self.assertEqual(len(plugin.mco_factories), 1)
self.assertEqual(len(plugin.ui_hooks_factories), 1)
self.assertFalse(plugin.broken)
self.assertEqual(plugin.error, "")
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