Beispiel #1
0
class TestAttribute(unittest.TestCase):

    def setUp(self):
        self.meta = StringMeta()

    def test_init(self):
        a = self.meta.make_attribute()
        self.assertIs(self.meta, a.meta)
        self.assertEquals(a.value, "")
        self.assertEquals("epics:nt/NTScalar:1.0", a.typeid)

    def test_set_value(self):
        value = "test_value"
        a = self.meta.make_attribute()
        a.process = Mock()
        a.set_value(value)
        self.assertEquals(a.value, value)
        a.process.report_changes.assert_called_once_with([['value'], value])

    def test_handle_request(self):
        a = self.meta.make_attribute()
        request = Put(endpoint=["1", "2", "value"], value=Mock())
        put_function = Mock()
        a.handle_request(request, put_function)
        put_function.assert_called_once_with(self.meta, request.value)
def takes_with_default_meta(meta_cls, *meta_args):
    default_args = meta_args + (
        "Default value for parameter. If not specified, parameter is required",
    )
    return method_takes(
        "name",
        StringMeta("Specify that this class will take a parameter name"),
        REQUIRED, "description", StringMeta("Description of this parameter"),
        REQUIRED, "default", meta_cls(*default_args), OPTIONAL)
 def test_put_root_update_response(self):
     attr1 = StringMeta("dummy").make_attribute()
     attr2 = StringMeta("dummy2").make_attribute()
     new_block_structure = OrderedDict(typeid='malcolm:core/Block:1.0')
     new_block_structure["attr1"] = attr1.to_dict()
     new_block_structure["attr2"] = attr2.to_dict()
     response = MagicMock(
         id=self.cc.BLOCK_ID,
         changes=[[[], new_block_structure]])
     self.cc.put(response)
     self.assertEqual(self.b.to_dict(), new_block_structure)
Beispiel #4
0
    def test_instantiate(self):
        @method_takes("desc", StringMeta("description"), REQUIRED, "foo",
                      StringMeta("optional thing"), "thing")
        def f(extra, params):
            return extra, 2, params.desc, params.foo

        ca = Mock(CAPart=f)
        parts = Mock(ca=ca)
        section = Section("ca.CAPart", dict(desc="my name"))
        result = section.instantiate({}, parts, "extra")
        self.assertEqual(result, ("extra", 2, "my name", "thing"))
Beispiel #5
0
class DummyPart1(object):
    @DummyController.Configuring
    def do_thing(self, task):
        pass

    @DummyController.Running
    @method_returns("foo", StringMeta("Value of foo"), REQUIRED, "bar",
                    StringMeta("Value of bar"), REQUIRED)
    def do_the_other_thing(self, task, returns):
        returns.foo = "foo1"
        returns.bar = "bar2"
        return returns
Beispiel #6
0
    def test_takes_given_optional(self):
        @method_takes("hello", StringMeta(), OPTIONAL)
        def say_hello(params):
            """Say hello"""
            print("Hello" + params.name)

        itakes = MapMeta()
        itakes.set_elements(ElementMap(OrderedDict(hello=StringMeta())))
        self.assertEqual(say_hello.MethodMeta.takes.to_dict(),
                         itakes.to_dict())
        self.assertEqual(say_hello.MethodMeta.returns.to_dict(),
                         MapMeta().to_dict())
        self.assertEqual(say_hello.MethodMeta.defaults, {})
Beispiel #7
0
    def test_returns_given_valid_sets(self):
        @method_returns("hello", StringMeta(), REQUIRED)
        def say_hello(ret):
            """Say hello"""
            ret.hello = "Hello"
            return ret

        ireturns = MapMeta()
        ireturns.set_elements(ElementMap(OrderedDict(hello=StringMeta())))
        ireturns.set_required(["hello"])
        self.assertEqual(say_hello.MethodMeta.takes.to_dict(),
                         MapMeta().to_dict())
        self.assertEqual(say_hello.MethodMeta.returns.to_dict(),
                         ireturns.to_dict())
        self.assertEqual(say_hello.MethodMeta.defaults, {})
Beispiel #8
0
def make_meta(subtyp, description, tags, writeable=True, labels=None):
    if subtyp == "enum":
        if writeable:
            widget_type = "combo"
        else:
            widget_type = "textupdate"
        tags.append(widget(widget_type))
        meta = ChoiceMeta(description, labels, tags)
    elif subtyp == "bit":
        if writeable:
            widget_type = "checkbox"
        else:
            widget_type = "led"
        tags.append(widget(widget_type))
        meta = BooleanMeta(description, tags)
    else:
        if writeable:
            widget_type = "textinput"
        else:
            widget_type = "textupdate"
        tags.append(widget(widget_type))
        if subtyp == "uint":
            meta = NumberMeta("uint32", description, tags)
        elif subtyp == "int":
            meta = NumberMeta("int32", description, tags)
        elif subtyp == "scalar":
            meta = NumberMeta("float64", description, tags)
        elif subtyp == "lut":
            meta = StringMeta(description, tags)
        elif subtyp in ("pos", "relative_pos"):
            meta = NumberMeta("float64", description, tags)
        else:
            raise ValueError("Unknown subtype %r" % subtyp)
    return meta
