Example #1
0
    def sync_proxy(self, mri, block):
        """Abstract method telling the ClientComms to sync this proxy Block
        with its remote counterpart. Should wait until it is connected

        Args:
            mri (str): The mri for the remote block
            block (BlockModel): The local proxy Block to keep in sync
        """
        # Send a root Subscribe to the server
        subscribe = Subscribe(path=[mri], delta=True)
        done_queue = Queue()

        def handle_response(response):
            # Called from tornado
            if not isinstance(response, Delta):
                # Return or Error is the end of our subscription, log and ignore
                self.log.debug("Proxy got response %r", response)
                done_queue.put(None)
            else:
                cothread.Callback(self._handle_response, response, block,
                                  done_queue)

        subscribe.set_callback(handle_response)
        IOLoopHelper.call(self._send_request, subscribe)
        done_queue.get(timeout=DEFAULT_TIMEOUT)
Example #2
0
 def _subscribe_to_block(self, block_name):
     self.client_comms = self.process.get_client_comms(block_name)
     assert self.client_comms, \
         "Process doesn't know about block %s" % block_name
     request = Subscribe(None, self, [block_name], delta=True)
     request.set_id(self.BLOCK_ID)
     self.client_comms.q.put(request)
Example #3
0
 def _subscribe_to_block(self, block_name):
     self.client_comms = self.process.get_client_comms(block_name)
     assert self.client_comms, \
         "Process doesn't know about block %s" % block_name
     request = Subscribe(None, self, [block_name], delta=True)
     request.set_id(self.BLOCK_ID)
     self.client_comms.q.put(request)
    def test_pos_table_deltas(self):
        queue = Queue()
        subscribe = Subscribe(path=["P"], delta=True)
        subscribe.set_callback(queue.put)
        self.o.handle_request(subscribe)
        delta = queue.get()
        capture_enums = delta.changes[0][1]["positions"]["meta"]["elements"][
            "capture"]["choices"]
        assert capture_enums[0] == PositionCapture.NO
        table = delta.changes[0][1]["positions"]["value"]
        assert table.name == ["COUNTER.OUT"]
        assert table.value == [0.0]
        assert table.scale == [1.0]
        assert table.offset == [0.0]
        assert table.capture == [PositionCapture.NO]

        self.o.handle_changes([("COUNTER.OUT", "20")])
        delta = queue.get()
        assert delta.changes == [
            [["positions", "value", "value"], [20.0]],
            [["positions", "timeStamp"], ANY],
        ]

        self.o.handle_changes([("COUNTER.OUT", "5"),
                               ("COUNTER.OUT.SCALE", 0.5)])
        delta = queue.get()
        assert delta.changes == [
            [["positions", "value", "value"], [2.5]],
            [["positions", "value", "scale"], [0.5]],
            [["positions", "timeStamp"], ANY],
        ]
Example #5
0
    def test_block_fields_lut(self):
        fields = OrderedDict()
        block_data = BlockData(8, "Lut description", fields)
        fields["FUNC"] = FieldData("param", "lut", "Function", [])

        o = PandABlockController(self.client, "MRI", "LUT3", block_data, "/docs")
        self.process.add_controller(o)
        b = self.process.block_view("MRI:LUT3")

        func = b.func
        assert func.meta.writeable is True
        assert func.meta.typeid == StringMeta.typeid
        assert func.meta.tags == ["group:parameters", "widget:textinput", "config:1"]

        queue = Queue()
        subscribe = Subscribe(path=["MRI:LUT3"], delta=True)
        subscribe.set_callback(queue.put)
        o.handle_request(subscribe)
        delta = queue.get()
        assert delta.changes[0][1]["func"]["value"] == ""
        assert '<path id="OR"' in delta.changes[0][1]["icon"]["value"]

        # This is the correct FUNC.RAW value for !A&!B&!C&!D&!E
        self.client.get_field.return_value = "1"
        ts = TimeStamp()
        o.handle_changes({"FUNC": "!A&!B&!C&!D&!E"}, ts)
        self.client.get_field.assert_called_once_with("LUT3", "FUNC.RAW")
        delta = queue.get()
        assert delta.changes == [
            [["func", "value"], "!A&!B&!C&!D&!E"],
            [["func", "timeStamp"], ts],
            [["icon", "value"], ANY],
            [["icon", "timeStamp"], ts],
        ]
        assert '<path id="OR"' not in delta.changes[2][1]
