def __notify_and_remove_none_values( self, parameters: PythonJsonStructure) -> PythonJsonStructure: """ Return parameters from the QCoDeS snapshot which are not None. Takes the parameters of the QCoDeS instrument snapshot. Removes all parameters which have a value of None. Returns the parameter settings which have a value. All parameters with None value will be listed in the log as an error. Args: parameters: The parameters of a QCoDeS instrument snapshot. Returns: PythonJsonStructure: Contains the instrument snapshot parameters without the instrument parameters which a none value. """ valued_parameters = PythonJsonStructure() none_value_parameters = PythonJsonStructure() for parameter_name, settings in parameters.items(): if 'value' in settings and settings['value'] is None: none_value_parameters[parameter_name] = settings else: valued_parameters[parameter_name] = settings if none_value_parameters: parameter_names = list(none_value_parameters.keys()) error_message = f'Parameter values of {self._instrument_name} are None. Please set: {parameter_names}.' logging.error(error_message) return valued_parameters
def test_serialization_container_types(self): """ Creates a PythonJsonStucture with all the data-types. Serializes the object and directly afterwards unserializes. The unserialized object should equal the original created PythonJsonStructure. Note: Currently a PythonJsonStructure with a tuple is not tested. A tuple object can only be serialized to a list. """ settable_containers = { 'list': [1, 2, 3], 'dict': { 'a': 1, 'b': 2, 'c': 3 }, 'ndarray': np.random.rand(3, 2, 4, 5).astype(np.cfloat), # 'tuple': (1, 2, 3), 'json_object': PythonJsonStructure() } for key, expected in settable_containers.items(): json_object = PythonJsonStructure({key: expected}) serialized_object = serialize(json_object) unserialized_object = unserialize(serialized_object) np.testing.assert_equal(json_object, unserialized_object)
def test_setitem_valid_arguments(self): settable_objects = { 'none': None, 'bool': False, 'int': 25, 'float': 3.141592, 'list': [1, 2, 3], 'str': 'some_string', 'bytes': b'1010101', 'json_object': PythonJsonStructure(), 'np.float32': np.float32(3.1415), 'np.float64': np.float64(-3.1415), 'np.int32': np.int32(4), 'np.in64': np.int64(-4), 'np.cfloat': np.random.rand(2, 4, 5, 3).astype(np.cfloat), 'tuple': (1, 2, 3), 'dict': { 'a': 1, 'b': 2, 'c': 3 }, 'ndarray': np.array([[1, 2], [3, 4]]) } json_object = PythonJsonStructure() for key, expected in settable_objects.items(): json_object[key] = expected np.testing.assert_array_equal(expected, json_object[key])
def test_length(self): object_a = PythonJsonStructure() self.assertEqual(0, len(object_a), 0) object_b = PythonJsonStructure({'a': 1}) self.assertEqual(1, len(object_b)) object_b['b'] = 2 self.assertEqual(2, len(object_b))
def test_apply(self): with patch.object(zhinst.utils, 'create_api_session', return_value=(MagicMock(), MagicMock(), MagicMock())), \ patch.object(qilib.configuration_helper.adapters.hdawg8_instrument_adapter.ZIHDAWG8, 'download_device_node_tree', return_value={}): config = PythonJsonStructure() config['instruments'] = PythonJsonStructure() config['instruments']['ZIHDAWG8InstrumentAdapter_DEV8048'] = PythonJsonStructure({ 'adapter_class_name': 'ZIHDAWG8InstrumentAdapter', 'address': 'DEV8048', 'config': {} }) config['settings'] = PythonJsonStructure({ 'awg_map': { 'P1': (0, 1), 'P2': (0, 2), 'dig_mk': (0, 1, 1) }, 'config': {} }) adapter = VirtualAwgInstrumentAdapter('') adapter.apply(config) self.assertEqual(adapter.instrument.settings.awg_map, {'P1': (0, 1), 'P2': (0, 2), 'dig_mk': (0, 1, 1) }) adapter.close_instrument()
def test_setdefault_dict_type(self): key = 'test' expected = {'a': 1, 'b': 2} json_object = PythonJsonStructure() return_value = json_object.setdefault(key, expected) self.assertEqual(expected, json_object[key]) self.assertEqual(expected, return_value)
def test_setdefault_default_present(self): key = 'test' expected = 12 json_object = PythonJsonStructure() return_value = json_object.setdefault(key, expected) self.assertEqual(expected, json_object[key]) self.assertEqual(expected, return_value)
def test_apply_delta_lazy(self): with patch( 'qilib.configuration_helper.instrument_configuration.InstrumentAdapterFactory' ) as mock_factory: mock_adapter = MagicMock() mock_adapter.read.return_value = PythonJsonStructure( param1={'value': 1}, param2={'value': 2}, param3={'value': 3}, param4={'value': 4}) mock_factory.get_instrument_adapter.return_value = mock_adapter instrument_configuration = InstrumentConfiguration( 'DummyClass', 'fake-address', self._storage, configuration=PythonJsonStructure(param1={'value': 1}, param2={'value': 42}, param3={'value': 33})) instrument_configuration.apply_delta_lazy() mock_adapter.read.assert_called_once_with(update=False) mock_adapter.apply.assert_called_once_with({ 'param2': { 'value': 42 }, 'param3': { 'value': 33 } })
def test_configuration_helper_integration(self): storage = StorageMemory('some_name') configuration_1 = PythonJsonStructure(amper=0.005) configuration_2 = PythonJsonStructure(frequency='2.4 GHz') with patch('qilib.configuration_helper.instrument_configuration.InstrumentAdapterFactory'): instrument_1 = InstrumentConfiguration('DummyClass', 'fake-address-1', storage, tag=['instrument_1'], configuration=configuration_1) instrument_2 = InstrumentConfiguration('DummyClass', 'fake-address-2', storage, tag=['instrument_2'], configuration=configuration_2) instrument_configuration_set = InstrumentConfigurationSet(storage, tag=['set'], instrument_configurations=[instrument_1, instrument_2]) instrument_configuration_set.store() configuration_helper = ConfigurationHelper(storage) configuration_helper.retrieve_inactive_configuration_from_storage(['set']) inactive_configuration = configuration_helper.inactive_configuration self.assertListEqual(inactive_configuration.tag, ['set']) self.assertListEqual(inactive_configuration.instrument_configurations[0].tag, ['instrument_1']) self.assertListEqual(inactive_configuration.instrument_configurations[1].tag, ['instrument_2']) self.assertDictEqual(configuration_1, inactive_configuration.instrument_configurations[0].configuration) self.assertDictEqual(configuration_2, inactive_configuration.instrument_configurations[1].configuration) repr_str = r"ConfigurationHelper\(StorageMemory\('some_name'\), InstrumentConfigurationSet\(StorageMemory\(" \ r"'some_name'\), \['configuration_set', '.*'\], \[\]\), " \ r"InstrumentConfigurationSet\(StorageMemory\('some_name'\), \['set'\], \[InstrumentConfiguration\(" \ r"'DummyClass', 'fake-address-1', StorageMemory\('some_name'\), \['instrument_1'\], " \ r"\{'amper': 0.005\}, None\), InstrumentConfiguration\('DummyClass', 'fake-address-2', " \ r"StorageMemory\('some_name'\), \['instrument_2'\], \{'frequency': '2.4 GHz'\}, None\)\]\)\)" self.assertRegex(repr(configuration_helper), repr_str)
def test_recursive_update(self): json_object = PythonJsonStructure() data = {'a1': [1, 2, 3], 'b1': {'a2': 2}} json_object.update(data) with self.assert_raises_invalid_data(): json_object['c1'] = object() with self.assert_raises_invalid_data(): json_object['b1']['b2'] = object()
def _filter_parameters( self, parameters: PythonJsonStructure) -> PythonJsonStructure: """ Removes the identifier parameter from the configuration settings. Args: parameters: A custom dictionary with all the SPI rack module settings. """ parameters.pop('IDN') return parameters
def test_setdefault_container_type(self): key = 'test' containers = [ [1, [2, 3], 2, [2, 3, [4, 5]]], (1, (2, 3), 8, (9, 10), (7, (1, 2))), np.random.rand(3, 2, 5, 1, 3), ] for expected in containers: json_object = PythonJsonStructure() return_value = json_object.setdefault(key, expected) np.testing.assert_equal(expected, json_object[key]) np.testing.assert_equal(expected, return_value)
def setUp(self): InstrumentAdapterFactory.adapter_instances = {} self.serial_port_settings = PythonJsonStructure(MagicMock(spec=dict())) self.mock_config = PythonJsonStructure({ 'version': 1.23, 'temperature': 293.4, 'battery': 'OK', 'serialport': self.serial_port_settings })
def read(self, update: bool = False) -> PythonJsonStructure: """ Additionally reads the gate_map, boundaries and configs of the nested dacs.""" config = PythonJsonStructure() config[CONFIG] = super().read(update) config[BOUNDARIES] = self._instrument.get_boundaries() config[GATE_MAP] = self._instrument.gate_map config[INSTRUMENTS] = PythonJsonStructure() for adapter_name, adapter in self._dac_adapters.items(): config[INSTRUMENTS][adapter_name] = PythonJsonStructure() config[INSTRUMENTS][adapter_name][CONFIG] = adapter.read(update) config[INSTRUMENTS][adapter_name][ADDRESS] = adapter.address config[INSTRUMENTS][adapter_name][ADAPTER_CLASS_NAME] = adapter.__class__.__name__ return config
def read(self, update: bool = False) -> PythonJsonStructure: config = super().read(update) config[INSTRUMENTS] = PythonJsonStructure() for adapter_name, adapter in self._adapters.items(): config[INSTRUMENTS][adapter_name] = PythonJsonStructure() config[INSTRUMENTS][adapter_name][ ADAPTER_CLASS_NAME] = adapter.__class__.__name__ config[INSTRUMENTS][adapter_name][ADDRESS] = adapter.address config[INSTRUMENTS][adapter_name][CONFIG] = adapter.read(update) config[SETTINGS] = PythonJsonStructure() config[SETTINGS][AWG_MAP] = self._instrument.settings.awg_map return config
def read(self, update: bool = False) -> PythonJsonStructure: """ Obtains a full set of settings from the instrument. Returns: Part of the instrument snapshot, i.e., parameter values, without the instrument's parameters which are explicitly filtered out, and the instrument name. """ configuration = PythonJsonStructure() if self._instrument is not None: snapshot = self._instrument.snapshot(update) parameters = self._filter_parameters(snapshot['parameters']) valued_parameters = self.__notify_and_remove_none_values( parameters) configuration.update(valued_parameters) return configuration
def test_apply(self): qilib.configuration_helper.adapters.DummyInstrumentAdapter = DummyInstrumentAdapter dummy_adapter = InstrumentAdapterFactory.get_instrument_adapter('DummyInstrumentAdapter', 'some_address') dummy_adapter.instrument.amplitude(1) dummy_adapter.instrument.frequency(1) dummy_adapter.instrument.enable_output(False) mock_virtual_dac_instance = MagicMock() with patch('qtt.instrument_drivers.adapters.virtual_dac_instrument_adapter.VirtualDAC') as mock_virtual_dac: mock_virtual_dac.return_value = mock_virtual_dac_instance adapter = VirtualDACInstrumentAdapter('spirack3_module3') mock_virtual_dac.assert_called() config = PythonJsonStructure() config['config'] = snapshot['parameters'] config['boundaries'] = {'P1': (-10, 10)} config['gate_map'] = {'P1': (0, 1)} config['instruments'] = {dummy_adapter.name: {'address': 'some_address', 'adapter_class_name': 'DummyInstrumentAdapter', 'config': {'amplitude': {'value': 1e-3}, 'frequency': {'value': 130e6}, 'enable_output': {'value': True}}}} adapter.apply(config) mock_virtual_dac_instance.set_boundaries.assert_called_with({'P1': (-10, 10)}) mock_virtual_dac_instance.add_instruments.assert_called_with([dummy_adapter.instrument]) self.assertDictEqual({'P1': (0, 1)}, mock_virtual_dac_instance.gate_map) self.assertEqual(1e-3, dummy_adapter.instrument.amplitude()) self.assertEqual(130e6, dummy_adapter.instrument.frequency()) self.assertTrue(dummy_adapter.instrument.enable_output()) dummy_adapter.close_instrument()
def read(self, update: bool = True) -> PythonJsonStructure: parameters = { 'version': self._instrument.get_firmware_version(), 'temperature': self._instrument.get_temperature(), 'battery': self._instrument.get_battery(), 'serialport': self._instrument.get_settings() } return PythonJsonStructure(parameters)
def test_update_invalid_data(self): json_object = PythonJsonStructure() args_data = {'a': 1, 'b': object()} kwargs_data = {'c': 3, 'd': object()} self.assert_raises_invalid_data(json_object.update, args_data) self.assert_raises_invalid_data(json_object.update, **kwargs_data) with self.assert_raises_invalid_data(): json_object['bla'] = [[], [], [[], [[object()]]]]
def _filter_parameters( self, parameters: PythonJsonStructure) -> PythonJsonStructure: for values in parameters.values(): if 'val_mapping' in values: values.pop('val_mapping') if 'on_off_mapping' in values: values.pop('on_off_mapping') return parameters
def test_update_valid_data(self): json_object = PythonJsonStructure() expected = {'a': 1, 'b': 2} json_object.update(expected) self.assertDictEqual(expected, json_object) json_object = PythonJsonStructure() expected = {'c': 3, 'd': 4} json_object.update(c=3, d=4) self.assertDictEqual(expected, json_object)
def test_change_name_with_config(self): adapter = DummyInstrumentAdapter('dummy_address') self.assertEqual('DummyInstrumentAdapter_dummy_address', adapter.name) self.assertEqual('DummyInstrumentAdapter_dummy_address', adapter.instrument.name) config = PythonJsonStructure(name='new_name') adapter.apply(config) self.assertEqual('DummyInstrumentAdapter_dummy_address', adapter.name) adapter.close_instrument()
def __init__(self, adapter_class_name: str, address: str, storage: StorageInterface, tag: Optional[List[str]] = None, configuration: Optional[PythonJsonStructure] = None, instrument_name: Optional[str] = None) -> None: """ A set of instrument configurations Args instrument_adapter_class_name: Name of the InstrumentAdapter subclass address: Address of the physical instrument storage: Any storage that implements the StorageInterface tag: A unique identifier for a instrument configuration set configuration: The instrument configuration instrument_name: User defined name for the instrument """ self._adapter_class_name = adapter_class_name self._address = address self._storage = storage self._instrument_name = instrument_name self._adapter = InstrumentAdapterFactory.get_instrument_adapter(adapter_class_name, address, instrument_name) self._configuration = PythonJsonStructure() if configuration is None else configuration self._tag = [self.STORAGE_BASE_TAG, adapter_class_name, StorageInterface.datetag_part()] if tag is None else tag
def _filter_parameters( self, parameters: PythonJsonStructure) -> PythonJsonStructure: for values in parameters.values(): if 'value' in values and isinstance(values['value'], np.int64): values['value'] = int(values['value']) if 'raw_value' in values and isinstance(values['raw_value'], np.int64): values['raw_value'] = int(values['raw_value']) if 'val_mapping' in values: values.pop('val_mapping') return parameters
def test_initialize_applies_configuration(self): mock_address = 'dev2331' mock_config = PythonJsonStructure(a=1, b='2', c=3.1415) scope_mock, factory_mock = TestUhfliScopeReader.__patch_scope_reader( mock_address) self.assertEqual(mock_address, scope_mock.adapter.address) scope_mock.initialize(mock_config) factory_mock.get_instrument_adapter.assert_called_once_with( 'ZIUHFLIInstrumentAdapter', mock_address) scope_mock.adapter.apply.assert_called_once_with(mock_config) self.assertEqual(mock_address, scope_mock.adapter.address)
def _filter_parameters(self, parameters: PythonJsonStructure) -> PythonJsonStructure: if parameters['box_averages']['value'] == 1: parameters.pop('box_averages') parameters.pop('card_available_length') parameters.pop('IDN') return parameters
def test_refresh(self): with patch( 'qilib.configuration_helper.instrument_configuration.InstrumentAdapterFactory' ) as mock_factory: mock_adapter = MagicMock() instrument_settings = PythonJsonStructure(param1={'value': 1}, param2={'value': 2}, param3={'value': 3}, param4={'value': 4}) mock_adapter.read.return_value = instrument_settings mock_factory.get_instrument_adapter.return_value = mock_adapter instrument_configuration = InstrumentConfiguration( 'DummyClass', 'fake-address', self._storage, configuration=PythonJsonStructure(param1={'value': 11}, param2={'value': 22}, param3={'value': 33}, param4={'value': 444})) instrument_configuration.refresh() self.assertDictEqual(instrument_settings, instrument_configuration.configuration)
def read(self, update: bool = True) -> PythonJsonStructure: """ Reads and returns all SPI rack module settings from the device. All module parameters will be collected, even if the parameter is write only. If the write only parameter has not been set, a None will be set as value. Args: update: Update the settings first before returning the settings configuration. Returns: A custom dictionary with all the SPI rack module settings. """ return PythonJsonStructure(super().read(update))
def load_configuration(file_path: str) -> PythonJsonStructure: """ Loads the instrument configuration from disk storage. Args: file_path: The store file location on disk. Returns: The loaded configuration from disk. """ with open(file_path, 'rb') as file_pointer: serialized_configuration = file_pointer.readlines() unserialized_configuration = dict( serialization.unserialize(serialized_configuration[0])) return PythonJsonStructure(unserialized_configuration)
def store(self) -> None: """ Saves object to storage. Raises: DuplicateTagError: If this object's tag is already in the database. """ if self._storage.tag_in_storage(self._tag): raise DuplicateTagError( f"InstrumentConfiguration for {self._adapter_class_name} with tag '{self._tag}' already in storage") document = PythonJsonStructure(adapter_class_name=self._adapter_class_name, address=self._address, instrument_name=self._instrument_name, configuration=self._configuration) self._storage.save_data(document, self._tag)