Beispiel #9
0
class HelloPart(Part):
    @method_takes(
        "name",
        StringMeta("a name"),
        REQUIRED,
        "sleep",
        NumberMeta("float64", "Time to wait before returning"),
        0,
    )
    @method_returns("greeting", StringMeta(description="a greeting"), REQUIRED)
    def greet(self, parameters, return_map):
        """Optionally sleep <sleep> seconds, then return a greeting to <name>"""
        print("Manufacturing greeting...")
        time.sleep(parameters.sleep)
        return_map.greeting = "Hello %s" % parameters.name
        return return_map
Beispiel #10
0
 def setUp(self):
     self.callback_result = 0
     self.callback_value = ''
     meta = StringMeta("meta for unit tests")
     self.proc = MagicMock(q=queue.Queue())
     self.proc.create_queue = MagicMock(side_effect=queue.Queue)
     self.block = Block()
     self.block.set_process_path(self.proc, ("testBlock",))
     self.attr = meta.make_attribute()
     self.attr2 = meta.make_attribute()
     self.method = MethodMeta("method for unit tests")
     self.method.returns.set_elements(ElementMap(dict(ret=StringMeta())))
     self.method2 = MethodMeta("method for unit tests")
     self.block.replace_endpoints(
         dict(testFunc=self.method, testFunc2=self.method2,
              testAttr=self.attr, testAttr2=self.attr2))
     self.bad_called_back = False
Beispiel #11
0
    def test_returns_not_given_req_or_opt_raises(self):
        with self.assertRaises(AssertionError):

            @method_returns("hello", StringMeta(), "A default")
            def say_hello(ret):
                """Say hello"""
                ret.hello = "Hello"
                return ret
 def setUp(self):
     n = NumberMeta(description='a number')
     s = StringMeta(description="a string")
     self.meta = MapMeta()
     self.meta.set_elements(ElementMap({"a": s, "b": s}))
     self.meta.set_required(["a"])
     self.nmeta = MapMeta()
     self.nmeta.set_elements(ElementMap({"a": n, "b": n}))
     self.nmeta.set_required(["a"])
Beispiel #13
0
 def setUp(self):
     self.callback_result = 0
     self.callback_value = ''
     meta = StringMeta("meta for unit tests")
     self.proc = MagicMock(q=queue.Queue())
     self.proc.create_queue = MagicMock(side_effect=queue.Queue)
     self.block = Block()
     self.block.set_process_path(self.proc, ("testBlock", ))
     self.attr = meta.make_attribute()
     self.attr2 = meta.make_attribute()
     self.method = MethodMeta("method for unit tests")
     self.method.returns.set_elements(ElementMap(dict(ret=StringMeta())))
     self.method2 = MethodMeta("method for unit tests")
     self.block.replace_endpoints(
         dict(testFunc=self.method,
              testFunc2=self.method2,
              testAttr=self.attr,
              testAttr2=self.attr2))
     self.bad_called_back = False
Beispiel #14
0
def capart_takes(*args):
    args = (
        "name",
        StringMeta("name of the created attribute"),
        REQUIRED,
        "description",
        StringMeta("desc of created attribute"),
        REQUIRED,
        "pv",
        StringMeta("full pv of demand and default for rbv"),
        None,
        "rbv",
        StringMeta("override for rbv"),
        None,
        "rbv_suff",
        StringMeta("set rbv ro pv + rbv_suff"),
        None,
    ) + args
    return method_takes(*args)
Beispiel #15
0
    def test_method_also_takes(self):
        @method_takes("hello", StringMeta(), REQUIRED, "hello2", BooleanMeta(),
                      False)
        class Thing(object):
            pass

        @method_also_takes("world", BooleanMeta(), REQUIRED, "hello2",
                           BooleanMeta(), True, "default", StringMeta(),
                           "nothing")
        class Thing2(Thing):
            pass

        # Check original hasn't been modified
        itakes = MapMeta()
        elements = OrderedDict()
        elements["hello"] = StringMeta()
        elements["hello2"] = BooleanMeta()
        itakes.set_elements(ElementMap(elements))
        itakes.set_required(["hello"])
        defaults = OrderedDict()
        defaults["hello2"] = False
        self.assertEqual(Thing.MethodMeta.takes.to_dict(), itakes.to_dict())
        self.assertEqual(Thing.MethodMeta.returns.to_dict(),
                         MapMeta().to_dict())
        self.assertEqual(Thing.MethodMeta.defaults, defaults)

        # Check new one overrides/improves on original
        itakes = MapMeta()
        elements = OrderedDict()
        elements["hello"] = StringMeta()
        elements["hello2"] = BooleanMeta()
        elements["world"] = BooleanMeta()
        elements["default"] = StringMeta()
        itakes.set_elements(ElementMap(elements))
        itakes.set_required(["hello", "world"])
        defaults = OrderedDict()
        defaults["hello2"] = True
        defaults["default"] = "nothing"
        self.assertEqual(Thing2.MethodMeta.takes.to_dict(), itakes.to_dict())
        self.assertEqual(Thing2.MethodMeta.returns.to_dict(),
                         MapMeta().to_dict())
        self.assertEqual(Thing2.MethodMeta.defaults, defaults)