Example #6
0
 def _start_client(self):
     # Called from cothread
     if self._conn is None:
         IOLoopHelper.call(self.recv_loop)
         self._connected_queue.get(timeout=self.connect_timeout)
         root_subscribe = Subscribe(path=[".", "blocks", "value"])
         root_subscribe.set_callback(self._update_remote_blocks)
         IOLoopHelper.call(self._send_request, root_subscribe)
Example #7
0
 def init(self, context):
     # type: (AContext) -> None
     super(RunnableChildPart, self).init(context)
     # Monitor the child configure Method for changes
     subscription = Subscribe(path=[self.mri, "configure"], delta=True)
     subscription.set_callback(self.update_part_configure_args)
     # Wait for the first update to come in
     self.child_controller.handle_request(subscription).wait()
Example #8
0
 def onFirstConnect(self, pv: SharedPV) -> None:
     # Store the PV, but don't open it now, let the first Delta do this
     with self._lock:
         self.pv = pv
     path = [self.controller.mri]
     if self.field is not None:
         path.append(self.field)
     request = Subscribe(path=path, delta=True)
     request.set_callback(self.handle)
     # No need to wait for first update here
     self.controller.handle_request(request)
Example #9
0
 def do_init(self):
     super(WebsocketClientComms, self).do_init()
     self.loop = IOLoop()
     self._request_lookup = {}
     self._subscription_keys = {}
     self._connected_queue = Queue()
     root_subscribe = Subscribe(id=0,
                                path=[".", "blocks"],
                                callback=self._update_remote_blocks)
     self._subscription_keys[root_subscribe.generate_key()] = root_subscribe
     self._request_lookup[0] = (root_subscribe, 0)
     self.start_io_loop()
Example #10
0
 def on_init(self, context: AContext) -> None:
     self.child_controller = context.get_controller(self.mri)
     if self.stateful:
         # Wait for a while until the child is ready as it changes the
         # save state
         wait_for_stateful_block_init(context, self.mri)
     # Save what we have
     self.on_save(context)
     subscribe = Subscribe(path=[self.mri, "meta", "fields"])
     subscribe.set_callback(self.update_part_exportable)
     # Wait for the first update to come in
     assert self.child_controller, "No child controller"
     self.child_controller.handle_request(subscribe).wait()
Example #11
0
 def __init__(self, process, block, block_name):
     """
     Args:
         process (Process): The process this should run under
         block (Block): The local block we should be controlling
         block_name (str): The local block's name
     """
     super(ClientController, self).__init__(block=block, process=process,
                                            block_name=block_name)
     request = Subscribe(
         None, self, [self.process.name, "remoteBlocks", "value"])
     request.set_id(self.REMOTE_BLOCKS_ID)
     self.process.q.put(request)
Example #12
0
    def _make_export_field(self, mri, attr_name, export_name):
        controller = self.process.get_controller(mri)
        path = [mri, attr_name]
        label = camel_to_title(export_name)
        ret = {}

        def update_field(response):
            if not isinstance(response, Delta):
                # Return or Error is the end of our subscription, log and ignore
                self.log.debug("Export got response %r", response)
                return
            if not ret:
                # First call, create the initial object
                export = deserialize_object(response.changes[0][1])
                if isinstance(export, AttributeModel):

                    def setter(v):
                        context = Context(self.process)
                        context.put(path, v)

                    # Strip out tags that we shouldn't export
                    # TODO: need to strip out port tags too...
                    export.meta.set_tags(
                        without_config_tags(
                            without_group_tags(export.meta.tags)))

                    ret["setter"] = setter
                else:

                    def setter_star_args(*args):
                        context = Context(self.process)
                        context.post(path, *args)

                    ret["setter"] = setter_star_args

                # Regenerate label
                export.meta.set_label(label)
                ret["export"] = export
            else:
                # Subsequent calls, update it
                with self.changes_squashed:
                    for change in response.changes:
                        ret["export"].apply_change(*change)

        subscription = Subscribe(path=path, delta=True)
        subscription.set_callback(update_field)
        self._subscriptions.append(subscription)
        # When we have waited for the subscription, the first update_field
        # will have been called
        controller.handle_request(subscription).wait()
        return ret["export"], ret["setter"]
