From 1cfd1de75130a57d27d3e9b17c6f41451457186b Mon Sep 17 00:00:00 2001 From: Tom Cobb Date: Wed, 11 Dec 2024 17:11:35 +0000 Subject: [PATCH] Reimplement DeviceCollector as auto_init_devices Functionality is the same, but the public interface is now a function rather than a class. Also makes sure that Devices that exist on entry, and are redeclared in the context manager are found. --- docs/examples/epics_demo.py | 4 +- src/ophyd_async/core/__init__.py | 4 +- src/ophyd_async/core/_device.py | 143 +++++++++--------- system_tests/epics/eiger/test_eiger_system.py | 6 +- ...collector.py => test_auto_init_devices.py} | 42 +++-- tests/core/test_device.py | 6 +- tests/core/test_mock_signal_backend.py | 4 +- tests/core/test_protocol.py | 6 +- tests/core/test_signal.py | 4 +- tests/core/test_utils.py | 12 +- tests/epics/adcore/test_drivers.py | 4 +- tests/epics/adcore/test_scans.py | 6 +- tests/epics/adcore/test_writers.py | 8 +- tests/epics/conftest.py | 4 +- tests/epics/demo/test_demo.py | 14 +- tests/epics/eiger/test_eiger_controller.py | 4 +- tests/epics/eiger/test_eiger_detector.py | 4 +- tests/epics/eiger/test_odin_io.py | 4 +- tests/epics/pvi/test_pvi.py | 4 +- tests/epics/test_motor.py | 4 +- tests/fastcs/panda/test_panda_connect.py | 4 +- tests/fastcs/panda/test_panda_control.py | 4 +- tests/fastcs/panda/test_panda_utils.py | 4 +- tests/fastcs/panda/test_trigger.py | 4 +- tests/fastcs/panda/test_writer.py | 8 +- tests/plan_stubs/test_fly.py | 4 +- tests/sim/demo/test_sim_motor.py | 8 +- tests/sim/test_sim_writer.py | 4 +- tests/tango/test_base_device.py | 6 +- 29 files changed, 175 insertions(+), 158 deletions(-) rename tests/core/{test_device_collector.py => test_auto_init_devices.py} (75%) diff --git a/docs/examples/epics_demo.py b/docs/examples/epics_demo.py index 0f0b1bfe6f..ce3ca3e2b6 100644 --- a/docs/examples/epics_demo.py +++ b/docs/examples/epics_demo.py @@ -7,7 +7,7 @@ from bluesky.utils import ProgressBarManager, register_transform from ophyd import Component, Device, EpicsSignal, EpicsSignalRO -from ophyd_async.core import DeviceCollector +from ophyd_async.core import auto_init_devices from ophyd_async.epics import demo # Create a run engine, with plotting, progressbar and transform @@ -31,7 +31,7 @@ class OldSensor(Device): det_old = OldSensor(pv_prefix, name="det_old") # Create ophyd-async devices -with DeviceCollector(): +with auto_init_devices(): det = demo.Sensor(pv_prefix) det_group = demo.SensorGroup(pv_prefix) samp = demo.SampleStage(pv_prefix) diff --git a/src/ophyd_async/core/__init__.py b/src/ophyd_async/core/__init__.py index 8b3be801db..60ca7f640c 100644 --- a/src/ophyd_async/core/__init__.py +++ b/src/ophyd_async/core/__init__.py @@ -5,7 +5,7 @@ StandardDetector, TriggerInfo, ) -from ._device import Device, DeviceCollector, DeviceConnector, DeviceVector +from ._device import Device, DeviceConnector, DeviceVector, auto_init_devices from ._device_filler import DeviceFiller from ._device_save_loader import ( all_at_once, @@ -93,7 +93,7 @@ "TriggerInfo", "Device", "DeviceConnector", - "DeviceCollector", + "auto_init_devices", "DeviceVector", "DeviceFiller", "all_at_once", diff --git a/src/ophyd_async/core/_device.py b/src/ophyd_async/core/_device.py index 36bed049ca..6f6438f2e2 100644 --- a/src/ophyd_async/core/_device.py +++ b/src/ophyd_async/core/_device.py @@ -2,7 +2,7 @@ import asyncio import sys -from collections.abc import Coroutine, Iterator, Mapping, MutableMapping +from collections.abc import Awaitable, Callable, Iterator, Mapping, MutableMapping from functools import cached_property from logging import LoggerAdapter, getLogger from typing import Any, TypeVar @@ -254,54 +254,18 @@ def __hash__(self): # to allow DeviceVector to be used as dict keys and in sets return hash(id(self)) -class DeviceCollector: - """Collector of top level Device instances to be used as a context manager - - Parameters - ---------- - set_name: - If True, call ``device.set_name(variable_name)`` on all collected - Devices - child_name_separator: - Use this as a separator if we call ``set_name``. - connect: - If True, call ``device.connect(mock)`` in parallel on all - collected Devices - mock: - If True, connect Signals in simulation mode - timeout: - How long to wait for connect before logging an exception - - Notes - ----- - Example usage:: - - [async] with DeviceCollector(): - t1x = motor.Motor("BLxxI-MO-TABLE-01:X") - t1y = motor.Motor("pva://BLxxI-MO-TABLE-01:Y") - # Names and connects devices here - assert t1x.comm.velocity.source - assert t1x.name == "t1x" +class DeviceContextManager: + """Sync/Async Context Manager that finds all the Devices declared within it. + Used in `auto_init` """ - def __init__( - self, - set_name=True, - child_name_separator: str = "-", - connect=True, - mock=False, - timeout: float = 10.0, - ): - self._set_name = set_name - self._child_name_separator = child_name_separator - self._connect = connect - self._mock = mock - self._timeout = timeout - self._names_on_enter: set[str] = set() - self._objects_on_exit: dict[str, Any] = {} - - def _caller_locals(self): + def __init__(self, process_devices: Callable[[dict[str, Device]], Awaitable[None]]): + self._process_devices = process_devices + self._locals_on_enter: dict[str, Any] = {} + self._locals_on_exit: dict[str, Any] = {} + + def _caller_locals(self) -> dict[str, Any]: """Walk up until we find a stack frame that doesn't have us as self""" try: raise ValueError @@ -314,34 +278,18 @@ def _caller_locals(self): assert ( caller_frame ), "No previous frame to the one with self in it, this shouldn't happen" - return caller_frame.f_locals + return caller_frame.f_locals.copy() - def __enter__(self) -> DeviceCollector: + def __enter__(self) -> DeviceContextManager: # Stash the names that were defined before we were called - self._names_on_enter = set(self._caller_locals()) + self._locals_on_enter = self._caller_locals() return self - async def __aenter__(self) -> DeviceCollector: + async def __aenter__(self) -> DeviceContextManager: return self.__enter__() - async def _on_exit(self) -> None: - # Name and kick off connect for devices - connect_coroutines: dict[str, Coroutine] = {} - for name, obj in self._objects_on_exit.items(): - if name not in self._names_on_enter and isinstance(obj, Device): - if self._set_name and not obj.name: - obj.set_name(name, child_name_separator=self._child_name_separator) - if self._connect: - connect_coroutines[name] = obj.connect( - self._mock, timeout=self._timeout - ) - - # Connect to all the devices - if connect_coroutines: - await wait_for_connection(**connect_coroutines) - async def __aexit__(self, type, value, traceback): - self._objects_on_exit = self._caller_locals() + self._locals_on_exit = self._caller_locals() await self._on_exit() def __exit__(self, type_, value, traceback): @@ -350,7 +298,7 @@ def __exit__(self, type_, value, traceback): "Cannot use DeviceConnector inside a plan, instead use " "`yield from ophyd_async.plan_stubs.ensure_connected(device)`" ) - self._objects_on_exit = self._caller_locals() + self._locals_on_exit = self._caller_locals() try: fut = call_in_bluesky_event_loop(self._on_exit()) except RuntimeError as e: @@ -360,3 +308,62 @@ def __exit__(self, type_, value, traceback): "user/explanations/event-loop-choice.html for more info." ) from e return fut + + async def _on_exit(self) -> None: + # Find all the devices + devices = { + name: obj + for name, obj in self._locals_on_exit.items() + if isinstance(obj, Device) and self._locals_on_enter.get(name) is not obj + } + # Call the provided process function on them + await self._process_devices(devices) + + +def auto_init_devices( + set_name=True, + child_name_separator: str = "-", + connect=True, + mock=False, + timeout: float = 10.0, +) -> DeviceContextManager: + """Auto initialise top level Device instances to be used as a context manager + + Parameters + ---------- + set_name: + If True, call ``device.set_name(variable_name)`` on all Devices + created within the context manager that have an empty ``name`` + child_name_separator: + Use this as a separator if we call ``set_name``. + connect: + If True, call ``device.connect(mock, timeout)`` in parallel on all + Devices created within the context manager + mock: + If True, connect Signals in mock mode + timeout: + How long to wait for connect before logging an exception + + Notes + ----- + Example usage:: + + [async] with auto_init_devices(): + t1x = motor.Motor("BLxxI-MO-TABLE-01:X") + t1y = motor.Motor("pva://BLxxI-MO-TABLE-01:Y") + # Names and connects devices here + assert t1x.name == "t1x" + """ + + async def process_devices(devices: dict[str, Device]): + if set_name: + for name, device in devices.items(): + if not device.name: + device.set_name(name, child_name_separator=child_name_separator) + if connect: + coros = { + name: device.connect(mock, timeout) for name, device in devices.items() + } + await wait_for_connection(**coros) + + return DeviceContextManager(process_devices) diff --git a/system_tests/epics/eiger/test_eiger_system.py b/system_tests/epics/eiger/test_eiger_system.py index 8a27c41689..6f94a43221 100644 --- a/system_tests/epics/eiger/test_eiger_system.py +++ b/system_tests/epics/eiger/test_eiger_system.py @@ -9,8 +9,8 @@ from ophyd_async.core import ( DetectorTrigger, Device, - DeviceCollector, StaticPathProvider, + auto_init_devices, ) from ophyd_async.epics.core import epics_signal_rw from ophyd_async.epics.eiger import EigerDetector, EigerTriggerInfo @@ -47,7 +47,7 @@ def RE(): @pytest.fixture async def setup_device(RE, ioc_prefixes): - async with DeviceCollector(): + async with auto_init_devices(): device = SetupDevice(ioc_prefixes[0], ioc_prefixes[1] + "FP:") await asyncio.gather( device.header_detail.set("all"), @@ -62,7 +62,7 @@ async def setup_device(RE, ioc_prefixes): @pytest.fixture async def test_eiger(RE, ioc_prefixes) -> EigerDetector: provider = StaticPathProvider(lambda: "test_eiger", Path(SAVE_PATH)) - async with DeviceCollector(): + async with auto_init_devices(): test_eiger = EigerDetector("", provider, ioc_prefixes[0], ioc_prefixes[1]) return test_eiger diff --git a/tests/core/test_device_collector.py b/tests/core/test_auto_init_devices.py similarity index 75% rename from tests/core/test_device_collector.py rename to tests/core/test_auto_init_devices.py index 18c9b5deb7..d7fe01e6ee 100644 --- a/tests/core/test_device_collector.py +++ b/tests/core/test_auto_init_devices.py @@ -7,8 +7,8 @@ from ophyd_async.core import ( DEFAULT_TIMEOUT, Device, - DeviceCollector, NotConnected, + auto_init_devices, ) from ophyd_async.epics import motor from ophyd_async.testing import set_mock_value @@ -33,10 +33,10 @@ async def connect( async def set(self, new_position: float): ... -async def test_device_collector_handles_top_level_errors(caplog): +async def test_auto_init_handles_top_level_errors(caplog): caplog.set_level(10) with pytest.raises(NotConnected) as exc: - async with DeviceCollector(): + async with auto_init_devices(): _ = FailingDevice("somename") assert not exc.value.__cause__ @@ -52,9 +52,9 @@ async def test_device_collector_handles_top_level_errors(caplog): assert device_log[0].levelname == "ERROR" -def test_sync_device_connector_no_run_engine_raises_error(): +def test_sync_auto_init_no_run_engine_raises_error(): with pytest.raises(NotConnected) as e: - with DeviceCollector(): + with auto_init_devices(): working_device = WorkingDevice("somename") assert e.value._errors == ( "Could not connect devices. Is the bluesky event loop running? See " @@ -64,26 +64,36 @@ def test_sync_device_connector_no_run_engine_raises_error(): assert not working_device.connected -def test_sync_device_connector_run_engine_created_connects(RE): - with DeviceCollector(): +def test_sync_auto_init_run_engine_created_connects(RE): + with auto_init_devices(): working_device = WorkingDevice("somename") assert working_device.connected +async def test_auto_init_detects_redeclared_devices(): + original_working_device = working_device = WorkingDevice() + + async with auto_init_devices(): + working_device = WorkingDevice() + assert original_working_device is not working_device + assert working_device.connected and working_device.name == "working_device" + assert not original_working_device.connected and original_working_device.name == "" + + def test_connecting_in_plan_raises(RE): def bad_plan(): yield from bps.null() - with DeviceCollector(): + with auto_init_devices(): working_device = WorkingDevice("somename") # noqa: F841 with pytest.raises(RuntimeError, match="Cannot use DeviceConnector inside a plan"): RE(bad_plan()) -def test_async_device_connector_run_engine_same_event_loop(): +def test_async_auto_init_run_engine_same_event_loop(): async def set_up_device(): - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): mock_motor = motor.Motor("BLxxI-MO-TABLE-01:X") set_mock_value(mock_motor.velocity, 1) return mock_motor @@ -126,17 +136,17 @@ def my_plan(): "loop to set the value, unlike real signals." ) ) -def test_async_device_connector_run_engine_different_event_loop(): +def test_async_auto_init_run_engine_different_event_loop(): async def set_up_device(): - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): mock_motor = motor.Motor("BLxxI-MO-TABLE-01:X") return mock_motor - device_connector_loop = asyncio.new_event_loop() + auto_init_loop = asyncio.new_event_loop() run_engine_loop = asyncio.new_event_loop() - assert run_engine_loop is not device_connector_loop + assert run_engine_loop is not auto_init_loop - mock_motor = device_connector_loop.run_until_complete(set_up_device()) + mock_motor = auto_init_loop.run_until_complete(set_up_device()) RE = RunEngine(loop=run_engine_loop) @@ -147,7 +157,7 @@ def my_plan(): # The set should fail since the run engine is on a different event loop assert ( - device_connector_loop.run_until_complete(mock_motor.user_setpoint.read())[ + auto_init_loop.run_until_complete(mock_motor.user_setpoint.read())[ "mock_motor-user_setpoint" ]["value"] != 3.14 diff --git a/tests/core/test_device.py b/tests/core/test_device.py index 9850da8eee..2a408c953a 100644 --- a/tests/core/test_device.py +++ b/tests/core/test_device.py @@ -8,11 +8,11 @@ from ophyd_async.core import ( DEFAULT_TIMEOUT, Device, - DeviceCollector, DeviceVector, NotConnected, Reference, SignalRW, + auto_init_devices, soft_signal_rw, wait_for_connection, ) @@ -126,8 +126,8 @@ async def test_children_of_device_with_different_separator( assert parent.dict_with_children[123].name == "parent_dict_with_children_123" -async def test_device_with_device_collector(): - async with DeviceCollector(mock=True): +async def test_device_with_auto_init(): + async with auto_init_devices(mock=True): parent = DummyDeviceGroup("parent") assert parent.name == "parent" diff --git a/tests/core/test_mock_signal_backend.py b/tests/core/test_mock_signal_backend.py index 27dd70b190..4460c9c115 100644 --- a/tests/core/test_mock_signal_backend.py +++ b/tests/core/test_mock_signal_backend.py @@ -6,11 +6,11 @@ from ophyd_async.core import ( Device, - DeviceCollector, MockSignalBackend, SignalRW, SignalW, SoftSignalBackend, + auto_init_devices, soft_signal_r_and_setter, soft_signal_rw, ) @@ -170,7 +170,7 @@ def err_text(text, wait): @pytest.fixture async def mock_signals(): - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): signal1 = epics_signal_rw(str, "READ_PV1", "WRITE_PV1", name="mock_name1") signal2 = epics_signal_rw(str, "READ_PV2", "WRITE_PV2", name="mock_name2") diff --git a/tests/core/test_protocol.py b/tests/core/test_protocol.py index 637d287213..b3f0a7e97a 100644 --- a/tests/core/test_protocol.py +++ b/tests/core/test_protocol.py @@ -4,10 +4,10 @@ from ophyd_async.core import ( AsyncReadable, - DeviceCollector, StandardFlyer, StaticFilenameProvider, StaticPathProvider, + auto_init_devices, ) from ophyd_async.epics import adsimdetector from ophyd_async.sim.demo import SimMotor @@ -17,7 +17,7 @@ async def make_detector(prefix: str, name: str, tmp_path: Path): fp = StaticFilenameProvider(f"test-{new_uid()}") dp = StaticPathProvider(fp, tmp_path) - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): det = adsimdetector.SimDetector(prefix, dp, name=name) det._config_sigs = [det.drv.acquire_time, det.drv.acquire] @@ -26,7 +26,7 @@ async def make_detector(prefix: str, name: str, tmp_path: Path): async def test_readable(): - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): det = await make_detector("test", "test det", Path("/tmp")) assert isinstance(SimMotor, AsyncReadable) assert isinstance(det, AsyncReadable) diff --git a/tests/core/test_signal.py b/tests/core/test_signal.py index c88597ec12..dee8a5e1c0 100644 --- a/tests/core/test_signal.py +++ b/tests/core/test_signal.py @@ -12,12 +12,12 @@ from ophyd_async.core import ( Array1D, - DeviceCollector, SignalR, SignalRW, SoftSignalBackend, StandardReadable, StrictEnum, + auto_init_devices, set_and_wait_for_other_value, set_and_wait_for_value, soft_signal_r_and_setter, @@ -275,7 +275,7 @@ def __init__(self, prefix: str, name="") -> None: @pytest.fixture async def mock_readable(): - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): mock_readable = DummyReadableArray("SIM:READABLE:", name="mock_readable") yield mock_readable diff --git a/tests/core/test_utils.py b/tests/core/test_utils.py index 2dea901a27..f389f5a7cc 100644 --- a/tests/core/test_utils.py +++ b/tests/core/test_utils.py @@ -5,7 +5,7 @@ from ophyd_async.core import ( DEFAULT_TIMEOUT, Device, - DeviceCollector, + auto_init_devices, SoftSignalBackend, NotConnected, SignalRW, @@ -179,9 +179,9 @@ def __init__(self, name: str = "") -> None: super().__init__(name) -async def test_error_handling_device_collector_mock(): +async def test_error_handling_auto_init_mock(): with pytest.raises(NotConnected) as e: - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): device = BadDatatypeDevice() device2 = BadDatatypeDevice() expected_output = NotConnected( @@ -205,11 +205,11 @@ def test_introspecting_sub_errors(): assert error.sub_errors == {"child1": sub_error1, "child2": sub_error2} -async def test_error_handling_device_collector(caplog): +async def test_error_handling_auto_init(caplog): caplog.set_level(10) with pytest.raises(NotConnected) as e: # flake8: noqa - async with DeviceCollector(timeout=0.1): + async with auto_init_devices(timeout=0.1): dummy_device_two_working_one_timeout_two_value_error = ( DummyDeviceTwoWorkingTwoTimeOutTwoValueError() ) @@ -271,7 +271,7 @@ async def test_combining_top_level_signal_and_child_device(): ) with pytest.raises(NotConnected) as e: - async with DeviceCollector(timeout=0.1): + async with auto_init_devices(timeout=0.1): dummy_device2 = DummyDeviceCombiningTopLevelSignalAndSubDevice() assert str(e.value) == ( "\ndummy_device2: NotConnected:\n" diff --git a/tests/epics/adcore/test_drivers.py b/tests/epics/adcore/test_drivers.py index 09c72836cf..adacbd90d4 100644 --- a/tests/epics/adcore/test_drivers.py +++ b/tests/epics/adcore/test_drivers.py @@ -5,7 +5,7 @@ from ophyd_async.core import ( DetectorController, - DeviceCollector, + auto_init_devices, ) from ophyd_async.epics import adcore from ophyd_async.testing import get_mock_put, set_mock_value @@ -15,7 +15,7 @@ @pytest.fixture def driver(RE) -> adcore.ADBaseIO: - with DeviceCollector(mock=True): + with auto_init_devices(mock=True): driver = adcore.ADBaseIO("DRV:", name="drv") return driver diff --git a/tests/epics/adcore/test_scans.py b/tests/epics/adcore/test_scans.py index bc70de97d6..23c6e8158a 100644 --- a/tests/epics/adcore/test_scans.py +++ b/tests/epics/adcore/test_scans.py @@ -12,11 +12,11 @@ AsyncStatus, DetectorController, DetectorTrigger, - DeviceCollector, FlyerController, StandardDetector, StandardFlyer, TriggerInfo, + auto_init_devices, ) from ophyd_async.epics import adcore, adsimdetector from ophyd_async.testing import set_mock_value @@ -54,7 +54,7 @@ def get_deadtime(self, exposure: float | None) -> float: @pytest.fixture def controller(RE) -> adsimdetector.SimController: - with DeviceCollector(mock=True): + with auto_init_devices(mock=True): drv = adcore.ADBaseIO("DRV") return adsimdetector.SimController(drv) @@ -62,7 +62,7 @@ def controller(RE) -> adsimdetector.SimController: @pytest.fixture def writer(RE, static_path_provider, tmp_path: Path) -> adcore.ADHDFWriter: - with DeviceCollector(mock=True): + with auto_init_devices(mock=True): hdf = adcore.NDFileHDFIO("HDF") return adcore.ADHDFWriter( diff --git a/tests/epics/adcore/test_writers.py b/tests/epics/adcore/test_writers.py index d7feff7e8f..6e876a150e 100644 --- a/tests/epics/adcore/test_writers.py +++ b/tests/epics/adcore/test_writers.py @@ -5,10 +5,10 @@ from ophyd_async.core import ( DatasetDescriber, - DeviceCollector, PathProvider, StandardDetector, StaticPathProvider, + auto_init_devices, ) from ophyd_async.epics import adaravis, adcore, adkinetix, adpilatus, advimba from ophyd_async.epics.core import epics_signal_r @@ -28,7 +28,7 @@ async def shape(self) -> tuple[int, int]: async def hdf_writer( RE, static_path_provider: StaticPathProvider ) -> adcore.ADHDFWriter: - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): hdf = adcore.NDFileHDFIO("HDF:") return adcore.ADHDFWriter( @@ -43,7 +43,7 @@ async def hdf_writer( async def hdf_writer_with_stats( RE, static_path_provider: StaticPathProvider ) -> adcore.ADHDFWriter: - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): hdf = adcore.NDFileHDFIO("HDF:") stats = adcore.NDPluginStatsIO("FOO:") @@ -64,7 +64,7 @@ async def detectors( static_path_provider: PathProvider, ) -> list[StandardDetector]: detectors = [] - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): detectors.append(advimba.VimbaDetector("VIMBA:", static_path_provider)) detectors.append(adkinetix.KinetixDetector("KINETIX:", static_path_provider)) detectors.append(adpilatus.PilatusDetector("PILATUS:", static_path_provider)) diff --git a/tests/epics/conftest.py b/tests/epics/conftest.py index e563207109..c6c00a0226 100644 --- a/tests/epics/conftest.py +++ b/tests/epics/conftest.py @@ -5,8 +5,8 @@ from bluesky.run_engine import RunEngine from ophyd_async.core import ( - DeviceCollector, StandardDetector, + auto_init_devices, ) from ophyd_async.testing import callback_on_mock_put, set_mock_value @@ -24,7 +24,7 @@ def generate_ad_standard_det( if detector_name.endswith("Detector"): detector_name = detector_name[: -len("Detector")] - with DeviceCollector(mock=True): + with auto_init_devices(mock=True): test_adstandard_det = ad_standard_detector_class( f"{detector_name.upper()}{number}:", static_path_provider, diff --git a/tests/epics/demo/test_demo.py b/tests/epics/demo/test_demo.py index eaa6c24cdd..05e6b5a439 100644 --- a/tests/epics/demo/test_demo.py +++ b/tests/epics/demo/test_demo.py @@ -9,9 +9,9 @@ from bluesky.run_engine import RunEngine from ophyd_async.core import ( - DeviceCollector, LazyMock, NotConnected, + auto_init_devices, ) from ophyd_async.epics import demo from ophyd_async.testing import ( @@ -28,7 +28,7 @@ @pytest.fixture async def mock_mover() -> demo.Mover: - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): mock_mover = demo.Mover("BLxxI-MO-TABLE-01:X:") # Signals connected here @@ -41,7 +41,7 @@ async def mock_mover() -> demo.Mover: @pytest.fixture async def mock_sensor() -> demo.Sensor: - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): mock_sensor = demo.Sensor("MOCK:SENSOR:") # Signals connected here @@ -51,7 +51,7 @@ async def mock_sensor() -> demo.Sensor: @pytest.fixture async def mock_sensor_group() -> demo.SensorGroup: - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): mock_sensor_group = demo.SensorGroup("MOCK:SENSOR:") # Signals connected here @@ -252,7 +252,7 @@ async def test_set_velocity(mock_mover: demo.Mover) -> None: async def test_mover_disconnected(): with pytest.raises(NotConnected): - async with DeviceCollector(timeout=0.1): + async with auto_init_devices(timeout=0.1): m = demo.Mover("ca://PRE:", name="mover") assert m.name == "mover" @@ -260,7 +260,7 @@ async def test_mover_disconnected(): async def test_sensor_disconnected(caplog): caplog.set_level(10) with pytest.raises(NotConnected): - async with DeviceCollector(timeout=0.1): + async with auto_init_devices(timeout=0.1): s = demo.Sensor("ca://PRE:", name="sensor") logs = caplog.get_records("call") logs = [log for log in logs if "_signal" not in log.pathname] @@ -317,7 +317,7 @@ async def test_assembly_renaming() -> None: async def test_dynamic_sensor_group_disconnected(): with pytest.raises(NotConnected) as e: - async with DeviceCollector(timeout=0.1): + async with auto_init_devices(timeout=0.1): mock_sensor_group_dynamic = demo.SensorGroup("MOCK:SENSOR:") expected = """ mock_sensor_group_dynamic: NotConnected: diff --git a/tests/epics/eiger/test_eiger_controller.py b/tests/epics/eiger/test_eiger_controller.py index 764f49028b..7dc3d1f493 100644 --- a/tests/epics/eiger/test_eiger_controller.py +++ b/tests/epics/eiger/test_eiger_controller.py @@ -3,8 +3,8 @@ from pytest import fixture, raises from ophyd_async.core import ( - DeviceCollector, TriggerInfo, + auto_init_devices, ) from ophyd_async.epics.eiger import EigerController, EigerDriverIO from ophyd_async.testing import callback_on_mock_put, get_mock_put, set_mock_value @@ -14,7 +14,7 @@ @fixture def eiger_driver_and_controller_no_arm(RE) -> DriverAndController: - with DeviceCollector(mock=True): + with auto_init_devices(mock=True): driver = EigerDriverIO("") controller = EigerController(driver) diff --git a/tests/epics/eiger/test_eiger_detector.py b/tests/epics/eiger/test_eiger_detector.py index 300d56ff04..6bd78a93dc 100644 --- a/tests/epics/eiger/test_eiger_detector.py +++ b/tests/epics/eiger/test_eiger_detector.py @@ -2,14 +2,14 @@ import pytest -from ophyd_async.core import DetectorTrigger, DeviceCollector +from ophyd_async.core import DetectorTrigger, auto_init_devices from ophyd_async.epics.eiger import EigerDetector, EigerTriggerInfo from ophyd_async.testing import get_mock_put @pytest.fixture def detector(RE): - with DeviceCollector(mock=True): + with auto_init_devices(mock=True): detector = EigerDetector("BL03I", MagicMock()) return detector diff --git a/tests/epics/eiger/test_odin_io.py b/tests/epics/eiger/test_odin_io.py index 4c369a80a9..6fd1675668 100644 --- a/tests/epics/eiger/test_odin_io.py +++ b/tests/epics/eiger/test_odin_io.py @@ -3,7 +3,7 @@ import pytest -from ophyd_async.core import DeviceCollector +from ophyd_async.core import auto_init_devices from ophyd_async.epics.eiger._odin_io import Odin, OdinWriter, Writing # noqa: PLC2701 from ophyd_async.testing import get_mock_put, set_mock_value @@ -12,7 +12,7 @@ @pytest.fixture def odin_driver_and_writer(RE) -> OdinDriverAndWriter: - with DeviceCollector(mock=True): + with auto_init_devices(mock=True): driver = Odin("") writer = OdinWriter(MagicMock(), lambda: "odin", driver) return driver, writer diff --git a/tests/epics/pvi/test_pvi.py b/tests/epics/pvi/test_pvi.py index 6391f98121..65012c3586 100644 --- a/tests/epics/pvi/test_pvi.py +++ b/tests/epics/pvi/test_pvi.py @@ -6,11 +6,11 @@ from ophyd_async.core import ( Device, - DeviceCollector, DeviceVector, SignalRW, SignalX, StandardReadable, + auto_init_devices, ) from ophyd_async.core import StandardReadableFormat as Format from ophyd_async.epics.core import PviDeviceConnector @@ -62,7 +62,7 @@ def with_pvi_connector( async def test_fill_pvi_entries_mock_mode(): - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): test_device = with_pvi_connector(Block3, "PREFIX:") # device vectors are typed diff --git a/tests/epics/test_motor.py b/tests/epics/test_motor.py index aabb120ac6..131723053b 100644 --- a/tests/epics/test_motor.py +++ b/tests/epics/test_motor.py @@ -8,7 +8,7 @@ from ophyd_async.core import ( CALCULATE_TIMEOUT, AsyncStatus, - DeviceCollector, + auto_init_devices, observe_value, soft_signal_rw, ) @@ -25,7 +25,7 @@ @pytest.fixture async def sim_motor(): - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): sim_motor = motor.Motor("BLxxI-MO-TABLE-01:X", name="sim_motor") set_mock_value(sim_motor.motor_egu, "mm") diff --git a/tests/fastcs/panda/test_panda_connect.py b/tests/fastcs/panda/test_panda_connect.py index e395ef1ca4..3ecfbd3444 100644 --- a/tests/fastcs/panda/test_panda_connect.py +++ b/tests/fastcs/panda/test_panda_connect.py @@ -9,9 +9,9 @@ from ophyd_async.core import ( Device, - DeviceCollector, DeviceVector, NotConnected, + auto_init_devices, ) from ophyd_async.fastcs.core import fastcs_connector from ophyd_async.fastcs.panda import ( @@ -65,7 +65,7 @@ def __init__(self, uri: str, name: str = ""): @pytest.fixture async def mock_panda(panda_t): - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): mock_panda = panda_t("PANDAQSRV:") assert mock_panda.name == "mock_panda" diff --git a/tests/fastcs/panda/test_panda_control.py b/tests/fastcs/panda/test_panda_control.py index 867d97330a..d0ac5262bf 100644 --- a/tests/fastcs/panda/test_panda_control.py +++ b/tests/fastcs/panda/test_panda_control.py @@ -4,7 +4,7 @@ import pytest -from ophyd_async.core import DetectorTrigger, Device, DeviceCollector, TriggerInfo +from ophyd_async.core import DetectorTrigger, Device, TriggerInfo, auto_init_devices from ophyd_async.epics.core import epics_signal_rw from ophyd_async.fastcs.core import fastcs_connector from ophyd_async.fastcs.panda import CommonPandaBlocks, PandaPcapController @@ -16,7 +16,7 @@ class Panda(CommonPandaBlocks): def __init__(self, uri: str, name: str = ""): super().__init__(name=name, connector=fastcs_connector(self, uri)) - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): mock_panda = Panda("PANDACONTROLLER:", name="mock_panda") mock_panda.phase_1_signal_units = epics_signal_rw(int, "") yield mock_panda diff --git a/tests/fastcs/panda/test_panda_utils.py b/tests/fastcs/panda/test_panda_utils.py index fc662fde5c..ab0372975e 100644 --- a/tests/fastcs/panda/test_panda_utils.py +++ b/tests/fastcs/panda/test_panda_utils.py @@ -2,7 +2,7 @@ import yaml from bluesky import RunEngine -from ophyd_async.core import DeviceCollector, load_device, save_device +from ophyd_async.core import auto_init_devices, load_device, save_device from ophyd_async.epics.core import epics_signal_rw from ophyd_async.fastcs.core import fastcs_connector from ophyd_async.fastcs.panda import ( @@ -21,7 +21,7 @@ class Panda(CommonPandaBlocks): def __init__(self, uri: str, name: str = ""): super().__init__(name=name, connector=fastcs_connector(self, uri)) - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): mock_panda = Panda("PANDA") mock_panda.phase_1_signal_units = epics_signal_rw(int, "") return mock_panda diff --git a/tests/fastcs/panda/test_trigger.py b/tests/fastcs/panda/test_trigger.py index fbe68a4229..87d29c36df 100644 --- a/tests/fastcs/panda/test_trigger.py +++ b/tests/fastcs/panda/test_trigger.py @@ -4,7 +4,7 @@ import pytest from pydantic import ValidationError -from ophyd_async.core import DeviceCollector +from ophyd_async.core import auto_init_devices from ophyd_async.fastcs.core import fastcs_connector from ophyd_async.fastcs.panda import ( CommonPandaBlocks, @@ -25,7 +25,7 @@ class Panda(CommonPandaBlocks): def __init__(self, uri: str, name: str = ""): super().__init__(name=name, connector=fastcs_connector(self, uri)) - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): mock_panda = Panda("PANDAQSRV:", "mock_panda") assert mock_panda.name == "mock_panda" diff --git a/tests/fastcs/panda/test_writer.py b/tests/fastcs/panda/test_writer.py index 3449408ae8..efd8bfb55f 100644 --- a/tests/fastcs/panda/test_writer.py +++ b/tests/fastcs/panda/test_writer.py @@ -8,11 +8,11 @@ from ophyd_async.core import ( Device, - DeviceCollector, HDFFile, SignalR, StaticFilenameProvider, StaticPathProvider, + auto_init_devices, ) from ophyd_async.fastcs.core import fastcs_connector from ophyd_async.fastcs.panda import ( @@ -66,7 +66,7 @@ def __init__(self, uri: str, name: str = ""): @pytest.fixture async def mock_panda(panda_t): - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): mock_panda = panda_t("mock_PANDA", name="mock_panda") # Mimic directory exists check that happens normally in the PandA IOC @@ -92,7 +92,7 @@ def check_dir_exits(value, **kwargs): async def mock_writer(tmp_path, mock_panda) -> PandaHDFWriter: fp = StaticFilenameProvider("data") dp = StaticPathProvider(fp, tmp_path / mock_panda.name, create_dir_depth=-1) - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): writer = PandaHDFWriter( path_provider=dp, name_provider=lambda: mock_panda.name, @@ -215,7 +215,7 @@ async def test_oserror_when_hdf_dir_does_not_exist(tmp_path, mock_panda): dp = StaticPathProvider( fp, tmp_path / mock_panda.name / "extra" / "dirs", create_dir_depth=-1 ) - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): writer = PandaHDFWriter( path_provider=dp, name_provider=lambda: "test-panda", diff --git a/tests/plan_stubs/test_fly.py b/tests/plan_stubs/test_fly.py index 6f74815316..57e0df3464 100644 --- a/tests/plan_stubs/test_fly.py +++ b/tests/plan_stubs/test_fly.py @@ -14,13 +14,13 @@ AsyncStatus, DetectorController, DetectorWriter, - DeviceCollector, FlyerController, SignalR, StandardDetector, StandardFlyer, WatchableAsyncStatus, WatcherUpdate, + auto_init_devices, observe_value, ) from ophyd_async.epics.core import epics_signal_rw @@ -173,7 +173,7 @@ class Panda(CommonPandaBlocks): def __init__(self, uri: str, name: str = ""): super().__init__(name=name, connector=fastcs_connector(self, uri)) - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): mock_panda = Panda("PANDAQSRV:", "mock_panda") assert mock_panda.name == "mock_panda" diff --git a/tests/sim/demo/test_sim_motor.py b/tests/sim/demo/test_sim_motor.py index e88dbee04c..67d1963b23 100644 --- a/tests/sim/demo/test_sim_motor.py +++ b/tests/sim/demo/test_sim_motor.py @@ -5,14 +5,14 @@ from bluesky.plans import spiral_square from bluesky.run_engine import RunEngine -from ophyd_async.core import DeviceCollector +from ophyd_async.core import auto_init_devices from ophyd_async.sim.demo import SimMotor async def test_move_sim_in_plan(): RE = RunEngine() - async with DeviceCollector(): + async with auto_init_devices(): m1 = SimMotor("M1") m2 = SimMotor("M2") @@ -25,7 +25,7 @@ async def test_move_sim_in_plan(): async def test_slow_move(): - async with DeviceCollector(): + async with auto_init_devices(): m1 = SimMotor("M1", instant=False) await m1.velocity.set(20) @@ -77,7 +77,7 @@ async def test_negative_move(): async def test_stop(): - async with DeviceCollector(): + async with auto_init_devices(): m1 = SimMotor("M1", instant=False) # this move should take 10 seconds but we will stop it after 0.5 diff --git a/tests/sim/test_sim_writer.py b/tests/sim/test_sim_writer.py index 5ee2bba97a..72f7394148 100644 --- a/tests/sim/test_sim_writer.py +++ b/tests/sim/test_sim_writer.py @@ -2,13 +2,13 @@ import pytest -from ophyd_async.core import DeviceCollector +from ophyd_async.core import auto_init_devices from ophyd_async.sim.demo import PatternDetectorWriter, PatternGenerator @pytest.fixture async def writer(static_path_provider) -> PatternDetectorWriter: - async with DeviceCollector(mock=True): + async with auto_init_devices(mock=True): driver = PatternGenerator() return PatternDetectorWriter(driver, static_path_provider, lambda: "NAME") diff --git a/tests/tango/test_base_device.py b/tests/tango/test_base_device.py index 60c6db9762..ec604d5d0c 100644 --- a/tests/tango/test_base_device.py +++ b/tests/tango/test_base_device.py @@ -10,7 +10,7 @@ from bluesky import RunEngine import tango -from ophyd_async.core import Array1D, DeviceCollector, SignalRW, T +from ophyd_async.core import Array1D, SignalRW, T, auto_init_devices from ophyd_async.core import StandardReadableFormat as Format from ophyd_async.tango.core import TangoReadable, get_python_type from ophyd_async.tango.demo import ( @@ -302,7 +302,7 @@ def compare_values(expected, received): async def test_connect(tango_test_device): values, description = await describe_class(tango_test_device) - async with DeviceCollector(): + async with auto_init_devices(): test_device = TestTangoReadable(tango_test_device) assert test_device.name == "test_device" @@ -349,7 +349,7 @@ async def test_connect_proxy(tango_test_device, proxy: bool | None): async def test_with_bluesky(tango_test_device): # now let's do some bluesky stuff RE = RunEngine() - with DeviceCollector(): + with auto_init_devices(): device = TestTangoReadable(tango_test_device) RE(bp.count([device]))