def __init__( self, serial: str, device_type: str, session: "Session", ): self._serial = serial self._device_type = device_type self._session = session try: self._options = session.daq_server.getString(f"/{serial}/features/options") except RuntimeError: self._options = "" # HF2 does not support listNodesJSON so we have the information hardcoded # (the node of HF2 will not change any more so this is safe) preloaded_json = None if "HF2" in self._device_type: preloaded_json = self._load_preloaded_json( Path(__file__).parent / "../../resources/nodedoc_hf2.json" ) nodetree = NodeTree( self._session.daq_server, prefix_hide=self._serial, list_nodes=[f"/{self._serial}/*"], preloaded_json=preloaded_json, ) # Add predefined parseres (in node_parser) to nodetree nodes nodetree.update_nodes( node_parser.get(self.__class__.__name__, {}), raise_for_invalid_node=False ) super().__init__(nodetree, tuple())
def test_init(connection, data_dir): tree = NodeTree(connection) connection.listNodesJSON.assert_called_once_with("*") assert "zi" in tree assert "ZI" in tree assert "dev1234" in tree assert "DEV1234" in tree assert "zi" in dir(tree) assert "dev1234" in dir(tree) tree = NodeTree(connection, "DEV1234") connection.listNodesJSON.assert_called_with("*") assert "zi" in tree assert "ZI" in tree assert "dev1234" not in tree assert "DEV1234" not in tree assert "zi" in dir(tree) assert "dev1234" not in dir(tree) json_path = data_dir / "nodedoc_daq_test.json" with json_path.open("r", encoding="UTF-8") as file: nodes_json = file.read() connection_module = MagicMock() connection_module.listNodesJSON.return_value = nodes_json tree = NodeTree(connection_module) connection_module.listNodesJSON.assert_called_with("*") assert "awgcontrol" in tree connection_broken = MagicMock() connection_broken.listNodesJSON.return_value = '{\n"zi/open": {\n"Node": "/ZI/OPEN"\n},\n"zi/close": {\n"Node": "/ZI/CLOSE"\n}\n}\n' with pytest.raises(Exception) as e_info: tree = NodeTree(connection_broken) assert "Leading slash not found" in e_info.value.args[0]
def test_get_wildcard(connection): tree = NodeTree(connection, "DEV1234") connection.get.return_value = OrderedDict([( "/dev1234/demods/0/impedance", { "timestamp": array("q", [3880906635]), "value": array("l", [123]), }, )]) result = tree.demods() assert result[tree.demods[0].impedance] == 123 connection.get.assert_called_with("/dev1234/demods", settingsonly=False, flat=True) # deep includes the timestamp result = tree.demods(deep=True) assert result[tree.demods[0].impedance] == (3880906635, 123) # nested dict result = tree.demods(flat=False) assert isinstance(result, OrderedDict) # nested dict result = tree.demods["*"].impedance(flat=False) assert isinstance(result, OrderedDict) # invalid node with pytest.raises(KeyError) as e_info: tree.invalid() # HF2 support connection.get.return_value = OrderedDict([("/dev1234/demods/0/impedance", nparray([125]))]) result = tree.demods() assert result[tree.demods[0].impedance] == 125 connection.get.assert_called_with("/dev1234/demods", settingsonly=False, flat=True) result = tree.demods(deep=True) assert result[tree.demods[0].impedance] == (None, 125) connection.get.return_value = OrderedDict([( "/dev1234/demods/0/impedance", { "timestamp": array("q", [3880906635]), "x": array("l", [123]), "y": array("l", [123]), }, )]) result = tree.demods() assert (result[tree.demods[0].impedance] == connection.get.return_value["/dev1234/demods/0/impedance"]) connection.get.assert_called_with("/dev1234/demods", settingsonly=False, flat=True)
def test_update_nodes(connection): tree = NodeTree(connection, "DEV1234") tree.update_nodes({ "demods/0/rate": { "Unit": "test" }, "demods/0/order": { "Unit": "test2" } }) assert tree.demods[0].rate.node_info.unit == "test" assert tree.demods[0].order.node_info.unit == "test2" with pytest.raises(KeyError) as e_info: tree.update_nodes({ "demods/0/rate": { "Unit": "test3" }, "test": { "Node": "test" } }) assert tree.demods[0].rate.node_info.unit == "test3" tree.update_nodes( { "demods/0/rate": { "Unit": "test3" }, "test": { "Node": "test4" } }, add=True) assert tree.test.node_info.path == "test4" assert tree.test.is_valid() is True # Test for not raising any errors tree.update_nodes( { "312/123": { "Unit": "test5" }, "testNOtexists": { "Node": "test5" } }, add=False, raise_for_invalid_node=False, ) assert tree.testNOtexists.is_valid() is False
def test_transactional_set(connection): tree = NodeTree(connection, "DEV1234") with tree.set_transaction(): tree.demods[0].rate(22.0) connection.set.assert_called_once_with([("/dev1234/demods/0/rate", 22.0)]) with tree.set_transaction(): tree.demods[0].rate(22.0) tree.demods[0].phaseshift(1) connection.set.assert_called_with([("/dev1234/demods/0/rate", 22.0), ("/dev1234/demods/0/phaseshift", 1)]) with tree.set_transaction(): tree.demods[0].rate(22.0) tree.transaction.add("demods/0/phaseshift", 2) connection.set.assert_called_with([("/dev1234/demods/0/rate", 22.0), ("/dev1234/demods/0/phaseshift", 2)]) with tree.set_transaction(): tree.system.impedance.calib.user.data(b"Test Binary Data") connection.set.assert_called_with([ ("/dev1234/system/impedance/calib/user/data", b"Test Binary Data") ]) with pytest.raises(AttributeError) as e_info: tree.transaction.add("demods/0/phaseshift", 2) with pytest.raises(RuntimeError) as e_info: with tree.set_transaction(): with tree.set_transaction(): pass
def test_parser(connection): tree = NodeTree(connection, "DEV1234") tree.update_node( "demods/0/rate", { "GetParser": lambda value: value + 10, "SetParser": lambda value: value + 10, }, ) connection.getDouble.return_value = 0 assert tree.demods[0].rate() == 10 tree.demods[0].rate(0) connection.set.assert_called_with(tree.demods[0].rate.node_info.path, 10)
def test_hash_node(connection): tree = NodeTree(connection, "DEV1234") test_dict = {tree.demods[0].rate: 0, tree.demods[0].trigger: 1} assert test_dict[tree.demods[0].rate] == 0 assert test_dict[tree.demods[0].trigger] == 1
def test_set(connection): tree = NodeTree(connection, "DEV1234") tree.demods[0].rate(22.0) connection.set.assert_called_with(tree.demods[0].rate.node_info.path, 22.0) tree.demods[0].rate(22.0, test=True) connection.set.assert_called_with(tree.demods[0].rate.node_info.path, 22.0, test=True) # sync set of nodes is only dependend on the input parameter not the # type of the node iself tree.demods[0].rate(22.0, deep=True) connection.syncSetDouble.assert_called_with( tree.demods[0].rate.node_info.path, 22.0) tree.demods[0].rate(0, deep=True) connection.syncSetInt.assert_called_once_with( tree.demods[0].rate.node_info.path, 0) tree.demods[0].rate("test", deep=True) connection.syncSetString.assert_called_once_with( tree.demods[0].rate.node_info.path, "test") with pytest.raises(Exception) as e_info: tree.demods[0].rate(complex(2, -3), deep=True) connection.syncSetString = None with pytest.raises(TypeError): tree.demods[0].rate("test", deep=True) with pytest.raises(KeyError): tree.demods.test("test")
def test_wait_for_state_change(connection): tree = NodeTree(connection, "DEV1234") connection.getInt.side_effect = [1] * 3 + [2] * 2 tree.demods[0].trigger.wait_for_state_change(2) connection.getInt.side_effect = None connection.getInt.return_value = 2 tree.demods[0].trigger.wait_for_state_change(2) connection.getInt.return_value = 1 with pytest.raises(TimeoutError) as e: tree.demods[0].trigger.wait_for_state_change(2, timeout=0.5) assert (str(e.value) == "/dev1234/demods/0/trigger did not change to the " "expected value within 0.5s. 2 != 1") with pytest.raises(TimeoutError) as e: tree.demods[0].trigger.wait_for_state_change(1, invert=True, timeout=0.5) assert (str( e.value) == "/dev1234/demods/0/trigger did not change from the " "expected value 1 within 0.5s.") connection.getInt.side_effect = [1] * 3 + [2] * 8 tree.demods["*"].trigger.wait_for_state_change(2) with pytest.raises(KeyError) as e_info: tree.hello.wait_for_state_change(1) with pytest.raises(KeyError) as e_info: tree.hello["*"].test.wait_for_state_change(1)
def test_node_access(connection): tree = NodeTree(connection, "DEV1234") assert tree.demods.root == tree # test local variable assert not tree._test assert not tree.demods._test # test attribute vs item assert tree.demods == tree["demods"] assert tree.demods == tree["/demods"] assert tree.demods.test == tree["demods/test"] assert tree.demods.test == tree.demods["/test"] assert tree.demods.test.world == tree.demods["test/world"] # buildin keywords are escaped with tailing underscore assert tree.in_.test == tree["in/test"] assert tree.test.and_ == tree["test/and"] # test invalid nodes assert tree.no.real.element.raw_tree == ("no", "real", "element") assert str(tree.no.real.element) == "/dev1234/no/real/element" with pytest.raises(KeyError) as e_info: tree.no.real.element() assert e_info.value.args[0] == str(tree.no.real.element)
def test_init_preloaded_json(nodedoc_dev1234_json): nodes_json = json.loads(nodedoc_dev1234_json) connection = MagicMock() # plain mock without json info tree = NodeTree(connection, prefix_hide="DEV1234", preloaded_json=nodes_json) assert tree.prefix_hide == "dev1234" connection.listNodesJSON.mock_object.assert_not_called()
def test_nodetree_iterator(connection): tree = NodeTree(connection, "DEV1234") counter = 0 for node, info in tree: assert node.node_info.path.lower() == info["Node"].lower() counter = counter + 1 assert counter == len(tree._flat_dict)
def test_to_raw_path(connection): tree = NodeTree(connection) with pytest.raises(ValueError): tree.to_raw_path("hello/world") assert tree.to_raw_path(Node(tree, tuple())) == "/" tree = NodeTree(connection, "DEV1234") assert tree.to_raw_path(Node(tree, tuple())) == "/dev1234"
def test_module_get_wildcard(connection): tree = NodeTree(connection, "DEV1234") return_value = OrderedDict([( "/dev1234/demods/0/impedance", { "timestamp": array("q", [3880906635]), "value": array("l", [123]), }, )]) connection.get.side_effect = [TypeError(), return_value] assert tree.demods()[tree.demods[0].impedance] == 123 connection.get.side_effect = [TypeError(), RuntimeError(), return_value] assert tree.demods()[tree.demods[0].impedance] == 123 connection.get.side_effect = [RuntimeError(), return_value] assert tree.demods()[tree.demods[0].impedance] == 123
def test_wildcard_node(connection): tree = NodeTree(connection, "DEV1234") wildcard_node = tree.demods["*"].rate assert wildcard_node.node_info.path == "/dev1234/demods/*/rate" with pytest.raises(KeyError) as e_info: wildcard_node.node_info.description # TODO add dummy Data to mock wildcard_node() wildcard_node(1) with tree.set_transaction(): wildcard_node = tree.demods["*"].rate(1) connection.get.return_value = None with pytest.raises(KeyError) as e_info: tree.hello["*"].rate() with pytest.raises(KeyError) as e_info: tree.hello["*"].rate(1)
def test_runtimerror_set_set_vector(connection): # tree.system.impedance.calib.user.data does work with set, but for # testing purposes call it tree = NodeTree(connection, "DEV1234") connection.set = Mock(side_effect=RuntimeError) tree.system.impedance.calib.user.data(b"Test Binary Data") connection.setVector.assert_called_with( tree.system.impedance.calib.user.data.node_info.path, b"Test Binary Data")
def _create_nodetree(self) -> NodeTree: """Create node tree for the SHFQA sweeper. Uses the hardcoded "resources/shfqa_sweeper_nodes.json" information and the SHFSweeper data classes to automatically create a valid node tree. (Automatically adds new parameters with dummy information) Returns: node tree for the shfqa sweeper """ json_path = Path( __file__).parent / "../../resources/shfqa_sweeper_nodes.json" with json_path.open("r") as file: raw_info = json.loads(file.read()) values = {} info = {} for config_class, parent_name in self._config_classes.items(): for parameter, default_value in asdict(config_class()).items(): node = ( f"/{parent_name[0]}/{self._renamed_nodes.get(parameter,parameter)}" ) try: info[node] = raw_info[node] except KeyError: # node not in json logger.warning(f"{node} is missing in {json_path}.") type_mapping = { int: "Integer (64 bit)", float: "Double", str: "String", bool: "Integer (64 bit)", np.ndarray: "ZIVectorData", } info[node] = { "Node": node, "Description": node, "Properties": "Read, Write", "Unit": "None", "Type": type_mapping[type(default_value)], } if "Options" in info[node]: option_map = {} for key, value in info[node]["Options"].items(): options = re.findall(r'"(.+?)"[,:]+', value) option_map.update({x: int(key) for x in options}) values[node] = option_map.get(default_value, default_value) else: values[node] = default_value info["/device"] = raw_info["/device"] values["/device"] = "" info["/envelope/enable"] = raw_info["/envelope/enable"] values["/envelope/enable"] = 0 return NodeTree(ConnectionDict(values, info))
def test_get_cached(connection): tree = NodeTree(connection, "DEV1234") tree.demods[0].adcselect() connection.getInt.assert_called_with( tree.demods[0].adcselect.node_info.path) tree.demods[0].rate() connection.getDouble.assert_called_with(tree.demods[0].rate.node_info.path) tree.features.serial() connection.getString.assert_called_with( tree.features.serial.node_info.path) # Complex Double tree.update_node("demods/0/rate", {"Type": "Complex Double"}) tree.demods[0].rate() connection.getComplex.assert_called_with( tree.demods[0].rate.node_info.path) connection.getComplex = None with pytest.raises(TypeError) as e_info: tree.demods[0].rate() # ZIVectorData with pytest.raises(TypeError) as e_info: tree.system.impedance.calib.user.data() # ZIDemodSample tree.demods[0].sample() connection.getSample.assert_called_with( tree.demods[0].sample.node_info.path) connection.getSample = None with pytest.raises(TypeError) as e_info: tree.demods[0].sample() # ZIDIOSample tree.dios[0].input() connection.getDIO.assert_called_with(tree.dios[0].input.node_info.path) # ZIAdvisorWave tree.update_node(tree.dios[0].input, {"Type": "ZIAdvisorWave"}) with pytest.raises(StopIteration): tree.dios[0].input() connection.get.assert_called_with(tree.dios[0].input.node_info.path, flat=True) # invalid type tree.update_node(tree.dios[0].input, {"Type": "InvalidType"}) with pytest.raises(RuntimeError): tree.dios[0].input()
def __init__(self, raw_module: ZIModule, session: "Session"): self._raw_module = raw_module self._session = session super().__init__(NodeTree(raw_module), tuple()) if "device" in self.root: self.root.update_nodes( { "/device": { "GetParser": self._get_device, "SetParser": self._set_device, } }, raise_for_invalid_node=False, )
def test_connection_dict(data_dir): data = {"/car/seat": 4, "/car/color": "blue", "/street/length": 110.4} json_path = data_dir / "nodedoc_fake.json" with json_path.open("r", encoding="UTF-8") as file: nodes_json = json.loads(file.read()) connection = ConnectionDict(data, nodes_json) tree = NodeTree(connection) assert tree.car.seat() == 4 assert tree.car.color() == "blue" assert tree.street.length() == 110.4 tree.car.seat(5) assert tree.car.seat() == 5 tree.street.length(1) assert tree.street.length() == 1.0 assert tree.street.length(deep=True) == (None, 1.0) tree.car["*"](1) assert tree.car.seat() == 1 assert tree.car.color() == "1" # subscribe and unsubscribe is not supported with pytest.raises(RuntimeError) as e_info: tree.car.seat.subscribe() with pytest.raises(RuntimeError) as e_info: tree.car.seat.unsubscribe() tree = NodeTree(connection, list_nodes=["/car/*"]) assert tree.car.seat() == 1 assert tree.car.color() == "1" with pytest.raises(KeyError): tree.street.length() connection.setVector("/car/seat", 5) assert tree.car.seat() == 5
def test_get_deep(connection): tree = NodeTree(connection, "DEV1234") with pytest.raises(TypeError) as e_info: tree.demods[0].rate(deep=True) connection.get.assert_called_with(tree.demods[0].rate.node_info.path, settingsonly=False, flat=True) with pytest.raises(TypeError) as e_info: tree.demods[0].rate(deep=True, test=True) # overwrite internally used kwarg with pytest.raises(TypeError) as e_info: tree.demods[0].rate(deep=True, settingsonly=True) connection.get.return_value = OrderedDict() with pytest.raises(TypeError) as e_info: tree.demods[0].rate(deep=True) # Real data # double node connection.get.return_value = OrderedDict([( "/dev1234/demods/0/rate", { "timestamp": array("q", [1236389131550]), "value": array("d", [1674.10717773]), }, )]) timestamp, data = tree.demods[0].rate(deep=True) assert timestamp == 1236389131550 assert data == 1674.10717773 # vector node connection.get.return_value = OrderedDict([( "/dev1234/system/impedance/calib/user/data", [{ "timestamp": 3880906635, "flags": 0, "vector": array("l", [123, 10, 32, 10, 125, 10]), }], )]) timestamp, data = tree.demods[0].sample(deep=True) assert timestamp == 3880906635 assert data == array("l", [123, 10, 32, 10, 125, 10]) # HF2 node connection.get.return_value = OrderedDict([("/dev1234/demods/0/rate", nparray([1674.10717773]))]) timestamp, data = tree.demods[0].sample(deep=True) assert data == 1674.10717773 assert timestamp == None
def test_node_iter(connection): tree = NodeTree(connection, "DEV1234") childs = [] for child, info in tree.demods[0]: childs.append(child) assert child.node_info.path.lower() == info["Node"].lower() assert all([child.raw_tree[-1] in tree.demods[0] for child in childs]) childs = [] for child, info in tree.demods["*"]: childs.append(child) assert child.node_info.path.lower() == info["Node"].lower() assert all([child.raw_tree[-1] in tree.demods["*"] for child in childs])
def test_get_as_event(connection): tree = NodeTree(connection, "DEV1234") tree.demods[0].sample.get_as_event() connection.getAsEvent.assert_called_once_with( tree.demods[0].sample.node_info.path) connection.getAsEvent.side_effect = [RuntimeError(), None, None] tree.demods["[1,2]"].sample.get_as_event() connection.getAsEvent.assert_any_call(tree.demods[1].sample.node_info.path) connection.getAsEvent.assert_any_call(tree.demods[2].sample.node_info.path) connection.getAsEvent.side_effect = RuntimeError() with pytest.raises(KeyError): tree.demods["*"].test.get_as_event()
def test_subscribe(connection): tree = NodeTree(connection, "DEV1234") tree.demods[0].sample.subscribe() connection.subscribe.assert_called_once_with( tree.demods[0].sample.node_info.path) tree.demods[0].sample.unsubscribe() connection.unsubscribe.assert_called_once_with( tree.demods[0].sample.node_info.path) connection.subscribe.side_effect = RuntimeError() connection.unsubscribe.side_effect = RuntimeError() with pytest.raises(KeyError): tree.demods["*"].test.subscribe() with pytest.raises(KeyError): tree.demods["*"].test.unsubscribe()
def test_options(connection): tree = NodeTree(connection, "DEV1234") tree.demods[0].trigger("continuous") connection.set.assert_called_with(tree.demods[0].trigger.node_info.path, "continuous") tree.demods[0].trigger("continuou") connection.set.assert_called_with(tree.demods[0].trigger.node_info.path, "continuou") connection.getInt.return_value = 0 assert tree.demods[0].trigger( ) == tree.demods[0].trigger.node_info.enum.continuous connection.getInt.return_value = 12345678 assert tree.demods[0].trigger() == 12345678
def node_tree(self, connection): tree = NodeTree(connection, "DEV1234") connection.get.return_value = OrderedDict([ ( "/dev1234/demods/0/rate", { "timestamp": array("q", [123]), "value": array("d", [2]), }, ), ( "/dev1234/demods/1/rate", { "timestamp": array("q", [1234]), "value": array("d", [3]), }, ), ]) return tree
def test_node_contains(connection): tree = NodeTree(connection, "DEV1234") assert "rate" in tree.demods[0] # existing child node assert "invalid" not in tree.demods[0] # non existing child node assert "node" not in tree.demods[0] # property
def test_nodelist_is_node(connection, hdawg): nt = NodeTree(connection, "DEV1234") bar = NodeList([hdawg], nt, ("foobar", )) assert bar[0] == hdawg assert bar == Node(nt, ("foobar", ))
def test_root_node(connection): tree = NodeTree(connection, "DEV1234") root_node = Node(tree, tuple()) assert "demods" in root_node
def test_len(connection): tree = NodeTree(connection, "DEV1234") assert len(tree.demods) == 4 with pytest.raises(TypeError): len(tree.demods[0])