Beispiel #16
0
 def setUp(self):
     self.serialized = OrderedDict()
     self.serialized["typeid"] = "malcolm:core/MethodMeta:1.0"
     self.takes = MapMeta()
     self.takes.set_elements(ElementMap({"in_attr": StringMeta("desc")}))
     self.serialized["takes"] = self.takes.to_dict()
     self.serialized["defaults"] = OrderedDict({"in_attr": "default"})
     self.serialized["description"] = "test_description"
     self.serialized["tags"] = ()
     self.serialized["writeable"] = True
     self.serialized["label"] = ""
     self.serialized["returns"] = MapMeta().to_dict()
 def _create_default_attributes(self):
     # Add the state, status and busy attributes
     self.state = ChoiceMeta("State of Block",
                             self.stateMachine.possible_states,
                             label="State").make_attribute()
     yield "state", self.state, None
     self.status = StringMeta("Status of Block",
                              label="Status").make_attribute()
     yield "status", self.status, None
     self.busy = BooleanMeta("Whether Block busy or not",
                             label="Busy").make_attribute()
     yield "busy", self.busy, None
Beispiel #18
0
 def _make_scale_offset(self, field_name):
     group_tag = self._make_group("outputs")
     meta = StringMeta("Units for position fields on this block",
                       tags=[group_tag, widget("textinput")])
     self._make_field_part(field_name + ".UNITS", meta, writeable=True)
     meta = NumberMeta("float64",
                       "Scale for block position fields",
                       tags=[group_tag, widget("textinput")])
     self._make_field_part(field_name + ".SCALE", meta, writeable=True)
     meta = NumberMeta("float64",
                       "Offset for block position fields",
                       tags=[group_tag, widget("textinput")])
     self._make_field_part(field_name + ".OFFSET", meta, writeable=True)
class RawMotorPart(LayoutPart):
    @ManagerController.Report
    @method_returns("cs_axis", StringMeta("CS axis (like A, B, I, 0)"),
                    REQUIRED, "cs_port", StringMeta("CS port name"), REQUIRED,
                    "acceleration_time",
                    NumberMeta("float64",
                               "Seconds to velocity"), REQUIRED, "resolution",
                    NumberMeta("float64",
                               "Motor resolution"), REQUIRED, "offset",
                    NumberMeta("float64",
                               "Motor user offset"), REQUIRED, "max_velocity",
                    NumberMeta("float64", "Maximum motor velocity"), REQUIRED,
                    "current_position",
                    NumberMeta("float64", "Current motor position"), REQUIRED)
    def report_cs_info(self, _, returns):
        returns.cs_axis = self.child.cs_axis
        returns.cs_port = self.child.cs_port
        returns.acceleration_time = self.child.acceleration_time
        returns.resolution = self.child.resolution
        returns.offset = self.child.offset
        returns.max_velocity = self.child.max_velocity
        returns.current_position = self.child.position
        return returns
Beispiel #20
0
class TestValidate(unittest.TestCase):
    def setUp(self):
        self.string_meta = StringMeta("test string description")

    def test_given_value_str_then_return(self):
        response = self.string_meta.validate("TestValue")

        self.assertEqual("TestValue", response)

    def test_given_value_int_then_cast_and_return(self):
        response = self.string_meta.validate(15)

        self.assertEqual("15", response)

    def test_given_value_float_then_cast_and_return(self):
        response = self.string_meta.validate(12.8)

        self.assertEqual("12.8", response)

    def test_given_value_None_then_return(self):
        response = self.string_meta.validate(None)

        self.assertEqual("", response)
class TestValidate(unittest.TestCase):

    def setUp(self):
        self.string_meta = StringMeta("test string description")

    def test_given_value_str_then_return(self):
        response = self.string_meta.validate("TestValue")

        self.assertEqual("TestValue", response)

    def test_given_value_int_then_cast_and_return(self):
        response = self.string_meta.validate(15)

        self.assertEqual("15", response)

    def test_given_value_float_then_cast_and_return(self):
        response = self.string_meta.validate(12.8)

        self.assertEqual("12.8", response)

    def test_given_value_None_then_return(self):
        response = self.string_meta.validate(None)

        self.assertEqual("", response)
