From 2e2afea0a5d590b44efbe85d474c01a867f23da3 Mon Sep 17 00:00:00 2001 From: Tom Cobb Date: Wed, 15 Mar 2017 11:44:59 +0000 Subject: [PATCH] Made stats plugin write its own XML attribute file --- malcolm/includes/ADCore/ndarray_parts.yaml | 6 ++++ malcolm/parts/ADCore/statspluginpart.py | 29 +++++++++++++++++-- .../test_ADCore/test_statspluginpart.py | 24 +++++++++++++-- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/malcolm/includes/ADCore/ndarray_parts.yaml b/malcolm/includes/ADCore/ndarray_parts.yaml index 148aae1c6..d4d692440 100644 --- a/malcolm/includes/ADCore/ndarray_parts.yaml +++ b/malcolm/includes/ADCore/ndarray_parts.yaml @@ -27,3 +27,9 @@ description: Current unique id number for frame rbv: $(prefix):UniqueId_RBV widget: textupdate + +- parts.ca.CACharArrayPart: + name: attributesFile + description: Filename for NDAttributes + pv: $(prefix):NDAttributesFile + widget: textinput diff --git a/malcolm/parts/ADCore/statspluginpart.py b/malcolm/parts/ADCore/statspluginpart.py index e4bca3a10..a6830f3e6 100644 --- a/malcolm/parts/ADCore/statspluginpart.py +++ b/malcolm/parts/ADCore/statspluginpart.py @@ -1,3 +1,9 @@ +import os +from xml.etree import cElementTree as ET + +from malcolm.compat import et_to_string +from malcolm.core import REQUIRED, method_takes +from malcolm.core.vmetas import StringMeta from malcolm.parts.builtin.childpart import ChildPart from malcolm.controllers.runnablecontroller import RunnableController from malcolm.parts.ADCore.hdfwriterpart import CalculatedNDAttributeDatasetInfo @@ -9,8 +15,27 @@ class StatsPluginPart(ChildPart): def report_info(self, _): return [CalculatedNDAttributeDatasetInfo(name="sum", attr="StatsTotal")] + def _make_attributes_xml(self): + # Make a root element with an NXEntry + root_el = ET.Element("Attributes") + ET.SubElement( + root_el, "Attribute", addr="0", datatype="DOUBLE", type="PARAM", + description="Sum of the array", name="StatsTotal", source="TOTAL", + ) + xml = et_to_string(root_el) + return xml + @RunnableController.Configure - def configure(self, task, completed_steps, steps_to_do, part_info): - task.put_many(self.child, dict( + @method_takes( + "filePath", StringMeta("File path to write data to"), REQUIRED) + def configure(self, task, completed_steps, steps_to_do, part_info, params): + file_dir, filename = params.filePath.rsplit(os.sep, 1) + fs = task.put_many_async(self.child, dict( enableCallbacks=True, computeStatistics=True)) + xml = self._make_attributes_xml() + attributes_filename = os.path.join( + file_dir, "%s-attributes.xml" % self.params.mri) + open(attributes_filename, "w").write(xml) + fs += task.put_async(self.child["attributesFile"], attributes_filename) + task.wait_all(fs) diff --git a/tests/test_parts/test_ADCore/test_statspluginpart.py b/tests/test_parts/test_ADCore/test_statspluginpart.py index 0c8820846..47274b256 100644 --- a/tests/test_parts/test_ADCore/test_statspluginpart.py +++ b/tests/test_parts/test_ADCore/test_statspluginpart.py @@ -21,18 +21,38 @@ def getitem(name): self.child.__getitem__.side_effect = getitem self.params = MagicMock() + self.params.mri = "BLOCK-STAT" self.process.get_block.return_value = self.child self.o = StatsPluginPart(self.process, self.params) + def test_report_info(self): + infos = self.o.report_info(ANY) + self.assertEqual(len(infos), 1) + self.assertEqual(infos[0].name, "sum") + self.assertEqual(infos[0].attr, "StatsTotal") + def test_configure(self): task = MagicMock() completed_steps = ANY steps_to_do = ANY part_info = ANY - self.o.configure(task, completed_steps, steps_to_do, part_info) - task.put_many.assert_called_once_with(self.child, dict( + params = MagicMock() + params.filePath = "/tmp/anything.h5" + infos = self.o.configure( + task, completed_steps, steps_to_do, part_info, params) + self.assertIsNone(infos) + task.put_many_async.assert_called_once_with(self.child, dict( enableCallbacks=True, computeStatistics=True)) + expected_filename = "/tmp/BLOCK-STAT-attributes.xml" + task.put_async.assert_called_once_with( + self.child["attributesFile"], expected_filename) + expected_xml = """ + + +""" + actual_xml = open(expected_filename).read().replace(">", ">\n") + self.assertEqual(actual_xml.splitlines(), expected_xml.splitlines()) if __name__ == "__main__": unittest.main(verbosity=2)