From 3adac382f4203930597c1426da36bb542fd05cdc Mon Sep 17 00:00:00 2001 From: Stefano Borini <sborini@enthought.com> Date: Thu, 26 Apr 2018 13:59:32 +0100 Subject: [PATCH] Changed output_slot_names to output_slot_info and fixed tests --- force_bdss/core/output_slot_info.py | 19 ++++++++++++ force_bdss/core_evaluation_driver.py | 8 ++--- force_bdss/core_mco_driver.py | 4 +-- .../data_sources/base_data_source_model.py | 11 +++++-- .../tests/test_base_data_source_model.py | 21 ++++++++++++-- force_bdss/io/workflow_reader.py | 8 +++++ force_bdss/kpi/base_kpi_calculator_model.py | 7 +++-- .../tests/test_base_kpi_calculator_model.py | 29 +++++++++++++------ force_bdss/tests/fixtures/test_null.json | 4 +-- .../tests/test_core_evaluation_driver.py | 27 +++++++++++++---- 10 files changed, 107 insertions(+), 31 deletions(-) create mode 100644 force_bdss/core/output_slot_info.py diff --git a/force_bdss/core/output_slot_info.py b/force_bdss/core/output_slot_info.py new file mode 100644 index 0000000..f294c53 --- /dev/null +++ b/force_bdss/core/output_slot_info.py @@ -0,0 +1,19 @@ +from traits.api import HasStrictTraits, Bool + +from ..local_traits import Identifier + + +class OutputSlotInfo(HasStrictTraits): + """ + Class that specifies the name and characteristics of the output slots + of a data source. + This entity will go in the model object, and associates the positional + order in the containing list with the variable name that refers to the + value that should be taken. + """ + #: The user defined name of the variable containing the value. + name = Identifier() + + #: True if the value associated to this output slot must be exported as + #: a KPI. + kpi = Bool(False) diff --git a/force_bdss/core_evaluation_driver.py b/force_bdss/core_evaluation_driver.py index 8f75105..6ff50dd 100644 --- a/force_bdss/core_evaluation_driver.py +++ b/force_bdss/core_evaluation_driver.py @@ -143,7 +143,7 @@ def _compute_layer_results(environment_data_values, log.error(error_txt) raise RuntimeError(error_txt) - if len(res) != len(model.output_slot_names): + if len(res) != len(model.output_slot_info): error_txt = ( "The number of data values ({} values) returned" " by '{}' does not match the number" @@ -152,7 +152,7 @@ def _compute_layer_results(environment_data_values, " error.").format( len(res), factory.name, - len(model.output_slot_names) + len(model.output_slot_info) ) log.error(error_txt) @@ -160,8 +160,8 @@ def _compute_layer_results(environment_data_values, # At this point, the returned data values are unnamed. # Add the names as specified by the user. - for dv, output_slot_name in zip(res, model.output_slot_names): - dv.name = output_slot_name + for dv, output_slot_info in zip(res, model.output_slot_info): + dv.name = output_slot_info.name # If the name was not specified, simply discard the value, # because apparently the user is not interested in it. diff --git a/force_bdss/core_mco_driver.py b/force_bdss/core_mco_driver.py index ea2cbfa..79c6844 100644 --- a/force_bdss/core_mco_driver.py +++ b/force_bdss/core_mco_driver.py @@ -57,11 +57,11 @@ class CoreMCODriver(BaseCoreDriver): def _deliver_start_event(self): output_names = [] for kpi in self.workflow.kpi_calculators: - output_names.extend(kpi.output_slot_names) + output_names.extend(kpi.output_slot_info) self._deliver_event(MCOStartEvent( input_names=tuple(p.name for p in self.workflow.mco.parameters), - output_names=tuple(output_names) + output_names=tuple([on.name for on in output_names]) )) @on_trait_change("mco:finished") diff --git a/force_bdss/data_sources/base_data_source_model.py b/force_bdss/data_sources/base_data_source_model.py index 04381be..ef9ccc1 100644 --- a/force_bdss/data_sources/base_data_source_model.py +++ b/force_bdss/data_sources/base_data_source_model.py @@ -1,6 +1,7 @@ from traits.api import ABCHasStrictTraits, Instance, List, Event from force_bdss.core.input_slot_map import InputSlotInfo +from force_bdss.core.output_slot_info import OutputSlotInfo from force_bdss.local_traits import Identifier from .i_data_source_factory import IDataSourceFactory @@ -22,12 +23,13 @@ class BaseDataSourceModel(ABCHasStrictTraits): #: slots. input_slot_info = List(Instance(InputSlotInfo), visible=False) - #: Allows to assign names to the output slots, so that they can be - #: referenced somewhere else (e.g. the KPICalculators). + #: Allows to assign names and KPI status to the output slots, so that + #: they can be referenced somewhere else (e.g. another layer's + #: DataSources). #: If the name is the empty string, it means that the user is not #: interested in preserving the information, and should therefore be #: discarded and not propagated further. - output_slot_names = List(Identifier(), visible=False) + output_slot_info = List(Instance(OutputSlotInfo), visible=False) #: This event claims that a change in the model influences the slots #: (either input or output). It must be triggered every time a specific @@ -44,4 +46,7 @@ class BaseDataSourceModel(ABCHasStrictTraits): state["input_slot_info"] = [ x.__getstate__() for x in self.input_slot_info ] + state["output_slot_info"] = [ + x.__getstate__() for x in self.output_slot_info + ] return state diff --git a/force_bdss/data_sources/tests/test_base_data_source_model.py b/force_bdss/data_sources/tests/test_base_data_source_model.py index 76d898d..cf189f9 100644 --- a/force_bdss/data_sources/tests/test_base_data_source_model.py +++ b/force_bdss/data_sources/tests/test_base_data_source_model.py @@ -1,6 +1,7 @@ import unittest from force_bdss.core.input_slot_map import InputSlotInfo +from force_bdss.core.output_slot_info import OutputSlotInfo try: import mock @@ -24,7 +25,7 @@ class TestBaseDataSourceModel(unittest.TestCase): { "__traits_version__": "4.6.0", "input_slot_info": [], - "output_slot_names": [] + "output_slot_info": [] }) model.input_slot_info = [ @@ -35,7 +36,10 @@ class TestBaseDataSourceModel(unittest.TestCase): name="bar" ) ] - model.output_slot_names = ["baz", "quux"] + model.output_slot_info = [ + OutputSlotInfo(name="baz"), + OutputSlotInfo(name="quux") + ] self.assertEqual( model.__getstate__(), @@ -53,5 +57,16 @@ class TestBaseDataSourceModel(unittest.TestCase): "name": "bar" } ], - "output_slot_names": ["baz", "quux"] + "output_slot_info": [ + { + "__traits_version__": "4.6.0", + "name": "baz", + "kpi": False + }, + { + "__traits_version__": "4.6.0", + "name": "quux", + "kpi": False + } + ] }) diff --git a/force_bdss/io/workflow_reader.py b/force_bdss/io/workflow_reader.py index 8241196..c2d78ab 100644 --- a/force_bdss/io/workflow_reader.py +++ b/force_bdss/io/workflow_reader.py @@ -4,6 +4,7 @@ import logging from traits.api import HasStrictTraits, Instance from force_bdss.core.input_slot_map import InputSlotInfo +from force_bdss.core.output_slot_info import OutputSlotInfo from force_bdss.core.workflow import Workflow from ..factory_registry_plugin import IFactoryRegistryPlugin @@ -157,6 +158,10 @@ class WorkflowReader(HasStrictTraits): model_data["input_slot_info"] = self._extract_input_slot_info( model_data["input_slot_info"] ) + model_data["output_slot_info"] = \ + self._extract_output_slot_info( + model_data["output_slot_info"] + ) layer.append(ds_factory.create_model(model_data)) layers.append(layer) @@ -220,6 +225,9 @@ class WorkflowReader(HasStrictTraits): def _extract_input_slot_info(self, info): return [InputSlotInfo(**d) for d in info] + def _extract_output_slot_info(self, info): + return [OutputSlotInfo(**d) for d in info] + def _extract_notification_listeners(self, wf_data): registry = self.factory_registry listeners = [] diff --git a/force_bdss/kpi/base_kpi_calculator_model.py b/force_bdss/kpi/base_kpi_calculator_model.py index bff66d0..bdbde3f 100644 --- a/force_bdss/kpi/base_kpi_calculator_model.py +++ b/force_bdss/kpi/base_kpi_calculator_model.py @@ -1,6 +1,6 @@ from traits.api import ABCHasStrictTraits, Instance, List, Event -from force_bdss.local_traits import Identifier +from force_bdss.core.output_slot_info import OutputSlotInfo from ..core.input_slot_map import InputSlotInfo from .i_kpi_calculator_factory import IKPICalculatorFactory @@ -27,7 +27,7 @@ class BaseKPICalculatorModel(ABCHasStrictTraits): #: If the name is the empty string, it means that the user is not #: interested in preserving the information, and should therefore be #: discarded and not propagated further. - output_slot_names = List(Identifier(), visible=False) + output_slot_info = List(Instance(OutputSlotInfo), visible=False) #: This event claims that a change in the model influences the slots #: (either input or output). It must be triggered every time a specific @@ -44,4 +44,7 @@ class BaseKPICalculatorModel(ABCHasStrictTraits): state["input_slot_info"] = [ x.__getstate__() for x in self.input_slot_info ] + state["output_slot_info"] = [ + x.__getstate__() for x in self.output_slot_info + ] return state diff --git a/force_bdss/kpi/tests/test_base_kpi_calculator_model.py b/force_bdss/kpi/tests/test_base_kpi_calculator_model.py index 6bc7bfb..391b2f1 100644 --- a/force_bdss/kpi/tests/test_base_kpi_calculator_model.py +++ b/force_bdss/kpi/tests/test_base_kpi_calculator_model.py @@ -1,6 +1,7 @@ import unittest from force_bdss.core.input_slot_map import InputSlotInfo +from force_bdss.core.output_slot_info import OutputSlotInfo from force_bdss.kpi.base_kpi_calculator_factory import BaseKPICalculatorFactory from force_bdss.kpi.base_kpi_calculator_model import BaseKPICalculatorModel @@ -23,18 +24,17 @@ class TestBaseKPICalculatorModel(unittest.TestCase): { "__traits_version__": "4.6.0", "input_slot_info": [], - "output_slot_names": [] + "output_slot_info": [] }) model.input_slot_info = [ - InputSlotInfo( - name="foo" - ), - InputSlotInfo( - name="bar" - ) + InputSlotInfo(name="foo"), + InputSlotInfo(name="bar") + ] + model.output_slot_info = [ + OutputSlotInfo(name="baz"), + OutputSlotInfo(name="quux") ] - model.output_slot_names = ["baz", "quux"] self.assertEqual( model.__getstate__(), @@ -52,5 +52,16 @@ class TestBaseKPICalculatorModel(unittest.TestCase): "name": "bar" } ], - "output_slot_names": ["baz", "quux"] + "output_slot_info": [ + { + "__traits_version__": "4.6.0", + "name": "baz", + "kpi": False, + }, + { + "__traits_version__": "4.6.0", + "name": "quux", + "kpi": False, + } + ] }) diff --git a/force_bdss/tests/fixtures/test_null.json b/force_bdss/tests/fixtures/test_null.json index 042261e..7101131 100644 --- a/force_bdss/tests/fixtures/test_null.json +++ b/force_bdss/tests/fixtures/test_null.json @@ -15,7 +15,7 @@ "model_data": { "input_slot_info": [ ], - "output_slot_names": [ + "output_slot_info": [ ] } } @@ -27,7 +27,7 @@ "model_data": { "input_slot_info": [ ], - "output_slot_names": [ + "output_slot_info": [ ] } } diff --git a/force_bdss/tests/test_core_evaluation_driver.py b/force_bdss/tests/test_core_evaluation_driver.py index 0e54df5..c0e76a1 100644 --- a/force_bdss/tests/test_core_evaluation_driver.py +++ b/force_bdss/tests/test_core_evaluation_driver.py @@ -3,6 +3,7 @@ import unittest import testfixtures import six +from force_bdss.core.output_slot_info import OutputSlotInfo from force_bdss.core.workflow import Workflow from force_bdss.tests.probe_classes.factory_registry_plugin import \ ProbeFactoryRegistryPlugin @@ -217,7 +218,11 @@ class TestCoreEvaluationDriver(unittest.TestCase): InputSlotInfo(name="foo"), InputSlotInfo(name="quux") ] - evaluator_model.output_slot_names = ["one", "", "three"] + evaluator_model.output_slot_info = [ + OutputSlotInfo(name="one"), + OutputSlotInfo(name=""), + OutputSlotInfo(name="three") + ] res = _compute_layer_results( data_values, @@ -292,7 +297,9 @@ class TestCoreEvaluationDriver(unittest.TestCase): InputSlotInfo(name="in1"), InputSlotInfo(name="in2") ] - model.output_slot_names = ["res1"] + model.output_slot_info = [ + OutputSlotInfo(name="res1") + ] wf.execution_layers[0].append(model) model = adder_factory.create_model() @@ -300,7 +307,9 @@ class TestCoreEvaluationDriver(unittest.TestCase): InputSlotInfo(name="in3"), InputSlotInfo(name="in4") ] - model.output_slot_names = ["res2"] + model.output_slot_info = [ + OutputSlotInfo(name="res2") + ] wf.execution_layers[0].append(model) # layer 1 @@ -309,7 +318,9 @@ class TestCoreEvaluationDriver(unittest.TestCase): InputSlotInfo(name="res1"), InputSlotInfo(name="res2") ] - model.output_slot_names = ["res3"] + model.output_slot_info = [ + OutputSlotInfo(name="res3") + ] wf.execution_layers[1].append(model) # layer 2 @@ -318,7 +329,9 @@ class TestCoreEvaluationDriver(unittest.TestCase): InputSlotInfo(name="res3"), InputSlotInfo(name="res1") ] - model.output_slot_names = ["res4"] + model.output_slot_info = [ + OutputSlotInfo(name="res4") + ] wf.execution_layers[2].append(model) # KPI layer @@ -327,7 +340,9 @@ class TestCoreEvaluationDriver(unittest.TestCase): InputSlotInfo(name="res4"), InputSlotInfo(name="res2") ] - model.output_slot_names = ["out1"] + model.output_slot_info = [ + OutputSlotInfo(name="out1") + ] wf.kpi_calculators.append(model) kpi_results = execute_workflow(wf, data_values) -- GitLab