class HelloPart(Part):
    @method_takes(
        "name",
        StringMeta("a name"),
        REQUIRED,
        "sleep",
        NumberMeta("float64", "Time to wait before returning"),
        0,
    )
    @method_returns("greeting", StringMeta(description="a greeting"), REQUIRED)
    def say_hello(self, parameters, return_map):
        """Says Hello to name

        Args:
            parameters(Map): The name of the person to say hello to
            return_map(Map): Return structure to complete and return

        Returns:
            Map: The greeting
        """

        return_map.greeting = "Hello %s" % parameters.name
        time.sleep(parameters.sleep)
        return return_map
Beispiel #23
0
 def test_put_root_update_response(self):
     attr1 = StringMeta("dummy").make_attribute()
     attr2 = StringMeta("dummy2").make_attribute()
     new_block_structure = OrderedDict(typeid='malcolm:core/Block:1.0')
     new_block_structure["attr1"] = attr1.to_dict()
     new_block_structure["attr2"] = attr2.to_dict()
     response = MagicMock(id=self.cc.BLOCK_ID,
                          changes=[[[], new_block_structure]])
     self.cc.put(response)
     self.assertEqual(self.b.to_dict(), new_block_structure)
    def test_to_dict(self):
        a_mock = MagicMock()
        s = StringMeta(description="a string")
        meta = Meta()
        meta.elements = OrderedDict()
        meta.elements["b"] = s
        meta.elements["c"] = s
        meta.elements["d"] = NumberMeta("int32")
        meta.elements["e"] = s
        m = Map(meta, {"b":"test", "d":123, "e":"e"})

        expected = OrderedDict()
        expected["typeid"] = "malcolm:core/Map:1.0"
        expected["b"] = "test"
        expected["d"] = 123
        expected["e"] = "e"
        self.assertEquals(expected, m.to_dict())
Beispiel #25
0
    def create_attributes(self):
        """Method that should provide Attribute instances for Block

        Yields:
            tuple: (string name, Attribute, callable put_function).
        """
        # Add the state, status and busy attributes
        self.state = ChoiceMeta("State of Block",
                                self.stateMachine.possible_states,
                                label="State").make_attribute()
        yield "state", self.state, None
        self.status = StringMeta("Status of Block",
                                 label="Status").make_attribute()
        yield "status", self.status, None
        self.busy = BooleanMeta("Whether Block busy or not",
                                label="Busy").make_attribute()
        yield "busy", self.busy, None
 def create_attributes(self):
     for data in super(ManagerController, self).create_attributes():
         yield data
     # Make a table for the layout info we need
     columns = OrderedDict()
     columns["name"] = StringArrayMeta("Name of layout part")
     columns["mri"] = StringArrayMeta("Malcolm full name of child block")
     columns["x"] = NumberArrayMeta("float64", "X Coordinate of child block")
     columns["y"] = NumberArrayMeta("float64", "Y Coordinate of child block")
     columns["visible"] = BooleanArrayMeta("Whether child block is visible")
     layout_table_meta = TableMeta("Layout of child blocks", columns=columns)
     layout_table_meta.set_writeable_in(sm.EDITABLE)
     self.layout = layout_table_meta.make_attribute()
     yield "layout", self.layout, self.set_layout
     self.layout_name = StringMeta(
         "Saved layout name to load").make_attribute()
     self.layout_name.meta.set_writeable_in(sm.EDITABLE)
     yield "layoutName", self.layout_name, self.load_layout
    def test_equals_maps(self):
        self.meta.to_dict = MagicMock()
        m1 = Map(self.meta, {"a":"test"})
        m2 = Map(self.meta, {"a":"test2"})
        self.assertFalse(m1 == m2)
        self.assertTrue(m1 != m2)
        m2.a = "test"
        self.assertTrue(m1 == m2)
        self.assertFalse(m1 != m2)

        m2 = Map(self.meta, {"a":"test", "b":"test"})
        self.assertFalse(m1 == m2)
        m1["b"] = "test"
        self.assertTrue(m1 == m2)

        s = StringMeta(description="a string")
        meta2 = Meta()
        meta2.elements = {"a":s, "b":s}
        meta2.required = ["a"]
        meta2.to_dict = self.meta.to_dict
        m2 = Map(meta2, {"a":"test", "b":"test"})
        self.assertTrue(m1 == m2)
Beispiel #28
0
class StatsPluginPart(ChildPart):
    @RunnableController.ReportStatus
    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
    @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)