Example #13
0
 def __init__(self, process, block, block_name):
     """
     Args:
         process (Process): The process this should run under
         block (Block): The local block we should be controlling
         block_name (str): The local block's name
     """
     super(ClientController, self).__init__(block=block,
                                            process=process,
                                            block_name=block_name)
     request = Subscribe(None, self,
                         [self.process.name, "remoteBlocks", "value"])
     request.set_id(self.REMOTE_BLOCKS_ID)
     self.process.q.put(request)
Example #14
0
 def init(self):
     subscribe = Subscribe(path=[self.params.mri],
                           delta=True,
                           callback=self.handle_response)
     self.client_comms.send_to_server(subscribe)
     # Wait until connected
     self._first_response_queue.get(timeout=5)
    def test_table_deltas(self):
        queue = Queue()
        subscribe = Subscribe(path=["P"], delta=True)
        subscribe.set_callback(queue.put)
        self.o.handle_request(subscribe)
        delta = queue.get()
        table = delta.changes[0][1]["bits"]["value"]
        assert table.name == ["TTLIN1.VAL", "TTLIN2.VAL", "PCOMP.OUT"]
        assert table.value == [False, False, False]
        assert table.capture == [False, False, False]

        self.o.handle_changes([("TTLIN1.VAL", "1")])
        delta = queue.get()
        assert delta.changes == [
            [["bits", "value", "value"], [True, False, False]],
            [["bits", "timeStamp"], ANY],
        ]
Example #16
0
 def test_concurrent(self):
     q = Queue()
     request = Subscribe(id=40, path=["hello_block", "greet"], delta=True)
     request.set_callback(q.put)
     self.controller.handle_request(request)
     # Get the initial subscribe value
     inital = q.get(timeout=0.1)
     self.assertIsInstance(inital, Delta)
     assert inital.changes[0][1]["took"]["value"] == dict(sleep=0, name="")
     assert inital.changes[0][1]["returned"]["value"] == {"return": ""}
     # Do a greet
     request = Post(id=44,
                    path=["hello_block", "greet"],
                    parameters=dict(name="me", sleep=1))
     request.set_callback(q.put)
     self.controller.handle_request(request)
     # Then an error
     request = Post(id=45, path=["hello_block", "error"])
     request.set_callback(q.put)
     self.controller.handle_request(request)
     # We should quickly get the error response first
     response = q.get(timeout=1.0)
     self.assertIsInstance(response, Error)
     assert response.id == 45
     # Then the long running greet delta
     response = q.get(timeout=3.0)
     self.assertIsInstance(response, Delta)
     assert len(response.changes) == 2
     assert response.changes[0][0] == ["took"]
     took = response.changes[0][1]
     assert took.value == dict(sleep=1, name="me")
     assert took.present == ["name", "sleep"]
     assert took.alarm == Alarm.ok
     assert response.changes[1][0] == ["returned"]
     returned = response.changes[1][1]
     assert returned.value == {"return": "Hello me"}
     assert returned.present == ["return"]
     assert returned.alarm == Alarm.ok
     # Check it took about 1s to run
     assert abs(1 - (returned.timeStamp.to_time() -
                     took.timeStamp.to_time())) < 0.4
     # And it's response
     response = q.get(timeout=1.0)
     self.assertIsInstance(response, Return)
     assert response.id == 44
     assert response.value == "Hello me"
Example #17
0
    def update_part_exportable(self, response):
        # Get a child context to check if we have a config field
        child = self.child_controller.block_view()
        spawned = []
        if response.value:
            new_fields = response.value
        else:
            new_fields = []

        # Remove any existing subscription that is not in the new fields
        for subscribe in self.config_subscriptions.values():
            attr_name = subscribe.path[-2]
            if attr_name not in new_fields:
                unsubscribe = Unsubscribe(subscribe.id, subscribe.callback)
                spawned.append(
                    self.child_controller.handle_request(unsubscribe))
                self.port_infos.pop(attr_name, None)

        # Add a subscription to any new field
        existing_fields = set(s.path[-2]
                              for s in self.config_subscriptions.values())
        for field in set(new_fields) - existing_fields:
            attr = getattr(child, field)
            if isinstance(attr, Attribute):
                for tag in attr.meta.tags:
                    match = port_tag_re.match(tag)
                    if match:
                        d, type, extra = match.groups()
                        self.port_infos[field] = PortInfo(name=field,
                                                          value=attr.value,
                                                          direction=d,
                                                          type=type,
                                                          extra=extra)
            if isinstance(attr, Attribute) and config() in attr.meta.tags:
                if self.config_subscriptions:
                    new_id = max(self.config_subscriptions) + 1
                else:
                    new_id = 1
                subscribe = Subscribe(id=new_id,
                                      path=[self.params.mri, field, "value"],
                                      callback=self.update_part_modified)
                self.config_subscriptions[new_id] = subscribe
                # Signal that any change we get is a difference
                if field not in self.saved_structure:
                    self.saved_structure[field] = None
                spawned.append(self.child_controller.handle_request(subscribe))

        # Wait for the first update to come in
        for s in spawned:
            s.wait()

        # Put data on the queue, so if spawns are handled out of order we
        # still get the most up to date data
        port_infos = [
            self.port_infos[f] for f in new_fields if f in self.port_infos
        ]
        self.exportable_update_queue.put((new_fields, port_infos))
        self.spawn(self._update_part_exportable).wait()
