Example #1
0
 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
     self.child_controller = None
     # {id: Subscribe} for subscriptions to config tagged fields
     self.config_subscriptions = {}
     # set(attribute_name) where the attribute is a config tagged field
     # we are modifying
     self.we_modified = set()
     # Update queue of modified alarms
     self.modified_update_queue = Queue()
     # Update queue of exportable fields
     self.exportable_update_queue = Queue()
     # {attr_name: PortInfo}
     self.port_infos = {}
     # Store params
     self.params = params
     super(ChildPart, self).__init__(params.name)
Example #2
0
 def testTwoMonitors(self):
     if PVAPY:
         # No need to do this test on the old server
         return
     assert "TESTCOUNTER" not in self.server._pvs
     # Make first monitor
     q1 = Queue()
     m1 = self.ctxt.monitor("TESTCOUNTER", q1.put)
     self.addCleanup(m1.close)
     counter = q1.get(timeout=1)
     self.assertStructureWithoutTsEqual(str(counter), str(counter_expected))
     assert len(self.server._pvs["TESTCOUNTER"]) == 1
     # Make a second monitor and check that also fires without making another
     # PV
     ctxt2 = self.make_pva_context()
     q2 = Queue()
     m2 = ctxt2.monitor("TESTCOUNTER", q2.put)
     self.addCleanup(m2.close)
     counter = q2.get(timeout=1)
     self.assertStructureWithoutTsEqual(str(counter), str(counter_expected))
     assert len(self.server._pvs["TESTCOUNTER"]) == 1
     # Check that a Put fires on both
     self.ctxt.put("TESTCOUNTER.counter", 5, "value")
     counter = q1.get(timeout=1)
     self.assertEqual(counter.counter.value, 5)
     counter = q2.get(timeout=1)
     self.assertEqual(counter.counter.value, 5)
Example #3
0
 def __init__(self, process, parts, params):
     self.params = params
     super(ProxyController, self).__init__(process, params.mri, parts)
     self.client_comms = process.get_controller(params.comms)
     self.update_health(self, Alarm.invalid("Uninitialized"))
     self._response_queue = Queue()
     self._notify_response = True
     self._first_response_queue = Queue()
Example #4
0
 def setUp(self):
     self.process = Process("proc")
     self.hello = call_with_params(hello_block, self.process, mri="hello")
     self.server = call_with_params(
         web_server_block, self.process, mri="server", port=self.socket)
     self.result = Queue()
     self.process.start()
