From b1e4ae124cf06b4c36c9db22912ebd57e58ff949 Mon Sep 17 00:00:00 2001 From: Jose Borreguero Date: Sun, 28 Apr 2024 08:32:42 -0400 Subject: [PATCH] Common entry-widget for MainGui and SFCalculatorUI * create deadtime entry widget Signed-off-by: Jose Borreguero * add default pull request template Signed-off-by: Jose Borreguero * deadtime_entry for the sf_calculator Signed-off-by: Jose Borreguero * deadtime options for the main GUI Signed-off-by: Jose Borreguero * deadtime unit tests for DeadTimeEntryPoint Signed-off-by: Jose Borreguero * deadtime unit tests for SFCalculator.apply_deadtime_update Signed-off-by: Jose Borreguero * deadtime unit tests for SFCalculator.show_dead_time_dialog Signed-off-by: Jose Borreguero * tyring different string to fool flake8 Signed-off-by: Jose Borreguero * tyring different string to fool flake8 Signed-off-by: Jose Borreguero * tyring different string to fool flake8 Signed-off-by: Jose Borreguero * test for file not in the data server Signed-off-by: Jose Borreguero * QtCore.Qt. instead of Qt. Signed-off-by: Jose Borreguero * ignore silly errors by mypy Signed-off-by: Jose Borreguero * ignore silly errors by mypy Signed-off-by: Jose Borreguero * unit tests for MainGui.apply_deadtime_update and for MainGui.show_deadtime_settings Signed-off-by: Jose Borreguero * ammend the pull-request template Signed-off-by: Jose Borreguero --------- Signed-off-by: Jose Borreguero --- .../pull_request_template.md | 8 - .github/pull_request_template.md | 37 + RefRed/configuration/loading_configuration.py | 2 +- RefRed/initialization/gui.py | 8 +- RefRed/interfaces/deadtime_entry.py | 41 + .../deadtime_settings.py} | 4 +- RefRed/interfaces/deadtime_settings.ui | 76 +- RefRed/interfaces/refred_main_interface.ui | 773 ++++++++++++++---- RefRed/interfaces/sf_calculator_interface.ui | 150 +++- RefRed/main.py | 23 + .../global_reduction_settings_handler.py | 2 +- .../sf_calculator/reduction_sf_calculator.py | 1 + RefRed/sf_calculator/sf_calculator.py | 17 +- test/test_fixtures.py | 2 + .../RefRed/interfaces/test_deadtime_entry.py | 42 + .../sf_calculator/test_sf_calculator.py | 81 +- test/unit/RefRed/test_main.py | 93 ++- 17 files changed, 1073 insertions(+), 287 deletions(-) delete mode 100644 .github/PULL_REQUEST_TEMPLATE/pull_request_template.md create mode 100644 .github/pull_request_template.md create mode 100644 RefRed/interfaces/deadtime_entry.py rename RefRed/{sf_calculator/dead_time.py => interfaces/deadtime_settings.py} (87%) create mode 100644 test/unit/RefRed/interfaces/test_deadtime_entry.py diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md deleted file mode 100644 index 32db7456..00000000 --- a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +++ /dev/null @@ -1,8 +0,0 @@ - -Fixes # - -## Description - -## Work Done - -See [CONTRIBUTING.rst](CONTRIBUTING.rst>). diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..7128c60c --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,37 @@ +# References +- EWM # + + +# Description of the changes: + + +# Manual test for the reviewer +Before running the manual tests, install the conda environment and install the source in editable mode +```bash +> conda env create --solver libmamba --name refred-dev --file ./environment.yml +> conda activate refred-dev +(refred-dev)> pip install -e . +``` +Start RefRed GUI +```bash +(refred-dev)> PYTHONPATH=$(pwd):$PYTHONPATH ./scripts/start_refred.py +``` +Or run tests +```bash +(refred-dev)> pytest test/unit/RefRed/test_main.py +``` + +# Check list for the reviewer +- [ ] I have verified the proposed changes +- [ ] Author included tests for the proposed changes +- [ ] best software practices + + [ ] clearly named variables (better to be verbose in variable names) + + [ ] code comments explaining the intent of code blocks + + [ ] new functions and classes detailed docstrings, parameters documented +- [ ] All tests are passing +- [ ] Documentation is up to date + +# Check list for the author +- [ ] I have added tests for my changes +- [ ] I have updated the documentation accordingly +- [ ] I included a link to IBM EWM Story or Defect diff --git a/RefRed/configuration/loading_configuration.py b/RefRed/configuration/loading_configuration.py index ee523faa..85f7cc31 100644 --- a/RefRed/configuration/loading_configuration.py +++ b/RefRed/configuration/loading_configuration.py @@ -180,7 +180,7 @@ def populate_main_gui_general_settings(self): o_scaling_factor_widget.set_enabled(status=scaling_factor_flag) use_dead_time = str2bool(self.getNodeValue(node_0, 'dead_time_correction')) - self.parent.ui.deadtime_checkbox.setChecked(use_dead_time) + self.parent.ui.deadtime_entry.applyCheckBox.setChecked(use_dead_time) def getMetadataObject(self, node) -> LConfigDataset: r"""Populate an instance of type LConfigDataset using the information contained in one of the diff --git a/RefRed/initialization/gui.py b/RefRed/initialization/gui.py index 5ee1eebb..b44ea5c9 100644 --- a/RefRed/initialization/gui.py +++ b/RefRed/initialization/gui.py @@ -53,13 +53,7 @@ def __init__(self, parent): # This is the angle offset box, which is no longer needed # but kept for advanced usage - self.parent.ui.groupBox_4.setVisible(False) - - # This is the TOF steps, which we also don't need at the moment - self.parent.ui.eventTofBins.setVisible(False) - self.parent.ui.label_33.setVisible(False) - self.parent.ui.label_29.setVisible(False) - + self.parent.ui.AngleOffsetGroupBox.setVisible(False) self.parent.ui.sf_button.setChecked(True) # Select the `DATA` tab as the currently active one diff --git a/RefRed/interfaces/deadtime_entry.py b/RefRed/interfaces/deadtime_entry.py new file mode 100644 index 00000000..64087062 --- /dev/null +++ b/RefRed/interfaces/deadtime_entry.py @@ -0,0 +1,41 @@ +# third party imports +from qtpy.QtWidgets import QGroupBox, QHBoxLayout, QCheckBox, QPushButton + + +class DeadTimeEntryPoint(QGroupBox): + def __init__(self, title='Dead Time Correction'): + super().__init__(title) + self.initUI() + + def initUI(self): + # Set the stylesheet for the group box to have a border + self.setStyleSheet( + "QGroupBox {" + " border: 1px solid gray;" + " border-radius: 5px;" + " margin-top: 1ex;" # space above the group box + "} " + "QGroupBox::title {" + " subcontrol-origin: margin;" + " subcontrol-position: top center;" # align the title to the center + " padding: 0 3px;" + "}" + ) + + self.applyCheckBox = QCheckBox('Apply', self) + self.applyCheckBox.stateChanged.connect(self.toggleSettingsButton) + self.settingsButton = QPushButton('Settings', self) + self.settingsButton.setEnabled(self.applyCheckBox.isChecked()) # enabled if we use the correction + + # Create a horizontal layout for the checkbox and settings button + hbox = QHBoxLayout() + hbox.addWidget(self.applyCheckBox) + hbox.addWidget(self.settingsButton) + hbox.addStretch(1) # This adds a stretchable space after the button (optional) + + # Set the layout for the group box + self.setLayout(hbox) + + def toggleSettingsButton(self, state): + # Enable the settings button if the checkbox is checked, disable otherwise + self.settingsButton.setEnabled(state) diff --git a/RefRed/sf_calculator/dead_time.py b/RefRed/interfaces/deadtime_settings.py similarity index 87% rename from RefRed/sf_calculator/dead_time.py rename to RefRed/interfaces/deadtime_settings.py index 347b1fcd..d3e31b02 100644 --- a/RefRed/sf_calculator/dead_time.py +++ b/RefRed/interfaces/deadtime_settings.py @@ -13,7 +13,7 @@ def __init__(self, parent: QWidget): self.ui = load_ui(ui_filename="deadtime_settings.ui", baseinstance=self) self.options = self.get_state_from_form() - def set_state(self, apply_correction, paralyzable, dead_time, tof_step): + def set_state(self, paralyzable, dead_time, tof_step): """ Store options and populate the form :param apply_correction: If True, dead time correction will be applied @@ -21,7 +21,6 @@ def set_state(self, apply_correction, paralyzable, dead_time, tof_step): :param dead_time: Value of the dead time in micro second :param tof_step: TOF binning in micro second """ - self.ui.apply_correction.setChecked(apply_correction) self.ui.use_paralyzable.setChecked(paralyzable) self.ui.dead_time_value.setValue(dead_time) self.ui.dead_time_tof.setValue(tof_step) @@ -32,7 +31,6 @@ def get_state_from_form(self): Read the options from the form. """ options = {} - options['apply_correction'] = self.ui.apply_correction.isChecked() options['paralyzable'] = self.ui.use_paralyzable.isChecked() options['dead_time'] = self.ui.dead_time_value.value() options['tof_step'] = self.ui.dead_time_tof.value() diff --git a/RefRed/interfaces/deadtime_settings.ui b/RefRed/interfaces/deadtime_settings.ui index 1b38743e..b4c7a9b5 100644 --- a/RefRed/interfaces/deadtime_settings.ui +++ b/RefRed/interfaces/deadtime_settings.ui @@ -9,10 +9,22 @@ 0 0 - 472 - 214 + 428 + 150 + + + 0 + 0 + + + + + 439 + 150 + + Dead Time Settings @@ -22,43 +34,6 @@ - - - - - - - - - true - - - - - - - <html><head/><body><p>Enable/Disable background subtraction</p></body></html> - - - Apply dead time correction - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - @@ -73,6 +48,12 @@ + + + 0 + 0 + + <html><head/><body><p>Use two background regions to estimate the background under the peak</p></body></html> @@ -183,8 +164,8 @@ - 130 - 16777215 + 0 + 100 @@ -203,19 +184,6 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - diff --git a/RefRed/interfaces/refred_main_interface.ui b/RefRed/interfaces/refred_main_interface.ui index 0d3f370b..985507af 100644 --- a/RefRed/interfaces/refred_main_interface.ui +++ b/RefRed/interfaces/refred_main_interface.ui @@ -38,8 +38,8 @@ 0 0 - 1544 - 1317 + 1540 + 1319 @@ -603,6 +603,15 @@ + + + + 0 + 0 + 0 + + + @@ -740,6 +749,15 @@ + + + + 0 + 0 + 0 + + + @@ -877,6 +895,15 @@ + + + + 0 + 0 + 0 + + + @@ -892,142 +919,144 @@ - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - - 0 - 0 - - - - The number of bins for the Time of Flight channels - - - TOF bins - - - - - - - - 100 - 0 - - - - The number of bins for the Time of Flight channels - - - 5 - - - 200 - - - 5 - - - 40 - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">µs</p></body></html> - - - - - - - - 70 - 0 - - - - - 70 - 16777215 - - - - Q binning - - - - - - - - 100 - 16777215 - - - - 0.01 - - - - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - ΔQ/Q - - - - - - - Use dead time correction - - - true - - - - - - - + + + + + + + TOF bins + + + + + + + 5 + + + 200 + + + 5 + + + 40 + + + + + + + µs + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Q binning + + + + + + + + 0 + 0 + + + + + 100 + 16777215 + + + + 0.01 + + + 32767 + + + + + + + ΔQ/Q + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 0 + + + + Dead Time Correction + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + - - - - + 16777215 @@ -1979,6 +2008,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 255 + 0 + + + @@ -1990,6 +2028,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 255 + 0 + + + @@ -2001,6 +2048,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 255 + 0 + + + @@ -2023,6 +2079,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 255 + 0 + + + @@ -2034,6 +2099,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 255 + 0 + + + @@ -2045,6 +2119,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 255 + 0 + + + @@ -2129,6 +2212,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 15 + 29 + + + @@ -2140,6 +2232,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 15 + 29 + + + @@ -2151,6 +2252,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 15 + 29 + + + @@ -2173,6 +2283,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 15 + 29 + + + @@ -2184,6 +2303,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 15 + 29 + + + @@ -2195,6 +2323,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 15 + 29 + + + @@ -2282,6 +2419,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 120 + 0 + + + @@ -2293,6 +2439,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 120 + 0 + + + @@ -2304,6 +2459,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 120 + 0 + + + @@ -2329,6 +2493,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 120 + 0 + + + @@ -2340,6 +2513,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 120 + 0 + + + @@ -2351,6 +2533,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 120 + 0 + + + @@ -2558,6 +2749,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 0 + 255 + + + @@ -2569,6 +2769,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 0 + 255 + + + @@ -2580,6 +2789,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 0 + 255 + + + @@ -2631,6 +2849,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 0 + 255 + + + @@ -2642,6 +2869,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 0 + 255 + + + @@ -2653,6 +2889,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 0 + 255 + + + @@ -2854,6 +3099,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 255 + 0 + + + @@ -2865,6 +3119,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 255 + 0 + + + @@ -2876,6 +3139,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 255 + 0 + + + @@ -2916,6 +3188,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 255 + 0 + + + @@ -2927,6 +3208,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 255 + 0 + + + @@ -2938,6 +3228,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 255 + 0 + + + @@ -2996,6 +3295,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 15 + 29 + + + @@ -3007,6 +3315,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 15 + 29 + + + @@ -3018,6 +3335,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 15 + 29 + + + @@ -3058,6 +3384,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 15 + 29 + + + @@ -3069,6 +3404,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 15 + 29 + + + @@ -3080,6 +3424,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 15 + 29 + + + @@ -3138,6 +3491,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 120 + 0 + + + @@ -3149,6 +3511,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 120 + 0 + + + @@ -3160,6 +3531,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 120 + 0 + + + @@ -3200,6 +3580,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 120 + 0 + + + @@ -3211,6 +3600,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 120 + 0 + + + @@ -3222,6 +3620,15 @@ p, li { white-space: pre-wrap; } + + + + 255 + 120 + 0 + + + @@ -3417,6 +3824,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 0 + 255 + + + @@ -3428,6 +3844,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 0 + 255 + + + @@ -3439,6 +3864,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 0 + 255 + + + @@ -3490,6 +3924,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 0 + 255 + + + @@ -3501,6 +3944,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 0 + 255 + + + @@ -3512,6 +3964,15 @@ p, li { white-space: pre-wrap; } + + + + 0 + 0 + 255 + + + @@ -3850,12 +4311,12 @@ p, li { white-space: pre-wrap; } true - - 50 - 25 + + 50 + false @@ -4882,7 +5343,7 @@ p, li { white-space: pre-wrap; } 0 0 1560 - 28 + 22 @@ -5208,6 +5669,12 @@ p, li { white-space: pre-wrap; } QTableWidget
RefRed/interfaces/mytablewidget.h
+ + DeadTimeEntryPoint + QGroupBox +
RefRed/interfaces/deadtime_entry.h
+ 1 +
@@ -5325,22 +5792,6 @@ p, li { white-space: pre-wrap; } - - qStep - textChanged(QString) - MainWindow - widget_modified() - - - 238 - 661 - - - 778 - 586 - - - angleOffsetValue textChanged(QString) @@ -5549,22 +6000,6 @@ p, li { white-space: pre-wrap; } - - eventTofBins - valueChanged(QString) - MainWindow - widget_modified() - - - 238 - 586 - - - 778 - 586 - - - angleOffsetError textChanged(QString) diff --git a/RefRed/interfaces/sf_calculator_interface.ui b/RefRed/interfaces/sf_calculator_interface.ui index ac5350ea..0f28ef2c 100644 --- a/RefRed/interfaces/sf_calculator_interface.ui +++ b/RefRed/interfaces/sf_calculator_interface.ui @@ -25,8 +25,8 @@ 0 0 - 1191 - 960 + 1187 + 914 @@ -178,6 +178,15 @@ + + + + 170 + 85 + 0 + + + @@ -189,6 +198,15 @@ + + + + 170 + 85 + 0 + + + @@ -200,6 +218,15 @@ + + + + 170 + 85 + 0 + + + @@ -265,6 +292,15 @@ + + + + 0 + 0 + 127 + + + @@ -276,6 +312,15 @@ + + + + 0 + 0 + 127 + + + @@ -287,6 +332,15 @@ + + + + 0 + 0 + 127 + + + @@ -352,6 +406,15 @@ + + + + 0 + 0 + 127 + + + @@ -363,6 +426,15 @@ + + + + 0 + 0 + 127 + + + @@ -374,6 +446,15 @@ + + + + 0 + 0 + 127 + + + @@ -439,6 +520,15 @@ + + + + 170 + 85 + 0 + + + @@ -450,6 +540,15 @@ + + + + 170 + 85 + 0 + + + @@ -461,6 +560,15 @@ + + + + 170 + 85 + 0 + + + @@ -780,13 +888,15 @@
- - - Dead time + + + + 0 + 0 + - - - :/General/cogwheel.png:/General/cogwheel.png + + Dead Time Correction @@ -1029,7 +1139,7 @@ 0 0 1221 - 28 + 22 @@ -1107,6 +1217,12 @@
RefRed/interfaces/mplwidgets.h
1 + + DeadTimeEntryPoint + QGroupBox +
RefRed/interfaces/deadtime_entry.h
+ 1 +
@@ -1464,22 +1580,6 @@ - - dead_time_button - clicked() - SFCalculatorInterface - show_dead_time_dialog() - - - 1010 - 457 - - - 610 - 387 - - - runSequenceLineEditEvent() diff --git a/RefRed/main.py b/RefRed/main.py index 1321156d..80aa67ac 100644 --- a/RefRed/main.py +++ b/RefRed/main.py @@ -25,6 +25,7 @@ from RefRed.initialization.gui import Gui as InitializeGui from RefRed.initialization.gui_connections import GuiConnections as MakeGuiConnections from RefRed.interfaces import load_ui +from RefRed.interfaces.deadtime_settings import DeadTimeSettingsView from RefRed.load_reduced_data_set.load_reduced_data_set_handler import LoadReducedDataSetHandler from RefRed.load_reduced_data_set.reduced_ascii_data_right_click import ReducedAsciiDataRightClick from RefRed.metadata.metadata_finder import MetadataFinder @@ -147,6 +148,11 @@ def __init__(self, argv=[], parent=None): backgrounds_settings["norm"].signal_first_background.connect(self.norm_back_checkbox) backgrounds_settings["norm"].signal_second_background.connect(self.norm_back_checkbox) + # deadtime_entry connections + self.deadtime_options = {"apply_deadtime": True, "paralyzable": True, "dead_time": 4.2, "tof_step": 150} + self.ui.deadtime_entry.applyCheckBox.stateChanged.connect(self.apply_deadtime_update) + self.ui.deadtime_entry.settingsButton.clicked.connect(self.show_deadtime_settings) + # home button of plots def home_clicked_yi_plot(self): HomePlotButtonClicked(parent=self, plot_type='yi') @@ -652,5 +658,22 @@ def settings_editor(self): o_settings_editor = SettingsEditor(parent=self) o_settings_editor.show() + def apply_deadtime_update(self): + r"""Update option apply_deadtime of attribute deadtime_options when the associated checkbox + changes its state""" + apply_deadtime = self.ui.deadtime_entry.applyCheckBox.isChecked() + if self.deadtime_options["apply_deadtime"] != apply_deadtime: + self.deadtime_options["apply_deadtime"] = apply_deadtime + + def show_deadtime_settings(self): + r"""Show the dialog for dead-time options. Update attribue deadtime options upon closing the dialog.""" + dt_settings = DeadTimeSettingsView(parent=self) + dt_settings.set_state( + self.deadtime_options["paralyzable"], self.deadtime_options["dead_time"], self.deadtime_options["tof_step"] + ) + dt_settings.exec_() + for option in ["paralyzable", "dead_time", "tof_step"]: + self.deadtime_options[option] = dt_settings.options[option] + def closeEvent(self, event=None): SaveUserConfiguration(parent=self) diff --git a/RefRed/reduction/global_reduction_settings_handler.py b/RefRed/reduction/global_reduction_settings_handler.py index a20bac74..194ac94a 100644 --- a/RefRed/reduction/global_reduction_settings_handler.py +++ b/RefRed/reduction/global_reduction_settings_handler.py @@ -24,7 +24,7 @@ def retrieve(self): self.angle_offset_error = self.get_angle_offset_error() self.tof_steps = self.get_tof_steps() self.apply_normalization = self.parent.ui.useNormalizationFlag.isChecked() - self.dead_time = self.parent.ui.deadtime_checkbox.isChecked() + self.dead_time = self.parent.ui.deadtime_entry.applyCheckBox.isChecked() def to_dict(self): """ diff --git a/RefRed/sf_calculator/reduction_sf_calculator.py b/RefRed/sf_calculator/reduction_sf_calculator.py index c5b7aacd..4a09bf7b 100644 --- a/RefRed/sf_calculator/reduction_sf_calculator.py +++ b/RefRed/sf_calculator/reduction_sf_calculator.py @@ -223,6 +223,7 @@ def generate_script( r")", ] script += "\n".join(mantid_call) + "\n" + return script def refreshOutputFileContainPreview(self, output_file_name): diff --git a/RefRed/sf_calculator/sf_calculator.py b/RefRed/sf_calculator/sf_calculator.py index 83525550..e9e42651 100644 --- a/RefRed/sf_calculator/sf_calculator.py +++ b/RefRed/sf_calculator/sf_calculator.py @@ -14,7 +14,7 @@ from RefRed import ORGANIZATION, APPNAME import RefRed.colors from RefRed.interfaces import load_ui -from RefRed.sf_calculator.dead_time import DeadTimeSettingsView +from RefRed.interfaces.deadtime_settings import DeadTimeSettingsView from RefRed.sf_calculator.fill_sf_gui_table import FillSFGuiTable from RefRed.sf_calculator.incident_medium_list_editor import IncidentMediumListEditor from RefRed.sf_calculator.load_and_sort_nxsdata_for_sf_calculator import ( @@ -118,6 +118,8 @@ def initConnections(self): self.yt_plot.toolbar.homeClicked.connect(self.homeYtPlot) self.yi_plot.toolbar.homeClicked.connect(self.homeYiPlot) self.forceSortByMetaData.clicked.connect(self.forceSrotTableByMetaData) + self.deadtime_entry.applyCheckBox.stateChanged.connect(self.apply_deadtime_update) + self.deadtime_entry.settingsButton.clicked.connect(self.show_dead_time_dialog) def initGui(self): palette = QtGui.QPalette() @@ -135,6 +137,8 @@ def initGui(self): # The file menu is not currently used, since we can't load or save # configurations. Just remove the menu by giving it an empty title. self.menuFile.setTitle("") + # deadtime correction + self.ui.deadtime_entry.applyCheckBox.setChecked(self.apply_deadtime) def homeYtPlot(self): [xmin, xmax, ymin, ymax] = self.yt_plot.toolbar.home_settings @@ -1038,18 +1042,21 @@ def tof_validation(self, tof_auto_switch, tof1, tof2, with_plot_update=True): self.TOFmanualToValue.setText("%.2f" % tof2) self.manualTOFtextFieldValidated(with_plot_update=with_plot_update) + def apply_deadtime_update(self): + r"""Update attribute apply_deadtime when the associated checkbox changes its state""" + apply_deadtime = self.ui.deadtime_entry.applyCheckBox.isChecked() + if self.apply_deadtime != apply_deadtime: + self.apply_deadtime = apply_deadtime + def show_dead_time_dialog(self): """ Pop up dialog for dead time options """ dt_settings = DeadTimeSettingsView(parent=self) - dt_settings.set_state( - self.apply_deadtime, self.paralyzable_deadtime, self.deadtime_value, self.deadtime_tof_step - ) + dt_settings.set_state(self.paralyzable_deadtime, self.deadtime_value, self.deadtime_tof_step) dt_settings.exec_() # Store dead time options - self.apply_deadtime = dt_settings.options['apply_correction'] self.paralyzable_deadtime = dt_settings.options['paralyzable'] self.deadtime_value = dt_settings.options['dead_time'] self.deadtime_tof_step = dt_settings.options['tof_step'] diff --git a/test/test_fixtures.py b/test/test_fixtures.py index 2b16f54f..5bca16d3 100644 --- a/test/test_fixtures.py +++ b/test/test_fixtures.py @@ -7,6 +7,8 @@ def test_data_server(data_server): assert Path(data_server.path_to('easy_data_set.csv')).exists() + with pytest.raises(FileNotFoundError): + Path(data_server.path_to('impossibe_to_find.dat')).exists() if __name__ == '__main__': diff --git a/test/unit/RefRed/interfaces/test_deadtime_entry.py b/test/unit/RefRed/interfaces/test_deadtime_entry.py new file mode 100644 index 00000000..efb34eeb --- /dev/null +++ b/test/unit/RefRed/interfaces/test_deadtime_entry.py @@ -0,0 +1,42 @@ +# third party imports +import pytest +from qtpy.QtCore import Qt # type: ignore + +# RefRed imports +from RefRed.interfaces.deadtime_entry import DeadTimeEntryPoint # Make sure to import your class correctly + + +@pytest.fixture +def dead_time_entry_point(qtbot): + widget = DeadTimeEntryPoint() + qtbot.addWidget(widget) + return widget + + +def test_initial_state(dead_time_entry_point): + assert not dead_time_entry_point.applyCheckBox.isChecked() + assert not dead_time_entry_point.settingsButton.isEnabled() + + +def test_checkbox_interaction(dead_time_entry_point, qtbot): + # Simulate checking the checkbox + qtbot.mouseClick(dead_time_entry_point.applyCheckBox, Qt.LeftButton) + # Test if the checkbox is checked + assert dead_time_entry_point.applyCheckBox.isChecked() + # Test if the settings button is now enabled + assert dead_time_entry_point.settingsButton.isEnabled() + + +def test_uncheck_checkbox(dead_time_entry_point, qtbot): + # First, check the checkbox + qtbot.mouseClick(dead_time_entry_point.applyCheckBox, Qt.LeftButton) + # Now, uncheck it + qtbot.mouseClick(dead_time_entry_point.applyCheckBox, Qt.LeftButton) + # Test if the checkbox is unchecked + assert not dead_time_entry_point.applyCheckBox.isChecked() + # Test if the settings button is now disabled + assert not dead_time_entry_point.settingsButton.isEnabled() + + +if __name__ == '__main__': + pytest.main([__file__]) diff --git a/test/unit/RefRed/sf_calculator/test_sf_calculator.py b/test/unit/RefRed/sf_calculator/test_sf_calculator.py index d9fc92d7..2d431820 100644 --- a/test/unit/RefRed/sf_calculator/test_sf_calculator.py +++ b/test/unit/RefRed/sf_calculator/test_sf_calculator.py @@ -1,12 +1,83 @@ +# third party imports import pytest +from qtpy import QtCore, QtWidgets # type: ignore +# RefRed imports +from RefRed.sf_calculator.sf_calculator import SFCalculator -def test_sf_calculator(): - """Test class SFCalculator - Note: this is a pytest-pyqt test - """ - return +class TestSFCalculator: + @pytest.fixture(autouse=True) + def setup_class(self, qtbot): + self.app = SFCalculator() + qtbot.addWidget(self.app) + + def test_apply_deadtime_update_checked(self, qtbot): + """Test the apply_deadtime_update function when the checkbox is checked.""" + # Ensure checkbox starts unchecked + self.app.ui.deadtime_entry.applyCheckBox.setChecked(False) + # Simulate checking the checkbox + qtbot.mouseClick(self.app.ui.deadtime_entry.applyCheckBox, QtCore.Qt.LeftButton) + # Assert that the apply_deadtime attribute is now True + assert self.app.apply_deadtime is True + + def test_apply_deadtime_update_unchecked(self, qtbot): + """Test the apply_deadtime_update function when the checkbox is unchecked.""" + # Ensure checkbox starts checked + self.app.ui.deadtime_entry.applyCheckBox.setChecked(True) + # Simulate unchecking the checkbox + qtbot.mouseClick(self.app.ui.deadtime_entry.applyCheckBox, QtCore.Qt.LeftButton) + # Assert that the apply_deadtime attribute is now False + assert self.app.apply_deadtime is False + + def test_show_dead_time_dialog_default_values(self, monkeypatch): + calculator = self.app # endow closure environment to MockDeadTimeSettingsView + + class MockDeadTimeSettingsView: + def __init__(self, parent=None): + r"""Mocking the DeadTimeSettingsView to return default values without user interaction""" + self.options = { + 'paralyzable': calculator.paralyzable_deadtime, + 'dead_time': calculator.deadtime_value, + 'tof_step': calculator.deadtime_tof_step, + } + + def exec_(self): + return QtWidgets.QDialog.Accepted + + def set_state(self, paralyzable, dead_time, tof_step): + self.options['paralyzable'] = paralyzable + self.options['dead_time'] = dead_time + self.options['tof_step'] = tof_step + + monkeypatch.setattr("RefRed.sf_calculator.sf_calculator.DeadTimeSettingsView", MockDeadTimeSettingsView) + self.app.show_dead_time_dialog() + assert self.app.paralyzable_deadtime is True + assert self.app.deadtime_value == 4.2 + assert self.app.deadtime_tof_step == 150 + + def test_show_dead_time_dialog_updated_values(self, monkeypatch): + # endow closure environment to MockDeadTimeSettingsView + new_paralyzable = False + new_dead_time = 5.0 + new_tof_step = 200 + + class MockDeadTimeSettingsView: + def __init__(self, parent=None): + r"""Mocking the DeadTimeSettingsView to return values without user interaction""" + self.options = {'paralyzable': new_paralyzable, 'dead_time': new_dead_time, 'tof_step': new_tof_step} + + def exec_(self): + return QtWidgets.QDialog.Accepted + + def set_state(self, paralyzable, dead_time, tof_step): + pass + + monkeypatch.setattr("RefRed.sf_calculator.sf_calculator.DeadTimeSettingsView", MockDeadTimeSettingsView) + self.app.show_dead_time_dialog() + assert self.app.paralyzable_deadtime == new_paralyzable + assert self.app.deadtime_value == new_dead_time + assert self.app.deadtime_tof_step == new_tof_step if __name__ == '__main__': diff --git a/test/unit/RefRed/test_main.py b/test/unit/RefRed/test_main.py index 8b6d71ba..c66f906a 100644 --- a/test/unit/RefRed/test_main.py +++ b/test/unit/RefRed/test_main.py @@ -1,21 +1,25 @@ -# third-party imports +# standard imports import unittest.mock as mock + +# third-party imports import pytest +from qtpy import QtCore, QtWidgets # type: ignore # RefRed imports from RefRed.main import MainGui class TestMainGui: - def test_init(self, qtbot): - window_main = MainGui() - qtbot.addWidget(window_main) - assert "Liquids Reflectometer Reduction" in window_main.windowTitle() + @pytest.fixture(autouse=True) + def setup_class(self, qtbot): + self.app = MainGui() + qtbot.addWidget(self.app) + + def test_init(self): + assert "Liquids Reflectometer Reduction" in self.app.windowTitle() - def test_run_reduction_button(self, qtbot): - window_main = MainGui() - qtbot.addWidget(window_main) - assert window_main.run_reduction_button() is None + def test_run_reduction_button(self): + assert self.app.run_reduction_button() is None @mock.patch('RefRed.main.MainGui.file_loaded_signal') @mock.patch('RefRed.main.InitializeGui') @@ -42,6 +46,77 @@ def test_load_configuration( mainGui.load_configuration() mockLoadConfiguration.assert_called() + def test_apply_deadtime_update_checked(self, qtbot): + """Test the apply_deadtime_update function when the checkbox is checked.""" + # Ensure checkbox starts unchecked + self.app.ui.deadtime_entry.applyCheckBox.setChecked(False) + # Simulate checking the checkbox + qtbot.mouseClick(self.app.ui.deadtime_entry.applyCheckBox, QtCore.Qt.LeftButton) + # Assert that the apply_deadtime attribute is now True + assert self.app.deadtime_options["apply_deadtime"] is True + + def test_apply_deadtime_update_unchecked(self, qtbot): + """Test the apply_deadtime_update function when the checkbox is unchecked.""" + # Ensure checkbox starts checked + self.app.ui.deadtime_entry.applyCheckBox.setChecked(True) + # Simulate unchecking the checkbox + qtbot.mouseClick(self.app.ui.deadtime_entry.applyCheckBox, QtCore.Qt.LeftButton) + # Assert that the apply_deadtime attribute is now False + assert self.app.deadtime_options["apply_deadtime"] is False + + def test_show_deadtime_settings_default_values(self, monkeypatch): + main_gui = self.app # endow closure environment to MockDeadTimeSettingsView + + class MockDeadTimeSettingsView: + def __init__(self, parent=None): + r"""Mocking the DeadTimeSettingsView to return default values without user interaction""" + self.options = { + 'paralyzable': main_gui.deadtime_options["paralyzable"], + 'dead_time': main_gui.deadtime_options["dead_time"], + 'tof_step': main_gui.deadtime_options["tof_step"], + } + + def exec_(self): + return QtWidgets.QDialog.Accepted + + def set_state(self, paralyzable, dead_time, tof_step): + self.options['paralyzable'] = paralyzable + self.options['dead_time'] = dead_time + self.options['tof_step'] = tof_step + + monkeypatch.setattr("RefRed.main.DeadTimeSettingsView", MockDeadTimeSettingsView) + self.app.show_deadtime_settings() + assert self.app.deadtime_options["paralyzable"] is True + assert self.app.deadtime_options["dead_time"] == 4.2 + assert self.app.deadtime_options["tof_step"] == 150 + + def test_show_deadtime_settings_updated_values(self, monkeypatch): + # endow closure environment to MockDeadTimeSettingsView + new_paralyzable = False + new_dead_time = 5.0 + new_tof_step = 200 + + class MockDeadTimeSettingsView: + def __init__(self, parent=None): + r"""Mocking the DeadTimeSettingsView to return default values without user interaction""" + self.options = { + 'paralyzable': new_paralyzable, + 'dead_time': new_dead_time, + 'tof_step': new_tof_step, + } + + def exec_(self): + return QtWidgets.QDialog.Accepted + + def set_state(self, paralyzable, dead_time, tof_step): + pass + + monkeypatch.setattr("RefRed.main.DeadTimeSettingsView", MockDeadTimeSettingsView) + self.app.show_deadtime_settings() + assert self.app.deadtime_options["paralyzable"] == new_paralyzable + assert self.app.deadtime_options["dead_time"] == new_dead_time + assert self.app.deadtime_options["tof_step"] == new_tof_step + if __name__ == '__main__': pytest.main([__file__])