from tornado import gen
from tornado.ioloop import IOLoop
from tornado.websocket import websocket_connect

from malcolm.core import ClientComms, Request, Subscribe, Response, \
    deserialize_object, method_takes
from malcolm.core.jsonutils import json_decode, json_encode
from malcolm.core.vmetas import StringMeta, NumberMeta


@method_takes("hostname", StringMeta("Hostname of malcolm websocket server"),
              "localhost", "port",
              NumberMeta("int32", "Port number to run up under"), 8080)
class WebsocketClientComms(ClientComms):
    """A class for a client to communicate with the server"""
    def __init__(self, process, params):
        """
        Args:
            process (Process): Process for primitive creation
            params (Map): Parameters map
        """
        super(WebsocketClientComms, self).__init__(process)
        self.url = "ws://%(hostname)s:%(port)d/ws" % params
        self.set_logger_name(self.url)
        # TODO: Are we starting one or more IOLoops here?
        self.conn = None
        self.loop = IOLoop.current()
        self.loop.add_callback(self.recv_loop)
        self.add_spawn_function(self.loop.start, self.stop_recv_loop)

    @gen.coroutine
Beispiel #30
0
class ManagerController(DefaultController):
    """RunnableDevice implementer that also exposes GUI for child parts"""
    # The stateMachine that this controller implements
    stateMachine = sm()

    ReportOutports = Hook()
    """Called before Layout to get outport info from children

    Args:
        task (Task): The task used to perform operations on child blocks

    Returns:
        [`OutportInfo`] - the type and value of each outport of the child
    """

    Layout = Hook()
    """Called when layout table set and at init to update child layout

    Args:
        task (Task): The task used to perform operations on child blocks
        part_info (dict): {part_name: [Info]} returned from Layout hook
        layout_table (Table): A possibly partial set of changes to the layout
            table that should be acted on

    Returns:
        [`LayoutInfo`] - the child layout resulting from this change
    """

    Load = Hook()
    """Called at load() or revert() to load child settings from a structure

    Args:
        task (Task): The task used to perform operations on child blocks
        structure (dict): {part_name: part_structure} where part_structure is
            the return from Save hook
    """

    Save = Hook()
    """Called at save() to serialize child settings into a dict structure

    Args:
        task (Task): The task used to perform operations on child blocks

    Returns:
        dict: serialized version of the child that could be loaded from
    """

    # attributes
    layout = None
    layout_name = None

    # {part_name: part_structure} of currently loaded settings
    load_structure = None

    def create_attributes(self):
        for data in super(ManagerController, self).create_attributes():
            yield data
        # Make a table for the layout info we need
        columns = OrderedDict()
        columns["name"] = StringArrayMeta("Name of layout part")
        columns["mri"] = StringArrayMeta("Malcolm full name of child block")
        columns["x"] = NumberArrayMeta("float64", "X Coordinate of child block")
        columns["y"] = NumberArrayMeta("float64", "Y Coordinate of child block")
        columns["visible"] = BooleanArrayMeta("Whether child block is visible")
        layout_table_meta = TableMeta("Layout of child blocks", columns=columns)
        layout_table_meta.set_writeable_in(sm.EDITABLE)
        self.layout = layout_table_meta.make_attribute()
        yield "layout", self.layout, self.set_layout
        self.layout_name = ChoiceMeta(
            "Saved layout name to load", []).make_attribute()
        self.layout_name.meta.set_writeable_in(
            self.stateMachine.AFTER_RESETTING)
        yield "layoutName", self.layout_name, self.load_layout
        assert os.path.isdir(self.params.configDir), \
            "%s is not a directory" % self.params.configDir

    def set_layout(self, value):
        # If it isn't a table, make it one
        if not isinstance(value, Table):
            value = Table(self.layout.meta, value)
        part_info = self.run_hook(self.ReportOutports, self.create_part_tasks())
        part_info = self.run_hook(
            self.Layout, self.create_part_tasks(), part_info, value)
        layout_table = Table(self.layout.meta)
        for name, layout_infos in LayoutInfo.filter_parts(part_info).items():
            assert len(layout_infos) == 1, \
                "%s returned more than 1 layout infos" % name
            layout_info = layout_infos[0]
            row = [name, layout_info.mri, layout_info.x, layout_info.y,
                   layout_info.visible]
            layout_table.append(row)
        self.layout.set_value(layout_table)

    def do_reset(self):
        super(ManagerController, self).do_reset()
        # This will trigger all parts to report their layout, making sure the
        # layout table has a valid value
        self.set_layout(Table(self.layout.meta))
        # List the configDir and add to choices
        self._set_layout_names()
        # If we have no load_structure (initial reset) define one
        if self.load_structure is None:
            if self.params.defaultConfig:
                self.load_layout(self.params.defaultConfig)
            else:
                self.load_structure = self._save_to_structure()

    @method_writeable_in(sm.READY)
    def edit(self):
        self.transition(sm.EDITABLE, "Layout editable")

    def go_to_error_state(self, exception):
        if self.state.value == sm.EDITABLE:
            # If we got a save or revert exception, don't go to fault
            self.log_exception("Fault occurred while trying to save/revert")
        else:
            super(ManagerController, self).go_to_error_state(exception)

    @method_writeable_in(sm.EDITABLE)
    @method_takes(
        "layoutName", StringMeta(
            "Name of layout to save to, if different from current layoutName"),
        None)
    def save(self, params):
        self.try_stateful_function(
            sm.SAVING, self.stateMachine.AFTER_RESETTING, self.do_save,
            params.layoutName)

    def do_save(self, layout_name=None):
        if not layout_name:
            layout_name = self.layout_name.value
        structure = self._save_to_structure()
        text = json_encode(structure, indent=2)
        filename = self._validated_config_filename(layout_name)
        open(filename, "w").write(text)
        self._set_layout_names(layout_name)
        self.layout_name.set_value(layout_name)
        self.load_structure = structure

    def _set_layout_names(self, extra_name=None):
        names = []
        if extra_name:
            names.append(extra_name)
        dir_name = self._make_config_dir()
        for f in os.listdir(dir_name):
            if os.path.isfile(
                    os.path.join(dir_name, f)) and f.endswith(".json"):
                names.append(f.split(".json")[0])
        self.layout_name.meta.set_choices(names)

    @method_writeable_in(sm.EDITABLE)
    def revert(self):
        self.try_stateful_function(
            sm.REVERTING, self.stateMachine.AFTER_RESETTING, self.do_revert)

    def do_revert(self):
        self._load_from_structure(self.load_structure)

    def _validated_config_filename(self, name):
        """Make config dir and return full file path and extension

        Args:
            name (str): Filename without dir or extension

        Returns:
            str: Full path including extensio
        """
        dir_name = self._make_config_dir()
        filename = os.path.join(dir_name, name.split(".json")[0] + ".json")
        return filename

    def _make_config_dir(self):
        dir_name = os.path.join(self.params.configDir, self.mri)
        try:
            os.mkdir(dir_name)
        except OSError:
            # OK if already exists, if not then it will fail on write anyway
            pass
        return dir_name

    def load_layout(self, value):
        # TODO: race condition if we get 2 loads at once...
        # Do we need a Loading state?
        filename = self._validated_config_filename(value)
        text = open(filename, "r").read()
        structure = json_decode(text)
        self._load_from_structure(structure)
        self.layout_name.set_value(value)

    def _save_to_structure(self):
        structure = OrderedDict()
        structure["layout"] = OrderedDict()
        for name, x, y, visible in sorted(
                zip(self.layout.value.name, self.layout.value.x,
                    self.layout.value.y, self.layout.value.visible)):
            layout_structure = OrderedDict()
            layout_structure["x"] = x
            layout_structure["y"] = y
            layout_structure["visible"] = visible
            structure["layout"][name] = layout_structure
        for part_name, part_structure in sorted(self.run_hook(
                self.Save, self.create_part_tasks()).items()):
            structure[part_name] = part_structure
        return structure

    def _load_from_structure(self, structure):
        table = Table(self.layout.meta)
        for part_name, part_structure in structure["layout"].items():
            table.append([part_name, "", part_structure["x"],
                          part_structure["y"], part_structure["visible"]])
        self.set_layout(table)
        self.run_hook(self.Load, self.create_part_tasks(), structure)
