From f6b1ab75d5dfd2bd7a2d73f6d920525313c25a1a Mon Sep 17 00:00:00 2001 From: larsevj Date: Thu, 5 Sep 2024 14:39:22 +0200 Subject: [PATCH] Improve experiment name validation --- .../ertwidgets/create_experiment_dialog.py | 29 ++++++---- .../simulation/ensemble_experiment_panel.py | 9 +++- .../gui/simulation/ensemble_smoother_panel.py | 13 +++-- .../iterated_ensemble_smoother_panel.py | 14 +++-- .../multiple_data_assimilation_panel.py | 25 +++++---- tests/unit_tests/gui/conftest.py | 2 +- tests/unit_tests/gui/test_main_window.py | 53 ++++++++++++++++++- 7 files changed, 114 insertions(+), 31 deletions(-) diff --git a/src/ert/gui/ertwidgets/create_experiment_dialog.py b/src/ert/gui/ertwidgets/create_experiment_dialog.py index 22a58da0794..789e715ee3e 100644 --- a/src/ert/gui/ertwidgets/create_experiment_dialog.py +++ b/src/ert/gui/ertwidgets/create_experiment_dialog.py @@ -9,13 +9,15 @@ QDialogButtonBox, QGridLayout, QLabel, - QLineEdit, QWidget, ) from ert.gui.ertnotifier import ErtNotifier from ert.gui.ertwidgets import StringBox, TextModel -from ert.validation.proper_name_argument import ExperimentValidation +from ert.validation.proper_name_argument import ( + ExperimentValidation, + ProperNameArgument, +) class CreateExperimentDialog(QDialog): @@ -41,9 +43,10 @@ def __init__( self._experiment_edit.setValidator(ExperimentValidation(notifier.storage)) ensemble_label = QLabel("Ensemble name:") - self._ensemble_edit = QLineEdit() - self._ensemble_edit.setMinimumWidth(200) - self._ensemble_edit.setPlaceholderText("My ensemble") + self._ensemble_edit = StringBox( + TextModel(""), placeholder_text="My_ensemble", minimum_width=200 + ) + self._ensemble_edit.setValidator(ProperNameArgument()) buttons = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, @@ -64,10 +67,7 @@ def __init__( self._ok_button.setEnabled(False) def enableOkButton() -> None: - self._ok_button.setEnabled( - len(self._experiment_edit.text()) != 0 - and len(self._ensemble_edit.text()) != 0 - ) + self._ok_button.setEnabled(self.isConfigurationValid()) self._experiment_edit.textChanged.connect(enableOkButton) self._ensemble_edit.textChanged.connect(enableOkButton) @@ -80,6 +80,14 @@ def enableOkButton() -> None: self.setLayout(layout) + self._experiment_edit.getValidationSupport().validationChanged.connect( + enableOkButton + ) + + self._ensemble_edit.getValidationSupport().validationChanged.connect( + enableOkButton + ) + self._experiment_edit.setFocus() @property @@ -89,3 +97,6 @@ def experiment_name(self) -> str: @property def ensemble_name(self) -> str: return self._ensemble_edit.text() + + def isConfigurationValid(self) -> bool: + return self._experiment_edit.isValid() and self._ensemble_edit.isValid() diff --git a/src/ert/gui/simulation/ensemble_experiment_panel.py b/src/ert/gui/simulation/ensemble_experiment_panel.py index cc9df95edb5..622b7aaaccf 100644 --- a/src/ert/gui/simulation/ensemble_experiment_panel.py +++ b/src/ert/gui/simulation/ensemble_experiment_panel.py @@ -14,7 +14,10 @@ from ert.mode_definitions import ENSEMBLE_EXPERIMENT_MODE from ert.run_models import EnsembleExperiment from ert.validation import RangeStringArgument -from ert.validation.proper_name_argument import ExperimentValidation +from ert.validation.proper_name_argument import ( + ExperimentValidation, + ProperNameArgument, +) from .experiment_config_panel import ExperimentConfigPanel @@ -46,14 +49,16 @@ def __init__(self, ensemble_size: int, run_path: str, notifier: ErtNotifier): ), ) self._experiment_name_field.setMinimumWidth(250) - layout.addRow("Experiment name:", self._experiment_name_field) self._experiment_name_field.setValidator( ExperimentValidation(self.notifier.storage) ) + self._experiment_name_field.setObjectName("experiment_field") + layout.addRow("Experiment name:", self._experiment_name_field) self._ensemble_name_field = StringBox( TextModel(""), placeholder_text="ensemble" ) + self._ensemble_name_field.setValidator(ProperNameArgument()) self._ensemble_name_field.setMinimumWidth(250) layout.addRow("Ensemble name:", self._ensemble_name_field) diff --git a/src/ert/gui/simulation/ensemble_smoother_panel.py b/src/ert/gui/simulation/ensemble_smoother_panel.py index 6c08008637c..8cabfd1daee 100644 --- a/src/ert/gui/simulation/ensemble_smoother_panel.py +++ b/src/ert/gui/simulation/ensemble_smoother_panel.py @@ -55,10 +55,11 @@ def __init__( ), ) self._experiment_name_field.setMinimumWidth(250) - layout.addRow("Experiment name:", self._experiment_name_field) self._experiment_name_field.setValidator( ExperimentValidation(self.notifier.storage) ) + self._experiment_name_field.setObjectName("experiment_field") + layout.addRow("Experiment name:", self._experiment_name_field) runpath_label = CopyableLabel(text=run_path) layout.addRow("Runpath:", runpath_label) @@ -90,10 +91,13 @@ def __init__( self.setLayout(layout) - self._ensemble_format_field.getValidationSupport().validationChanged.connect( # noqa + self._experiment_name_field.getValidationSupport().validationChanged.connect( + self.simulationConfigurationChanged + ) + self._ensemble_format_field.getValidationSupport().validationChanged.connect( self.simulationConfigurationChanged ) - self._active_realizations_field.getValidationSupport().validationChanged.connect( # noqa + self._active_realizations_field.getValidationSupport().validationChanged.connect( self.simulationConfigurationChanged ) @@ -111,7 +115,8 @@ def _update_experiment_name_placeholder(self) -> None: def isConfigurationValid(self) -> bool: return ( - self._ensemble_format_field.isValid() + self._experiment_name_field.isValid() + and self._ensemble_format_field.isValid() and self._active_realizations_field.isValid() ) diff --git a/src/ert/gui/simulation/iterated_ensemble_smoother_panel.py b/src/ert/gui/simulation/iterated_ensemble_smoother_panel.py index 332f4016ab4..9d4e1138cb4 100644 --- a/src/ert/gui/simulation/iterated_ensemble_smoother_panel.py +++ b/src/ert/gui/simulation/iterated_ensemble_smoother_panel.py @@ -47,6 +47,7 @@ def __init__( ExperimentConfigPanel.__init__(self, IteratedEnsembleSmoother) self.analysis_config = analysis_config layout = QFormLayout() + self.setObjectName("iterated_ensemble_smoother_panel") self._experiment_name_field = StringBox( TextModel(""), @@ -55,10 +56,11 @@ def __init__( ), ) self._experiment_name_field.setMinimumWidth(250) - layout.addRow("Experiment name:", self._experiment_name_field) self._experiment_name_field.setValidator( ExperimentValidation(self.notifier.storage) ) + self._experiment_name_field.setObjectName("experiment_field") + layout.addRow("Experiment name:", self._experiment_name_field) runpath_label = CopyableLabel(text=run_path) layout.addRow("Runpath:", runpath_label) @@ -103,10 +105,13 @@ def __init__( self._active_realizations_field.setValidator(RangeStringArgument(ensemble_size)) layout.addRow("Active realizations", self._active_realizations_field) - self._iterated_target_ensemble_format_field.getValidationSupport().validationChanged.connect( # noqa + self._experiment_name_field.getValidationSupport().validationChanged.connect( + self.simulationConfigurationChanged + ) + self._iterated_target_ensemble_format_field.getValidationSupport().validationChanged.connect( self.simulationConfigurationChanged ) - self._active_realizations_field.getValidationSupport().validationChanged.connect( # noqa + self._active_realizations_field.getValidationSupport().validationChanged.connect( self.simulationConfigurationChanged ) self.setLayout(layout) @@ -127,7 +132,8 @@ def _update_experiment_name_placeholder(self) -> None: def isConfigurationValid(self) -> bool: return ( - self._iterated_target_ensemble_format_field.isValid() + self._experiment_name_field.isValid() + and self._iterated_target_ensemble_format_field.isValid() and self._active_realizations_field.isValid() ) diff --git a/src/ert/gui/simulation/multiple_data_assimilation_panel.py b/src/ert/gui/simulation/multiple_data_assimilation_panel.py index f7b3c0beba4..d9a154fe5fa 100644 --- a/src/ert/gui/simulation/multiple_data_assimilation_panel.py +++ b/src/ert/gui/simulation/multiple_data_assimilation_panel.py @@ -66,10 +66,12 @@ def __init__( ), ) self._experiment_name_field.setMinimumWidth(250) - layout.addRow("Experiment name:", self._experiment_name_field) self._experiment_name_field.setValidator( ExperimentValidation(self.notifier.storage) ) + self._experiment_name_field.setObjectName("experiment_field") + layout.addRow("Experiment name:", self._experiment_name_field) + runpath_label = CopyableLabel(text=run_path) layout.addRow("Runpath:", runpath_label) @@ -119,13 +121,16 @@ def __init__( self._ensemble_selector.currentIndexChanged.connect(self.update_experiment_name) layout.addRow("Restart from:", self._ensemble_selector) - self._target_ensemble_format_field.getValidationSupport().validationChanged.connect( # noqa + self._experiment_name_field.getValidationSupport().validationChanged.connect( + self.simulationConfigurationChanged + ) + self._target_ensemble_format_field.getValidationSupport().validationChanged.connect( self.simulationConfigurationChanged ) - self._active_realizations_field.getValidationSupport().validationChanged.connect( # noqa + self._active_realizations_field.getValidationSupport().validationChanged.connect( self.simulationConfigurationChanged ) - self._relative_iteration_weights_box.getValidationSupport().validationChanged.connect( # noqa + self._relative_iteration_weights_box.getValidationSupport().validationChanged.connect( self.simulationConfigurationChanged ) @@ -158,15 +163,14 @@ def update_experiment_name(self) -> None: @Slot(bool) def update_experiment_edit(self, checked: bool) -> None: + self._experiment_name_field.clear() + self._experiment_name_field.enable_validation(not checked) + self._experiment_name_field.setEnabled(not checked) if checked: self._experiment_name_field.setText( self._ensemble_selector.selected_ensemble.experiment.name ) - else: - self._experiment_name_field.clear() - self._experiment_name_field.enable_validation(not checked) - self._experiment_name_field.setEnabled(not checked) self._evaluate_weights_box_enabled() def _evaluate_weights_box_enabled(self) -> None: @@ -219,7 +223,7 @@ def updateVisualizationOfNormalizedWeights() -> None: else: normalized_weights_model.setValue("The weights are invalid!") - self._relative_iteration_weights_box.getValidationSupport().validationChanged.connect( # noqa + self._relative_iteration_weights_box.getValidationSupport().validationChanged.connect( updateVisualizationOfNormalizedWeights ) @@ -227,7 +231,8 @@ def updateVisualizationOfNormalizedWeights() -> None: def isConfigurationValid(self) -> bool: return ( - self._target_ensemble_format_field.isValid() + self._experiment_name_field.isValid() + and self._target_ensemble_format_field.isValid() and self._active_realizations_field.isValid() and self._relative_iteration_weights_box.isValid() and self.weights_valid diff --git a/tests/unit_tests/gui/conftest.py b/tests/unit_tests/gui/conftest.py index 17eafc7a0c6..c8614827bb1 100644 --- a/tests/unit_tests/gui/conftest.py +++ b/tests/unit_tests/gui/conftest.py @@ -529,7 +529,7 @@ def handle_popup_dialog(): def add_experiment_manually( - qtbot, gui, experiment_name="My experiment", ensemble_name="default" + qtbot, gui, experiment_name="My_experiment", ensemble_name="default" ): manage_tool = gui.tools["Manage experiments"] manage_tool.trigger() diff --git a/tests/unit_tests/gui/test_main_window.py b/tests/unit_tests/gui/test_main_window.py index 3ccc1adc01d..5ed85d787b1 100644 --- a/tests/unit_tests/gui/test_main_window.py +++ b/tests/unit_tests/gui/test_main_window.py @@ -25,6 +25,7 @@ import ert.gui from ert.config import ErtConfig from ert.gui.about_dialog import AboutDialog +from ert.gui.ertwidgets import StringBox from ert.gui.ertwidgets.analysismodulevariablespanel import AnalysisModuleVariablesPanel from ert.gui.ertwidgets.create_experiment_dialog import CreateExperimentDialog from ert.gui.ertwidgets.ensembleselector import EnsembleSelector @@ -42,7 +43,13 @@ ) from ert.gui.tools.plot.plot_window import PlotApi, PlotWindow from ert.plugins import ErtPluginManager -from ert.run_models import SingleTestRun +from ert.run_models import ( + EnsembleExperiment, + EnsembleSmoother, + IteratedEnsembleSmoother, + MultipleDataAssimilation, + SingleTestRun, +) from ert.services import StorageService from .conftest import ( @@ -434,8 +441,19 @@ def test_that_the_manage_experiments_tool_can_be_used( def handle_add_dialog(): dialog = wait_for_child(current_tab, qtbot, CreateExperimentDialog) + + dialog._experiment_edit.setText("es_mda") + assert not dialog._ok_button.isEnabled() + dialog._experiment_edit.setText(" @not_v alid") + assert not dialog._ok_button.isEnabled() dialog._experiment_edit.setText("my-experiment") + assert dialog._ok_button.isEnabled() + + dialog._ensemble_edit.setText(" @not_v alid") + assert not dialog._ok_button.isEnabled() dialog._ensemble_edit.setText("_new_ensemble_") + assert dialog._ok_button.isEnabled() + qtbot.mouseClick(dialog._ok_button, Qt.MouseButton.LeftButton) QTimer.singleShot(1000, handle_add_dialog) @@ -682,3 +700,36 @@ def test_help_menu(qtbot): qtbot.mouseClick( get_child(about_dialog, QPushButton, name="close_button"), Qt.LeftButton ) + + +def test_validation_of_experiment_names_in_run_models( + ensemble_experiment_has_run_no_failure, qtbot +): + gui = ensemble_experiment_has_run_no_failure + experiment_panel = get_child(gui, ExperimentPanel) + experiment_types = get_child(experiment_panel, QComboBox, name="experiment_type") + run_experiment = get_child(experiment_panel, QWidget, name="run_experiment") + + experiment_types_to_test = ( + (EnsembleExperiment.name(), "Ensemble_experiment_panel"), + (EnsembleSmoother.name(), "ensemble_smoother_panel"), + (MultipleDataAssimilation.name(), "ES_MDA_panel"), + (IteratedEnsembleSmoother.name(), "iterated_ensemble_smoother_panel"), + ) + for exp_type, panel_name in experiment_types_to_test: + print(f"{exp_type}") + experiment_types.setCurrentText(exp_type) + + experiment_config_panel = get_child(gui, QWidget, name=panel_name) + experiment_field = get_child( + experiment_config_panel, StringBox, name="experiment_field" + ) + print(f"{experiment_field.get_text=}") + experiment_field.setText(" @not val id") + assert not run_experiment.isEnabled() + + experiment_field.setText("valid_") + assert run_experiment.isEnabled() + + experiment_field.setText("ensemble_experiment") + assert not run_experiment.isEnabled()