diff --git a/docs/how-to/create-beamline.md b/docs/how-to/create-beamline.md index 919d856457b..228d811fb81 100644 --- a/docs/how-to/create-beamline.md +++ b/docs/how-to/create-beamline.md @@ -23,28 +23,31 @@ The following example creates a fictitious beamline ``w41``, with a simulated tw ```python + from functools import cache + from pathlib import Path + from ophyd_async.core import PathProvider from ophyd_async.epics.adaravis import AravisDetector - from dodal.common.beamlines.beamline_utils import ( - device_factory, - get_path_provider, - set_path_provider, - ) from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline from dodal.common.beamlines.device_helpers import CAM_SUFFIX, HDF5_SUFFIX - from dodal.common.visit import LocalDirectoryServiceClient, StaticVisitPathProvider + from dodal.common.visit import RemoteDirectoryServiceClient, StaticVisitPathProvider + from dodal.device_manager import DeviceManager from dodal.devices.synchrotron import Synchrotron from dodal.log import set_beamline as set_log_beamline - from dodal.utils import BeamlinePrefix + from dodal.utils import BeamlinePrefix, get_beamline_name BL = get_beamline_name("s41") # Default used when not on a live beamline PREFIX = BeamlinePrefix(BL) set_log_beamline(BL) # Configure logging and util functions set_utils_beamline(BL) - # Currently we must hard-code the visit, determining the visit is WIP. - set_path_provider( - StaticVisitPathProvider( + devices = DeviceManager() + + @devices.fixture + @cache + def path_provider() -> PathProvider: + # Currently we must hard-code the visit, determining the visit is WIP. + return StaticVisitPathProvider( BL, # Root directory for all detectors Path("/dls/w41/data/YYYY/cm12345-1"), @@ -52,7 +55,7 @@ The following example creates a fictitious beamline ``w41``, with a simulated tw client=RemoteDirectoryServiceClient("http://s41-control:8088/api"), # Else if no GDA server use a LocalDirectoryServiceClient(), ) - ) + """ Define device factory functions below this point. @@ -63,23 +66,22 @@ The following example creates a fictitious beamline ``w41``, with a simulated tw """ This decorator gives extra desirable behaviour to this factory function: - it may be instantiated automatically, selectively on live beamline - - caching and re-using the result for subsequent calls - it automatically names the device if no name is explicitly set - it may be skipped when make_all_devices is called on this module - it must be explicitly connected (which may be automated by tools) - when connected it may connect to a simulated backend - it may be connected concurrently (when automated by tools) - """" - @device_factory(skip = BL == "s41") + """ + @devices.factory(skip = BL == "s41") def synchrotron() -> Synchrotron: return Synchrotron() - @device_factory() - def d11() -> AravisDetector: + @devices.factory() + def d11(path_provider: PathProvider) -> AravisDetector: return AravisDetector( f"{PREFIX.beamline_prefix}-DI-DCAM-01:", - path_provider=get_path_provider(), + path_provider=path_provider, drv_suffix=CAM_SUFFIX, fileio_suffix=HDF5_SUFFIX, ) diff --git a/src/dodal/beamlines/i03.py b/src/dodal/beamlines/i03.py index 30133e4b162..14e35d185e7 100644 --- a/src/dodal/beamlines/i03.py +++ b/src/dodal/beamlines/i03.py @@ -1,17 +1,14 @@ -from ophyd_async.core import Reference +from functools import cache + +from ophyd_async.core import PathProvider, Reference from ophyd_async.fastcs.eiger import EigerDetector as FastEiger from ophyd_async.fastcs.panda import HDFPanda from yarl import URL from dodal.common.beamlines.beamline_parameters import get_beamline_parameters -from dodal.common.beamlines.beamline_utils import ( - device_factory, - device_instantiation, - get_path_provider, - set_path_provider, -) from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline from dodal.common.udc_directory_provider import PandASubpathProvider +from dodal.device_manager import DeviceManager from dodal.devices.aperturescatterguard import ( AperturePosition, ApertureScatterguard, @@ -71,8 +68,6 @@ set_log_beamline(BL) set_utils_beamline(BL) -set_path_provider(PandASubpathProvider()) - I03_ZEBRA_MAPPING = ZebraMapping( outputs=ZebraTTLOutputs(TTL_DETECTOR=1, TTL_SHUTTER=2, TTL_XSPRESS3=3, TTL_PANDA=4), sources=ZebraSources(), @@ -80,13 +75,22 @@ PREFIX = BeamlinePrefix(BL) +devices = DeviceManager() + + +@devices.fixture +@cache +def path_provider() -> PathProvider: + return PandASubpathProvider() + + +@devices.fixture +def daq_configuration_path() -> str: + return DAQ_CONFIGURATION_PATH -@device_factory() + +@devices.factory() def aperture_scatterguard() -> ApertureScatterguard: - """Get the i03 aperture and scatterguard device, instantiate it if it hasn't already - been. If this is called when already instantiated in i03, it will return the existing - object. - """ params = get_beamline_parameters() return ApertureScatterguard( aperture_prefix=f"{PREFIX.beamline_prefix}-MO-MAPT-01:", @@ -96,37 +100,28 @@ def aperture_scatterguard() -> ApertureScatterguard: ) -@device_factory() +@devices.factory() def attenuator() -> BinaryFilterAttenuator: - """Get the i03 attenuator device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return BinaryFilterAttenuator( prefix=f"{PREFIX.beamline_prefix}-EA-ATTN-01:", num_filters=16, ) -@device_factory() +@devices.factory() def beamstop() -> Beamstop: - """Get the i03 beamstop device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return Beamstop( prefix=f"{PREFIX.beamline_prefix}-MO-BS-01:", beamline_parameters=get_beamline_parameters(), ) -@device_factory() +@devices.factory() def dcm() -> DCM: - """Get the i03 DCM device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return DCM(prefix=f"{PREFIX.beamline_prefix}-MO-DCM-01:") -@device_factory() +@devices.factory() def vfm() -> FocusingMirrorWithStripes: return FocusingMirrorWithStripes( prefix=f"{PREFIX.beamline_prefix}-OP-VFM-01:", @@ -137,7 +132,7 @@ def vfm() -> FocusingMirrorWithStripes: ) -@device_factory() +@devices.factory() def mirror_voltages() -> MirrorVoltages: return MirrorVoltages( prefix=f"{PREFIX.beamline_prefix}-MO-PSU-01:", @@ -145,334 +140,214 @@ def mirror_voltages() -> MirrorVoltages: ) -@device_factory() +@devices.factory() def backlight() -> Backlight: - """Get the i03 backlight device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return Backlight(prefix=PREFIX.beamline_prefix) -@device_factory() +@devices.factory() def detector_motion() -> DetectorMotion: - """Get the i03 detector motion device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return DetectorMotion( device_prefix=f"{PREFIX.beamline_prefix}-MO-DET-01:", pmac_prefix=f"{PREFIX.beamline_prefix}-MO-PMAC-02:", ) -@device_factory() -def eiger(mock: bool = False) -> EigerDetector: - """Get the i03 Eiger device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ - - return device_instantiation( - device_factory=EigerDetector, - name="eiger", - prefix="-EA-EIGER-01:", - wait=False, - fake=mock, - ) - +@devices.v1_init(EigerDetector, prefix="BL03I-EA-EIGER-01:", wait=False) +def eiger(eiger: EigerDetector) -> EigerDetector: + return eiger -@device_factory() -def fastcs_eiger() -> FastEiger: - """Get the i03 FastCS Eiger device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ +@devices.factory() +def fastcs_eiger(path_provider: PathProvider) -> FastEiger: return FastEiger( prefix=PREFIX.beamline_prefix, - path_provider=get_path_provider(), + path_provider=path_provider, drv_suffix="-EA-EIGER-02:", hdf_suffix="-EA-EIGER-01:OD:", ) -@device_factory() +@devices.factory() def zebra_fast_grid_scan() -> ZebraFastGridScanThreeD: - """Get the i03 zebra_fast_grid_scan device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return ZebraFastGridScanThreeD( prefix=f"{PREFIX.beamline_prefix}-MO-SGON-01:", ) -@device_factory() +@devices.factory() def panda_fast_grid_scan() -> PandAFastGridScan: - """Get the i03 panda_fast_grid_scan device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - This is used instead of the zebra_fast_grid_scan device when using the PandA. - """ + """This is used instead of the zebra_fast_grid_scan device when using the PandA.""" return PandAFastGridScan(prefix=f"{PREFIX.beamline_prefix}-MO-SGON-01:") -@device_factory() +@devices.factory() def oav( params: OAVConfigBeamCentre | None = None, ) -> OAVBeamCentreFile: - """Get the i03 OAV device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return OAVBeamCentreFile( prefix=f"{PREFIX.beamline_prefix}-DI-OAV-01:", config=params or OAVConfigBeamCentre(ZOOM_PARAMS_FILE, DISPLAY_CONFIG), ) -@device_factory() +@devices.factory() def pin_tip_detection() -> PinTipDetection: - """Get the i03 pin tip detection device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return PinTipDetection(f"{PREFIX.beamline_prefix}-DI-OAV-01:") -@device_factory() +@devices.factory() def smargon() -> Smargon: - """Get the i03 Smargon device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return Smargon(f"{PREFIX.beamline_prefix}-MO-SGON-01:") -@device_factory() +@devices.factory() def s4_slit_gaps() -> S4SlitGaps: - """Get the i03 s4_slit_gaps device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return S4SlitGaps(f"{PREFIX.beamline_prefix}-AL-SLITS-04:") -@device_factory() +@devices.factory() def synchrotron() -> Synchrotron: - """Get the i03 synchrotron device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return Synchrotron() -@device_factory() -def undulator(daq_configuration_path: str | None = None) -> UndulatorInKeV: - """Get the i03 undulator device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ +@devices.factory() +def undulator(baton: Baton, daq_configuration_path: str) -> UndulatorInKeV: return UndulatorInKeV( f"{BeamlinePrefix(BL).insertion_prefix}-MO-SERVC-01:", - # evaluate here not as parameter default to enable post-import mocking - id_gap_lookup_table_path=f"{daq_configuration_path or DAQ_CONFIGURATION_PATH}/lookup/BeamLine_Undulator_toGap.txt", - baton=baton(), + id_gap_lookup_table_path=f"{daq_configuration_path}/lookup/BeamLine_Undulator_toGap.txt", + baton=baton, ) -@device_factory() -def undulator_dcm(daq_configuration_path: str | None = None) -> UndulatorDCM: - """Get the i03 undulator DCM device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ - # evaluate here not as parameter default to enable post-import mocking - undulator_singleton = ( - undulator(daq_configuration_path=daq_configuration_path) - if daq_configuration_path and daq_configuration_path != DAQ_CONFIGURATION_PATH - else undulator() - ) +@devices.factory() +def undulator_dcm( + undulator: UndulatorInKeV, dcm: DCM, daq_configuration_path: str +) -> UndulatorDCM: return UndulatorDCM( - undulator=undulator_singleton, - dcm=dcm(), - daq_configuration_path=daq_configuration_path or DAQ_CONFIGURATION_PATH, + undulator=undulator, + dcm=dcm, + daq_configuration_path=daq_configuration_path, ) -@device_factory() +@devices.factory() def zebra() -> Zebra: - """Get the i03 zebra device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return Zebra( prefix=f"{PREFIX.beamline_prefix}-EA-ZEBRA-01:", mapping=I03_ZEBRA_MAPPING, ) -@device_factory() +@devices.factory() def xspress3mini() -> Xspress3: - """Get the i03 Xspress3Mini device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return Xspress3(f"{PREFIX.beamline_prefix}-EA-XSP3-01:") -@device_factory() -def panda() -> HDFPanda: - """Get the i03 panda device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ +@devices.factory() +def panda(path_provider: PathProvider) -> HDFPanda: return HDFPanda( f"{PREFIX.beamline_prefix}-EA-PANDA-01:", - path_provider=get_path_provider(), + path_provider=path_provider, ) -@device_factory() +@devices.factory() def sample_shutter() -> ZebraShutter: - """Get the i03 sample shutter device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return ZebraShutter(f"{PREFIX.beamline_prefix}-EA-SHTR-01:") -@device_factory() +@devices.factory() def hutch_shutter() -> HutchShutter: - """Get the i03 hutch shutter device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return HutchShutter(f"{PREFIX.beamline_prefix}-PS-SHTR-01:") -@device_factory() +@devices.factory() def flux() -> Flux: - """Get the i03 flux device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return Flux(f"{PREFIX.beamline_prefix}-MO-FLUX-01:") -@device_factory() -def xbpm_feedback() -> XBPMFeedback: - """Get the i03 XBPM feeback device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ - return XBPMFeedback(f"{PREFIX.beamline_prefix}-EA-FDBK-01:", baton=baton()) +@devices.factory() +def xbpm_feedback(baton: Baton) -> XBPMFeedback: + return XBPMFeedback(f"{PREFIX.beamline_prefix}-EA-FDBK-01:", baton=baton) -@device_factory() +@devices.factory() def zocalo() -> ZocaloResults: - """Get the i03 ZocaloResults device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return ZocaloResults(results_source=ZocaloSource.GPU) -@device_factory() +@devices.factory() def robot() -> BartRobot: - """Get the i03 robot device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return BartRobot(f"{PREFIX.beamline_prefix}-MO-ROBOT-01:") -@device_factory() +@devices.factory() def webcam() -> Webcam: - """Get the i03 webcam, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return Webcam(url=URL("http://i03-webcam1/axis-cgi/jpg/image.cgi")) -@device_factory() +@devices.factory() def thawer() -> Thawer: - """Get the i03 thawer, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return Thawer(f"{PREFIX.beamline_prefix}-EA-THAW-01") -@device_factory() +@devices.factory() def lower_gonio() -> XYZStage: - """Get the i03 lower gonio device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return XYZStage(f"{PREFIX.beamline_prefix}-MO-GONP-01:") -@device_factory() +@devices.factory() def cryostream() -> CryoStream: - """Get the i03 cryostream device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return CryoStream(PREFIX.beamline_prefix) -@device_factory() +@devices.factory() def cryostream_gantry() -> CryoStreamGantry: - """Get the i03 cryostream gantry device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return CryoStreamGantry(PREFIX.beamline_prefix) -@device_factory() +@devices.factory() def diamond_filter() -> DiamondFilter[I03Filters]: - """Get the i03 diamond filter device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return DiamondFilter[I03Filters]( f"{PREFIX.beamline_prefix}-MO-FLTR-01:Y", I03Filters ) -@device_factory() +@devices.factory() def qbpm() -> QBPM: - """Get the i03 qbpm device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return QBPM(f"{PREFIX.beamline_prefix}-DI-QBPM-01:") -@device_factory() +@devices.factory() def baton() -> Baton: - """Get the i03 baton device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return Baton(f"{PREFIX.beamline_prefix}-CS-BATON-01:") -@device_factory() +@devices.factory() def fluorescence_det_motion() -> FluorescenceDetector: - """Get the i03 device for moving the fluorescence detector, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return FluorescenceDetector(f"{PREFIX.beamline_prefix}-EA-FLU-01:") -@device_factory() -def scintillator() -> Scintillator: - """Get the i03 scintillator device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ +@devices.factory() +def scintillator(aperture_scatterguard: ApertureScatterguard) -> Scintillator: return Scintillator( f"{PREFIX.beamline_prefix}-MO-SCIN-01:", - Reference(aperture_scatterguard()), + Reference(aperture_scatterguard), get_beamline_parameters(), ) -@device_factory() +@devices.factory() def collimation_table() -> CollimationTable: - """Get the i03 device for moving the collimation table, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ return CollimationTable(prefix=f"{PREFIX.beamline_prefix}-MO-TABLE-01") -@device_factory() -def beamsize() -> Beamsize: - """Get the i03 beamsize device, instantiate it if it hasn't already been. - If this is called when already instantiated in i03, it will return the existing object. - """ - return Beamsize( - aperture_scatterguard=aperture_scatterguard(), - ) +@devices.factory() +def beamsize(aperture_scatterguard: ApertureScatterguard) -> Beamsize: + return Beamsize(aperture_scatterguard) -@device_factory() +@devices.factory() def ipin() -> IPin: - """Get the i03 ipin device, instantiate it if it hasn't already been. - If this is called when already instantiated in i04, it will return the existing object. - """ return IPin(f"{PREFIX.beamline_prefix}-EA-PIN-01:") diff --git a/src/dodal/plans/configure_arm_trigger_and_disarm_detector.py b/src/dodal/plans/configure_arm_trigger_and_disarm_detector.py index 91dc4d89cfe..808a42c9c70 100644 --- a/src/dodal/plans/configure_arm_trigger_and_disarm_detector.py +++ b/src/dodal/plans/configure_arm_trigger_and_disarm_detector.py @@ -12,7 +12,7 @@ ) from ophyd_async.fastcs.eiger import EigerDetector -from dodal.beamlines.i03 import fastcs_eiger, set_path_provider +from dodal.beamlines.i03 import fastcs_eiger from dodal.devices.detector import DetectorParams from dodal.log import LOGGER, do_default_logging_setup @@ -163,9 +163,7 @@ def set_mx_settings_pvs( PurePath("/dls/i03/data/2025/cm40607-2/test_new_eiger/"), ) - set_path_provider(path_provider) - - eiger = fastcs_eiger(connect_immediately=True) + eiger = fastcs_eiger.build(connect_immediately=True, path_provider=path_provider) run_engine( configure_arm_trigger_and_disarm_detector( eiger=eiger, diff --git a/src/dodal/utils.py b/src/dodal/utils.py index 9be4675e23e..8b6ebe649b8 100644 --- a/src/dodal/utils.py +++ b/src/dodal/utils.py @@ -11,7 +11,7 @@ from importlib import import_module from inspect import signature from os import environ -from types import ModuleType +from types import FunctionType, ModuleType from typing import ( Any, Generic, @@ -240,7 +240,8 @@ def make_device( def make_all_devices( module: str | ModuleType | None = None, include_skipped: bool = False, **kwargs ) -> tuple[dict[str, AnyDevice], dict[str, Exception]]: - """Makes all devices in the given beamline module. + """Makes all devices in the given beamline module, for those modules using device factories + as opposed to the DeviceManager. In cases of device interdependencies it ensures a device is created before any which depend on it. @@ -413,7 +414,9 @@ def is_v2_device_factory(func: Callable) -> TypeGuard[V2DeviceFactory]: def is_any_device_factory(func: Callable) -> TypeGuard[AnyDeviceFactory]: - return is_v1_device_factory(func) or is_v2_device_factory(func) + return isinstance(func, FunctionType | DeviceInitializationController) and ( + is_v1_device_factory(func) or is_v2_device_factory(func) + ) def is_v2_device_type(obj: type[Any]) -> bool: diff --git a/tests/common/beamlines/test_device_instantiation.py b/tests/common/beamlines/test_device_instantiation.py index 4f9bc96b1c9..7ce915f5ce4 100644 --- a/tests/common/beamlines/test_device_instantiation.py +++ b/tests/common/beamlines/test_device_instantiation.py @@ -4,6 +4,7 @@ from ophyd_async.core import NotConnectedError from dodal.beamlines import all_beamline_modules +from dodal.device_manager import DeviceManager from dodal.utils import BLUESKY_PROTOCOLS, make_all_devices @@ -44,6 +45,10 @@ def test_devices_are_identical(module_and_devices_for_beamline): Ensures that for every beamline all device functions prevent duplicate instantiation. """ bl_mod, devices_a, _ = module_and_devices_for_beamline + if isinstance(getattr(bl_mod, "devices", None), DeviceManager): + # DeviceManager beamline modules do not cache device instances + return + devices_b, _ = make_all_devices( bl_mod, include_skipped=True, @@ -55,7 +60,7 @@ def test_devices_are_identical(module_and_devices_for_beamline): if device is not devices_b[device_name] ] total_number_of_devices = len(devices_a) - non_identical_number_of_devies = len(devices_a) + non_identical_number_of_devices = len(devices_a) assert len(non_identical_names) == 0, ( - f"{non_identical_number_of_devies}/{total_number_of_devices} devices were not identical: {non_identical_names}" + f"{non_identical_number_of_devices}/{total_number_of_devices} devices were not identical: {non_identical_names}" ) diff --git a/tests/conftest.py b/tests/conftest.py index fe4b41820ef..b326effebac 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -11,6 +11,7 @@ from conftest import mock_attributes_table from dodal.common.beamlines import beamline_parameters, beamline_utils from dodal.common.beamlines.commissioning_mode import set_commissioning_signal +from dodal.device_manager import DeviceManager from dodal.devices.baton import Baton from dodal.devices.detector import DetectorParams from dodal.devices.detector.det_dim_constants import EIGER2_X_16M_SIZE @@ -32,11 +33,20 @@ def module_and_devices_for_beamline(request: pytest.FixtureRequest): with patch.dict(os.environ, {"BEAMLINE": beamline}, clear=True): bl_mod = importlib.import_module("dodal.beamlines." + beamline) mock_beamline_module_filepaths(beamline, bl_mod) - devices, exceptions = make_all_devices( - bl_mod, - include_skipped=True, - fake_with_ophyd_sim=True, - ) + if isinstance( + device_manager := getattr(bl_mod, "devices", None), DeviceManager + ): + result = device_manager.build_all(include_skipped=True, mock=True).connect() + devices, exceptions = ( + result.devices, + result.connection_errors | result.build_errors, + ) + else: + devices, exceptions = make_all_devices( + bl_mod, + include_skipped=True, + fake_with_ophyd_sim=True, + ) yield (bl_mod, devices, exceptions) beamline_utils.clear_devices() for factory in collect_factories(bl_mod).values(): diff --git a/tests/test_utils.py b/tests/test_utils.py index bedefc5cdca..89aeb9d561b 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -8,7 +8,7 @@ from bluesky.protocols import Readable from ophyd_async.epics.motor import Motor -from dodal.beamlines import i03, i23 +from dodal.beamlines import i04, i23 from dodal.devices.diamond_filter import DiamondFilter, I03Filters from dodal.utils import ( AnyDevice, @@ -313,7 +313,7 @@ def test_invalid_beamline_variable_causes_get_device_module_to_raise(bl): get_beamline_based_on_environment_variable() -@pytest.mark.parametrize("bl,module", [("i03", i03), ("i23", i23)]) +@pytest.mark.parametrize("bl,module", [("i04", i04), ("i23", i23)]) def test_valid_beamline_variable_causes_get_device_module_to_return_module(bl, module): with patch.dict(os.environ, {"BEAMLINE": bl}): assert get_beamline_based_on_environment_variable() == module @@ -488,40 +488,24 @@ def test_is_v2_device_type(input: Any, expected_result: bool): def test_calling_factory_with_different_args_raises_an_exception(): - i03.undulator(daq_configuration_path=MOCK_DAQ_CONFIG_PATH) + i04.oav(params=MagicMock()) with pytest.raises( RuntimeError, match="Device factory method called multiple times with different parameters", ): - i03.undulator(daq_configuration_path=MOCK_DAQ_CONFIG_PATH + "x") - i03.undulator.cache_clear() + i04.oav(params=MagicMock()) + i04.oav.cache_clear() -def test_calling_factory_with_different_args_does_not_raise_an_exception_after_cache_clear( - alternate_config, -): - i03.undulator(daq_configuration_path=MOCK_DAQ_CONFIG_PATH) - i03.undulator.cache_clear() - i03.undulator(daq_configuration_path=alternate_config) - i03.undulator.cache_clear() - - -def test_factories_can_be_called_in_any_order(alternate_config): - i03.undulator_dcm(daq_configuration_path=alternate_config) - i03.undulator(daq_configuration_path=alternate_config) - - i03.undulator_dcm.cache_clear() - i03.undulator.cache_clear() - - i03.undulator(daq_configuration_path=alternate_config) - i03.undulator_dcm(daq_configuration_path=alternate_config) - - i03.undulator.cache_clear() - i03.undulator_dcm.cache_clear() +def test_calling_factory_with_different_args_does_not_raise_an_exception_after_cache_clear(): + i04.oav(params=MagicMock()) + i04.oav.cache_clear() + i04.oav(params=MagicMock()) + i04.oav.cache_clear() -def test_factory_calls_are_cached(alternate_config): - undulator1 = i03.undulator(daq_configuration_path=alternate_config) - undulator2 = i03.undulator(daq_configuration_path=alternate_config) +def test_factory_calls_are_cached(): + undulator1 = i04.undulator() + undulator2 = i04.undulator() assert undulator1 is undulator2 - i03.undulator.cache_clear() + i04.undulator.cache_clear()