Loading quantify_scheduler/instrument_coordinator/components/base.py +22 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ from __future__ import annotations from abc import abstractmethod from typing import Any from typing import Any, Dict from qcodes.instrument import parameter from qcodes.instrument import base from qcodes.utils import validators Loading @@ -13,6 +13,27 @@ from qcodes.utils import validators class InstrumentCoordinatorComponentBase(base.Instrument): """The InstrumentCoordinator component abstract interface.""" # NB `_instances` also used by `Instrument` class _no_gc_intances: Dict[str, InstrumentCoordinatorComponentBase] = dict() def __new__( cls, instrument: base.InstrumentBase, *args, **kwargs ) -> InstrumentCoordinatorComponentBase: """Keeps track of the intances of this class. NB This is done intentionally to prevent the intances from being garbage collected. """ instance = super().__new__(cls, *args, **kwargs) cls._no_gc_intances[instrument.name] = instance return instance def close(self): """Makes sure the intance reference is realeased so that garbage collector can claim the object""" _ = self._no_gc_intances.pop(self.instrument_ref()) super().close() def __init__( self, instrument: base.InstrumentBase, Loading tests/scheduler/instrument_coordinator/test_instrument_coordinator.py +135 −105 Original line number Diff line number Diff line Loading @@ -3,46 +3,94 @@ # pylint: disable=missing-module-docstring # pylint: disable=missing-class-docstring # pylint: disable=missing-function-docstring # pylint: disable=unused-argument # pylint: disable=too-many-arguments from __future__ import annotations from typing import List import gc from dataclasses import dataclass from unittest.mock import call import pytest from qcodes import Instrument from quantify_scheduler.instrument_coordinator import InstrumentCoordinator from quantify_scheduler.instrument_coordinator.components import base as base_component def make_component( mocker, name: str class MyICC(base_component.InstrumentCoordinatorComponentBase): @property def is_running(self): pass def start(self): pass def stop(self): pass def prepare(self, options): pass def retrieve_acquisition(self): pass def wait_done(self, timeout_sec: int = 10): pass @pytest.fixture(autouse=True, name="close_all_instruments") def fixture_close_all_instruments(): """Makes sure that after startup and teardown all instruments are closed""" Instrument.close_all() yield Instrument.close_all() # cretes a few dummy compoents avialable to be used in each test @pytest.fixture(scope="function", name="dummy_components") def fixture_dummy_components( mocker, request ) -> base_component.InstrumentCoordinatorComponentBase: mocker.patch("qcodes.instrument.Instrument.record_instance") component = mocker.create_autospec( base_component.InstrumentCoordinatorComponentBase, instance=True # Crete a QCoDeS intrument for realistic emulation instruments = [Instrument(f"dev{i}") for i in range(3)] components = [] for instrument in instruments: comp = MyICC(instrument) for func in ("prepare", "start", "stop", "wait_done", "retrieve_acquisition"): mocker.patch.object( comp, func, wraps=getattr(comp, func), ) component.name = name return component components.append(comp) def cleanup_tmp(): # This should prevent the garbage collector from colleting the qcodes instrument for instrument in instruments: instrument.close() def make_instrument_coordinator(mocker, name: str) -> InstrumentCoordinator: mocker.patch("qcodes.instrument.Instrument.record_instance") instrument_coordinator = InstrumentCoordinator(name) request.addfinalizer(cleanup_tmp) instrument_coordinator._mock_instr_dict = {} return components # add a mock find instrument def mock_find_instrument(instr_name: str): return instrument_coordinator._mock_instr_dict[instr_name] instrument_coordinator.find_instrument = mock_find_instrument @pytest.fixture(scope="function", name="instrument_coordinator") def fixture_instrument_coordinator(request) -> InstrumentCoordinator: instrument_coordinator = InstrumentCoordinator("ic_0000") def cleanup_tmp(): # This should prevent the garbage collector from colleting the qcodes instrument instrument_coordinator.close() request.addfinalizer(cleanup_tmp) return instrument_coordinator def test_constructor(mocker): # Act instrument_coordinator = make_instrument_coordinator(mocker, "ic0") def test_constructor(close_all_instruments, instrument_coordinator): # Assert assert len(instrument_coordinator.components()) == 0 Loading @@ -56,16 +104,25 @@ def test_constructor(mocker): ([False, False], False), ], ) def test_is_running(mocker, states: List[bool], expected: bool): def test_is_running( close_all_instruments, instrument_coordinator, dummy_components, states: List[bool], expected: bool, mocker, ): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") mocker.patch.object(MyICC, "is_running") # necessary for overriding `is_running` for i, state in enumerate(states): component = make_component(mocker, f"dev{i}") component.is_running = state for state in states: # popping ensures the reference to the object is released after this for loop component = dummy_components.pop(0) instrument_coordinator.add_component(component) component.is_running = state instrument_coordinator._mock_instr_dict[component.name] = component # force garbage collection to emulate qcodes correcly gc.collect() # Act is_running = instrument_coordinator.is_running Loading @@ -74,52 +131,47 @@ def test_is_running(mocker, states: List[bool], expected: bool): assert is_running == expected def test_get_component(mocker): def test_get_component(close_all_instruments, instrument_coordinator, dummy_components): for i in range(len(dummy_components)): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") component1 = make_component(mocker, "dev1234") instrument_coordinator.add_component(component1) # required for the mock find_instrument to work instrument_coordinator._mock_instr_dict[component1.name] = component1 component_ = dummy_components.pop(0) instrument_coordinator.add_component(component_) # Act component = instrument_coordinator.get_component("dev1234") component = instrument_coordinator.get_component(f"ic_dev{i}") # Assert assert component1 == component assert component_ == component def test_get_component_failed(mocker): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") def test_get_component_failed(close_all_instruments, instrument_coordinator): # Act with pytest.raises(KeyError) as execinfo: instrument_coordinator.get_component("dev1234") instrument_coordinator.get_component("ic_dev1234") # Assert assert execinfo.value.args[0] == "'dev1234' is not a component of ic0!" assert execinfo.value.args[0] == "'ic_dev1234' is not a component of ic_0000!" def test_add_component_failed_duplicate(mocker): def test_add_component_failed_duplicate( close_all_instruments, instrument_coordinator, dummy_components ): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") component1 = make_component(mocker, "dev1234") component1 = dummy_components.pop(0) instrument_coordinator.add_component(component1) # Act with pytest.raises(ValueError) as execinfo: instrument_coordinator.add_component(component1) instrument_coordinator.add_component(component1) # Assert assert execinfo.value.args[0] == "'dev1234' has already been added!" assert execinfo.value.args[0] == "'ic_dev0' has already been added!" def test_add_component_failed_type_validation(mocker): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") def test_add_component_failed_type_validation( close_all_instruments, instrument_coordinator ): @dataclass class DummyComponent: name: str Loading @@ -140,34 +192,28 @@ def test_add_component_failed_type_validation(mocker): ) def test_remove_component(mocker): def test_remove_component( close_all_instruments, instrument_coordinator, dummy_components ): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") component1 = make_component(mocker, "dev1234") component2 = make_component(mocker, "dev5678") component1, component2 = dummy_components.pop(0), dummy_components.pop(0) instrument_coordinator.add_component(component1) instrument_coordinator.add_component(component2) # required for the mock find_instrument to work instrument_coordinator._mock_instr_dict[component1.name] = component1 instrument_coordinator._mock_instr_dict[component2.name] = component2 # Act assert instrument_coordinator.components() == ["dev1234", "dev5678"] instrument_coordinator.remove_component("dev1234") assert instrument_coordinator.components() == ["dev5678"] assert instrument_coordinator.components() == ["ic_dev0", "ic_dev1"] instrument_coordinator.remove_component("ic_dev0") assert instrument_coordinator.components() == ["ic_dev1"] def test_prepare(mocker): def test_prepare( close_all_instruments, instrument_coordinator, dummy_components, mocker ): # NB order of fixtures matters for teardown, keep mocker as last! # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") component1 = make_component(mocker, "dev1234") component2 = make_component(mocker, "dev5678") component1 = dummy_components.pop(0) component2 = dummy_components.pop(0) instrument_coordinator.add_component(component1) instrument_coordinator.add_component(component2) # required for the mock find_instrument to work instrument_coordinator._mock_instr_dict[component1.name] = component1 instrument_coordinator._mock_instr_dict[component2.name] = component2 get_component_spy = mocker.patch.object( instrument_coordinator, Loading @@ -176,28 +222,22 @@ def test_prepare(mocker): ) # Act args = {"dev1234": {"foo": 1}, "dev5678": {"foo": 2}} args = {"ic_dev0": {"foo": 0}, "ic_dev1": {"foo": 1}} instrument_coordinator.prepare(args) # Assert assert get_component_spy.call_args_list == [ call("dev1234"), call("dev5678"), ] component1.prepare.assert_called_with(args["dev1234"]) component2.prepare.assert_called_with(args["dev5678"]) assert get_component_spy.call_args_list == [call("ic_dev0"), call("ic_dev1")] component1.prepare.assert_called_with(args["ic_dev0"]) component2.prepare.assert_called_with(args["ic_dev1"]) def test_start(mocker): def test_start(close_all_instruments, instrument_coordinator, dummy_components): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") component1 = make_component(mocker, "dev1234") component2 = make_component(mocker, "dev5678") component1 = dummy_components.pop(0) component2 = dummy_components.pop(0) instrument_coordinator.add_component(component1) instrument_coordinator.add_component(component2) # required for the mock find_instrument to work instrument_coordinator._mock_instr_dict[component1.name] = component1 instrument_coordinator._mock_instr_dict[component2.name] = component2 # Act instrument_coordinator.start() Loading @@ -207,16 +247,12 @@ def test_start(mocker): component2.start.assert_called() def test_stop(mocker): def test_stop(close_all_instruments, instrument_coordinator, dummy_components): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") component1 = make_component(mocker, "dev1234") component2 = make_component(mocker, "dev5678") component1 = dummy_components.pop(0) component2 = dummy_components.pop(0) instrument_coordinator.add_component(component1) instrument_coordinator.add_component(component2) # required for the mock find_instrument to work instrument_coordinator._mock_instr_dict[component1.name] = component1 instrument_coordinator._mock_instr_dict[component2.name] = component2 # Act instrument_coordinator.stop() Loading @@ -226,16 +262,14 @@ def test_stop(mocker): component2.stop.assert_called() def test_retrieve_acquisition(mocker): def test_retrieve_acquisition( close_all_instruments, instrument_coordinator, dummy_components ): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") component1 = make_component(mocker, "dev1234") component2 = make_component(mocker, "dev5678") component1 = dummy_components.pop(0) component2 = dummy_components.pop(0) instrument_coordinator.add_component(component1) instrument_coordinator.add_component(component2) # required for the mock find_instrument to work instrument_coordinator._mock_instr_dict[component1.name] = component1 instrument_coordinator._mock_instr_dict[component2.name] = component2 component1.retrieve_acquisition.return_value = {0: [1, 2, 3, 4]} component2.retrieve_acquisition.return_value = None Loading @@ -246,19 +280,15 @@ def test_retrieve_acquisition(mocker): # Assert component1.retrieve_acquisition.assert_called() component2.retrieve_acquisition.assert_called() assert {"dev1234": {0: [1, 2, 3, 4]}} == data assert {"ic_dev0": {0: [1, 2, 3, 4]}} == data def test_wait_done(mocker): def test_wait_done(close_all_instruments, instrument_coordinator, dummy_components): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") component1 = make_component(mocker, "dev1234") component2 = make_component(mocker, "dev5678") component1 = dummy_components.pop(0) component2 = dummy_components.pop(0) instrument_coordinator.add_component(component1) instrument_coordinator.add_component(component2) # required for the mock find_instrument to work instrument_coordinator._mock_instr_dict[component1.name] = component1 instrument_coordinator._mock_instr_dict[component2.name] = component2 timeout: int = 1 Loading Loading
quantify_scheduler/instrument_coordinator/components/base.py +22 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ from __future__ import annotations from abc import abstractmethod from typing import Any from typing import Any, Dict from qcodes.instrument import parameter from qcodes.instrument import base from qcodes.utils import validators Loading @@ -13,6 +13,27 @@ from qcodes.utils import validators class InstrumentCoordinatorComponentBase(base.Instrument): """The InstrumentCoordinator component abstract interface.""" # NB `_instances` also used by `Instrument` class _no_gc_intances: Dict[str, InstrumentCoordinatorComponentBase] = dict() def __new__( cls, instrument: base.InstrumentBase, *args, **kwargs ) -> InstrumentCoordinatorComponentBase: """Keeps track of the intances of this class. NB This is done intentionally to prevent the intances from being garbage collected. """ instance = super().__new__(cls, *args, **kwargs) cls._no_gc_intances[instrument.name] = instance return instance def close(self): """Makes sure the intance reference is realeased so that garbage collector can claim the object""" _ = self._no_gc_intances.pop(self.instrument_ref()) super().close() def __init__( self, instrument: base.InstrumentBase, Loading
tests/scheduler/instrument_coordinator/test_instrument_coordinator.py +135 −105 Original line number Diff line number Diff line Loading @@ -3,46 +3,94 @@ # pylint: disable=missing-module-docstring # pylint: disable=missing-class-docstring # pylint: disable=missing-function-docstring # pylint: disable=unused-argument # pylint: disable=too-many-arguments from __future__ import annotations from typing import List import gc from dataclasses import dataclass from unittest.mock import call import pytest from qcodes import Instrument from quantify_scheduler.instrument_coordinator import InstrumentCoordinator from quantify_scheduler.instrument_coordinator.components import base as base_component def make_component( mocker, name: str class MyICC(base_component.InstrumentCoordinatorComponentBase): @property def is_running(self): pass def start(self): pass def stop(self): pass def prepare(self, options): pass def retrieve_acquisition(self): pass def wait_done(self, timeout_sec: int = 10): pass @pytest.fixture(autouse=True, name="close_all_instruments") def fixture_close_all_instruments(): """Makes sure that after startup and teardown all instruments are closed""" Instrument.close_all() yield Instrument.close_all() # cretes a few dummy compoents avialable to be used in each test @pytest.fixture(scope="function", name="dummy_components") def fixture_dummy_components( mocker, request ) -> base_component.InstrumentCoordinatorComponentBase: mocker.patch("qcodes.instrument.Instrument.record_instance") component = mocker.create_autospec( base_component.InstrumentCoordinatorComponentBase, instance=True # Crete a QCoDeS intrument for realistic emulation instruments = [Instrument(f"dev{i}") for i in range(3)] components = [] for instrument in instruments: comp = MyICC(instrument) for func in ("prepare", "start", "stop", "wait_done", "retrieve_acquisition"): mocker.patch.object( comp, func, wraps=getattr(comp, func), ) component.name = name return component components.append(comp) def cleanup_tmp(): # This should prevent the garbage collector from colleting the qcodes instrument for instrument in instruments: instrument.close() def make_instrument_coordinator(mocker, name: str) -> InstrumentCoordinator: mocker.patch("qcodes.instrument.Instrument.record_instance") instrument_coordinator = InstrumentCoordinator(name) request.addfinalizer(cleanup_tmp) instrument_coordinator._mock_instr_dict = {} return components # add a mock find instrument def mock_find_instrument(instr_name: str): return instrument_coordinator._mock_instr_dict[instr_name] instrument_coordinator.find_instrument = mock_find_instrument @pytest.fixture(scope="function", name="instrument_coordinator") def fixture_instrument_coordinator(request) -> InstrumentCoordinator: instrument_coordinator = InstrumentCoordinator("ic_0000") def cleanup_tmp(): # This should prevent the garbage collector from colleting the qcodes instrument instrument_coordinator.close() request.addfinalizer(cleanup_tmp) return instrument_coordinator def test_constructor(mocker): # Act instrument_coordinator = make_instrument_coordinator(mocker, "ic0") def test_constructor(close_all_instruments, instrument_coordinator): # Assert assert len(instrument_coordinator.components()) == 0 Loading @@ -56,16 +104,25 @@ def test_constructor(mocker): ([False, False], False), ], ) def test_is_running(mocker, states: List[bool], expected: bool): def test_is_running( close_all_instruments, instrument_coordinator, dummy_components, states: List[bool], expected: bool, mocker, ): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") mocker.patch.object(MyICC, "is_running") # necessary for overriding `is_running` for i, state in enumerate(states): component = make_component(mocker, f"dev{i}") component.is_running = state for state in states: # popping ensures the reference to the object is released after this for loop component = dummy_components.pop(0) instrument_coordinator.add_component(component) component.is_running = state instrument_coordinator._mock_instr_dict[component.name] = component # force garbage collection to emulate qcodes correcly gc.collect() # Act is_running = instrument_coordinator.is_running Loading @@ -74,52 +131,47 @@ def test_is_running(mocker, states: List[bool], expected: bool): assert is_running == expected def test_get_component(mocker): def test_get_component(close_all_instruments, instrument_coordinator, dummy_components): for i in range(len(dummy_components)): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") component1 = make_component(mocker, "dev1234") instrument_coordinator.add_component(component1) # required for the mock find_instrument to work instrument_coordinator._mock_instr_dict[component1.name] = component1 component_ = dummy_components.pop(0) instrument_coordinator.add_component(component_) # Act component = instrument_coordinator.get_component("dev1234") component = instrument_coordinator.get_component(f"ic_dev{i}") # Assert assert component1 == component assert component_ == component def test_get_component_failed(mocker): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") def test_get_component_failed(close_all_instruments, instrument_coordinator): # Act with pytest.raises(KeyError) as execinfo: instrument_coordinator.get_component("dev1234") instrument_coordinator.get_component("ic_dev1234") # Assert assert execinfo.value.args[0] == "'dev1234' is not a component of ic0!" assert execinfo.value.args[0] == "'ic_dev1234' is not a component of ic_0000!" def test_add_component_failed_duplicate(mocker): def test_add_component_failed_duplicate( close_all_instruments, instrument_coordinator, dummy_components ): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") component1 = make_component(mocker, "dev1234") component1 = dummy_components.pop(0) instrument_coordinator.add_component(component1) # Act with pytest.raises(ValueError) as execinfo: instrument_coordinator.add_component(component1) instrument_coordinator.add_component(component1) # Assert assert execinfo.value.args[0] == "'dev1234' has already been added!" assert execinfo.value.args[0] == "'ic_dev0' has already been added!" def test_add_component_failed_type_validation(mocker): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") def test_add_component_failed_type_validation( close_all_instruments, instrument_coordinator ): @dataclass class DummyComponent: name: str Loading @@ -140,34 +192,28 @@ def test_add_component_failed_type_validation(mocker): ) def test_remove_component(mocker): def test_remove_component( close_all_instruments, instrument_coordinator, dummy_components ): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") component1 = make_component(mocker, "dev1234") component2 = make_component(mocker, "dev5678") component1, component2 = dummy_components.pop(0), dummy_components.pop(0) instrument_coordinator.add_component(component1) instrument_coordinator.add_component(component2) # required for the mock find_instrument to work instrument_coordinator._mock_instr_dict[component1.name] = component1 instrument_coordinator._mock_instr_dict[component2.name] = component2 # Act assert instrument_coordinator.components() == ["dev1234", "dev5678"] instrument_coordinator.remove_component("dev1234") assert instrument_coordinator.components() == ["dev5678"] assert instrument_coordinator.components() == ["ic_dev0", "ic_dev1"] instrument_coordinator.remove_component("ic_dev0") assert instrument_coordinator.components() == ["ic_dev1"] def test_prepare(mocker): def test_prepare( close_all_instruments, instrument_coordinator, dummy_components, mocker ): # NB order of fixtures matters for teardown, keep mocker as last! # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") component1 = make_component(mocker, "dev1234") component2 = make_component(mocker, "dev5678") component1 = dummy_components.pop(0) component2 = dummy_components.pop(0) instrument_coordinator.add_component(component1) instrument_coordinator.add_component(component2) # required for the mock find_instrument to work instrument_coordinator._mock_instr_dict[component1.name] = component1 instrument_coordinator._mock_instr_dict[component2.name] = component2 get_component_spy = mocker.patch.object( instrument_coordinator, Loading @@ -176,28 +222,22 @@ def test_prepare(mocker): ) # Act args = {"dev1234": {"foo": 1}, "dev5678": {"foo": 2}} args = {"ic_dev0": {"foo": 0}, "ic_dev1": {"foo": 1}} instrument_coordinator.prepare(args) # Assert assert get_component_spy.call_args_list == [ call("dev1234"), call("dev5678"), ] component1.prepare.assert_called_with(args["dev1234"]) component2.prepare.assert_called_with(args["dev5678"]) assert get_component_spy.call_args_list == [call("ic_dev0"), call("ic_dev1")] component1.prepare.assert_called_with(args["ic_dev0"]) component2.prepare.assert_called_with(args["ic_dev1"]) def test_start(mocker): def test_start(close_all_instruments, instrument_coordinator, dummy_components): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") component1 = make_component(mocker, "dev1234") component2 = make_component(mocker, "dev5678") component1 = dummy_components.pop(0) component2 = dummy_components.pop(0) instrument_coordinator.add_component(component1) instrument_coordinator.add_component(component2) # required for the mock find_instrument to work instrument_coordinator._mock_instr_dict[component1.name] = component1 instrument_coordinator._mock_instr_dict[component2.name] = component2 # Act instrument_coordinator.start() Loading @@ -207,16 +247,12 @@ def test_start(mocker): component2.start.assert_called() def test_stop(mocker): def test_stop(close_all_instruments, instrument_coordinator, dummy_components): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") component1 = make_component(mocker, "dev1234") component2 = make_component(mocker, "dev5678") component1 = dummy_components.pop(0) component2 = dummy_components.pop(0) instrument_coordinator.add_component(component1) instrument_coordinator.add_component(component2) # required for the mock find_instrument to work instrument_coordinator._mock_instr_dict[component1.name] = component1 instrument_coordinator._mock_instr_dict[component2.name] = component2 # Act instrument_coordinator.stop() Loading @@ -226,16 +262,14 @@ def test_stop(mocker): component2.stop.assert_called() def test_retrieve_acquisition(mocker): def test_retrieve_acquisition( close_all_instruments, instrument_coordinator, dummy_components ): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") component1 = make_component(mocker, "dev1234") component2 = make_component(mocker, "dev5678") component1 = dummy_components.pop(0) component2 = dummy_components.pop(0) instrument_coordinator.add_component(component1) instrument_coordinator.add_component(component2) # required for the mock find_instrument to work instrument_coordinator._mock_instr_dict[component1.name] = component1 instrument_coordinator._mock_instr_dict[component2.name] = component2 component1.retrieve_acquisition.return_value = {0: [1, 2, 3, 4]} component2.retrieve_acquisition.return_value = None Loading @@ -246,19 +280,15 @@ def test_retrieve_acquisition(mocker): # Assert component1.retrieve_acquisition.assert_called() component2.retrieve_acquisition.assert_called() assert {"dev1234": {0: [1, 2, 3, 4]}} == data assert {"ic_dev0": {0: [1, 2, 3, 4]}} == data def test_wait_done(mocker): def test_wait_done(close_all_instruments, instrument_coordinator, dummy_components): # Arrange instrument_coordinator = make_instrument_coordinator(mocker, "ic0") component1 = make_component(mocker, "dev1234") component2 = make_component(mocker, "dev5678") component1 = dummy_components.pop(0) component2 = dummy_components.pop(0) instrument_coordinator.add_component(component1) instrument_coordinator.add_component(component2) # required for the mock find_instrument to work instrument_coordinator._mock_instr_dict[component1.name] = component1 instrument_coordinator._mock_instr_dict[component2.name] = component2 timeout: int = 1 Loading