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 _mqtt_receive(self, clnt, userdata, message): [block, attribute] = message.topic.split("/") self._disable_mqtt() controller = self.process.get_controller(block) request = Put(path=[block, attribute, "value"], value=message.payload, callback=self._enable_mqtt) controller.handle_request(request)
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"
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
def set_value(self, value): self._state = self.RUNNING request = Put(self, None, self.endpoint + ("value",), str(value)) return request