class HelloPart(Part): """Defines greet and error `Method` objects on a `Block`""" def __init__(self, params): super(HelloPart, self).__init__(params.name) @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 @method_takes() def error(self): """Raise an error""" raise RuntimeError("You called method error()")
class MyPart(Part): context = None exception = None @method_takes('param1', StringMeta(), REQUIRED, 'param2', StringMeta(), REQUIRED) @method_returns('ret', StringMeta(), OPTIONAL) def my_method(self, params, returns): returns.ret = params.param1 + params.param2 return returns
def test_takes_given_defaults(self): @method_takes("hello", StringMeta(), "Something") def say_hello(params): """Say hello""" print("Hello" + params.name) itakes = MapMeta() itakes.set_elements(OrderedDict(hello=StringMeta())) assert say_hello.MethodModel.takes.to_dict() == itakes.to_dict() assert say_hello.MethodModel.returns.to_dict() == MapMeta().to_dict() assert say_hello.MethodModel.defaults == {"hello": "Something"}
def test_takes_given_required(self): @method_takes("hello", StringMeta(), REQUIRED) def say_hello(params): """Say hello""" print("Hello" + params.name) itakes = MapMeta() itakes.set_elements(OrderedDict(hello=StringMeta())) itakes.set_required(["hello"]) assert say_hello.MethodModel.takes.to_dict() == itakes.to_dict() assert say_hello.MethodModel.returns.to_dict() == MapMeta().to_dict() assert say_hello.MethodModel.defaults == {}
def test_instantiate(self, mock_import): @method_takes("desc", StringMeta("description"), REQUIRED, "foo", StringMeta("optional thing"), "thing") def f(extra, params): return extra, 2, params.desc, params.foo mock_import.return_value = Mock(MyPart=f) section = Section("f", 1, "mymodule.parts.MyPart", dict(desc="my name")) result = section.instantiate({}, "extra") mock_import.assert_called_once_with("malcolm.modules.mymodule.parts") assert result == ("extra", 2, "my name", "thing")
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(OrderedDict(hello=StringMeta())) ireturns.set_required(["hello"]) assert say_hello.MethodModel.takes.to_dict() == MapMeta().to_dict() assert say_hello.MethodModel.returns.to_dict() == ireturns.to_dict() assert say_hello.MethodModel.defaults == {}
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
class TestAttribute(unittest.TestCase): def setUp(self): self.meta = StringMeta() self.o = self.meta.create_attribute_model() def test_init(self): self.assertIs(self.o.meta, self.meta) assert self.o.value == "" assert self.o.typeid == "epics:nt/NTScalar:1.0" def test_set_value(self): value = "test_value" self.o.set_value(value) assert self.o.value == value def test_set_alarm(self): alarm = Alarm(AlarmSeverity.MAJOR_ALARM, AlarmStatus.DEVICE_STATUS, "bad") self.o.set_alarm(alarm) assert self.o.alarm == alarm def test_set_timeStamp(self): timeStamp = TimeStamp() self.o.set_timeStamp(timeStamp) assert self.o.timeStamp == timeStamp
def setUp(self): self.serialized = OrderedDict() self.serialized["typeid"] = "epics:nt/NTScalar:1.0" self.serialized["meta"] = StringMeta("desc").to_dict() self.serialized["value"] = "some string" self.serialized["alarm"] = Alarm().to_dict() self.serialized["timeStamp"] = TimeStamp().to_dict()
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
def test_make_view(self): method_view = self.o._make_appropriate_view(self.context, self.part.my_method) attribute_view = self.o._make_appropriate_view(self.context, self.part.myAttribute) dict_view = self.o._make_appropriate_view(self.context, { 'a': self.part.myAttribute, 'm': self.part.my_method }) list_view = self.o._make_appropriate_view( self.context, [self.part.myAttribute, self.part.my_method]) model = Model() model_view = self.o._make_appropriate_view(self.context, model) none_view = self.o._make_appropriate_view(self.context, None) block_data = BlockModel() block_data.set_endpoint_data("attr", StringMeta().create_attribute_model()) block_data.set_endpoint_data("method", MethodModel()) block_data.set_notifier_path(MagicMock(), ["block"]) block_view = self.o._make_appropriate_view(self.context, block_data) # Todo check create_part_contexts worked self.o.create_part_contexts() # using __call__ assert method_view().ret == 'world' assert attribute_view.value == "hello_block" assert dict_view['a'].value == "hello_block" assert list_view[0].value == "hello_block"
def create_attribute_models(self): for data in super(PortsPart, self).create_attribute_models(): yield data # note 3rd part of inport tag is its disconnected value in_tag = "inport:int32:" in_name = "inportConnector" in_port = StringMeta(in_name, [in_tag, "config"]).create_attribute_model() in_port.meta.set_writeable_in(sm.READY) yield in_name, in_port, in_port.set_value out_name = "outportConnector" out_tag = "outport:int32:%s" % self.name out_port = StringMeta(in_name, [out_tag]).create_attribute_model() out_port.meta.set_writeable_in(sm.READY) yield out_name, out_port, out_port.set_value
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): self.data = BlockModel() self.data.set_endpoint_data("attr", StringMeta().create_attribute_model()) self.data.set_endpoint_data("method", MethodModel()) self.data.set_notifier_path(Mock(), ["block"]) self.controller = Mock() self.context = Mock() self.o = make_block_view(self.controller, self.context, self.data)
def setUp(self): n = NumberMeta(description='a number') s = StringMeta(description="a string") self.meta = MapMeta() self.meta.set_elements({"a": s, "b": s}) self.meta.set_required(["a"]) self.nmeta = MapMeta() self.nmeta.set_elements({"a": n, "b": n}) self.nmeta.set_required(["a"])
class ExcaliburFileMungePart(StatefulChildPart): @RunnableController.Configure @method_takes( "formatName", StringMeta( "Argument for fileTemplate, normally filename without extension"), "det") def configure(self, context, completed_steps, steps_to_do, part_info, params): pass
class FemChildPart(DatasetRunnableChildPart): # MethodMeta will be filled in at reset() @RunnableController.Configure @method_takes("fileDir", StringMeta("File dir to write HDF files into"), REQUIRED) def configure(self, context, completed_steps, steps_to_do, part_info, params): # Throw away the dataset info the superclass returns super(FemChildPart, self).configure(context, completed_steps, steps_to_do, part_info, params)
def test_method_also_takes(self): @method_takes("hello", StringMeta(), REQUIRED, "hello2", BooleanMeta(), False) class Thing(object): def __init__(self): 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(elements) itakes.set_required(["hello"]) defaults = OrderedDict() defaults["hello2"] = False assert Thing.MethodModel.takes.to_dict() == itakes.to_dict() assert Thing.MethodModel.returns.to_dict() == MapMeta().to_dict() assert Thing.MethodModel.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(elements) itakes.set_required(["hello", "world"]) defaults = OrderedDict() defaults["hello2"] = True defaults["default"] = "nothing" assert Thing2.MethodModel.takes.to_dict() == itakes.to_dict() assert Thing2.MethodModel.returns.to_dict() == MapMeta().to_dict() assert Thing2.MethodModel.defaults == defaults
def setUp(self): self.serialized = OrderedDict() self.serialized["typeid"] = "malcolm:core/Method:1.0" self.takes = MapMeta() self.takes.set_elements({"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()
class StatsPluginPart(StatefulChildPart): """Part for controlling a `stats_plugin_block` in a Device""" # The NDAttributes file we write to say what to capture attributes_filename = None @RunnableController.ReportStatus def report_info(self, _): statistic, _, attr = self._get_statistic_source_attr() return [CalculatedNDAttributeDatasetInfo(name=statistic, attr=attr)] def _get_statistic_source_attr(self): statistic = self.params.statistic source = statistics[statistic] attr = "STATS_%s" % source return statistic, source, attr def _make_attributes_xml(self): # Make a root element with an NXEntry root_el = ET.Element("Attributes") statistic, source, attr = self._get_statistic_source_attr() ET.SubElement(root_el, "Attribute", addr="0", datatype="DOUBLE", type="PARAM", description="%s of the array" % statistic.title(), name=attr, source=source) xml = et_to_string(root_el) return xml @RunnableController.Configure @method_takes("fileDir", StringMeta("File directory to write data to"), REQUIRED) def configure(self, context, completed_steps, steps_to_do, part_info, params): child = context.block_view(self.params.mri) fs = child.put_attribute_values_async( dict(enableCallbacks=True, computeStatistics=True)) xml = self._make_attributes_xml() self.attributes_filename = os.path.join( params.fileDir, "%s-attributes.xml" % self.params.mri) with open(self.attributes_filename, "w") as f: f.write(xml) fs.append( child.attributesFile.put_value_async(self.attributes_filename)) context.wait_all_futures(fs) @RunnableController.PostRunReady def post_run_ready(self, context): # Delete the attribute XML file os.remove(self.attributes_filename)
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 FemChildPart(DatasetRunnableChildPart): # MethodMeta will be filled in at reset() @RunnableController.Configure @method_takes("fileDir", StringMeta("File dir to write HDF files into"), REQUIRED) def configure(self, context, completed_steps, steps_to_do, part_info, params): # Throw away the dataset info the superclass returns super(FemChildPart, self).configure(context, completed_steps, steps_to_do, part_info, params) # Sleep after configuration - recommended to allow at least 1s after starting Excalibur before taking first frame # following testing on J13. Otherwise FEM1 may not be ready and will drop a frame. print("Sleeping...") context.sleep(1.0) print("Slept")
def test_to_dict(self): s = StringMeta(description="a string") meta = MapMeta() elements = OrderedDict() elements["b"] = s elements["c"] = s elements["d"] = NumberMeta("int32") elements["e"] = s meta.set_elements(elements) 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" assert expected == m.to_dict()
def test_equals_maps(self): self.meta.to_dict = MagicMock() m1 = Map(self.meta, {"a": "test"}) m2 = Map(self.meta, {"a": "test2"}) assert not m1 == m2 assert m1 != m2 m2.a = "test" assert m1 == m2 assert not m1 != m2 m2 = Map(self.meta, {"a": "test", "b": "test"}) assert not m1 == m2 m1["b"] = "test" assert 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"}) assert m1 == m2
class MyPart(Part): context = None exception = None @MyController.TestHook def func(self, context): if self.exception: raise self.exception self.context = context return dict(foo="bar") @method_takes() @method_returns('ret', StringMeta(), OPTIONAL) def my_method(self, returns=MapMeta()): returns.ret = 'world' return returns def create_attribute_models(self): meta = StringMeta(description="MyString") self.myAttribute = meta.create_attribute_model( initial_value='hello_block') yield "myAttribute", self.myAttribute, self.myAttribute.set_value
# Make a table for the dataset info we produce columns = OrderedDict() columns["name"] = StringArrayMeta("Dataset name") columns["filename"] = StringArrayMeta( "Filename of HDF file relative to fileDir") columns["type"] = ChoiceArrayMeta("Type of dataset", dataset_types) columns["rank"] = NumberArrayMeta("int32", "Rank (number of dimensions)") columns["path"] = StringArrayMeta("Dataset path within HDF file") columns["uniqueid"] = StringArrayMeta("UniqueID array path within HDF file") dataset_table_meta = TableMeta("Datsets produced in HDF file", elements=columns, tags=[widget("table")]) @method_takes("name", StringMeta("Name of the Part within the controller"), REQUIRED) class DatasetTablePart(Part): """Exposes an Attribute that reports the datasets that will be written during a scan""" def __init__(self, params): # Created attributes self.datasets = None super(DatasetTablePart, self).__init__(params.name) def create_attribute_models(self): # Create read-only attribute showing the datasets we are creating self.datasets = dataset_table_meta.create_attribute_model() yield "datasets", self.datasets, None @RunnableController.PostConfigure
import numpy as np from malcolm.compat import OrderedDict from malcolm.core import Part, REQUIRED, method_takes, serialize_object, \ Attribute, Subscribe, Unsubscribe, Put, Alarm, AlarmSeverity, AlarmStatus, \ Queue from malcolm.modules.builtin.controllers import ManagerController from malcolm.modules.builtin.infos import PortInfo, LayoutInfo from malcolm.modules.builtin.vmetas import StringMeta from malcolm.tags import config port_tag_re = re.compile(r"(in|out)port:(.*):(.*)") @method_takes("name", StringMeta("Name of the Part within the controller"), REQUIRED, "mri", StringMeta("Malcolm resource id of child object"), REQUIRED) class ChildPart(Part): def __init__(self, params): # Layout options self.x = 0 self.y = 0 self.visible = None # {part_name: visible} saying whether part_name is visible self.part_visible = {} # {attr_name: attr_value} of last saved/loaded structure self.saved_structure = {} # {attr_name: modified_message} of current values self.modified_messages = {} # The controller hosting our child
request.set_callback(self.on_response) self._server_part.on_request(request) def on_response(self, response): # called from any thread self._loop.add_callback(self._server_part.on_response, response, self.write_message) # http://stackoverflow.com/q/24851207 # TODO: remove this when the web gui is hosted from the box def check_origin(self, origin): return True @method_takes("name", StringMeta("Name of the subdomain to host the websocket on"), "ws") class WebsocketServerPart(Part): def __init__(self, params): self.params = params # {id: Subscribe} self._subscription_keys = {} # [mri] self._published = [] super(WebsocketServerPart, self).__init__(params.name) @HTTPServerComms.ReportHandlers def report_handlers(self, context, loop): regexp = r"/%s" % self.params.name info = HandlerInfo(regexp, MalcWebSocketHandler,
def create_meta(self, description, tags): return StringMeta(description=description, tags=tags)
import os import subprocess import types import sys from malcolm.core import method_takes, REQUIRED, Importer from malcolm.modules.builtin.vmetas import StringMeta, NumberMeta @method_takes("name", StringMeta("The name of the defined parameter"), REQUIRED, "value", StringMeta("The value of the defined parameter"), REQUIRED) def string(params): """Define a string parameter to be used within this YAML file""" return {params.name: params.value} @method_takes("name", StringMeta("The name of the defined parameter"), REQUIRED, "value", NumberMeta("float64", "The value of the defined parameter"), REQUIRED) def float64(params): """Define a string parameter to be used within this YAML file""" return {params.name: params.value} @method_takes("name", StringMeta("The name of the defined parameter"), REQUIRED, "value", NumberMeta("int32", "The value of the defined parameter"), REQUIRED) def int32(params):