Example #18
0
 def init(self, context):
     # Save what we have
     self.save(context)
     # Monitor the child configure for changes
     self.child_controller = context.get_controller(self.params.mri)
     subscribe = Subscribe(path=[self.params.mri, "meta", "fields"],
                           callback=self.update_part_exportable)
     # Wait for the first update to come in
     self.child_controller.handle_request(subscribe).wait()
Example #19
0
 def init(self, context):
     self.configure_args_update_queue = Queue()
     super(RunnableChildPart, self).init(context)
     # Monitor the child configure Method for changes
     self.serialized_configure = MethodModel().to_dict()
     subscription = Subscribe(
         path=[self.params.mri, "configure"], delta=True,
         callback=self.update_part_configure_args)
     # Wait for the first update to come in
     self.child_controller.handle_request(subscription).wait()
Example #20
0
 def test_counter_subscribe(self):
     q = Queue()
     # Subscribe to the value
     sub = Subscribe(id=20, path=["counting", "counter"], delta=False)
     sub.set_callback(q.put)
     self.controller.handle_request(sub)
     # Check initial return
     response = q.get(timeout=1.0)
     self.assertIsInstance(response, Update)
     assert response.id == 20
     assert response.value["typeid"] == "epics:nt/NTScalar:1.0"
     assert response.value["value"] == 0
     # Post increment()
     post = Post(id=21, path=["counting", "increment"])
     post.set_callback(q.put)
     self.controller.handle_request(post)
     # Check the value updates...
     response = q.get(timeout=1)
     self.assertIsInstance(response, Update)
     assert response.id == 20
     assert response.value["value"] == 1
     # ... then we get the return
     response = q.get(timeout=1)
     self.assertIsInstance(response, Return)
     assert response.id == 21
     assert response.value is None
     # Check we can put too
     put = Put(id=22, path=["counting", "counter", "value"], value=31)
     put.set_callback(q.put)
     self.controller.handle_request(put)
     # Check the value updates...
     response = q.get(timeout=1)
     self.assertIsInstance(response, Update)
     assert response.id == 20
     assert response.value["value"] == 31
     # ... then we get the return
     response = q.get(timeout=1)
     self.assertIsInstance(response, Return)
     assert response.id == 22
     assert response.value is None
     # And that there isn't anything else
     with self.assertRaises(TimeoutError):
         q.get(timeout=0.05)
Example #21
0
 def __init__(self, mri, controller, request):
     super(PvaMonitorImplementation, self).__init__(mri, controller,
                                                    request)
     self._mu = pvaccess.MonitorServiceUpdater()
     self.getPVStructure()
     self._do_update = False
     path, _ = self._dict_to_path_value(self._request)
     request = Subscribe(path=[self._mri] + path,
                         delta=True,
                         callback=self._on_response)
     self._controller.handle_request(request)
Example #22
0
 def __init__(self, process, block):
     QAbstractItemModel.__init__(self)
     self.controller = process.get_controller(block.mri)
     self.block = block
     self.id_ = 1
     self.root_item = BlockItem((self.block.mri,), block)
     # map id -> item
     self.item_lookup = {}
     # TODO: unsubscribe when done
     self.response_received.connect(self.handle_response)
     self.send_request(Subscribe(path=[self.block.mri], delta=True)).wait()
 def __init__(self, process, block):
     QAbstractItemModel.__init__(self)
     self.process = process
     self.block = block
     self.id_ = 1
     self.block_path = tuple(block.path_relative_to(process))
     self.root_item = BlockItem(self.block_path, block)
     # map id -> request
     self.requests = {}
     # TODO: unsubscribe when done
     self.response_received.connect(self.handle_response)
     request = Subscribe(None, None, self.block_path, delta=True)
     self.send_request(request)
