From b6daf987d3e151236fcf4d5701f4d08b5cbc61e6 Mon Sep 17 00:00:00 2001
From: Stefano Borini <sborini@enthought.com>
Date: Fri, 21 Jul 2017 10:25:40 +0100
Subject: [PATCH] Documentation and tests

---
 .../data_sources/base_data_source_bundle.py   | 35 +++++++++++-
 .../data_sources/i_data_source_bundle.py      |  1 -
 .../tests/test_base_data_source_bundle.py     | 23 ++++++++
 force_bdss/kpi/base_kpi_calculator_bundle.py  | 43 +++++++++++++-
 force_bdss/kpi/i_kpi_calculator_bundle.py     |  2 +
 .../tests/test_base_kpi_calculator_bundle.py  | 23 ++++++++
 .../base_multi_criteria_optimizer_bundle.py   | 57 +++++++++++++++++--
 .../mco/i_multi_criteria_optimizer_bundle.py  |  5 +-
 ...st_base_multi_criteria_optimizer_bundle.py | 27 +++++++++
 9 files changed, 205 insertions(+), 11 deletions(-)
 create mode 100644 force_bdss/data_sources/tests/test_base_data_source_bundle.py
 create mode 100644 force_bdss/kpi/tests/test_base_kpi_calculator_bundle.py
 create mode 100644 force_bdss/mco/tests/test_base_multi_criteria_optimizer_bundle.py

diff --git a/force_bdss/data_sources/base_data_source_bundle.py b/force_bdss/data_sources/base_data_source_bundle.py
index 6ad3d76..ab53763 100644
--- a/force_bdss/data_sources/base_data_source_bundle.py
+++ b/force_bdss/data_sources/base_data_source_bundle.py
@@ -6,22 +6,51 @@ from .i_data_source_bundle import IDataSourceBundle
 
 @provides(IDataSourceBundle)
 class BaseDataSourceBundle(ABCHasStrictTraits):
+    """Base class for DataSource bundles. Reimplement this class to
+    create your own DataSource.
+    """
+    # NOTE: changes to this class must be ported also to the IDataSourceBundle
+
     #: Unique identifier that identifies the bundle uniquely in the
     #: universe of bundles. Create one with the function bundle_id()
     id = String()
 
-    #: A human readable name of the bundle
+    #: A human readable name of the bundle. Spaces allowed
     name = String()
 
     @abc.abstractmethod
     def create_data_source(self, application, model):
         """Factory method.
         Must return the bundle-specific BaseDataSource instance.
+
+        Parameters
+        ----------
+        application: Application
+            The envisage application.
+        model: BaseDataSourceModel
+            The model of the data source, instantiated with create_model()
+
+        Returns
+        -------
+        BaseDataSource
+            The specific instance of the generated DataSource
         """
-        pass
 
     @abc.abstractmethod
     def create_model(self, model_data=None):
         """Factory method.
-        Must return the bundle-specific BaseDataSourceModel instance.
+        Creates the model object (or network of model objects) of the KPI
+        calculator. The model can provide a traits UI View according to
+        traitsui specifications, so that a UI can be provided automatically.
+
+        Parameters
+        ----------
+        model_data: dict or None
+            A dictionary containing the information to recreate the model.
+            If None, an empty (with defaults) model will be returned.
+
+        Returns
+        -------
+        BaseDataSourceModel
+            The model
         """
diff --git a/force_bdss/data_sources/i_data_source_bundle.py b/force_bdss/data_sources/i_data_source_bundle.py
index 5270245..8ed2556 100644
--- a/force_bdss/data_sources/i_data_source_bundle.py
+++ b/force_bdss/data_sources/i_data_source_bundle.py
@@ -13,7 +13,6 @@ class IDataSourceBundle(Interface):
         """Factory method.
         Must return the bundle-specific BaseDataSource instance.
         """
