From 857f5a5d2654fb629fd4ab7438e8d6f2988260ca Mon Sep 17 00:00:00 2001 From: Stefano Borini <sborini@enthought.com> Date: Wed, 20 Jun 2018 18:29:31 +0100 Subject: [PATCH] Introduces base class and interface for the factories --- force_bdss/api.py | 1 + force_bdss/core/base_factory.py | 55 +++++++++++++++++++ force_bdss/core/i_factory.py | 21 +++++++ .../data_sources/base_data_source_factory.py | 54 ++---------------- .../data_sources/i_data_source_factory.py | 19 ++----- force_bdss/mco/base_mco_factory.py | 47 +++------------- force_bdss/mco/i_mco_factory.py | 19 ++----- .../parameters/base_mco_parameter_factory.py | 45 ++++----------- .../mco/parameters/i_mco_parameter_factory.py | 23 ++++++++ .../base_notification_listener_factory.py | 44 ++------------- .../i_notification_listener_factory.py | 19 ++----- force_bdss/ui_hooks/base_ui_hooks_factory.py | 43 ++------------- force_bdss/ui_hooks/i_ui_hooks_factory.py | 17 ++---- 13 files changed, 150 insertions(+), 257 deletions(-) create mode 100644 force_bdss/core/base_factory.py create mode 100644 force_bdss/core/i_factory.py create mode 100644 force_bdss/mco/parameters/i_mco_parameter_factory.py diff --git a/force_bdss/api.py b/force_bdss/api.py index df58bc8..ff4094d 100644 --- a/force_bdss/api.py +++ b/force_bdss/api.py @@ -4,6 +4,7 @@ from .ids import plugin_id, factory_id # noqa from .core.data_value import DataValue # noqa from .core.workflow import Workflow # noqa from .core.slot import Slot # noqa +from .core.i_factory import IFactory # noqa from .data_sources.base_data_source_model import BaseDataSourceModel # noqa from .data_sources.base_data_source import BaseDataSource # noqa diff --git a/force_bdss/core/base_factory.py b/force_bdss/core/base_factory.py new file mode 100644 index 0000000..0171bdf --- /dev/null +++ b/force_bdss/core/base_factory.py @@ -0,0 +1,55 @@ +from envisage.plugin import Plugin +from traits.api import HasStrictTraits, Str, Instance + +from force_bdss.ids import factory_id + + +class BaseFactory(HasStrictTraits): + #: Unique identifier that identifies the factory uniquely in the + #: universe of factories. Create one with the function factory_id() + id = Str() + + #: A human readable name of the factory. Spaces allowed + name = Str() + + #: Reference to the plugin that carries this factory + #: This is automatically set by the system. you should not define it + #: in your subclass. + plugin = Instance(Plugin, allow_none=False) + + def __init__(self, plugin): + super(BaseFactory, self).__init__(plugin=plugin) + + self.name = self.get_name() + identifier = self.get_identifier() + try: + id = self._global_id(identifier) + except ValueError: + raise ValueError( + "Invalid identifier {} returned by " + "{}.get_identifier()".format( + identifier, + self.__class__.__name__ + ) + ) + self.id = id + + 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_identifier was not implemented in factory {}".format( + self.__class__)) + + def _global_id(self, identifier): + return factory_id(self.plugin.id, identifier) diff --git a/force_bdss/core/i_factory.py b/force_bdss/core/i_factory.py new file mode 100644 index 0000000..d874885 --- /dev/null +++ b/force_bdss/core/i_factory.py @@ -0,0 +1,21 @@ +from envisage.plugin import Plugin +from traits.api import Interface, Str, Instance + + +class IFactory(Interface): + """Envisage required interface for the BaseDataSourceFactory. + You should not need to use this directly. + + Refer to the BaseDataSourceFactory for documentation. + """ + id = Str() + + name = Str() + + plugin = Instance(Plugin, allow_none=False) + + def get_name(self): + pass + + def get_identifier(self): + pass diff --git a/force_bdss/data_sources/base_data_source_factory.py b/force_bdss/data_sources/base_data_source_factory.py index 6c28f56..206321c 100644 --- a/force_bdss/data_sources/base_data_source_factory.py +++ b/force_bdss/data_sources/base_data_source_factory.py @@ -1,17 +1,16 @@ import logging -from traits.api import provides, Str, Instance, Type, HasStrictTraits -from envisage.plugin import Plugin +from traits.api import provides, Type +from force_bdss.core.base_factory import BaseFactory 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__) @provides(IDataSourceFactory) -class BaseDataSourceFactory(HasStrictTraits): +class BaseDataSourceFactory(BaseFactory): """Base class for DataSource factories. Reimplement this class to create your own DataSource. @@ -32,13 +31,6 @@ class BaseDataSourceFactory(HasStrictTraits): """ # 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 = Str() - - #: A human readable name of the factory. Spaces allowed - name = Str() - #: The data source to be instantiated. Define this to your DataSource data_source_class = Type(BaseDataSource, allow_none=False) @@ -46,30 +38,11 @@ class BaseDataSourceFactory(HasStrictTraits): #: Define this to your DataSourceModel model_class = Type(BaseDataSourceModel, allow_none=False) - #: Reference to the plugin that carries this factory - #: This is automatically set by the system. you should not define it - #: in your subclass. - plugin = Instance(Plugin, allow_none=False) - - def __init__(self, plugin, *args, **kwargs): - self.plugin = plugin - super(BaseDataSourceFactory, self).__init__(*args, **kwargs) + def __init__(self, plugin): + super(BaseDataSourceFactory, self).__init__(plugin=plugin) 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() - try: - id = factory_id(self.plugin.id, identifier) - except ValueError: - raise ValueError( - "Invalid identifier {} returned by " - "{}.get_identifier()".format( - identifier, - self.__class__.__name__ - ) - ) - self.id = id def get_data_source_class(self): """Must be reimplemented to return the DataSource class. @@ -85,23 +58,6 @@ class BaseDataSourceFactory(HasStrictTraits): "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_identifier was not implemented in factory {}".format( - self.__class__)) - def create_data_source(self): """Factory method. Must return the factory-specific BaseDataSource instance. diff --git a/force_bdss/data_sources/i_data_source_factory.py b/force_bdss/data_sources/i_data_source_factory.py index bbeb624..d7a7ffe 100644 --- a/force_bdss/data_sources/i_data_source_factory.py +++ b/force_bdss/data_sources/i_data_source_factory.py @@ -1,17 +1,14 @@ -from envisage.api import Plugin -from traits.api import Interface, Str, Instance, Type +from traits.api import Type +from force_bdss.core.i_factory import IFactory -class IDataSourceFactory(Interface): + +class IDataSourceFactory(IFactory): """Envisage required interface for the BaseDataSourceFactory. You should not need to use this directly. Refer to the BaseDataSourceFactory for documentation. """ - id = Str() - - name = Str() - data_source_class = Type( "force_bdss.data_sources.base_data_source.BaseDataSource", allow_none=False @@ -22,16 +19,8 @@ class IDataSourceFactory(Interface): allow_none=False ) - plugin = Instance(Plugin, allow_none=False) - def get_data_source_class(self): pass def get_model_class(self): pass - - def get_name(self): - pass - - def get_identifier(self): - pass diff --git a/force_bdss/mco/base_mco_factory.py b/force_bdss/mco/base_mco_factory.py index c823655..5f15c7a 100644 --- a/force_bdss/mco/base_mco_factory.py +++ b/force_bdss/mco/base_mco_factory.py @@ -1,8 +1,7 @@ import logging -from traits.api import HasStrictTraits, Str, provides, Instance, Type -from envisage.plugin import Plugin +from traits.api import provides, Type -from force_bdss.ids import factory_id +from force_bdss.core.base_factory import BaseFactory 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 @@ -12,17 +11,11 @@ log = logging.getLogger(__name__) @provides(IMCOFactory) -class BaseMCOFactory(HasStrictTraits): +class BaseMCOFactory(BaseFactory): """Base class for the MultiCriteria Optimizer factory. """ # NOTE: any changes to the interface of this class must be replicated - # in the IMultiCriteriaOptimizerFactory interface class. - - #: A unique ID produced with the factory_id() routine. - id = Str() - - #: A user friendly name of the factory. Spaces allowed. - name = Str() + # in the IMCOFactory interface class. #: The optimizer class to instantiate. Define this to your MCO class. optimizer_class = Type(BaseMCO, allow_none=False) @@ -33,29 +26,12 @@ class BaseMCOFactory(HasStrictTraits): #: The communicator associated to the MCO. Define this to your MCO comm. communicator_class = Type(BaseMCOCommunicator, allow_none=False) - #: A reference to the Plugin that holds this factory. - plugin = Instance(Plugin, allow_none=False) - - def __init__(self, plugin, *args, **kwargs): - self.plugin = plugin - super(BaseMCOFactory, self).__init__(*args, **kwargs) + def __init__(self, plugin): + super(BaseMCOFactory, self).__init__(plugin=plugin) - 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() - try: - id = factory_id(self.plugin.id, identifier) - except ValueError: - raise ValueError( - "Invalid identifier {} returned by " - "{}.get_identifier()".format( - identifier, - self.__class__.__name__ - ) - ) - self.id = id def get_optimizer_class(self): raise NotImplementedError( @@ -72,16 +48,6 @@ class BaseMCOFactory(HasStrictTraits): "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 @@ -135,3 +101,4 @@ class BaseMCOFactory(HasStrictTraits): ------- List of BaseMCOParameterFactory """ + return [] diff --git a/force_bdss/mco/i_mco_factory.py b/force_bdss/mco/i_mco_factory.py index 9791017..9e27870 100644 --- a/force_bdss/mco/i_mco_factory.py +++ b/force_bdss/mco/i_mco_factory.py @@ -1,17 +1,14 @@ -from traits.api import Interface, Str, Instance, Type -from envisage.plugin import Plugin +from traits.api import Type +from force_bdss.core.i_factory import IFactory -class IMCOFactory(Interface): + +class IMCOFactory(IFactory): """Interface for the BaseMCOFactory. You should not need it, as its main use is for envisage support. Refer to BaseMCOFactory for documentation """ - id = Str() - - name = Str() - optimizer_class = Type( "force_bdss.mco.base_mco.BaseMCO", allow_none=False @@ -28,8 +25,6 @@ class IMCOFactory(Interface): allow_none=False ) - plugin = Instance(Plugin, allow_none=False) - def get_model_class(self): pass @@ -39,12 +34,6 @@ class IMCOFactory(Interface): def get_optimizer_class(self): pass - def get_identifier(self): - pass - - def get_name(self): - pass - def create_optimizer(self): pass diff --git a/force_bdss/mco/parameters/base_mco_parameter_factory.py b/force_bdss/mco/parameters/base_mco_parameter_factory.py index 63d91fd..258f90e 100644 --- a/force_bdss/mco/parameters/base_mco_parameter_factory.py +++ b/force_bdss/mco/parameters/base_mco_parameter_factory.py @@ -1,9 +1,13 @@ -from traits.api import HasStrictTraits, Str, Type, Instance +from traits.api import Str, Type, Instance, provides +from force_bdss.core.base_factory import BaseFactory from force_bdss.ids import mco_parameter_id +from force_bdss.mco.parameters.i_mco_parameter_factory import \ + IMCOParameterFactory -class BaseMCOParameterFactory(HasStrictTraits): +@provides(IMCOParameterFactory) +class BaseMCOParameterFactory(BaseFactory): """Factory that produces the model instance of a given BASEMCOParameter instance. @@ -16,12 +20,6 @@ class BaseMCOParameterFactory(HasStrictTraits): mco_factory = Instance('force_bdss.mco.base_mco_factory.BaseMCOFactory', allow_none=False) - #: A unique string identifying the parameter - id = Str() - - #: A user friendly name (for the UI) - name = Str() - #: A long description of the parameter description = Str() @@ -31,16 +29,6 @@ class BaseMCOParameterFactory(HasStrictTraits): allow_none=False ) - 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( @@ -51,25 +39,13 @@ class BaseMCOParameterFactory(HasStrictTraits): "get_model_class was not implemented in factory {}".format( self.__class__)) - def __init__(self, mco_factory, *args, **kwargs): + def __init__(self, mco_factory): self.mco_factory = mco_factory - super(BaseMCOParameterFactory, self).__init__(*args, **kwargs) + super(BaseMCOParameterFactory, self).__init__( + plugin=mco_factory.plugin) - self.name = self.get_name() self.description = self.get_description() self.model_class = self.get_model_class() - identifier = self.get_identifier() - try: - id = mco_parameter_id(self.mco_factory.id, identifier) - except ValueError: - raise ValueError( - "Invalid identifier {} returned by " - "{}.get_identifier()".format( - identifier, - self.__class__.__name__ - ) - ) - self.id = id def create_model(self, data_values=None): """Creates the instance of the model class and returns it. @@ -90,3 +66,6 @@ class BaseMCOParameterFactory(HasStrictTraits): data_values = {} return self.model_class(factory=self, **data_values) + + def _global_id(self, identifier): + return mco_parameter_id(self.mco_factory.id, identifier) diff --git a/force_bdss/mco/parameters/i_mco_parameter_factory.py b/force_bdss/mco/parameters/i_mco_parameter_factory.py new file mode 100644 index 0000000..8aa646f --- /dev/null +++ b/force_bdss/mco/parameters/i_mco_parameter_factory.py @@ -0,0 +1,23 @@ +from traits.api import Instance, Type, Str +from force_bdss.core.i_factory import IFactory + + +class IMCOParameterFactory(IFactory): + mco_factory = Instance('force_bdss.mco.base_mco_factory.BaseMCOFactory', + allow_none=False) + + description = Str() + + model_class = Type( + "force_bdss.mco.parameters.base_mco_parameter.BaseMCOParameter", + allow_none=False + ) + + def get_description(self): + """""" + + def get_model_class(self): + """""" + + def create_model(self, data_values=None): + """""" diff --git a/force_bdss/notification_listeners/base_notification_listener_factory.py b/force_bdss/notification_listeners/base_notification_listener_factory.py index 0104558..8b716a2 100644 --- a/force_bdss/notification_listeners/base_notification_listener_factory.py +++ b/force_bdss/notification_listeners/base_notification_listener_factory.py @@ -1,10 +1,10 @@ import logging from traits.api import ( - HasStrictTraits, Instance, Str, provides, Type, Bool + provides, Type, Bool ) from envisage.plugin import Plugin -from force_bdss.ids import factory_id +from force_bdss.core.base_factory import BaseFactory from force_bdss.notification_listeners.base_notification_listener import \ BaseNotificationListener from force_bdss.notification_listeners.base_notification_listener_model \ @@ -16,17 +16,11 @@ log = logging.getLogger(__name__) @provides(INotificationListenerFactory) -class BaseNotificationListenerFactory(HasStrictTraits): +class BaseNotificationListenerFactory(BaseFactory): """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 = Str() - - #: Name of the factory. User friendly for UI - 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 #: not supposed to be configured by the user. @@ -40,10 +34,7 @@ class BaseNotificationListenerFactory(HasStrictTraits): #: listener model class. model_class = Type(BaseNotificationListenerModel, allow_none=False) - #: A reference to the containing plugin - plugin = Instance(Plugin, allow_none=False) - - def __init__(self, plugin, *args, **kwargs): + def __init__(self, plugin): """Initializes the instance. Parameters @@ -51,25 +42,10 @@ class BaseNotificationListenerFactory(HasStrictTraits): plugin: Plugin The plugin that holds this factory. """ - self.plugin = plugin - super(BaseNotificationListenerFactory, self).__init__(*args, **kwargs) + super(BaseNotificationListenerFactory, self).__init__(plugin=plugin) self.listener_class = self.get_listener_class() self.model_class = self.get_model_class() - self.name = self.get_name() - identifier = self.get_identifier() - try: - id = factory_id(self.plugin.id, identifier) - except ValueError: - raise ValueError( - "Invalid identifier {} returned by " - "{}.get_identifier()".format( - identifier, - self.__class__.__name__ - ) - ) - - self.id = id def get_listener_class(self): raise NotImplementedError( @@ -81,16 +57,6 @@ class BaseNotificationListenerFactory(HasStrictTraits): "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. diff --git a/force_bdss/notification_listeners/i_notification_listener_factory.py b/force_bdss/notification_listeners/i_notification_listener_factory.py index 3474685..86b8002 100644 --- a/force_bdss/notification_listeners/i_notification_listener_factory.py +++ b/force_bdss/notification_listeners/i_notification_listener_factory.py @@ -1,17 +1,14 @@ -from traits.api import Interface, String, Instance, Type, Bool -from envisage.plugin import Plugin +from traits.api import Type, Bool +from force_bdss.core.i_factory import IFactory -class INotificationListenerFactory(Interface): + +class INotificationListenerFactory(IFactory): """Envisage required interface for the BaseNotificationListenerFactory. You should not need to use this directly. Refer to the BaseNotificationListenerFactory for documentation. """ - id = String() - - name = String() - ui_visible = Bool() listener_class = Type( @@ -26,14 +23,6 @@ class INotificationListenerFactory(Interface): allow_none=False ) - plugin = Instance(Plugin, allow_none=False) - - def get_name(self): - pass - - def get_identifier(self): - pass - def get_model_class(self): pass diff --git a/force_bdss/ui_hooks/base_ui_hooks_factory.py b/force_bdss/ui_hooks/base_ui_hooks_factory.py index 2aaa66c..29d3397 100644 --- a/force_bdss/ui_hooks/base_ui_hooks_factory.py +++ b/force_bdss/ui_hooks/base_ui_hooks_factory.py @@ -1,8 +1,8 @@ import logging -from traits.api import HasStrictTraits, Instance, Str, provides, Type +from traits.api import provides, Type from envisage.plugin import Plugin -from force_bdss.ids import factory_id +from force_bdss.core.base_factory import BaseFactory from force_bdss.ui_hooks.base_ui_hooks_manager import BaseUIHooksManager from .i_ui_hooks_factory import IUIHooksFactory @@ -10,25 +10,16 @@ log = logging.getLogger(__name__) @provides(IUIHooksFactory) -class BaseUIHooksFactory(HasStrictTraits): +class BaseUIHooksFactory(BaseFactory): """Base class for UIHooksFactory. UI Hooks are extensions that perform actions associated to specific moments of the UI lifetime. """ - #: identifier of the factory - id = Str() - - #: Name of the factory. User friendly for UI - name = Str() - #: The UI Hooks manager class to instantiate. Define this to your #: base hook managers. ui_hooks_manager_class = Type(BaseUIHooksManager, allow_none=False) - #: A reference to the containing plugin - plugin = Instance(Plugin, allow_none=False) - - def __init__(self, plugin, *args, **kwargs): + def __init__(self, plugin): """Initializes the instance. Parameters @@ -36,23 +27,9 @@ class BaseUIHooksFactory(HasStrictTraits): plugin: Plugin The plugin that holds this factory. """ - self.plugin = plugin - super(BaseUIHooksFactory, self).__init__(*args, **kwargs) + super(BaseUIHooksFactory, self).__init__(plugin=plugin) self.ui_hooks_manager_class = self.get_ui_hooks_manager_class() - self.name = self.get_name() - identifier = self.get_identifier() - try: - id = factory_id(self.plugin.id, identifier) - except ValueError: - raise ValueError( - "Invalid identifier {} returned by " - "{}.get_identifier()".format( - identifier, - self.__class__.__name__ - ) - ) - self.id = id def get_ui_hooks_manager_class(self): raise NotImplementedError( @@ -60,16 +37,6 @@ class BaseUIHooksFactory(HasStrictTraits): "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 diff --git a/force_bdss/ui_hooks/i_ui_hooks_factory.py b/force_bdss/ui_hooks/i_ui_hooks_factory.py index c809f3a..fcdf705 100644 --- a/force_bdss/ui_hooks/i_ui_hooks_factory.py +++ b/force_bdss/ui_hooks/i_ui_hooks_factory.py @@ -1,21 +1,18 @@ -from traits.api import Interface, Str, Instance, Type +from traits.api import Instance, Type from envisage.plugin import Plugin +from force_bdss.core.i_factory import IFactory -class IUIHooksFactory(Interface): + +class IUIHooksFactory(IFactory): """Envisage required interface for the BaseUIHooksFactory. You should not need to use this directly. Refer to the BaseUIHooksFactory for documentation. """ - id = Str() - - name = Str() - ui_hooks_manager_class = Type( "force_bdss.ui_hooks.base_ui_hooks_manager.BaseUIHooksManager", allow_none=False - ) plugin = Instance(Plugin, allow_none=False) @@ -23,11 +20,5 @@ class IUIHooksFactory(Interface): def get_ui_hooks_manager_class(self): pass - def get_name(self): - pass - - def get_identifier(self): - pass - def create_ui_hooks_manager(self): pass -- GitLab