Example #24
0
 def test_concurrency(self):
     q = Queue()
     # Subscribe to the whole block
     sub = Subscribe(id=0, path=["mri"], delta=True)
     sub.set_callback(q.put)
     self.c.handle_request(sub)
     # We should get first Delta through with initial value
     r = q.get().to_dict()
     assert r["id"] == 0
     assert len(r["changes"]) == 1
     assert len(r["changes"][0]) == 2
     assert r["changes"][0][0] == []
     assert r["changes"][0][1]["meta"]["label"] == "My label"
     assert r["changes"][0][1]["label"]["value"] == "My label"
     # Do a Put on the label
     put = Put(id=2, path=["mri", "label", "value"], value="New", get=True)
     put.set_callback(q.put)
     self.c.handle_request(put)
     # Check we got two updates before the return
     r = q.get().to_dict()
     assert r["id"] == 0
     assert len(r["changes"]) == 2
     assert len(r["changes"][0]) == 2
     assert r["changes"][0][0] == ["label", "value"]
     assert r["changes"][0][1] == "New"
     assert len(r["changes"][0]) == 2
     assert r["changes"][1][0] == ["label", "timeStamp"]
     r = q.get().to_dict()
     assert r["id"] == 0
     assert len(r["changes"]) == 1
     assert len(r["changes"][0]) == 2
     assert r["changes"][0][0] == ["meta", "label"]
     assert r["changes"][0][1] == "New"
     # Then the return
     r3 = q.get().to_dict()
     assert r3["id"] == 2
     assert r3["value"] == "New"
Example #25
0
 def test_counter_subscribe(self):
     q = Queue()
     sub = Subscribe(id=20,
                     path=["counting", "counter"],
                     delta=False,
                     callback=q.put)
     self.controller.handle_request(sub)
     response = q.get(timeout=1.0)
     self.assertIsInstance(response, Update)
     assert response.id == 20
     assert response.value["typeid"] == "epics:nt/NTScalar:1.0"
     assert response.value["value"] == 0
     post = Post(id=21, path=["counting", "increment"], callback=q.put)
     self.controller.handle_request(post)
     response = q.get(timeout=1)
     self.assertIsInstance(response, Update)
     assert response.id == 20
     assert response.value["value"] == 1
     response = q.get(timeout=1)
     self.assertIsInstance(response, Return)
     assert response.id == 21
     assert response.value == None
     with self.assertRaises(TimeoutError):
         q.get(timeout=0.05)
Example #26
0
    def _make_export_field(self, mri, attr_name):
        controller = self.process.get_controller(mri)
        path = [mri, attr_name]
        ret = {}

        def update_field(response):
            if not isinstance(response, Delta):
                # Return or Error is the end of our subscription, log and ignore
                self.log.debug("Export got response %r", response)
                return
            if not ret:
                # First call, create the initial object
                ret["export"] = deserialize_object(response.changes[0][1])
                context = Context(self.process)
                if isinstance(ret["export"], AttributeModel):
                    def setter(v):
                        context.put(path, v)
                else:
                    def setter(*args):
                        context.post(path, *args)
                ret["setter"] = setter
            else:
                # Subsequent calls, update it
                with self.changes_squashed:
                    for cp, value in response.changes:
                        ob = ret["export"]
                        for p in cp[:-1]:
                            ob = ob[p]
                        getattr(ob, "set_%s" % cp[-1])(value)

        subscription = Subscribe(path=path, delta=True, callback=update_field)
        self._subscriptions.append(subscription)
        # When we have waited for the subscription, the first update_field
        # will have been called
        controller.handle_request(subscription).wait()
        return ret["export"], ret["setter"]