Beispiel #31
0
    Args:
        type (str): Type of the port, e.g. bool or NDArray
        value (str): Value that will be set when port is selected, e.g.
            PCOMP1.OUT or DET.STATS
    """
    def __init__(self, type, value):
        self.type = type
        self.value = value


sm = ManagerStateMachine


@method_also_takes(
    "configDir", StringMeta("Directory to write save/load config to"), REQUIRED,
    "defaultConfig", StringMeta("Default config to load"), "",
)
class ManagerController(DefaultController):
    """RunnableDevice implementer that also exposes GUI for child parts"""
    # The stateMachine that this controller implements
    stateMachine = sm()

    ReportOutports = Hook()
    """Called before Layout to get outport info from children

    Args:
        task (Task): The task used to perform operations on child blocks

    Returns:
        [`OutportInfo`] - the type and value of each outport of the child
 def setUp(self):
     self.string_meta = StringMeta("test string description")
class ManagerController(DefaultController):
    """RunnableDevice implementer that also exposes GUI for child parts"""
    # The stateMachine that this controller implements
    stateMachine = sm()

    ReportOutports = Hook()
    """Called before Layout to get outport info from children

    Args:
        task (Task): The task used to perform operations on child blocks

    Returns:
        [`OutportInfo`] - the type and value of each outport of the child
    """

    Layout = Hook()
    """Called when layout table set and at init to update child layout

    Args:
        task (Task): The task used to perform operations on child blocks
        part_info (dict): {part_name: [Info]} returned from Layout hook
        layout_table (Table): A possibly partial set of changes to the layout
            table that should be acted on

    Returns:
        [`LayoutInfo`] - the child layout resulting from this change
    """

    Load = Hook()
    """Called at load() or revert() to load child settings from a structure

    Args:
        task (Task): The task used to perform operations on child blocks
        structure (dict): {part_name: part_structure} where part_structure is
            the return from Save hook
    """

    Save = Hook()
    """Called at save() to serialize child settings into a dict structure

    Args:
        task (Task): The task used to perform operations on child blocks
        structure (dict): {part_name: part_structure} where part_structure is
            the return from Save hook
    """

    # attributes
    layout = None
    layout_name = None

    # state to revert to
    revert_structure = None

    def create_attributes(self):
        for data in super(ManagerController, self).create_attributes():
            yield data
        # Make a table for the layout info we need
        columns = OrderedDict()
        columns["name"] = StringArrayMeta("Name of layout part")
        columns["mri"] = StringArrayMeta("Malcolm full name of child block")
        columns["x"] = NumberArrayMeta("float64", "X Coordinate of child block")
        columns["y"] = NumberArrayMeta("float64", "Y Coordinate of child block")
        columns["visible"] = BooleanArrayMeta("Whether child block is visible")
        layout_table_meta = TableMeta("Layout of child blocks", columns=columns)
        layout_table_meta.set_writeable_in(sm.EDITABLE)
        self.layout = layout_table_meta.make_attribute()
        yield "layout", self.layout, self.set_layout
        self.layout_name = StringMeta(
            "Saved layout name to load").make_attribute()
        self.layout_name.meta.set_writeable_in(sm.EDITABLE)
        yield "layoutName", self.layout_name, self.load_layout

    def set_layout(self, value):
        part_info = self.run_hook(self.ReportOutports, self.create_part_tasks())
        part_info = self.run_hook(
            self.Layout, self.create_part_tasks(), part_info, value)
        layout_table = Table(self.layout.meta)
        for name, layout_infos in LayoutInfo.filter_parts(part_info).items():
            assert len(layout_infos) == 1, \
                "%s returned more than 1 layout infos" % name
            layout_info = layout_infos[0]
            row = [name, layout_info.mri, layout_info.x, layout_info.y,
                   layout_info.visible]
            layout_table.append(row)
        self.layout.set_value(layout_table)

    def do_reset(self):
        super(ManagerController, self).do_reset()
        self.set_layout(Table(self.layout.meta))

    @method_writeable_in(sm.EDITABLE)
    def edit(self):
        self.try_stateful_function(sm.EDITING, sm.EDITABLE, self.do_edit)

    def do_edit(self):
        self.revert_structure = self._save_to_structure()

    @method_writeable_in(sm.EDITABLE)
    @method_takes(
        "layoutName", StringMeta(
            "Name of layout to save to, if different from current layoutName"),
        None)
    def save(self, params):
        self.try_stateful_function(
            sm.SAVING, self.stateMachine.AFTER_RESETTING, self.do_save,
            params.layoutName)

    def do_save(self, layout_name=None):
        if layout_name is None or layout_name == '':
            layout_name = self.layout_name.value
        structure = self._save_to_structure()
        filename = "/tmp/" + layout_name + ".json"
        text = json_encode(structure, indent=2)
        open(filename, "w").write(text)
        self.layout_name.set_value(layout_name)

    @method_writeable_in(sm.EDITABLE)
    def revert(self):
        self.try_stateful_function(
            sm.REVERTING, self.stateMachine.AFTER_RESETTING, self.do_revert)

    def do_revert(self):
        self._load_from_structure(self.revert_structure)

    def load_layout(self, value):
        # TODO: Look for value in our save file location
        filename = "/tmp/" + value + ".json"
        text = open(filename, "r").read()
        structure = json_decode(text)
        self._load_from_structure(structure)
        self.layout_name.set_value(value)

    def _save_to_structure(self):
        structure = self.run_hook(self.Save, self.create_part_tasks())
        structure["layout"] = self.layout.value.to_dict()
        return structure

    def _load_from_structure(self, structure):
        table = self.layout.meta.validate(structure["layout"])
        self.set_layout(table)
        self.run_hook(self.Load, self.create_part_tasks(), structure)