Example #5
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
        """
        done_queue = Queue()
        self._queues[mri] = done_queue
        update_fields = set()

        def callback(value=None):
            if isinstance(value, Exception):
                # Disconnect or Cancelled or RemoteError
                if isinstance(value, Disconnected):
                    # We will get a reconnect with a whole new structure
                    update_fields.clear()
                    block.health.set_value(
                        value="pvAccess disconnected",
                        alarm=Alarm.disconnected("pvAccess disconnected"),
                    )
            else:
                with block.notifier.changes_squashed:
                    if not update_fields:
                        self.log.debug("Regenerating from %s", list(value))
                        self._regenerate_block(block, value, update_fields)
                        done_queue.put(None)
                    else:
                        self._update_block(block, value, update_fields)

        m = self._ctxt.monitor(mri, callback, notify_disconnect=True)
        self._monitors.add(m)
        done_queue.get(timeout=DEFAULT_TIMEOUT)
Example #6
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]
    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],
        ]
 def initialize(self, registrar=None, validators=()):
     self._registrar = registrar
     # {id: mri}
     self._id_to_mri = {}
     self._validators = validators
     self._queue = Queue()
     self._counter = 0
Example #9
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 #10
0
 def try_aborting_function(self, start_state, end_state, func, *args):
     try:
         # To make the running function fail we need to stop any running
         # contexts (if running a hook) or make transition() fail with
         # AbortedError. Both of these are accomplished here
         with self._lock:
             original_state = self.state.value
             self.abort_queue = Queue()
             self.transition(start_state)
             for context in self.part_contexts.values():
                 context.stop()
         if original_state not in (ss.READY, ss.ARMED, ss.PAUSED):
             # Something was running, let it finish aborting
             try:
                 self.abort_queue.get(timeout=ABORT_TIMEOUT)
             except TimeoutError:
                 self.log.warning("Timeout waiting while %s" % start_state)
         with self._lock:
             # Now we've waited for a while we can remove the error state
             # for transition in case a hook triggered it rather than a
             # transition
             self.part_contexts[self].ignore_stops_before_now()
         func(*args)
         self.abortable_transition(end_state)
     except AbortedError:
         self.abort_queue.put(None)
         raise
     except Exception as e:  # pylint:disable=broad-except
         self.go_to_error_state(e)
         raise
Example #11
0
 def testMonitorEverythingInitial(self):
     q = Queue()
     m = self.ctxt.monitor("TESTCOUNTER", q.put)
     self.addCleanup(m.close)
     counter = q.get(timeout=1)
     self.assertStructureWithoutTsEqual(str(counter), str(counter_expected))
     self.assertTrue(counter.changedSet().issuperset(
         {"meta.fields", "counter.value", "zero.meta.description"}))
     self.assertEqual(counter["counter.value"], 0)
     self.assertEqual(counter["zero.meta.description"],
                      "Zero the counter attribute")
     self.ctxt.put("TESTCOUNTER.counter", 5, "value")
     counter = q.get(timeout=1)
     self.assertEqual(counter.counter.value, 5)
     self.assertEqual(
         counter.changedSet(),
         {
             "counter.value",
             "counter.timeStamp.userTag",
             "counter.timeStamp.secondsPastEpoch",
             "counter.timeStamp.nanoseconds",
         },
     )
     self.ctxt.put("TESTCOUNTER.counter", 0, "value")
     counter = q.get(timeout=1)
     self.assertStructureWithoutTsEqual(str(counter), str(counter_expected))
 def setUp(self):
     self.process = Process("proc")
     self.hello = hello_block(mri="hello")[-1]
     self.process.add_controller(self.hello)
     self.server = web_server_block(mri="server", port=self.socket)[-1]
     self.process.add_controller(self.server)
     self.result = Queue()
     self.process.start()
Example #13
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()
 def start_poll_loop(self):
     # queue to listen for stop events
     if not self.client.started:
         self._stop_queue = Queue()
         if self.client.started:
             self.client.stop()
         self.client.start(self.process.spawn, socket)
     if not self._blocks_parts:
         self._make_blocks_parts()
     if self._poll_spawned is None:
         self._poll_spawned = self.process.spawn(self._poll_loop)
Example #15
0
 def start_poll_loop(self):
     # queue to listen for stop events
     if not self._client.started:
         self._stop_queue = Queue()
         if self._client.started:
             self._client.stop()
         self._client.start(self.process.spawn, socket)
     if not self._child_controllers:
         self._make_child_controllers()
     if self._poll_spawned is None:
         self._poll_spawned = self.process.spawn(self._poll_loop)
Example #16
0
 def test_hello_good_input(self):
     q = Queue()
     request = Post(id=44,
                    path=["hello_block", "greet"],
                    parameters=dict(name="thing"))
     request.set_callback(q.put)
     self.controller.handle_request(request)
     response = q.get(timeout=1.0)
     self.assertIsInstance(response, Return)
     assert response.id == 44
     assert response.value == "Hello thing"
Example #17
0
 def do_configure(self, state: str, params: ConfigureParams) -> None:
     if state == ss.FINISHED:
         # If we were finished then do a reset before configuring
         self.run_hooks(
             builtin.hooks.ResetHook(p, c)
             for p, c in self.create_part_contexts().items()
         )
     # Clear out any old part contexts now rather than letting gc do it
     for context in self.part_contexts.values():
         context.unsubscribe_all()
     # These are the part tasks that abort() and pause() will operate on
     self.part_contexts = self.create_part_contexts()
     # So add one for ourself too so we can be aborted
     assert self.process, "No attached process"
     self.part_contexts[self] = Context(self.process)
     # Store the params for use in seek()
     self.configure_params = params
     # Tell everything to get into the right state to Configure
     self.run_hooks(PreConfigureHook(p, c) for p, c in self.part_contexts.items())
     # This will calculate what we need from the generator, possibly a long
     # call
     params.generator.prepare()
     # Set the steps attributes that we will do across many run() calls
     self.total_steps.set_value(params.generator.size)
     self.completed_steps.set_value(0)
     self.configured_steps.set_value(0)
     # TODO: We can be cleverer about this and support a different number
     # of steps per run for each run by examining the generator structure
     self.steps_per_run = self.get_steps_per_run(
         params.generator, params.axesToMove, params.breakpoints
     )
     # Get any status from all parts
     part_info = self.run_hooks(
         ReportStatusHook(p, c) for p, c in self.part_contexts.items()
     )
     # Run the configure command on all parts, passing them info from
     # ReportStatus. Parts should return any reporting info for PostConfigure
     completed_steps = 0
     self.breakpoint_index = 0
     steps_to_do = self.steps_per_run[self.breakpoint_index]
     part_info = self.run_hooks(
         ConfigureHook(p, c, completed_steps, steps_to_do, part_info, **kw)
         for p, c, kw in self._part_params()
     )
     # Take configuration info and reflect it as attribute updates
     self.run_hooks(
         PostConfigureHook(p, c, part_info) for p, c in self.part_contexts.items()
     )
     # Update the completed and configured steps
     self.configured_steps.set_value(steps_to_do)
     self.completed_steps.meta.display.set_limitHigh(params.generator.size)
     # Reset the progress of all child parts
     self.progress_updates = {}
     self.resume_queue = Queue()
Example #18
0
 def _request_response(self, request_cls, path, **kwargs):
     queue = Queue()
     request = request_cls(path=[self._mri] + path,
                           callback=queue.put,
                           **kwargs)
     self._controller.handle_request(request)
     response = queue.get()
     if isinstance(response, Error):
         raise ResponseError(response.message)
     else:
         return response
Example #19
0
 def testMonitorSubfieldInitial(self):
     q = Queue()
     m = self.ctxt.monitor("TESTCOUNTER", q.put, "meta.fields")
     self.addCleanup(m.close)
     counter = q.get(timeout=1)
     self.assertEqual(counter.getID(), "structure")
     # P4P only says leaves have changed
     self.assertEqual(counter.changedSet(), {"meta.fields"})
     self.assertEqual(counter.meta.fields,
                      ["health", "counter", "delta", "zero", "increment"])
     fields_code = dict(counter.meta.type().aspy()[2])["fields"]
     self.assertEqual(fields_code, "as")
Example #20
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()
 def start_poll_loop(self):
     # queue to listen for stop events
     if not self.client.started:
         self._stop_queue = Queue()
         if self.client.started:
             self.client.stop()
         from socket import socket
         if self.use_cothread:
             cothread = maybe_import_cothread()
             if cothread:
                 from cothread.cosocket import socket
         self.client.start(self.spawn, socket)
     if not self._blocks_parts:
         self._make_blocks_parts()
     if self._poll_spawned is None:
         self._poll_spawned = self.spawn(self._poll_loop)
Example #22
0
    def send_put(self, mri, attribute_name, value):
        """Abstract method to dispatch a Put to the server

        Args:
            mri (str): The mri of the Block
            attribute_name (str): The name of the Attribute within the Block
            value: The value to put
        """
        q = Queue()
        request = Put(path=[mri, attribute_name, "value"], value=value)
        request.set_callback(q.put)
        IOLoopHelper.call(self._send_request, request)
        response = q.get()
        if isinstance(response, Error):
            raise response.message
        else:
            return response.value
Example #23
0
 def test_concurrent(self):
     q = Queue()
     request = Post(id=44,
                    path=["hello_block", "greet"],
                    parameters=dict(name="me", sleep=1))
     request.set_callback(q.put)
     self.controller.handle_request(request)
     request = Post(id=45, path=["hello_block", "error"])
     request.set_callback(q.put)
     self.controller.handle_request(request)
     response = q.get(timeout=1.0)
     self.assertIsInstance(response, Error)
     assert response.id == 45
     response = q.get(timeout=3.0)
     self.assertIsInstance(response, Return)
     assert response.id == 44
     assert response.value == "Hello me"
Example #24
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"
    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 #26
0
 def wait_for_good_status(self, deadline):
     q = Queue()
     m = util.catools.camonitor(self.status_pv,
                                q.put,
                                datatype=util.catools.DBR_STRING)
     status = None
     try:
         while True:
             try:
                 status = q.get(deadline - time.time())
             except TimeoutError:
                 return status
             else:
                 if status == self.good_status:
                     return status
     finally:
         m.close()
Example #27
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 #28
0
    def send_post(self, mri, method_name, **params):
        """Abstract method to dispatch a Post to the server

        Args:
            mri (str): The mri of the Block
            method_name (str): The name of the Method within the Block
            params: The parameters to send

        Returns:
            The return results from the server
        """
        q = Queue()
        request = Post(path=[mri, method_name], parameters=params)
        request.set_callback(q.put)
        IOLoopHelper.call(self._send_request, request)
        response = q.get()
        if isinstance(response, Error):
            raise response.message
        else:
            return response.value
 def __init__(
     self,
     mri: builtin.controllers.AMri,
     hostname: AHostname = "localhost",
     port: APort = 8008,
     connect_timeout: AConnectTimeout = DEFAULT_TIMEOUT,
 ) -> None:
     super().__init__(mri)
     self.hostname = hostname
     self.port = port
     self.connect_timeout = connect_timeout
     self._connected_queue = Queue()
     # {new_id: request}
     self._request_lookup: Dict[int, Request] = {}
     self._next_id = 1
     self._conn: Optional[WebSocketClientConnection] = None
     # Create read-only attribute for the remotely reachable blocks
     self.remote_blocks = TableMeta.from_table(
         BlockTable, "Remotely reachable blocks").create_attribute_model()
     self.field_registry.add_attribute_model("remoteBlocks",
                                             self.remote_blocks)
Example #30
0
 def __init__(self):
     assert not self._instance, \
         "Can't create more than one instance of Singleton. Use instance()"
     self.cothread = maybe_import_cothread()
     if self.cothread:
         # We can use it in this thread
         from cothread import catools
         self.in_cothread_thread = True
     else:
         # We need our own thread to run it in
         q = Queue()
         threading.Thread(target=_import_cothread, args=(q,)).start()
         self.cothread, catools = q.get()
         self.in_cothread_thread = False
     self.catools = catools
     self.DBR_STRING = catools.DBR_STRING
     self.DBR_LONG = catools.DBR_LONG
     self.DBR_DOUBLE = catools.DBR_DOUBLE
     self.FORMAT_CTRL = catools.FORMAT_CTRL
     self.FORMAT_TIME = catools.FORMAT_TIME
     self.DBR_ENUM = catools.DBR_ENUM
     self.DBR_CHAR_STR = catools.DBR_CHAR_STR