From 0f611b71a1f9bb8ec608aad05a1b2e26669e1656 Mon Sep 17 00:00:00 2001 From: David Perl Date: Tue, 13 Feb 2024 16:06:47 +0000 Subject: [PATCH 1/6] #331 fix device tests --- src/dodal/beamlines/beamline_parameters.py | 19 +++--- src/dodal/beamlines/i24.py | 8 ++- src/dodal/devices/DCM.py | 4 +- .../unit_tests/test_device_instantiation.py | 66 ++++++++++++++----- tests/beamlines/unit_tests/test_i24.py | 3 +- 5 files changed, 70 insertions(+), 30 deletions(-) diff --git a/src/dodal/beamlines/beamline_parameters.py b/src/dodal/beamlines/beamline_parameters.py index d680b81459e..ae3a64e6aa8 100644 --- a/src/dodal/beamlines/beamline_parameters.py +++ b/src/dodal/beamlines/beamline_parameters.py @@ -1,4 +1,4 @@ -from typing import Any, Tuple, cast +from typing import Any, Optional, Tuple, cast from dodal.log import LOGGER from dodal.utils import get_beamline_name @@ -87,11 +87,14 @@ def parse_list(cls, value: str): return list_output -def get_beamline_parameters(): - beamline_name = get_beamline_name("s03") - beamline_param_path = BEAMLINE_PARAMETER_PATHS.get(beamline_name) - if beamline_param_path is None: - raise KeyError( - "No beamline parameter path found, maybe 'BEAMLINE' environment variable is not set!" - ) +def get_beamline_parameters(beamline_param_path: Optional[str] = None): + """Loads the beamline parameters from the specified path, or according to the + environment variable if none is given""" + if not beamline_param_path: + beamline_name = get_beamline_name("s03") + beamline_param_path = BEAMLINE_PARAMETER_PATHS.get(beamline_name) + if beamline_param_path is None: + raise KeyError( + "No beamline parameter path found, maybe 'BEAMLINE' environment variable is not set!" + ) return GDABeamlineParameters.from_file(beamline_param_path) diff --git a/src/dodal/beamlines/i24.py b/src/dodal/beamlines/i24.py index 9d5660a5699..4c0e54a683e 100644 --- a/src/dodal/beamlines/i24.py +++ b/src/dodal/beamlines/i24.py @@ -10,14 +10,14 @@ from dodal.devices.i24.pmac import PMAC from dodal.devices.oav.oav_detector import OAV, OAVConfigParams from dodal.devices.zebra import Zebra -from dodal.log import set_beamline +from dodal.log import set_beamline as set_log_beamline from dodal.utils import get_beamline_name, skip_device ZOOM_PARAMS_FILE = "/dls_sw/i24/software/gda/config/xml/jCameraManZoomLevels.xml" DISPLAY_CONFIG = "/dls_sw/i24/software/gda_versions/var/display.configuration" BL = get_beamline_name("s24") -set_beamline(BL) +set_log_beamline(BL) set_utils_beamline(BL) @@ -108,7 +108,9 @@ def oav(wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False) -> @skip_device(lambda: BL == "s24") -def vgonio(wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False) -> OAV: +def vgonio( + wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False +) -> VGonio: """Get the i24 vgonio device, instantiate it if it hasn't already been. If this is called when already instantiated, it will return the existing object. """ diff --git a/src/dodal/devices/DCM.py b/src/dodal/devices/DCM.py index 706981f6009..41b26cbab42 100644 --- a/src/dodal/devices/DCM.py +++ b/src/dodal/devices/DCM.py @@ -15,7 +15,9 @@ def __init__(self, *args, daq_configuration_path: str, **kwargs): ) # I03 configures the DCM Perp as a side effect of applying this fixed value to the DCM Offset after an energy change # Nb this parameter is misleadingly named to confuse you - self.fixed_offset_mm = get_beamline_parameters()["DCM_Perp_Offset_FIXED"] + self.fixed_offset_mm = get_beamline_parameters( + daq_configuration_path + "/domain/beamlineParameters" + )["DCM_Perp_Offset_FIXED"] """ A double crystal monochromator (DCM), used to select the energy of the beam. diff --git a/tests/beamlines/unit_tests/test_device_instantiation.py b/tests/beamlines/unit_tests/test_device_instantiation.py index 83b6e9a1179..e5c3378a1f8 100644 --- a/tests/beamlines/unit_tests/test_device_instantiation.py +++ b/tests/beamlines/unit_tests/test_device_instantiation.py @@ -1,36 +1,68 @@ +import importlib +import os from typing import Any +from unittest.mock import patch -from dodal.beamlines import beamline_utils, i03, i04, i04_1, i23, i24, p38, p45 +import pytest + +from dodal.beamlines import beamline_utils from dodal.utils import BLUESKY_PROTOCOLS, make_all_devices -ALL_BEAMLINES = {i03, i04, i04_1, i23, i24, p38, p45} +ALL_BEAMLINES = {"i03", "i04", "i04_1", "i23", "i24", "p38", "p45"} + +mock_paths = [ + ("DAQ_CONFIGURATION_PATH", "tests/devices/unit_tests/test_daq_configuration"), + ("ZOOM_PARAMS_FILE", "tests/devices/unit_tests/test_jCameraManZoomLevels.xml"), + ("DISPLAY_CONFIG", "tests/devices/unit_tests/test_display.configuration"), +] +mock_attributes_table = { + "i03": mock_paths, + "s03": mock_paths, + "i04": mock_paths, + "s04": mock_paths, +} def follows_bluesky_protocols(obj: Any) -> bool: return any((isinstance(obj, protocol) for protocol in BLUESKY_PROTOCOLS)) -def test_device_creation(RE): +def mock_bl(beamline): + bl_mod = importlib.import_module("dodal.beamlines." + beamline) + if mock_attributes := mock_attributes_table.get(beamline): + [bl_mod.__setattr__(attr[0], attr[1]) for attr in mock_attributes] + return bl_mod + + +@pytest.mark.parametrize("beamline", ALL_BEAMLINES) +def test_device_creation(RE, beamline): """ Ensures that for every beamline all device factories are using valid args and creating types that conform to Bluesky protocols. """ - for beamline in ALL_BEAMLINES: - devices = make_all_devices(beamline, fake_with_ophyd_sim=True) - for device_name, device in devices.items(): - assert device_name in beamline_utils.ACTIVE_DEVICES - assert follows_bluesky_protocols(device) - assert len(beamline_utils.ACTIVE_DEVICES) == len(devices) - beamline_utils.clear_devices() + for bl in [beamline, "s" + beamline[1:]]: + with patch.dict(os.environ, {"BEAMLINE": bl}, clear=True): + bl_mod = mock_bl(beamline) + devices = make_all_devices(bl_mod, fake_with_ophyd_sim=True) + for device_name, device in devices.items(): + assert device_name in beamline_utils.ACTIVE_DEVICES + assert follows_bluesky_protocols(device) + assert len(beamline_utils.ACTIVE_DEVICES) == len(devices) + beamline_utils.clear_devices() + del bl_mod -def test_devices_are_identical(RE): +@pytest.mark.parametrize("beamline", ALL_BEAMLINES) +def test_devices_are_identical(RE, beamline): """ Ensures that for every beamline all device functions prevent duplicate instantiation. """ - for beamline in ALL_BEAMLINES: - devices_a = make_all_devices(beamline, fake_with_ophyd_sim=True) - devices_b = make_all_devices(beamline, fake_with_ophyd_sim=True) - for device_name in devices_a.keys(): - assert devices_a[device_name] is devices_b[device_name] - beamline_utils.clear_devices() + for bl in [beamline, "s" + beamline[1:]]: + with patch.dict(os.environ, {"BEAMLINE": beamline}, clear=True): + bl_mod = mock_bl(beamline) + devices_a = make_all_devices(bl_mod, fake_with_ophyd_sim=True) + devices_b = make_all_devices(bl_mod, fake_with_ophyd_sim=True) + for device_name in devices_a.keys(): + assert devices_a[device_name] is devices_b[device_name] + beamline_utils.clear_devices() + del bl_mod diff --git a/tests/beamlines/unit_tests/test_i24.py b/tests/beamlines/unit_tests/test_i24.py index 2be285dc73d..500ef771c32 100644 --- a/tests/beamlines/unit_tests/test_i24.py +++ b/tests/beamlines/unit_tests/test_i24.py @@ -13,13 +13,14 @@ def setup_module(): def test_device_creation(): + i24.BL = "i24" devices = make_all_devices(i24, fake_with_ophyd_sim=True) assert len(devices) > 0 for device_name in devices.keys(): assert device_name in beamline_utils.ACTIVE_DEVICES assert len(beamline_utils.ACTIVE_DEVICES) == len(devices) - vgonio: VGonio = beamline_utils.ACTIVE_DEVICES["vgonio"] + vgonio: VGonio = beamline_utils.ACTIVE_DEVICES["vgonio"] # type: ignore assert vgonio.prefix == "BL24I-MO-VGON-01:" assert vgonio.kappa.prefix == "BL24I-MO-VGON-01:KAPPA" From ae2690cdf6a2304836870ea46e49b23a37c223dc Mon Sep 17 00:00:00 2001 From: David Perl Date: Tue, 13 Feb 2024 16:07:20 +0000 Subject: [PATCH 2/6] #331 add test data --- .../domain/beamlineParameters | 299 ++++++++++++++++++ .../BeamLineEnergy_DCM_Pitch_converter.txt | 25 ++ .../BeamLineEnergy_DCM_Roll_converter.txt | 7 + 3 files changed, 331 insertions(+) create mode 100644 tests/devices/unit_tests/test_daq_configuration/domain/beamlineParameters create mode 100644 tests/devices/unit_tests/test_daq_configuration/lookup/BeamLineEnergy_DCM_Pitch_converter.txt create mode 100644 tests/devices/unit_tests/test_daq_configuration/lookup/BeamLineEnergy_DCM_Roll_converter.txt diff --git a/tests/devices/unit_tests/test_daq_configuration/domain/beamlineParameters b/tests/devices/unit_tests/test_daq_configuration/domain/beamlineParameters new file mode 100644 index 00000000000..20e7eca27fe --- /dev/null +++ b/tests/devices/unit_tests/test_daq_configuration/domain/beamlineParameters @@ -0,0 +1,299 @@ +# +# +BeamLine BL03I + +## BLSE=FB switches between scan alignment and feedback alignment +## by creating bl energy scannable with beamLineSpecificEnergy_FB +## after changing you must restart servers or >>> reset_namespace +BLSE=FB + +## BPFB (Beam Position FeedBack) +## HALF (default) only off during data collection +## FULL only off for XBPM2 during attenuation optimisation, fluo when trans < 2% and wedged MAD +## UNAVAILABLE (not default) prevents xbpm_feedback.py trying to access EPICS IOC that may not be running +BPFB=FULL +## Note: only beamline scientists control whether feedback is enabled +## via the XBPM feedback EDM screen in Synoptic + +# DCM parameters +DCM_Perp_Offset_FIXED = 25.6 +# +# beamstop +# +parked_x = 4.49 +parked_y = -50.0 +parked_y_plate = -50.5 +parked_z = -49.5 +parked_z_robot = 30.0 + +in_beam_z_MIN_START_POS = 60.0 + +in_beam_x_HIGHRES = 1.52 +in_beam_y_HIGHRES = 44.78 +in_beam_z_HIGHRES = 30.0 + +in_beam_x_STANDARD = 1.52 +in_beam_y_STANDARD = 44.78 +in_beam_z_STANDARD = 30.0 + +in_beam_x_LOWRES = 1.52 +in_beam_y_LOWRES = 44.78 +in_beam_z_LOWRES = 48 + +checkCryojet = No +#If is to be moved in by the script. If not Yes then control is handed to the robot on activate script +#To force the cryojet run hutch_utilities.hutch.forceCryoOut() +manualCryojet = Yes + +######################################################### +############# All these need checking! ############ +######################################################### + +#Aperture - Scatterguard positions +# 100 micron ap +miniap_x_LARGE_APERTURE = 2.389 +miniap_y_LARGE_APERTURE = 40.986 +miniap_z_LARGE_APERTURE = 15.8 + +sg_x_LARGE_APERTURE = 5.25 +sg_y_LARGE_APERTURE = 4.43 + +# 50 micron ap +miniap_x_MEDIUM_APERTURE = 2.384 +miniap_y_MEDIUM_APERTURE = 44.967 +miniap_z_MEDIUM_APERTURE = 15.8 +sg_x_MEDIUM_APERTURE = 5.285 +sg_y_MEDIUM_APERTURE = 0.46 + +# 20 micron ap +miniap_x_SMALL_APERTURE = 2.430 +miniap_y_SMALL_APERTURE = 48.974 +miniap_z_SMALL_APERTURE = 15.8 +sg_x_SMALL_APERTURE = 5.3375 +sg_y_SMALL_APERTURE = -3.55 + +# Robot load +miniap_x_ROBOT_LOAD = 2.386 +miniap_y_ROBOT_LOAD = 31.40 +miniap_z_ROBOT_LOAD = 15.8 +sg_x_ROBOT_LOAD = 5.25 +sg_y_ROBOT_LOAD = 4.43 + +# manual mount +miniap_x_MANUAL_LOAD = -4.91 +miniap_y_MANUAL_LOAD = -49.0 +miniap_z_MANUAL_LOAD = -10.0 + +sg_x_MANUAL_LOAD = -4.7 +sg_y_MANUAL_LOAD = 1.8 + +miniap_x_SCIN_MOVE = -4.91 +# prion setting +#miniap_x_SCIN_MOVE = 0.0 +sg_x_SCIN_MOVE = -4.75 + +scin_y_SCIN_IN = 100.855 +scin_y_SCIN_OUT = -0.02 +scin_z_SCIN_IN = 101.5115 + + +scin_z_SCIN_OUT = 0.1 + +#distance to move gonx,y,z when scintillator is put in with standard pins +# For old gonio: +gon_x_SCIN_OUT_DISTANCE = 1.0 +# For SmarGon: +gon_x_SCIN_OUT_DISTANCE_smargon = 1 + +gon_y_SCIN_OUT_DISTANCE = 2.0 +gon_z_SCIN_OUT_DISTANCE = -0.5 + +#CASS motor position tolerances (mm) +miniap_x_tolerance = 0.004 +miniap_y_tolerance = 0.1 +miniap_z_tolerance = 0.1 +sg_x_tolerance = 0.1 +sg_y_tolerance = 0.1 +scin_y_tolerance = 0.1 +scin_z_tolerance = 0.12 +gon_x_tolerance = 0.01 +gon_y_tolerance = 0.1 +gon_z_tolerance = 0.001 +bs_x_tolerance = 0.02 +bs_y_tolerance = 0.005 +bs_z_tolerance = 0.3 +crl_x_tolerance = 0.01 +crl_y_tolerance = 0.01 +crl_pitch_tolerance = 0.01 +crl_yaw_tolerance = 0.01 +sg_y_up_movement_tolerance = 1.0 + +sg_x_timeout = 10 +sg_y_timeout = 10 +miniap_x_timeout = 60 +miniap_y_timeout = 10 +gon_x_timeout = 60 +gon_y_timeout = 30 +gon_z_timeout = 30 +crl_x_timeout = 10 +crl_y_timeout = 10 +crl_pitch_timeout = 10 +crl_yaw_timeout = 10 + +col_inbeam_tolerance = 1.0 + +# robot load collimation table reference positions (mm) +col_parked_tolerance = 1.0 +col_parked_upstream_x = 0.0 +col_parked_downstream_x = 0.0 +col_parked_upstream_y = 0.0 +col_parked_inboard_y = 0.0 +col_parked_outboard_y = 0.0 + +## CRL positions for low and high energy lens sets. Should deliver beam to same position on scintillator. +## Normally should only adjust the low energy set to match the position of the high energy that you've +## already checked on the scintillator screen. + +crl_x_LOWE = -11.78 +crl_y_LOWE = -4.3 +crl_pitch_LOWE = -4.75 +crl_yaw_LOWE = -1.0 + +crl_x_HIGHE = 2.22 +crl_y_HIGHE = -4.30 +crl_pitch_HIGHE = -2.75 +crl_yaw_HIGHE = 0 + + +######################################################### +########## End of new parameters ########### +######################################################### + + +#Beam visualisation parameters +MinBackStopZ = 30.0 +BackStopYsafe = 20.0 +BackStopXyag = -4.8 +BackStopYyag = 17.20 +BackStopZyag = 19.1 +SampleYnormal = 2.65 +SampleYshift = 2.0 +parked_fluo_x = -18.0 +in_beam_fluo_x = 12.0 +move_fluo = Yes +safe_det_z_default = 900 +safe_det_z_sampleChanger = 337 +store_data_collections_in_ispyb = Yes +TakePNGsOfSample = Yes + +#robot requires these values +gonio_parked_x = 0.0 +gonio_parked_y = 0.0 +gonio_parked_z = 0.0 +gonio_parked_omega = 0 +gonio_parked_chi = 0 +gonio_parked_phi = 0 + +# The following used by setupBeamLine script +setupBeamLine_energyStart = 7000.0 +setupBeamLine_energyEnd = 17000.0 +setupBeamLine_energyStep = 500 +setupBeamLine_rollStart = -4 +setupBeamLine_rollEnd = 4 +setupBeamLine_rollSteps = 21 +setupBeamLine_pitchStart = -3.7 +setupBeamLine_pitchEnd = -3.5 +setupBeamLine_pitchSteps = 200 +#values below in microns +beamXCentre = 0 +beamYCentre = 0 +beamXYSettleTime = 6.0 +beamXYTolerance = 5.0 +DataCollection_TurboMode = Yes +#time in seconds. If not set then the default is 0.1 + +#The following are used by beamLineenergy script +beamLineEnergy_rollBeamX 50 +beamLineEnergy_rollBeamY 200 +beamLineEnergy__rollWidth = .2 +beamLineEnergy__rollStep = .02 +beamLineEnergy__pitchWidth = .02 +beamLineEnergy__pitchStep = .002 +beamLineEnergy__fpitchWidth = .02 +beamLineEnergy__fpitchStep = .001 +beamLineEnergy__adjustSlits = No +#dataCollectionMinSampleCurrent = 0.245 +dataCollectionMinSampleCurrent = 0.000 +dataCollectionSampleCurrent qbpm3 + +#Mark is using the following in some test scripts +MinIPin = 1.0 +YAGPin = 1 +RotationAxisPin = 2 +PtPin = 3 +PowderPin = 4 + +iPinInDetZ = 340.0 + +DataCollectionDetX = -7.8504 +DataCollectionDetYaw = 6.499 +DataCollectionDetY = 48.0 + +# StandardEnergy on i03 is 12700eV +StandardEnergy = 12700 + +keyence_max_attempts = 1 +# Move gonio 100 microns, see difference in keyence values +# Then do 100/difference, put that number below +# Sign may change between Smargon and MiniKappa +keyence_slopeYToX = 2.5 +keyence_slopeYToY = -2.5 +keyence_slopeXToZ = 3.23 + +YAGSamX = 1022 +YAGSamY = -98.0 +YAGSamZ = -147 +YAGOmega = 0.0 + +#ipin value must be < ipin_threshold above background for data collection +ipin_threshold = 0.1 + +# energy thresholds for mirror stripes +# - first threshold is between bare/Rh stripes (e.g. 7000) +# - second threshold is between Rh/Pt stripes (e.g. 18000) +mirror_threshold_bare_rh = 6900 +mirror_threshold_rh_pt = 30000 + +# flux conversion factors +flux_factor_no_aperture = 1 +flux_factor_LARGE_APERTURE = 0.738 +flux_factor_MEDIUM_APERTURE = 0.36 +flux_factor_SMALL_APERTURE = 0.084 +flux_factor_no_aperture_plate = 1 +flux_factor_LARGE_APERTURE_plate = 0.738 +flux_factor_MEDIUM_APERTURE_plate = 0.36 +flux_factor_SMALL_APERTURE_plate = 0.084 + +# assuming gain 10^3 +pin_diode_factor = 2.66E19 + +# Fluorescence/Vortex detector settings +attenuation_optimisation_type = deadtime # deadtime or total_counts + +#Deadtime settings +fluorescence_analyser_deadtimeThreshold=0.002 # used by edge scans +fluorescence_spectrum_deadtimeThreshold=0.0005 # used by spectrum + +#Other settings +fluorescence_attenuation_low_roi = 100 +fluorescence_attenuation_high_roi = 2048 +attenuation_optimisation_optimisation_cycles = 10 +attenuation_optimisation_start_transmission = 0.1 # per cent +fluorescence_mca_sca_offset = 400 + +#Total count settings +attenuation_optimisation_multiplier = 2 +attenuation_optimisation_target_count = 2000 +attenuation_optimisation_upper_limit = 50000 +attenuation_optimisation_lower_limit = 20000 + diff --git a/tests/devices/unit_tests/test_daq_configuration/lookup/BeamLineEnergy_DCM_Pitch_converter.txt b/tests/devices/unit_tests/test_daq_configuration/lookup/BeamLineEnergy_DCM_Pitch_converter.txt new file mode 100644 index 00000000000..449e920f738 --- /dev/null +++ b/tests/devices/unit_tests/test_daq_configuration/lookup/BeamLineEnergy_DCM_Pitch_converter.txt @@ -0,0 +1,25 @@ +# Bragg pitch +# Degree values for pitch are interpreted as mrad +# The values cannot change direction. +# last update 2023/06/26 NP +Units Deg mrad +Units Deg Deg +19.24347 -0.79775 +16.40949 -0.78679 +14.31123 -0.77838 +12.69287 -0.77276 +11.40555 -0.77276 +10.35662 -0.77031 +9.48522 -0.76693 +8.95826 -0.76387 +8.74953 -0.76387 +8.12020 -0.76387 +7.57556 -0.76354 +7.09950 -0.76166 +6.67997 -0.76044 +6.30732 -0.75953 +5.97411 -0.75845 +5.67434 -0.75796 +5.40329 -0.75789 +5.15700 -0.75551 +4.93218 -0.75513 diff --git a/tests/devices/unit_tests/test_daq_configuration/lookup/BeamLineEnergy_DCM_Roll_converter.txt b/tests/devices/unit_tests/test_daq_configuration/lookup/BeamLineEnergy_DCM_Roll_converter.txt new file mode 100644 index 00000000000..329f29f0990 --- /dev/null +++ b/tests/devices/unit_tests/test_daq_configuration/lookup/BeamLineEnergy_DCM_Roll_converter.txt @@ -0,0 +1,7 @@ +#Bragg angle against roll( absolute number) +#reloadLookupTables() +# last update 2023/01/19 NP +Units Deg mrad +26.4095 -0.2799 +6.3075 -0.2799 + From 54565137cbe7808c574963f56f7a2383c9cdb40a Mon Sep 17 00:00:00 2001 From: David Perl Date: Tue, 13 Feb 2024 16:57:55 +0000 Subject: [PATCH 3/6] #331 fix mocking of config gile paths --- .../unit_tests/test_beamline_utils.py | 20 +++++++++++-------- .../unit_tests/test_device_instantiation.py | 17 +++------------- tests/conftest.py | 18 +++++++++++++++++ .../devices/unit_tests/test_undulator_dcm.py | 5 +++-- 4 files changed, 36 insertions(+), 24 deletions(-) diff --git a/tests/beamlines/unit_tests/test_beamline_utils.py b/tests/beamlines/unit_tests/test_beamline_utils.py index 7477287ad2a..87ef6e66aa4 100644 --- a/tests/beamlines/unit_tests/test_beamline_utils.py +++ b/tests/beamlines/unit_tests/test_beamline_utils.py @@ -13,6 +13,14 @@ from dodal.devices.zebra import Zebra from dodal.utils import make_all_devices +from ...conftest import mock_beamline_module_filepaths + + +@pytest.fixture +def reset_i03(): + beamline_utils.clear_devices() + mock_beamline_module_filepaths("i03", i03) + def test_instantiate_function_makes_supplied_device(): device_types = [Zebra, ApertureScatterguard, Smargon] @@ -24,8 +32,7 @@ def test_instantiate_function_makes_supplied_device(): assert isinstance(dev, device) -def test_instantiating_different_device_with_same_name(): - beamline_utils.clear_devices() +def test_instantiating_different_device_with_same_name(reset_i03): dev1 = beamline_utils.device_instantiation( # noqa Zebra, "device", "", False, False, None ) @@ -43,8 +50,7 @@ def test_instantiating_different_device_with_same_name(): assert dev2 in beamline_utils.ACTIVE_DEVICES.values() -def test_instantiate_function_fake_makes_fake(): - beamline_utils.clear_devices() +def test_instantiate_function_fake_makes_fake(reset_i03): fake_zeb: Zebra = beamline_utils.device_instantiation( i03.Zebra, "zebra", "", True, True, None ) @@ -52,8 +58,8 @@ def test_instantiate_function_fake_makes_fake(): assert isinstance(fake_zeb.pc.arm_source, FakeEpicsSignal) -def test_clear_devices(RE): - beamline_utils.clear_devices() +def test_clear_devices(RE, reset_i03): + mock_beamline_module_filepaths("i03", i03) devices = make_all_devices(i03, fake_with_ophyd_sim=True) assert len(beamline_utils.ACTIVE_DEVICES) == len(devices.keys()) beamline_utils.clear_devices() @@ -61,8 +67,6 @@ def test_clear_devices(RE): def test_device_is_new_after_clearing(RE): - beamline_utils.clear_devices() - def _make_devices_and_get_id(): return [ id(device) diff --git a/tests/beamlines/unit_tests/test_device_instantiation.py b/tests/beamlines/unit_tests/test_device_instantiation.py index e5c3378a1f8..648d6743257 100644 --- a/tests/beamlines/unit_tests/test_device_instantiation.py +++ b/tests/beamlines/unit_tests/test_device_instantiation.py @@ -8,19 +8,9 @@ from dodal.beamlines import beamline_utils from dodal.utils import BLUESKY_PROTOCOLS, make_all_devices -ALL_BEAMLINES = {"i03", "i04", "i04_1", "i23", "i24", "p38", "p45"} +from ...conftest import mock_beamline_module_filepaths -mock_paths = [ - ("DAQ_CONFIGURATION_PATH", "tests/devices/unit_tests/test_daq_configuration"), - ("ZOOM_PARAMS_FILE", "tests/devices/unit_tests/test_jCameraManZoomLevels.xml"), - ("DISPLAY_CONFIG", "tests/devices/unit_tests/test_display.configuration"), -] -mock_attributes_table = { - "i03": mock_paths, - "s03": mock_paths, - "i04": mock_paths, - "s04": mock_paths, -} +ALL_BEAMLINES = {"i03", "i04", "i04_1", "i23", "i24", "p38", "p45"} def follows_bluesky_protocols(obj: Any) -> bool: @@ -29,8 +19,7 @@ def follows_bluesky_protocols(obj: Any) -> bool: def mock_bl(beamline): bl_mod = importlib.import_module("dodal.beamlines." + beamline) - if mock_attributes := mock_attributes_table.get(beamline): - [bl_mod.__setattr__(attr[0], attr[1]) for attr in mock_attributes] + mock_beamline_module_filepaths(beamline, bl_mod) return bl_mod diff --git a/tests/conftest.py b/tests/conftest.py index 815a14d4ed6..3830a24463b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -12,6 +12,24 @@ from dodal.devices.focusing_mirror import VFMMirrorVoltages from dodal.log import LOGGER, GELFTCPHandler, set_up_logging_handlers +MOCK_DAQ_CONFIG_PATH = "tests/devices/unit_tests/test_daq_configuration" +mock_paths = [ + ("DAQ_CONFIGURATION_PATH", MOCK_DAQ_CONFIG_PATH), + ("ZOOM_PARAMS_FILE", "tests/devices/unit_tests/test_jCameraManZoomLevels.xml"), + ("DISPLAY_CONFIG", "tests/devices/unit_tests/test_display.configuration"), +] +mock_attributes_table = { + "i03": mock_paths, + "s03": mock_paths, + "i04": mock_paths, + "s04": mock_paths, +} + + +def mock_beamline_module_filepaths(bl_name, bl_module): + if mock_attributes := mock_attributes_table.get(bl_name): + [bl_module.__setattr__(attr[0], attr[1]) for attr in mock_attributes] + def pytest_runtest_setup(item): beamline_utils.clear_devices() diff --git a/tests/devices/unit_tests/test_undulator_dcm.py b/tests/devices/unit_tests/test_undulator_dcm.py index 5893b291257..69679936d42 100644 --- a/tests/devices/unit_tests/test_undulator_dcm.py +++ b/tests/devices/unit_tests/test_undulator_dcm.py @@ -5,7 +5,6 @@ from ophyd.sim import make_fake_device from ophyd.status import Status -from dodal.beamlines.i03 import DAQ_CONFIGURATION_PATH from dodal.devices.DCM import DCM from dodal.devices.undulator import Undulator, UndulatorGapAccess from dodal.devices.undulator_dcm import ( @@ -15,6 +14,8 @@ _get_energy_distance_table, ) +from ...conftest import MOCK_DAQ_CONFIG_PATH + @pytest.fixture def fake_undulator_dcm() -> UndulatorDCM: @@ -23,7 +24,7 @@ def fake_undulator_dcm() -> UndulatorDCM: lookup_table_path="./tests/devices/unit_tests/test_beamline_undulator_to_gap_lookup_table.txt", ) dcm: DCM = make_fake_device(DCM)( - name="dcm", daq_configuration_path=DAQ_CONFIGURATION_PATH + name="dcm", daq_configuration_path=MOCK_DAQ_CONFIG_PATH ) undulator_dcm: UndulatorDCM = make_fake_device(UndulatorDCM)( undulator, dcm, name="undulator_dcm" From b6ea322d42ff5502062b84b78fa7d8fc37f1ca52 Mon Sep 17 00:00:00 2001 From: David Perl Date: Tue, 13 Feb 2024 17:12:33 +0000 Subject: [PATCH 4/6] #331 add inits for pytest --- tests/beamlines/__init__.py | 0 tests/beamlines/unit_tests/__init__.py | 0 tests/devices/i04/__init__.py | 0 tests/devices/unit_tests/i24/__init__.py | 0 tests/unit_tests/__init__.py | 0 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/beamlines/__init__.py create mode 100644 tests/beamlines/unit_tests/__init__.py create mode 100644 tests/devices/i04/__init__.py create mode 100644 tests/devices/unit_tests/i24/__init__.py create mode 100644 tests/unit_tests/__init__.py diff --git a/tests/beamlines/__init__.py b/tests/beamlines/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/beamlines/unit_tests/__init__.py b/tests/beamlines/unit_tests/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/devices/i04/__init__.py b/tests/devices/i04/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/devices/unit_tests/i24/__init__.py b/tests/devices/unit_tests/i24/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/unit_tests/__init__.py b/tests/unit_tests/__init__.py new file mode 100644 index 00000000000..e69de29bb2d From b2c71b352ea3f6ec02db24a8b526c9630d40a19e Mon Sep 17 00:00:00 2001 From: David Perl Date: Wed, 14 Feb 2024 12:27:41 +0000 Subject: [PATCH 5/6] #331 only run tests once for each BL and include skipped --- src/dodal/utils.py | 14 +++++-- .../unit_tests/test_device_instantiation.py | 42 ++++++++++--------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/dodal/utils.py b/src/dodal/utils.py index 893ccc61d80..2becfb17553 100644 --- a/src/dodal/utils.py +++ b/src/dodal/utils.py @@ -110,7 +110,7 @@ def wrapper(*args, **kwds) -> T: def make_all_devices( - module: Union[str, ModuleType, None] = None, **kwargs + module: Union[str, ModuleType, None] = None, include_skipped: bool = False, **kwargs ) -> Dict[str, AnyDevice]: """Makes all devices in the given beamline module. @@ -126,7 +126,7 @@ def make_all_devices( """ if isinstance(module, str) or module is None: module = import_module(module or __name__) - factories = collect_factories(module) + factories = collect_factories(module, include_skipped) devices: dict[str, AnyDevice] = invoke_factories(factories, **kwargs) return devices @@ -167,11 +167,17 @@ def extract_dependencies( yield name -def collect_factories(module: ModuleType) -> dict[str, AnyDeviceFactory]: +def collect_factories( + module: ModuleType, include_skipped: bool = False +) -> dict[str, AnyDeviceFactory]: factories: dict[str, AnyDeviceFactory] = {} for var in module.__dict__.values(): - if callable(var) and is_any_device_factory(var) and not _is_device_skipped(var): + if ( + callable(var) + and is_any_device_factory(var) + and (include_skipped or not _is_device_skipped(var)) + ): factories[var.__name__] = var return factories diff --git a/tests/beamlines/unit_tests/test_device_instantiation.py b/tests/beamlines/unit_tests/test_device_instantiation.py index 648d6743257..c8330d860e8 100644 --- a/tests/beamlines/unit_tests/test_device_instantiation.py +++ b/tests/beamlines/unit_tests/test_device_instantiation.py @@ -29,16 +29,17 @@ def test_device_creation(RE, beamline): Ensures that for every beamline all device factories are using valid args and creating types that conform to Bluesky protocols. """ - for bl in [beamline, "s" + beamline[1:]]: - with patch.dict(os.environ, {"BEAMLINE": bl}, clear=True): - bl_mod = mock_bl(beamline) - devices = make_all_devices(bl_mod, fake_with_ophyd_sim=True) - for device_name, device in devices.items(): - assert device_name in beamline_utils.ACTIVE_DEVICES - assert follows_bluesky_protocols(device) - assert len(beamline_utils.ACTIVE_DEVICES) == len(devices) - beamline_utils.clear_devices() - del bl_mod + with patch.dict(os.environ, {"BEAMLINE": beamline}, clear=True): + bl_mod = mock_bl(beamline) + devices = make_all_devices( + bl_mod, include_skipped=True, fake_with_ophyd_sim=True + ) + for device_name, device in devices.items(): + assert device_name in beamline_utils.ACTIVE_DEVICES + assert follows_bluesky_protocols(device) + assert len(beamline_utils.ACTIVE_DEVICES) == len(devices) + beamline_utils.clear_devices() + del bl_mod @pytest.mark.parametrize("beamline", ALL_BEAMLINES) @@ -46,12 +47,15 @@ def test_devices_are_identical(RE, beamline): """ Ensures that for every beamline all device functions prevent duplicate instantiation. """ - for bl in [beamline, "s" + beamline[1:]]: - with patch.dict(os.environ, {"BEAMLINE": beamline}, clear=True): - bl_mod = mock_bl(beamline) - devices_a = make_all_devices(bl_mod, fake_with_ophyd_sim=True) - devices_b = make_all_devices(bl_mod, fake_with_ophyd_sim=True) - for device_name in devices_a.keys(): - assert devices_a[device_name] is devices_b[device_name] - beamline_utils.clear_devices() - del bl_mod + with patch.dict(os.environ, {"BEAMLINE": beamline}, clear=True): + bl_mod = mock_bl(beamline) + devices_a = make_all_devices( + bl_mod, include_skipped=True, fake_with_ophyd_sim=True + ) + devices_b = make_all_devices( + bl_mod, include_skipped=True, fake_with_ophyd_sim=True + ) + for device_name in devices_a.keys(): + assert devices_a[device_name] is devices_b[device_name] + beamline_utils.clear_devices() + del bl_mod From 0029972dd3bcd523b2d899111fa94778cf955806 Mon Sep 17 00:00:00 2001 From: David Perl Date: Wed, 14 Feb 2024 12:32:48 +0000 Subject: [PATCH 6/6] #331 delete some unused bulk from test params file --- .../domain/beamlineParameters | 163 +----------------- 1 file changed, 2 insertions(+), 161 deletions(-) diff --git a/tests/devices/unit_tests/test_daq_configuration/domain/beamlineParameters b/tests/devices/unit_tests/test_daq_configuration/domain/beamlineParameters index 20e7eca27fe..df3951b8fcf 100644 --- a/tests/devices/unit_tests/test_daq_configuration/domain/beamlineParameters +++ b/tests/devices/unit_tests/test_daq_configuration/domain/beamlineParameters @@ -1,10 +1,8 @@ # # -BeamLine BL03I +BeamLine BL03S -## BLSE=FB switches between scan alignment and feedback alignment -## by creating bl energy scannable with beamLineSpecificEnergy_FB -## after changing you must restart servers or >>> reset_namespace +## Test data for device instantiation BLSE=FB ## BPFB (Beam Position FeedBack) @@ -28,26 +26,6 @@ parked_z_robot = 30.0 in_beam_z_MIN_START_POS = 60.0 -in_beam_x_HIGHRES = 1.52 -in_beam_y_HIGHRES = 44.78 -in_beam_z_HIGHRES = 30.0 - -in_beam_x_STANDARD = 1.52 -in_beam_y_STANDARD = 44.78 -in_beam_z_STANDARD = 30.0 - -in_beam_x_LOWRES = 1.52 -in_beam_y_LOWRES = 44.78 -in_beam_z_LOWRES = 48 - -checkCryojet = No -#If is to be moved in by the script. If not Yes then control is handed to the robot on activate script -#To force the cryojet run hutch_utilities.hutch.forceCryoOut() -manualCryojet = Yes - -######################################################### -############# All these need checking! ############ -######################################################### #Aperture - Scatterguard positions # 100 micron ap @@ -108,137 +86,6 @@ gon_x_SCIN_OUT_DISTANCE_smargon = 1 gon_y_SCIN_OUT_DISTANCE = 2.0 gon_z_SCIN_OUT_DISTANCE = -0.5 -#CASS motor position tolerances (mm) -miniap_x_tolerance = 0.004 -miniap_y_tolerance = 0.1 -miniap_z_tolerance = 0.1 -sg_x_tolerance = 0.1 -sg_y_tolerance = 0.1 -scin_y_tolerance = 0.1 -scin_z_tolerance = 0.12 -gon_x_tolerance = 0.01 -gon_y_tolerance = 0.1 -gon_z_tolerance = 0.001 -bs_x_tolerance = 0.02 -bs_y_tolerance = 0.005 -bs_z_tolerance = 0.3 -crl_x_tolerance = 0.01 -crl_y_tolerance = 0.01 -crl_pitch_tolerance = 0.01 -crl_yaw_tolerance = 0.01 -sg_y_up_movement_tolerance = 1.0 - -sg_x_timeout = 10 -sg_y_timeout = 10 -miniap_x_timeout = 60 -miniap_y_timeout = 10 -gon_x_timeout = 60 -gon_y_timeout = 30 -gon_z_timeout = 30 -crl_x_timeout = 10 -crl_y_timeout = 10 -crl_pitch_timeout = 10 -crl_yaw_timeout = 10 - -col_inbeam_tolerance = 1.0 - -# robot load collimation table reference positions (mm) -col_parked_tolerance = 1.0 -col_parked_upstream_x = 0.0 -col_parked_downstream_x = 0.0 -col_parked_upstream_y = 0.0 -col_parked_inboard_y = 0.0 -col_parked_outboard_y = 0.0 - -## CRL positions for low and high energy lens sets. Should deliver beam to same position on scintillator. -## Normally should only adjust the low energy set to match the position of the high energy that you've -## already checked on the scintillator screen. - -crl_x_LOWE = -11.78 -crl_y_LOWE = -4.3 -crl_pitch_LOWE = -4.75 -crl_yaw_LOWE = -1.0 - -crl_x_HIGHE = 2.22 -crl_y_HIGHE = -4.30 -crl_pitch_HIGHE = -2.75 -crl_yaw_HIGHE = 0 - - -######################################################### -########## End of new parameters ########### -######################################################### - - -#Beam visualisation parameters -MinBackStopZ = 30.0 -BackStopYsafe = 20.0 -BackStopXyag = -4.8 -BackStopYyag = 17.20 -BackStopZyag = 19.1 -SampleYnormal = 2.65 -SampleYshift = 2.0 -parked_fluo_x = -18.0 -in_beam_fluo_x = 12.0 -move_fluo = Yes -safe_det_z_default = 900 -safe_det_z_sampleChanger = 337 -store_data_collections_in_ispyb = Yes -TakePNGsOfSample = Yes - -#robot requires these values -gonio_parked_x = 0.0 -gonio_parked_y = 0.0 -gonio_parked_z = 0.0 -gonio_parked_omega = 0 -gonio_parked_chi = 0 -gonio_parked_phi = 0 - -# The following used by setupBeamLine script -setupBeamLine_energyStart = 7000.0 -setupBeamLine_energyEnd = 17000.0 -setupBeamLine_energyStep = 500 -setupBeamLine_rollStart = -4 -setupBeamLine_rollEnd = 4 -setupBeamLine_rollSteps = 21 -setupBeamLine_pitchStart = -3.7 -setupBeamLine_pitchEnd = -3.5 -setupBeamLine_pitchSteps = 200 -#values below in microns -beamXCentre = 0 -beamYCentre = 0 -beamXYSettleTime = 6.0 -beamXYTolerance = 5.0 -DataCollection_TurboMode = Yes -#time in seconds. If not set then the default is 0.1 - -#The following are used by beamLineenergy script -beamLineEnergy_rollBeamX 50 -beamLineEnergy_rollBeamY 200 -beamLineEnergy__rollWidth = .2 -beamLineEnergy__rollStep = .02 -beamLineEnergy__pitchWidth = .02 -beamLineEnergy__pitchStep = .002 -beamLineEnergy__fpitchWidth = .02 -beamLineEnergy__fpitchStep = .001 -beamLineEnergy__adjustSlits = No -#dataCollectionMinSampleCurrent = 0.245 -dataCollectionMinSampleCurrent = 0.000 -dataCollectionSampleCurrent qbpm3 - -#Mark is using the following in some test scripts -MinIPin = 1.0 -YAGPin = 1 -RotationAxisPin = 2 -PtPin = 3 -PowderPin = 4 - -iPinInDetZ = 340.0 - -DataCollectionDetX = -7.8504 -DataCollectionDetYaw = 6.499 -DataCollectionDetY = 48.0 - # StandardEnergy on i03 is 12700eV StandardEnergy = 12700 @@ -274,12 +121,6 @@ flux_factor_LARGE_APERTURE_plate = 0.738 flux_factor_MEDIUM_APERTURE_plate = 0.36 flux_factor_SMALL_APERTURE_plate = 0.084 -# assuming gain 10^3 -pin_diode_factor = 2.66E19 - -# Fluorescence/Vortex detector settings -attenuation_optimisation_type = deadtime # deadtime or total_counts - #Deadtime settings fluorescence_analyser_deadtimeThreshold=0.002 # used by edge scans fluorescence_spectrum_deadtimeThreshold=0.0005 # used by spectrum