From 546299410df6647818fa036a57b54d00c044738a Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 27 Oct 2026 10:05:30 +0000 Subject: [PATCH 1/2] calibration: use a Scan Manager entry (pymodaq 5.3) instead of the old scanner xml The BeamShapingCalibration scanner selects Camera and Shaper through a .scan entry generated by scripts/make_calibration_entry.py. Also adapt the extension to the DAQScan 5.3 attributes. Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01CAhZwmbyCSpSgfTyicUxuS --- .../2026/20261027/Dataset_20261027_000.h5" | Bin 0 -> 7680 bytes .../2026/20261027/Dataset_20261027_001.h5" | Bin 0 -> 7680 bytes .../2026/20261027/Dataset_20261027_002.h5" | Bin 0 -> 7680 bytes .../2026/20261027/Dataset_20261027_003.h5" | Bin 0 -> 7680 bytes .../2026/20261027/Dataset_20261027_004.h5" | Bin 0 -> 7680 bytes .../2026/20261027/Dataset_20261027_005.h5" | Bin 0 -> 7680 bytes docs/src/user_guide/calibration.rst | 4 +- .../resources/holography_calibration.scan | Bin 0 -> 2609 bytes .../resources/holography_calibration.xml | 1 - .../scanners/calibration.py | 1 - .../scripts/make_calibration_entry.py | 56 ++++++++++++++++++ .../utilities/calibrating.py | 18 +++--- tests/test_calibration.py | 49 +++++++++++++++ 13 files changed, 116 insertions(+), 13 deletions(-) create mode 100644 "C:\\Data/2026/20261027/Dataset_20261027_000.h5" create mode 100644 "C:\\Data/2026/20261027/Dataset_20261027_001.h5" create mode 100644 "C:\\Data/2026/20261027/Dataset_20261027_002.h5" create mode 100644 "C:\\Data/2026/20261027/Dataset_20261027_003.h5" create mode 100644 "C:\\Data/2026/20261027/Dataset_20261027_004.h5" create mode 100644 "C:\\Data/2026/20261027/Dataset_20261027_005.h5" create mode 100644 src/pymodaq_plugins_beam_shaping/resources/holography_calibration.scan delete mode 100644 src/pymodaq_plugins_beam_shaping/resources/holography_calibration.xml create mode 100644 src/pymodaq_plugins_beam_shaping/scripts/make_calibration_entry.py create mode 100644 tests/test_calibration.py diff --git "a/C:\\Data/2026/20261027/Dataset_20261027_000.h5" "b/C:\\Data/2026/20261027/Dataset_20261027_000.h5" new file mode 100644 index 0000000000000000000000000000000000000000..fa5626c7d63dd2e03c251aba0ae61fc7705b71b2 GIT binary patch literal 7680 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 F_zQv5DsBJ( literal 0 HcmV?d00001 diff --git "a/C:\\Data/2026/20261027/Dataset_20261027_005.h5" "b/C:\\Data/2026/20261027/Dataset_20261027_005.h5" new file mode 100644 index 0000000000000000000000000000000000000000..d2126f921c6a97110d4e497fda31be40588f7e77 GIT binary patch literal 7680 zcmeHM&2Jl35TErrPMSK!l%&v9sw{)lRJdVd;(QeZb{y9MM=`dG=*ifzn^>{E#%s5= zXgMJS2LuP;g5bgt=m`m=swXN@ArKs@N=OBSDv|yPNC?8r``Fr+*0Eh7Kt{^zdC7S5aUc2I5k42IW<)Y&80GxF2j#<$^>Hr0R zdO}Vv`bPA)=K)l3!8l+?dNmzify0UdIFkLL7Sae1-c$UMehCfSAyV~l)oQb>=d&+m z&J}7#QLk8nEReR?5P`a*1TxVMlF!z&eIcox%Q4QEYnctbT+P;txl+M$Idd(`Aup5r7Ts4T2$FHwl80+ea-v;7s%MUaKjlIigecvH)zF3WzO2??e2!dq#`WnqUZhe zW71LoM<1*&$DVZ@B#{gl$z3Q_U^tmQA3+;`!QBh{zgnBH))~+y!#Mr-kA9ZoaS4ht z4&YEQwgkx~spFu~o;pKr2xC@NM;-)lI>6xorw5!~r_(bk6(+wuAJas z#+%jTZ89=nw%ml|uKUR`uDHIrS*TqXapT7DRAGo8j(W3d9mjZz&7eRec>mWsA6ie= zhI_Wy<$OHTf=dC_risVYdPPsRXg<)XSud8YHN!2M7&CBab0QE;rB>i!7Vc;#jD|m1 z9DVuY&?hwd9x0lPCD@U2uqYI0(lt06BRM@q9V5v_bD!XQF;p`(`DvJ<`*c$3eSGBf z&*5||!mnNOW_}7D;=TJo&T{cv$4)ebqv&ifk|#@YE~Uv5Z~>;U$$Q4cNjV}0NPg?> zUoJ@4B5USFBC7Nq`B=nq@&igUnC6>|&mu2Ju@PgBiPcI;l$Yl3~qaltw6D%e7u%4W*ms&TN zt~Cm{Exax{Nq#E1ema37ad`mCpV+1Z=sjE0%U)?2Zcjt#Q~o0A#JT(581I({QjUK< z9!e%dXJC|f1G}2>c`tv}8&z~>i^rxk|8d-qOz(sGsZp%d$xm*vo<+g;T2E*EV7pk^ zq{!hkCU~#=>%`j%R-1%&pidktJKZO6mINPce}=h1aqOVic5e-!UVp`Hn7fw>tiFrU%1;Ph6|+%F|*B9^$3_lr-sCuX!0fq4!| zshfzUbL9Qv&1g&7?9%Mw^ul~_adysJCj-TwJMw@@fz53T*cPxYU|YbpfNcTW0=5Ng z3;c&I5KhOVSOU6DTfldR-Ccmyn_(wRQXv3ea!7D|{3kzLCjq{tkl^O)`N!Z@Qo(u; z34TbtI0I`W5E$2X-g^QLwFo}f-pK%~qKOf^wMWiDnn3YYkua{_@_z?!lHep4#CBXa zK7D2TEkd#BZ?Zr%773fxZ8pb&-<98b{8q!pi%JDCQ?2_q4OYVtYE;)yVHn(0tz3B_ z9a&ui5BBlyr_K5iO=ZFxTiG6~)b!eKs^z;Dw_Cp%Q8h%xA}IS_Wi)c#HCe4g?1$AG50e-NrvljyC0&#DYUOI99G*{1)k G1^xno3o3m8 literal 0 HcmV?d00001 diff --git a/docs/src/user_guide/calibration.rst b/docs/src/user_guide/calibration.rst index 5e5926d..c74c6ad 100644 --- a/docs/src/user_guide/calibration.rst +++ b/docs/src/user_guide/calibration.rst @@ -29,7 +29,9 @@ Calibration Procedure --------------------- 1. **Open the Calibration Tool**: Click **Calibration** |equalizer| in the toolbar or navigate to **Shaping > Calibration > Calibration**. -2. **Select the SLM**: Ensure the **Shaper** module is loaded in PyMoDAQ’s Dashboard. +2. **Select the SLM and the camera**: Ensure an actuator named **Shaper** (the SLM) and a detector named **Camera** + (seeing the fringes) are loaded in PyMoDAQ’s Dashboard. The scan configuration (``BeamShapingCalibration`` + scanner, ``Shaper`` and ``Camera`` selected) is a Scan Manager entry shipped with the package. 3. **Run Calibration**: The tool performs a **double-slit experiment**: diff --git a/src/pymodaq_plugins_beam_shaping/resources/holography_calibration.scan b/src/pymodaq_plugins_beam_shaping/resources/holography_calibration.scan new file mode 100644 index 0000000000000000000000000000000000000000..59c1b3faa117f7d5df2e7369348caacd92b46cda GIT binary patch literal 2609 zcmd5;O^?$s5Dg!z1ql#bI7hh@B&2Rv+6zh}vE3CHidM7|2SC-Nowk-7JJ`;$`9u5z z{vR{0n+B;=a7quA?dNgy-uTV9Q4~FzRQa`XrjDZMfpvz4mm^JpmSerBB-#l&C)CQ) z&Wjr`P@qHeS-ABLxHW+frLd01d-MxmI4w3u2|3AYhjjM-*EE2!t4kavE2FD2iJfqg zR$(uRZ-o^(BZDM1Sm;~ut217~LMvGh6I!5Rd=bJF6ipc3m7o@3%hqas-2imXuJw

?zXvUEYx=1vk1cnf{7Tz9doA7$=rqY$YDxc$`2?a|!HvT?IUax8Da%-j zLO9F*W=4an-kaFZ&NnmsUZHXVB;!-aD+%5zRMoGxCtj!hMru$^cXwEMxZI-=|3N4u zWhC+w^)+4iG?ZX0^6V0!;L@NLHUcSf15RkgCFAq(m+fs{w#nG!hALuaL$lxOV9sSb zs8fFsX9vawqD!e^XW{n->v+Q39bcoZmP>IrOp@%3tjL6zwk{8`*5%QVKEJqN+PY-c zc#t(759 TuaE7vtQw;d['Camera']['Shaper']000256str('Scan1D')str('BeamShapingCalibration')1025510010101[][]011000str('scan')0000str('h5py')11http://hsds.sebastienweber.frpymodaq_userpymodaq000C:\DataScanC:\Datanp.nanstr('zlib')5 \ No newline at end of file diff --git a/src/pymodaq_plugins_beam_shaping/scanners/calibration.py b/src/pymodaq_plugins_beam_shaping/scanners/calibration.py index e999b4a..f0af671 100644 --- a/src/pymodaq_plugins_beam_shaping/scanners/calibration.py +++ b/src/pymodaq_plugins_beam_shaping/scanners/calibration.py @@ -4,7 +4,6 @@ @author: Sebastien Weber """ -from cProfile import label from typing import List, Tuple, Any, TYPE_CHECKING import re import numpy as np diff --git a/src/pymodaq_plugins_beam_shaping/scripts/make_calibration_entry.py b/src/pymodaq_plugins_beam_shaping/scripts/make_calibration_entry.py new file mode 100644 index 0000000..4463be4 --- /dev/null +++ b/src/pymodaq_plugins_beam_shaping/scripts/make_calibration_entry.py @@ -0,0 +1,56 @@ +"""Generate the Scan Manager entry used by the SLM calibration (resources/holography_calibration.scan) + +The entry selects the detector named Camera, the actuator named Shaper and the BeamShapingCalibration scanner. Only the +names matter: mock modules are loaded in a Dashboard to create the entry with the Scan Manager itself, so it stays +valid whatever the real camera and SLM are. Run it again if the format of the entries changes with PyMoDAQ. +""" +import sys +import time +from pathlib import Path + +from pymodaq.control_modules.enums import DAQTypesEnum +from pymodaq.utils.managers.modules import ModuleType +from pymodaq.utils.managers.modules.loader import PluginInfo + +from pymodaq_plugins_beam_shaping.utilities.calibrating import CALIBRATION_ENTRY + + +def create_dashboard_with_camera_and_shaper(qapp, timeout=20.): + """ Create a Dashboard with a detector named Camera and an actuator named Shaper (mock ones)""" + from pymodaq.dashboard import create_load_dashboard + + _, dashboard = create_load_dashboard() + dashboard.module_creator.load_created_modules([ + [PluginInfo(id=1, name='Shaper', class_name='MockShaper', type=ModuleType.Actuator, do_init=False)], + [PluginInfo(id=2, name='Camera', class_name='MockShaperCamera', type=ModuleType.Detector, do_init=False, + daq_type=DAQTypesEnum.DAQ2D)]]) + start = time.time() + while time.time() - start < timeout and len(dashboard.modules_manager.modules_all) < 2: + qapp.processEvents() + return dashboard + + +def main(entry_path: Path = CALIBRATION_ENTRY): + from pymodaq_gui.qt_utils import mkQApp + from pymodaq.extensions import DAQScan + from pymodaq.utils.gui_utils.loader_utils import create_extension + + qapp = mkQApp('CalibrationEntry') + dashboard = create_dashboard_with_camera_and_shaper(qapp) + _, daq_scan = create_extension(dashboard, DAQScan) + + scan_manager = daq_scan.scan_manager + modules = scan_manager.modules_manager + for name, selected in (('detectors', ['Camera']), ('actuators', ['Shaper'])): + modules.settings[name] = dict(all_items=modules.settings[name]['all_items'], selected=selected) + scan_manager.scanner.settings.child('scan_type').setValue('Scan1D') + scan_manager.scanner.settings.child('scan_sub_type').setValue('BeamShapingCalibration') + + entry_path.unlink(missing_ok=True) + scan_manager.save_entries(entry_path) + print(f'Entry saved in {entry_path}') + + +if __name__ == '__main__': + main() + sys.exit(0) diff --git a/src/pymodaq_plugins_beam_shaping/utilities/calibrating.py b/src/pymodaq_plugins_beam_shaping/utilities/calibrating.py index f7168b2..4033871 100644 --- a/src/pymodaq_plugins_beam_shaping/utilities/calibrating.py +++ b/src/pymodaq_plugins_beam_shaping/utilities/calibrating.py @@ -32,9 +32,9 @@ logger = set_logger(get_module_name(__file__)) -# TODO: the xml file resources/holography_calibration.xml was a scan configuration of the pymodaq < 5.3 scanner manager -# (ScanManager.get_scanner_folder no longer exists). It has to be rewritten as an entry of the scan manager of 5.3 -# (folder given by ScanManager.get_entry_folder) before BeamShapingCalibration can be used again. +# Scan Manager entry (pymodaq >= 5.3) selecting the detector named Camera, the actuator named Shaper and the +# BeamShapingCalibration scanner. It is generated by scripts/make_calibration_entry.py +CALIBRATION_ENTRY = Path(__file__).parents[1].joinpath('resources', 'holography_calibration.scan') def check_monotonic(phases: np.ndarray) -> bool: @@ -160,7 +160,7 @@ def do_things_after_ui_setup(self): self.show_widgets(False) def show_widgets(self, show=True): - for widget in (self.ui.dock_command, self.ui.get_toolbar('scan_manager')): + for widget in (self.dock_command, self.get_toolbar('scan_manager')): widget.setVisible(show) def do_things_after_experiment_set(self, experiment_name: str): @@ -175,11 +175,7 @@ def do_things_after_experiment_set(self, experiment_name: str): if hasattr(self, 'scan_manager'): #could happen because base class calls do_things_after_experiment_set before # scan_manager is set - self.scan_manager.entry = 'holography_calibration' - self.scan_manager.execute_entry() - - QtWidgets.QApplication.processEvents() - + self.scan_manager.execute_entry(CALIBRATION_ENTRY) self.connect_start_stop_step() def connect_start_stop_step(self): @@ -227,6 +223,7 @@ def connect_things(self): self.scan_done_signal.connect(self.save_calibration) def save_calibration(self): + dwa_calibration = None with DataLoader(self.h5saver) as loader: try: dwa_calibration = loader.load_data_from_name_origin( @@ -265,7 +262,8 @@ def save_calibration(self): saver.add_data(where=saver.raw_group, data=dwa_calibration) except NameError: pass - self.show_calibration(show=True, calibration_dwa=dwa_calibration) + if dwa_calibration is not None: + self.show_calibration(show=True, calibration_dwa=dwa_calibration) @classmethod def get_calibration_dwa(cls) -> DataWithAxes: diff --git a/tests/test_calibration.py b/tests/test_calibration.py new file mode 100644 index 0000000..3225aaf --- /dev/null +++ b/tests/test_calibration.py @@ -0,0 +1,49 @@ +"""The SLM calibration is a DAQScan whose scan configuration comes from a Scan Manager entry""" +import numpy as np +import pytest + +from pymodaq_data import DataRaw, DataToExport + + +def test_calibration_scanner_phase_from_fringes(qtbot): + from types import SimpleNamespace + from pymodaq.utils.scanner.scanner import Scanner + import pymodaq_plugins_beam_shaping.scanners.calibration # registers the scanner # noqa: F401 + + shaper = SimpleNamespace(title='Shaper', units='') + scanner = Scanner(actuators=[shaper], selected_actuators=[shaper]) + scanner.settings.child('scan_type').setValue('Scan1D') + scanner.settings.child('scan_sub_type').setValue('BeamShapingCalibration') + calibration = scanner.scanner + assert calibration.n_steps == 256 + + data = calibration.data_actuator_at(100) # grey level on the right half of the SLM + assert data.as_grey_levels + assert set(np.unique(data[0])) == {0, 100} + + x = np.arange(1024) + phases = [] + for grey in range(0, 256, 32): + fringes = 100 + 50 * np.cos(2 * np.pi * x / 16 + grey / 255 * 3 * np.pi) + dwa = DataRaw('Camera', data=[np.tile(fringes, (50, 1))]) + phase = calibration.process_data(DataToExport('Camera', data=[dwa])).get_data_from_name('Phase') + phases.append(phase[0][0]) + assert np.unwrap(np.array(phases) - phases[0])[-1] == pytest.approx(224 / 255 * 3 * np.pi, rel=1e-2) + + +def test_calibration_extension_uses_scan_manager_entry(qtbot): + from pymodaq_gui.qt_utils import mkQApp + from pymodaq.utils.gui_utils.loader_utils import create_extension + from pymodaq_plugins_beam_shaping.scripts.make_calibration_entry import create_dashboard_with_camera_and_shaper + from pymodaq_plugins_beam_shaping.utilities.calibrating import BeamShapingCalibration, CALIBRATION_ENTRY + + assert CALIBRATION_ENTRY.is_file() + dashboard = create_dashboard_with_camera_and_shaper(mkQApp('tests')) + win, calibration = create_extension(dashboard, BeamShapingCalibration) + calibration.do_things_after_experiment_set('test') + + assert calibration.scan_manager.settings is not None + assert calibration.scanner.settings['scan_type'] == 'Scan1D' + assert calibration.scanner.settings['scan_sub_type'] == 'BeamShapingCalibration' + assert calibration.modules_manager.selected_actuators_name == ['Shaper'] + assert calibration.modules_manager.selected_detectors_name == ['Camera'] From 304e029af76b785df9b34838ee5a2bb33a7fb7c6 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 27 Oct 2026 10:07:31 +0000 Subject: [PATCH 2/2] remove h5 files created by the test run, keep the test from writing outside tmp_path Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01CAhZwmbyCSpSgfTyicUxuS --- "C:\\Data/2026/20261027/Dataset_20261027_000.h5" | Bin 7680 -> 0 bytes "C:\\Data/2026/20261027/Dataset_20261027_001.h5" | Bin 7680 -> 0 bytes "C:\\Data/2026/20261027/Dataset_20261027_002.h5" | Bin 7680 -> 0 bytes "C:\\Data/2026/20261027/Dataset_20261027_003.h5" | Bin 7680 -> 0 bytes "C:\\Data/2026/20261027/Dataset_20261027_004.h5" | Bin 7680 -> 0 bytes "C:\\Data/2026/20261027/Dataset_20261027_005.h5" | Bin 7680 -> 0 bytes tests/test_calibration.py | 3 ++- 7 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 "C:\\Data/2026/20261027/Dataset_20261027_000.h5" delete mode 100644 "C:\\Data/2026/20261027/Dataset_20261027_001.h5" delete mode 100644 "C:\\Data/2026/20261027/Dataset_20261027_002.h5" delete mode 100644 "C:\\Data/2026/20261027/Dataset_20261027_003.h5" delete mode 100644 "C:\\Data/2026/20261027/Dataset_20261027_004.h5" delete mode 100644 "C:\\Data/2026/20261027/Dataset_20261027_005.h5" diff --git "a/C:\\Data/2026/20261027/Dataset_20261027_000.h5" "b/C:\\Data/2026/20261027/Dataset_20261027_000.h5" deleted file mode 100644 index fa5626c7d63dd2e03c251aba0ae61fc7705b71b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7680 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 F_zQv5DsBJ( diff --git "a/C:\\Data/2026/20261027/Dataset_20261027_005.h5" "b/C:\\Data/2026/20261027/Dataset_20261027_005.h5" deleted file mode 100644 index d2126f921c6a97110d4e497fda31be40588f7e77..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7680 zcmeHM&2Jl35TErrPMSK!l%&v9sw{)lRJdVd;(QeZb{y9MM=`dG=*ifzn^>{E#%s5= zXgMJS2LuP;g5bgt=m`m=swXN@ArKs@N=OBSDv|yPNC?8r``Fr+*0Eh7Kt{^zdC7S5aUc2I5k42IW<)Y&80GxF2j#<$^>Hr0R zdO}Vv`bPA)=K)l3!8l+?dNmzify0UdIFkLL7Sae1-c$UMehCfSAyV~l)oQb>=d&+m z&J}7#QLk8nEReR?5P`a*1TxVMlF!z&eIcox%Q4QEYnctbT+P;txl+M$Idd(`Aup5r7Ts4T2$FHwl80+ea-v;7s%MUaKjlIigecvH)zF3WzO2??e2!dq#`WnqUZhe zW71LoM<1*&$DVZ@B#{gl$z3Q_U^tmQA3+;`!QBh{zgnBH))~+y!#Mr-kA9ZoaS4ht z4&YEQwgkx~spFu~o;pKr2xC@NM;-)lI>6xorw5!~r_(bk6(+wuAJas z#+%jTZ89=nw%ml|uKUR`uDHIrS*TqXapT7DRAGo8j(W3d9mjZz&7eRec>mWsA6ie= zhI_Wy<$OHTf=dC_risVYdPPsRXg<)XSud8YHN!2M7&CBab0QE;rB>i!7Vc;#jD|m1 z9DVuY&?hwd9x0lPCD@U2uqYI0(lt06BRM@q9V5v_bD!XQF;p`(`DvJ<`*c$3eSGBf z&*5||!mnNOW_}7D;=TJo&T{cv$4)ebqv&ifk|#@YE~Uv5Z~>;U$$Q4cNjV}0NPg?> zUoJ@4B5USFBC7Nq`B=nq@&igUnC6>|&mu2Ju@PgBiPcI;l$Yl3~qaltw6D%e7u%4W*ms&TN zt~Cm{Exax{Nq#E1ema37ad`mCpV+1Z=sjE0%U)?2Zcjt#Q~o0A#JT(581I({QjUK< z9!e%dXJC|f1G}2>c`tv}8&z~>i^rxk|8d-qOz(sGsZp%d$xm*vo<+g;T2E*EV7pk^ zq{!hkCU~#=>%`j%R-1%&pidktJKZO6mINPce}=h1aqOVic5e-!UVp`Hn7fw>tiFrU%1;Ph6|+%F|*B9^$3_lr-sCuX!0fq4!| zshfzUbL9Qv&1g&7?9%Mw^ul~_adysJCj-TwJMw@@fz53T*cPxYU|YbpfNcTW0=5Ng z3;c&I5KhOVSOU6DTfldR-Ccmyn_(wRQXv3ea!7D|{3kzLCjq{tkl^O)`N!Z@Qo(u; z34TbtI0I`W5E$2X-g^QLwFo}f-pK%~qKOf^wMWiDnn3YYkua{_@_z?!lHep4#CBXa zK7D2TEkd#BZ?Zr%773fxZ8pb&-<98b{8q!pi%JDCQ?2_q4OYVtYE;)yVHn(0tz3B_ z9a&ui5BBlyr_K5iO=ZFxTiG6~)b!eKs^z;Dw_Cp%Q8h%xA}IS_Wi)c#HCe4g?1$AG50e-NrvljyC0&#DYUOI99G*{1)k G1^xno3o3m8 diff --git a/tests/test_calibration.py b/tests/test_calibration.py index 3225aaf..cadaeef 100644 --- a/tests/test_calibration.py +++ b/tests/test_calibration.py @@ -31,7 +31,8 @@ def test_calibration_scanner_phase_from_fringes(qtbot): assert np.unwrap(np.array(phases) - phases[0])[-1] == pytest.approx(224 / 255 * 3 * np.pi, rel=1e-2) -def test_calibration_extension_uses_scan_manager_entry(qtbot): +def test_calibration_extension_uses_scan_manager_entry(qtbot, tmp_path, monkeypatch): + monkeypatch.chdir(tmp_path) # the DAQScan creates its h5 file with a relative path on Linux from pymodaq_gui.qt_utils import mkQApp from pymodaq.utils.gui_utils.loader_utils import create_extension from pymodaq_plugins_beam_shaping.scripts.make_calibration_entry import create_dashboard_with_camera_and_shaper