Beispiel #34
0
from malcolm.core import Part, method_takes, REQUIRED, MethodMeta
from malcolm.core.vmetas import StringMeta, NumberMeta, BooleanMeta
from malcolm.controllers.defaultcontroller import DefaultController
from malcolm.parts.ca.cothreadimporter import CothreadImporter


@method_takes(
    "name", StringMeta("name of the created method"), REQUIRED, "description",
    StringMeta("desc of created method"), REQUIRED, "pv",
    StringMeta("full pv to write to when method called"), REQUIRED, "statusPv",
    StringMeta("Status pv to see if successful"), None, "goodStatus",
    StringMeta("Good value for status pv"), "", "value",
    NumberMeta("int32", "value to write to pv when method called"), 1, "wait",
    BooleanMeta("Wait for caput callback?"), True)
class CAActionPart(Part):
    method = None

    def __init__(self, process, params):
        self.cothread, self.catools = CothreadImporter.get_cothread(process)
        super(CAActionPart, self).__init__(process, params)

    def create_methods(self):
        # MethodMeta instance
        self.method = MethodMeta(self.params.description)
        # TODO: set widget tag?
        yield self.params.name, self.method, self.caput

    @DefaultController.Reset
    def connect_pvs(self, _):
        # make the connection in cothread's thread
        pvs = [self.params.pv]