Example #27
0
    def update_part_exportable(self, response: Response) -> None:
        # Get a child context to check if we have a config field
        assert self.child_controller, "No child controller"
        child = self.child_controller.block_view()
        spawned = []
        if isinstance(response, Update):
            new_fields = response.value
            assert isinstance(new_fields, Sequence), f"Bad field list {new_fields}"
        elif isinstance(response, Return):
            # We got a return with None, so clear out all of the
            # config_subscriptions
            new_fields = []
        else:
            self.log.warning("Got unexpected response {response}")
            return

        # Remove any existing subscription that is not in the new fields
        for subscribe in self.config_subscriptions.values():
            attr_name = subscribe.path[-2]
            if attr_name not in new_fields:
                unsubscribe = Unsubscribe(subscribe.id)
                unsubscribe.set_callback(subscribe.callback)
                spawned.append(self.child_controller.handle_request(unsubscribe))
                self.port_infos.pop(attr_name, None)

        # Add a subscription to any new field
        existing_fields = set(s.path[-2] for s in self.config_subscriptions.values())
        for field in set(new_fields) - existing_fields:
            attr = getattr(child, field)
            if isinstance(attr, Attribute):
                # Cache tags here
                tags = attr.meta.tags
                # Check if the attribute has any port tags, and store for
                # when we are asked for LayoutInfo
                port_info = Port.port_tag_details(tags)
                info: PortInfo
                if port_info:
                    is_source, port, extra = port_info
                    if is_source:
                        info = SourcePortInfo(
                            name=field, port=port, connected_value=extra
                        )
                    else:
                        info = SinkPortInfo(
                            name=field,
                            port=port,
                            disconnected_value=extra,
                            value=attr.value,
                        )
                    self.port_infos[field] = info
                # If we are config tagged then subscribe so we can calculate
                # if we are modified
                if self._unmanaged_attr(field) and get_config_tag(tags):
                    if self.config_subscriptions:
                        new_id = max(self.config_subscriptions) + 1
                    else:
                        new_id = 1
                    subscribe = Subscribe(id=new_id, path=[self.mri, field, "value"])
                    subscribe.set_callback(self.update_part_modified)
                    self.config_subscriptions[new_id] = subscribe
                    spawned.append(self.child_controller.handle_request(subscribe))

        # Wait for the first update to come in for every subscription
        for s in spawned:
            s.wait()
        port_infos = [self.port_infos[f] for f in new_fields if f in self.port_infos]
        assert self.registrar, "No registrar assigned"
        self.registrar.report(PartExportableInfo(new_fields, port_infos))
Example #28
0
    def test_block_fields_adder(self):
        fields = OrderedDict()
        block_data = BlockData(2, "Adder description", fields)
        fields["INPA"] = FieldData("pos_mux", "", "Input A", ["A.OUT", "B.OUT"])
        fields["INPB"] = FieldData("pos_mux", "", "Input B", ["A.OUT", "B.OUT"])
        fields["DIVIDE"] = FieldData(
            "param", "enum", "Divide output", ["/1", "/2", "/4"]
        )
        fields["OUT"] = FieldData("pos_out", "", "Output", ["No", "Capture"])
        fields["HEALTH"] = FieldData("read", "enum", "What's wrong", ["OK", "Very Bad"])

        o = PandABlockController(self.client, "MRI", "ADDER1", block_data, "/docs")
        self.process.add_controller(o)
        b = self.process.block_view("MRI:ADDER1")

        assert list(b) == [
            "meta",
            "health",
            "icon",
            "label",
            "help",
            "inputs",
            "inpa",
            "inpb",
            "parameters",
            "divide",
            "outputs",
            "out",
        ]

        group = b.inputs
        assert group.meta.tags == ["widget:group", "config:1"]

        inpa = b.inpa
        assert inpa.meta.writeable is True
        assert inpa.meta.typeid == ChoiceMeta.typeid
        assert inpa.meta.tags == [
            "group:inputs",
            "sinkPort:int32:ZERO",
            "widget:combo",
            "config:1",
        ]
        assert inpa.meta.choices == ["A.OUT", "B.OUT"]
        inpa.put_value("A.OUT")
        self.client.set_field.assert_called_once_with("ADDER1", "INPA", "A.OUT")
        self.client.reset_mock()

        divide = b.divide
        assert divide.meta.writeable is True
        assert divide.meta.typeid == ChoiceMeta.typeid
        assert divide.meta.tags == ["group:parameters", "widget:combo", "config:1"]
        assert divide.meta.choices == ["/1", "/2", "/4"]

        out = b.out
        assert out.meta.writeable is False
        assert out.meta.typeid == NumberMeta.typeid
        assert out.meta.dtype == "int32"
        assert out.meta.tags == [
            "group:outputs",
            "sourcePort:int32:ADDER1.OUT",
            "widget:textupdate",
        ]

        queue = Queue()
        subscribe = Subscribe(path=["MRI:ADDER1", "out"], delta=True)
        subscribe.set_callback(queue.put)
        o.handle_request(subscribe)
        delta = queue.get(timeout=1)
        assert delta.changes[0][1]["value"] == 0

        ts = TimeStamp()
        o.handle_changes({"OUT": "145"}, ts)
        delta = queue.get(timeout=1)
        assert delta.changes == [
            [["value"], 145],
            [["timeStamp"], ts],
        ]

        subscribe = Subscribe(path=["MRI:ADDER1", "health"], delta=True)
        subscribe.set_callback(queue.put)
        o.handle_request(subscribe)
        delta = queue.get(timeout=1)
        assert delta.changes[0][1]["value"] == "OK"

        ts = TimeStamp()
        o.handle_changes({"HEALTH": "Very Bad"}, ts)
        delta = queue.get(timeout=1)
        assert delta.changes == [
            [["value"], "Very Bad"],
            [["alarm"], Alarm.major("Very Bad")],
            [["timeStamp"], ts],
        ]
        o.handle_changes({"HEALTH": "OK"}, ts)
        delta = queue.get(timeout=1)
        assert delta.changes == [
            [["value"], "OK"],
            [["alarm"], Alarm.ok],
            [["timeStamp"], ts],
        ]
 def subscribe_server_blocks(self):
     """Subscribe to process blocks"""
     request = Subscribe(None, None, [".", "blocks", "value"])
     request.set_id(self.SERVER_BLOCKS_ID)
     self.send_to_server(request)
