def put(self, pv: SharedPV, op: ServerOperation) -> None: path = [self.controller.mri] # We work out what to Put by taking every field that is marked as # changed and walking up the tree, adding every dotted field name # to the tree on the way up. This set will contain something like: # {"attr.value", "attr"} # Or for a table: # {"table.value.colA", "table.value.colB", "table.value", "table"} # Or if self.field: # {"value"} changed_fields_inc_parents = op.value().changedSet(parents=True, expand=False) # Taking the intersection with all puttable paths should yield the # thing we want to change, so value_changed would be: # {"attr.value"} or {"table.value"} or {"value"} value_changed = changed_fields_inc_parents.intersection(self.put_paths) assert ( len(value_changed) == 1 ), "Can only do a Put to a single field, got %s" % list(value_changed) changed = list(value_changed)[0] if self.field is not None: # Only accept a Put to "value" assert changed == "value", "Can only put to value of %s.%s, not %s" % ( self.controller.mri, self.field, changed, ) path += [self.field, "value"] op_value = op.value() else: # Get the path and string "value" from the put value split = changed.split(".") assert (len(split) == 2 and split[1] == "value"), "Can only put to value of %s.%s, not %s" % ( self.controller.mri, split[0], split[1], ) path += list(split) op_value = op.value()[split[0]] value = convert_value_to_dict(op_value)["value"] put = Put(path=path, value=value) def handle_put_response(response: Response) -> None: if isinstance(response, Return): op.done() else: if isinstance(response, Error): message = stringify_error(response.message) else: message = "BadResponse: %s" % response.to_dict() op.done(error=message) put.set_callback(handle_put_response) self.controller.handle_request(put).get()
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
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)
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"