Beispiel #35
0
 def create_meta(self, description, tags):
     return StringMeta(description=description, tags=tags)
Beispiel #36
0
class LayoutPart(Part):
    # Child block object
    child = None

    # {part_name: visible} saying whether part_name is visible
    part_visible = None

    # Layout options
    x = 0
    y = 0
    visible = False
    mri = None
    name = None

    def store_params(self, params):
        self.name = params.name
        self.child = self.process.get_block(params.child)
        self.mri = params.child
        self.part_visible = {}

    @ManagerController.UpdateLayout
    @method_takes("layout_table", layout_table_meta, REQUIRED, "outport_table",
                  outport_table_meta, REQUIRED)
    @method_returns("mri", StringMeta("Malcolm full name of child block"),
                    REQUIRED, "x",
                    NumberMeta("float64",
                               "X Co-ordinate of child block"), REQUIRED, "y",
                    NumberMeta("float64", "X Co-ordinate of child block"),
                    REQUIRED, "visible",
                    BooleanMeta("Whether child block is visible"), REQUIRED)
    def update_layout_table(self, task, params, returns):
        for i, name in enumerate(params.layout_table.name):
            _, _, x, y, visible = params.layout_table[i]
            if name == self.name:
                if self.visible and not visible:
                    self.sever_inports(task)
                self.x = x
                self.y = y
                self.visible = visible
            else:
                was_visible = self.part_visible.get(name, True)
                if was_visible and not visible:
                    self.sever_outports(task, name, params.outport_table)
                self.part_visible[name] = visible
        returns.mri = self.mri
        returns.x = self.x
        returns.y = self.y
        returns.visible = self.visible
        return returns

    def _get_flowgraph_ports(self, direction="out"):
        # {attr_name: port_tag}
        ports = OrderedDict()
        for attr_name in self.child.endpoints:
            attr = self.child[attr_name]
            if isinstance(attr, Attribute):
                for tag in attr.meta.tags:
                    if tag.startswith("flowgraph:%sport" % direction):
                        ports[attr] = tag
        return ports

    def sever_inports(self, task):
        inports = self._get_flowgraph_ports("in")
        futures = []
        for attr in inports:
            futures += task.put_async(attr, attr.meta.choices[0])
        task.wait_all(futures)

    def sever_outports(self, task, name, outport_table):
        # Find the outports of this part
        # {outport_value: typ} e.g. "PCOMP.OUT" -> "bit"
        outports = {}
        for i, n in enumerate(outport_table.name):
            if n == name:
                outports[outport_table.value[i]] = outport_table.type[i]
        inports = self._get_flowgraph_ports("in")
        futures = []
        for attr, port_tag in inports.items():
            typ = port_tag.split(":")[2]
            if outports.get(attr.value, None) == typ:
                futures += task.put_async(attr, attr.meta.choices[0])
        task.wait_all(futures)

    @ManagerController.ListOutports
    @method_returns("type",
                    StringArrayMeta("Type of outport (e.g. bit or pos)"),
                    REQUIRED, "value",
                    StringArrayMeta("Value of outport (e.g. PULSE1.OUT)"),
                    REQUIRED)
    def list_outports(self, _, returns):
        outports = self._get_flowgraph_ports("out")
        types = []
        values = []
        for port_tag in outports.values():
            _, _, typ, name = port_tag.split(":", 4)
            types.append(typ)
            values.append(name)
        returns.type = types
        returns.value = values
        return returns
 def setUp(self):
     self.meta = StringMeta()
 def test_to_dict(self):
     a = StringMeta("desc").make_attribute()
     a.set_value("some string")
     self.assertEqual(a.to_dict(), self.serialized)