Example #30
0
    def test_handle_request(self):
        q = Queue()

        request = Get(id=41, path=["mri", "myAttribute"])
        request.set_callback(q.put)
        self.o.handle_request(request)
        response = q.get(timeout=0.1)
        self.assertIsInstance(response, Return)
        assert response.id == 41
        assert response.value["value"] == "hello_block"
        self.part.my_attribute.meta.writeable = False
        request = Put(
            id=42, path=["mri", "myAttribute"], value="hello_block2", get=True
        )
        request.set_callback(q.put)
        self.o.handle_request(request)
        response = q.get(timeout=0.1)
        self.assertIsInstance(response, Error)  # not writeable
        assert response.id == 42

        self.part.my_attribute.meta.writeable = True
        self.o.handle_request(request)
        response = q.get(timeout=0.1)
        self.assertIsInstance(response, Return)
        assert response.id == 42
        assert response.value == "hello_block2"

        request = Post(id=43, path=["mri", "method"])
        request.set_callback(q.put)
        self.o.handle_request(request)
        response = q.get(timeout=0.1)
        self.assertIsInstance(response, Return)
        assert response.id == 43
        assert response.value == "world"

        # cover the controller._handle_post path for parameters
        request = Post(id=43, path=["mri", "method"], parameters={"dummy": 1})
        request.set_callback(q.put)
        self.o.handle_request(request)
        response = q.get(timeout=0.1)
        self.assertIsInstance(response, Error)
        assert response.id == 43
        assert (
            str(response.message)
            == "Given keys ['dummy'], some of which aren't in allowed keys []"
        )

        request = Subscribe(id=44, path=["mri", "myAttribute"], delta=False)
        request.set_callback(q.put)
        self.o.handle_request(request)
        response = q.get(timeout=0.1)
        self.assertIsInstance(response, Update)
        assert response.id == 44
        assert response.value["typeid"] == "epics:nt/NTScalar:1.0"
        assert response.value["value"] == "hello_block2"

        request = Unsubscribe(id=44)
        request.set_callback(q.put)
        self.o.handle_request(request)
        response = q.get(timeout=0.1)
        self.assertIsInstance(response, Return)
        assert response.id == 44
Example #31
0
 def _subscribe(self, block, attribute):
     controller = self.process.get_controller(block)
     request = Subscribe(path=[block, attribute, "value"],
                         callback=self._on_response)
     controller.handle_request(request)
Example #32
0
 def subscribe_server_blocks(self):
     """Subscribe to process blocks"""
     request = Subscribe(None, None, [".", "blocks", "value"])
     request.set_id(self.SERVER_BLOCKS_ID)
     self.send_to_server(request)
Example #33
0
 def subscribe_server_blocks(self, _):
     """Subscribe to process blocks"""
     request = Subscribe(None, None, [".", "blocks", "value"])
     request.set_id(self.SERVER_BLOCKS_ID)
     self.loop.add_callback(self.send_to_server, request)