-        pass
 
     def create_model(self, model_data=None):
         """Factory method.
diff --git a/force_bdss/data_sources/tests/test_base_data_source_bundle.py b/force_bdss/data_sources/tests/test_base_data_source_bundle.py
new file mode 100644
index 0000000..3564a7e
--- /dev/null
+++ b/force_bdss/data_sources/tests/test_base_data_source_bundle.py
@@ -0,0 +1,23 @@
+import unittest
+
+from force_bdss.data_sources.base_data_source_bundle import \
+    BaseDataSourceBundle
+
+
+class DummyDataSourceBundle(BaseDataSourceBundle):
+    id = "foo"
+
+    name = "bar"
+
+    def create_data_source(self, application, model):
+        pass
+
+    def create_model(self, model_data=None):
+        pass
+
+
+class TestBaseDataSourceBundle(unittest.TestCase):
+    def test_initialization(self):
+        bundle = DummyDataSourceBundle()
+        self.assertEqual(bundle.id, 'foo')
+        self.assertEqual(bundle.name, 'bar')
diff --git a/force_bdss/kpi/base_kpi_calculator_bundle.py b/force_bdss/kpi/base_kpi_calculator_bundle.py
index 75705c7..5ae4063 100644
--- a/force_bdss/kpi/base_kpi_calculator_bundle.py
+++ b/force_bdss/kpi/base_kpi_calculator_bundle.py
@@ -6,14 +6,53 @@ from .i_kpi_calculator_bundle import IKPICalculatorBundle
 
 @provides(IKPICalculatorBundle)
 class BaseKPICalculatorBundle(ABCHasStrictTraits):
+    """Base class for the Key Performance Indicator calculator bundles.
+    Inherit from this class to create a bundle, and reimplement the abstract
+    methods.
+    """
+    # NOTE: any changes in this interface must be ported to
+    # IKPICalculatorBundle
+
+    #: A unique ID generated with bundle_id() routine
     id = String()
 
+    #: A UI friendly name for the bundle. Can contain spaces.
     name = String()
 
     @abc.abstractmethod
     def create_kpi_calculator(self, application, model):
-        pass
+        """Factory method.
+        Creates and returns an instance of a KPI Calculator, associated
+        to the given application and model.
+
+        Parameters
+        ----------
+        application: Application
+            The envisage application.
+        model: BaseKPICalculatorModel
+            The model of the calculator, instantiated with create_model()
+
+        Returns
+        -------
+        BaseKPICalculator
+            The specific instance of the generated KPICalculator
+        """
 
     @abc.abstractmethod
     def create_model(self, model_data=None):
-        pass
+        """Factory method.
+        Creates the model object (or network of model objects) of the KPI
+        calculator. The model can provide a traits UI View according to
+        traitsui specifications, so that a UI can be provided automatically.
+
+        Parameters
+        ----------
+        model_data: dict or None
+            A dictionary containing the information to recreate the model.
+            If None, an empty (with defaults) model will be returned.
+
+        Returns
+        -------
+        BaseKPICalculatorModel
+            The model
+        """
diff --git a/force_bdss/kpi/i_kpi_calculator_bundle.py b/force_bdss/kpi/i_kpi_calculator_bundle.py
index 84b8f90..938e7de 100644
--- a/force_bdss/kpi/i_kpi_calculator_bundle.py
+++ b/force_bdss/kpi/i_kpi_calculator_bundle.py
@@ -2,6 +2,8 @@ from traits.api import Interface, String
 
 
 class IKPICalculatorBundle(Interface):
+    """Envisage required interface for the BaseKPICalculatorBundle.
+    You should not need to use this directly."""
     id = String()
 
     name = String()
diff --git a/force_bdss/kpi/tests/test_base_kpi_calculator_bundle.py b/force_bdss/kpi/tests/test_base_kpi_calculator_bundle.py
new file mode 100644
index 0000000..30dc60e
--- /dev/null
+++ b/force_bdss/kpi/tests/test_base_kpi_calculator_bundle.py
@@ -0,0 +1,23 @@
+import unittest
+
+from force_bdss.kpi.base_kpi_calculator_bundle import \
+    BaseKPICalculatorBundle
+
+
+class DummyKPICalculatorBundle(BaseKPICalculatorBundle):
+    id = "foo"
+
+    name = "bar"
+
+    def create_kpi_calculator(self, application, model):
+        pass
+
+    def create_model(self, model_data=None):
+        pass
+
+
+class TestBaseKPICalculatorBundle(unittest.TestCase):
+    def test_initialization(self):
+        bundle = DummyKPICalculatorBundle()
+        self.assertEqual(bundle.id, 'foo')
+        self.assertEqual(bundle.name, 'bar')
diff --git a/force_bdss/mco/base_multi_criteria_optimizer_bundle.py b/force_bdss/mco/base_multi_criteria_optimizer_bundle.py
index d44f387..228ec4c 100644
--- a/force_bdss/mco/base_multi_criteria_optimizer_bundle.py
+++ b/force_bdss/mco/base_multi_criteria_optimizer_bundle.py
@@ -10,18 +10,67 @@ from force_bdss.mco.i_multi_criteria_optimizer_bundle import (
 
 @provides(IMultiCriteriaOptimizerBundle)
 class BaseMultiCriteriaOptimizerBundle(ABCHasStrictTraits):
+    """Base class for the MultiCriteria Optimizer bundle.
+    """
+    # NOTE: any changes to the interface of this class must be replicated
+    # in the IMultiCriteriaOptimizerBundle interface class.
+
+    #: A unique ID produced with the bundle_id() routine.
     id = String()
 
+    #: A user friendly name of the bundle. Spaces allowed.
     name = String()
 
     @abc.abstractmethod
     def create_optimizer(self, application, model):
-        pass
+        """Factory method.
+        Creates the optimizer with the given application
+        and model and returns it to the caller.
+
+        Parameters
+        ----------
+        application: Application
+            The envisage application instance
+        model: BaseMCOModel
+            The model to associate to the optimizer, instantiated through
+            create_model()
+
+        Returns
+        -------
+        BaseMCOOptimizer
+            The optimizer
+        """
 
     @abc.abstractmethod
     def create_model(self, model_data=None):
-        pass
+        """Factory method.
+        Creates the model object (or network of model objects) of the MCO.
+        The model can provide a traits UI View according to traitsui
+        specifications, so that a UI can be provided automatically.
+
+        Parameters
+        ----------
+        model_data: dict or None
+            A dictionary of data that can be interpreted appropriately to
+            recreate the model. If None, an empty (with defaults) model will
+            be created and returned.
+
+        Returns
+        -------
+        BaseMCOModel
+            The MCOModel
+        """
 
     @abc.abstractmethod
-    def create_communicator(self, model_data):
-        pass
+    def create_communicator(self, application, model):
+        """Factory method. Returns the communicator class that allows
+        exchange between the MCO and the evaluator code.
+
+        Parameters
+        ----------
+        application: Application
+            The envisage application instance
+        model: BaseMCOModel
+            The model to associate to the optimizer, instantiated through
+            create_model()
+        """
diff --git a/force_bdss/mco/i_multi_criteria_optimizer_bundle.py b/force_bdss/mco/i_multi_criteria_optimizer_bundle.py
index 24557e4..82a857a 100644
--- a/force_bdss/mco/i_multi_criteria_optimizer_bundle.py
+++ b/force_bdss/mco/i_multi_criteria_optimizer_bundle.py
@@ -2,6 +2,9 @@ from traits.api import Interface, String
 
 
 class IMultiCriteriaOptimizerBundle(Interface):
+    """Interface for the MultiCriteria Optimizer bundle.
+    You should not need it, as its main use is for envisage support.
+    """
     id = String()
 
     name = String()
@@ -12,5 +15,5 @@ class IMultiCriteriaOptimizerBundle(Interface):
     def create_model(self, model_data=None):
         pass
 
-    def create_communicator(self, model_data):
+    def create_communicator(self, application, model):
         pass
diff --git a/force_bdss/mco/tests/test_base_multi_criteria_optimizer_bundle.py b/force_bdss/mco/tests/test_base_multi_criteria_optimizer_bundle.py
new file mode 100644
index 0000000..de89488
--- /dev/null
+++ b/force_bdss/mco/tests/test_base_multi_criteria_optimizer_bundle.py
@@ -0,0 +1,27 @@
+import unittest
+
+from force_bdss.mco.base_multi_criteria_optimizer_bundle import (
+    BaseMultiCriteriaOptimizerBundle
+)
+
+
+class DummyMCOBundle(BaseMultiCriteriaOptimizerBundle):
+    id = "foo"
+
+    name = "bar"
+
+    def create_optimizer(self, application, model):
+        pass
+
+    def create_model(self, model_data=None):
+        pass
+
+    def create_communicator(self, model_data):
+        pass
+
+
+class TestBaseDataSourceBundle(unittest.TestCase):
+    def test_initialization(self):
+        bundle = DummyMCOBundle()
+        self.assertEqual(bundle.id, 'foo')
+        self.assertEqual(bundle.name, 'bar')
-- 
GitLab