diff --git a/src/ert/gui/main.py b/src/ert/gui/main.py index 650af23fd27..48cc56c4394 100755 --- a/src/ert/gui/main.py +++ b/src/ert/gui/main.py @@ -3,7 +3,6 @@ import logging import os import sys -import webbrowser from signal import SIG_DFL, SIGINT, signal from typing import Optional, Tuple @@ -14,7 +13,7 @@ from collections import Counter -from qtpy.QtCore import QDir, Qt +from qtpy.QtCore import QDir from qtpy.QtGui import QIcon from qtpy.QtWidgets import QApplication, QWidget @@ -24,19 +23,10 @@ capture_validation, ) from ert.gui.main_window import ErtMainWindow -from ert.gui.simulation import ExperimentPanel from ert.gui.tools.event_viewer import ( - EventViewerTool, GUILogHandler, add_gui_log_handler, ) -from ert.gui.tools.export import ExportTool -from ert.gui.tools.load_results import LoadResultsTool -from ert.gui.tools.manage_experiments import ManageExperimentsTool -from ert.gui.tools.plot import PlotTool -from ert.gui.tools.plugins import PluginHandler, PluginsTool -from ert.gui.tools.workflows import WorkflowsTool -from ert.libres_facade import LibresFacade from ert.namespace import Namespace from ert.plugins import ErtPluginManager from ert.services import StorageService @@ -44,7 +34,6 @@ from ert.storage.local_storage import local_storage_set_ert_config from .suggestor import Suggestor -from .summarypanel import SummaryPanel def run_gui(args: Namespace, plugin_manager: Optional[ErtPluginManager] = None) -> int: @@ -167,59 +156,16 @@ def continue_action() -> None: ) -def _clicked_help_button(menu_label: str, link: str) -> None: - logger = logging.getLogger(__name__) - logger.info(f"Pressed help button {menu_label}") - webbrowser.open(link) - - -def _clicked_about_button(about_dialog: QWidget) -> None: - logger = logging.getLogger(__name__) - logger.info("Pressed help button About") - about_dialog.show() - - def _setup_main_window( - config: ErtConfig, + ert_config: ErtConfig, args: Namespace, log_handler: GUILogHandler, storage: Storage, plugin_manager: Optional[ErtPluginManager] = None, ) -> ErtMainWindow: # window reference must be kept until app.exec returns: - facade = LibresFacade(config) - config_file = args.config - window = ErtMainWindow(config_file, plugin_manager) + window = ErtMainWindow(args.config, ert_config, plugin_manager, log_handler) window.notifier.set_storage(storage) - window.setWidget( - ExperimentPanel( - config, window.notifier, config_file, facade.get_ensemble_size() - ) - ) - - plugin_handler = PluginHandler( - window.notifier, - [wfj for wfj in config.workflow_jobs.values() if wfj.is_plugin()], - window, - ) - - window.addDock( - "Configuration summary", - SummaryPanel(config), - area=Qt.DockWidgetArea.BottomDockWidgetArea, - ) - window.addTool(PlotTool(config_file, window)) - window.addTool(ExportTool(config, window.notifier)) - window.addTool(WorkflowsTool(config, window.notifier)) - window.addTool( - ManageExperimentsTool( - config, window.notifier, config.model_config.num_realizations - ) - ) - window.addTool(PluginsTool(plugin_handler, window.notifier, config)) - window.addTool(LoadResultsTool(facade, window.notifier)) - event_viewer = EventViewerTool(log_handler, config_file) - window.addTool(event_viewer) - window.close_signal.connect(event_viewer.close_wnd) + window.post_init() window.adjustSize() return window diff --git a/src/ert/gui/main_window.py b/src/ert/gui/main_window.py index a19e0c9cc82..2af15f86727 100644 --- a/src/ert/gui/main_window.py +++ b/src/ert/gui/main_window.py @@ -1,100 +1,237 @@ from __future__ import annotations +import datetime import functools import webbrowser -from typing import TYPE_CHECKING, Dict, Optional +from typing import Dict, Optional -from qtpy.QtCore import QSettings, Qt, Signal -from qtpy.QtGui import QCloseEvent +from qtpy.QtCore import QSize, Qt, Signal, Slot +from qtpy.QtGui import QCloseEvent, QCursor, QIcon from qtpy.QtWidgets import ( QAction, - QDockWidget, + QFrame, + QHBoxLayout, QMainWindow, + QMenu, QToolButton, QVBoxLayout, QWidget, ) +from ert import LibresFacade +from ert.config import ErtConfig from ert.gui.about_dialog import AboutDialog from ert.gui.ertnotifier import ErtNotifier from ert.gui.find_ert_info import find_ert_info +from ert.gui.simulation import ExperimentPanel +from ert.gui.simulation.run_dialog import RunDialog +from ert.gui.tools.event_viewer import EventViewerTool, GUILogHandler +from ert.gui.tools.export import ExportTool +from ert.gui.tools.load_results import LoadResultsTool +from ert.gui.tools.manage_experiments import ManageExperimentsPanel +from ert.gui.tools.plot.plot_window import PlotWindow +from ert.gui.tools.plugins import PluginHandler, PluginsTool +from ert.gui.tools.workflows import WorkflowsTool from ert.plugins import ErtPluginManager -if TYPE_CHECKING: - from ert.gui.tools import Tool +BUTTON_STYLE_SHEET: str = """ + QToolButton { + border-radius: 10px; + background-color: rgba(255, 255, 255, 0); + padding-top: 5px; + padding-bottom: 10px; + } + QToolButton:hover { + background-color: rgba(50, 50, 50, 90); + } + QToolButton::menu-indicator { + right: 10px; bottom: 5px; + } +""" class ErtMainWindow(QMainWindow): close_signal = Signal() def __init__( - self, config_file: str, plugin_manager: Optional[ErtPluginManager] = None + self, + config_file: str, + ert_config: ErtConfig, + plugin_manager: Optional[ErtPluginManager] = None, + log_handler: Optional[GUILogHandler] = None, ): QMainWindow.__init__(self) self.notifier = ErtNotifier(config_file) - self.tools: Dict[str, Tool] = {} + self.plugins_tool: Optional[PluginsTool] = None + self.ert_config = ert_config + self.config_file = config_file + self.log_handler = log_handler self.setWindowTitle(f"ERT - {config_file} - {find_ert_info()}") - self.plugin_manager = plugin_manager - self.__main_widget: Optional[QWidget] = None - - self.central_widget = QWidget() - self.central_layout = QVBoxLayout() + self.central_widget = QFrame(self) + self.central_layout = QHBoxLayout(self.central_widget) + self.central_layout.setContentsMargins(0, 0, 0, 0) + self.central_layout.setSpacing(0) self.central_widget.setLayout(self.central_layout) + self.facade = LibresFacade(self.ert_config) + self.side_frame = QFrame(self) + self.side_frame.setStyleSheet("background-color: lightgray;") + self.vbox_layout = QVBoxLayout(self.side_frame) + self.side_frame.setLayout(self.vbox_layout) + + self.central_panels_map: Dict[str, QWidget] = {} + self._experiment_panel: Optional[ExperimentPanel] = None + self._plot_window: Optional[PlotWindow] = None + self._manage_experiments_panel: Optional[ManageExperimentsPanel] = None + self._add_sidebar_button("Start simulation", QIcon("img:library_add.svg")) + self._add_sidebar_button("Create plot", QIcon("img:timeline.svg")) + self._add_sidebar_button("Manage experiments", QIcon("img:build_wrench.svg")) + self.results_button = self._add_sidebar_button( + "Simulation status", QIcon("img:in_progress.svg") + ) + self.results_button.setEnabled(False) + self.run_dialog_counter = 0 + + self.vbox_layout.addStretch() + self.central_layout.addWidget(self.side_frame) + self.central_widget.setMinimumWidth(1500) + self.central_widget.setMinimumHeight(800) self.setCentralWidget(self.central_widget) - toolbar = self.addToolBar("Tools") - assert toolbar is not None - self.toolbar = toolbar - self.toolbar.setObjectName("Toolbar") - self.toolbar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextUnderIcon) + self.__add_tools_menu() + self.__add_help_menu() + + def select_central_widget(self) -> None: + actor = self.sender() + if actor: + index_name = actor.property("index") + + for widget in self.central_panels_map.values(): + widget.setVisible(False) + + if ( + index_name == "Manage experiments" + and not self._manage_experiments_panel + ): + self._manage_experiments_panel = ManageExperimentsPanel( + self.ert_config, + self.notifier, + self.ert_config.model_config.num_realizations, + ) + + self.central_panels_map["Manage experiments"] = ( + self._manage_experiments_panel + ) + self.central_layout.addWidget(self._manage_experiments_panel) + + if index_name == "Create plot": + if self._plot_window: + self._plot_window.close() + self._plot_window = PlotWindow(self.config_file, self) + self.central_layout.addWidget(self._plot_window) + self.central_panels_map["Create plot"] = self._plot_window + + if index_name == "Simulation status": + # select the only available simulation + for k, v in self.central_panels_map.items(): + if isinstance(v, RunDialog): + index_name = k + break + + for i, widget in self.central_panels_map.items(): + widget.setVisible(i == index_name) + + @Slot(object) + def slot_add_widget(self, run_dialog: RunDialog) -> None: + for widget in self.central_panels_map.values(): + widget.setVisible(False) + + run_dialog.setParent(self) + date_time = datetime.datetime.now(datetime.timezone.utc).strftime( + "%Y-%d-%m %H:%M:%S" + ) + experiment_type = run_dialog._run_model.name() + simulation_id = experiment_type + " : " + date_time + self.central_panels_map[simulation_id] = run_dialog + self.run_dialog_counter += 1 + self.central_layout.addWidget(run_dialog) + + def add_sim_run_option(simulation_id: str) -> None: + menu = self.results_button.menu() + if menu: + action_list = menu.actions() + act = QAction(text=simulation_id, parent=menu) + act.setProperty("index", simulation_id) + act.triggered.connect(self.select_central_widget) + + if action_list: + menu.insertAction(action_list[0], act) + else: + menu.addAction(act) + + if self.run_dialog_counter == 2: + # swap from button to menu selection + self.results_button.clicked.disconnect(self.select_central_widget) + self.results_button.setMenu(QMenu()) + self.results_button.setPopupMode(QToolButton.InstantPopup) - self.setCorner(Qt.Corner.TopLeftCorner, Qt.DockWidgetArea.LeftDockWidgetArea) - self.setCorner( - Qt.Corner.BottomLeftCorner, Qt.DockWidgetArea.BottomDockWidgetArea + for prev_date_time, widget in self.central_panels_map.items(): + if isinstance(widget, RunDialog): + add_sim_run_option(prev_date_time) + elif self.run_dialog_counter > 2: + add_sim_run_option(date_time) + + self.results_button.setEnabled(True) + + def post_init(self) -> None: + experiment_panel = ExperimentPanel( + self.ert_config, + self.notifier, + self.config_file, + self.facade.get_ensemble_size(), ) + self.central_layout.addWidget(experiment_panel) + self._experiment_panel = experiment_panel + self.central_panels_map["Start simulation"] = self._experiment_panel - self.setCorner(Qt.Corner.TopRightCorner, Qt.DockWidgetArea.RightDockWidgetArea) - self.setCorner( - Qt.Corner.BottomRightCorner, Qt.DockWidgetArea.BottomDockWidgetArea + experiment_panel.experiment_started.connect(self.slot_add_widget) + + plugin_handler = PluginHandler( + self.notifier, + [wfj for wfj in self.ert_config.workflow_jobs.values() if wfj.is_plugin()], + self, ) + self.plugins_tool = PluginsTool(plugin_handler, self.notifier, self.ert_config) + if self.plugins_tool: + self.plugins_tool.setParent(self) + menubar = self.menuBar() + if menubar: + menubar.insertMenu( + self.help_menu.menuAction(), self.plugins_tool.get_menu() + ) - menuBar = self.menuBar() - assert menuBar is not None - view_menu = menuBar.addMenu("&View") - assert view_menu is not None - self.__view_menu = view_menu - self.__add_help_menu() - self.__fetchSettings() + def _add_sidebar_button(self, name: str, icon: QIcon) -> QToolButton: + button = QToolButton(self.side_frame) + button.setFixedSize(85, 95) + button.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + button.setStyleSheet(BUTTON_STYLE_SHEET) + pad = 45 + icon_size = QSize(button.size().width() - pad, button.size().height() - pad) + button.setIconSize(icon_size) + button.setIcon(icon) + button.setToolTip(name) + objname = name.replace(" ", "_") + button_text = name.replace(" ", "\n") + button.setObjectName(f"button_{objname}") + button.setText(button_text) + button.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextUnderIcon) + self.vbox_layout.addWidget(button) - def addDock( - self, - name: str, - widget: Optional[QWidget], - area: Qt.DockWidgetArea = Qt.DockWidgetArea.RightDockWidgetArea, - allowed_areas: Qt.DockWidgetArea = Qt.DockWidgetArea.AllDockWidgetAreas, - ) -> QDockWidget: - dock_widget = QDockWidget(name) - dock_widget.setObjectName(f"{name}Dock") - dock_widget.setWidget(widget) - dock_widget.setAllowedAreas(allowed_areas) - - self.addDockWidget(area, dock_widget) - - self.__view_menu.addAction(dock_widget.toggleViewAction()) - return dock_widget - - def addTool(self, tool: Tool) -> None: - tool.setParent(self) - self.tools[tool.getName()] = tool - self.toolbar.addAction(tool.getAction()) - - if tool.isPopupMenu(): - tool_button = self.toolbar.widgetForAction(tool.getAction()) - assert tool_button is not None - tool_button.setPopupMode(QToolButton.InstantPopup) + button.clicked.connect(self.select_central_widget) + button.setProperty("index", name) + return button def __add_help_menu(self) -> None: menuBar = self.menuBar() @@ -116,38 +253,41 @@ def __add_help_menu(self) -> None: show_about.setObjectName("about_action") show_about.triggered.connect(self.__showAboutMessage) - def __saveSettings(self) -> None: - settings = QSettings("Equinor", "Ert-Gui") - settings.setValue("geometry", self.saveGeometry()) - settings.setValue("windowState", self.saveState()) + self.help_menu = help_menu + + def __add_tools_menu(self) -> None: + menu_bar = self.menuBar() + assert menu_bar is not None + tools_menu = menu_bar.addMenu("&Tools") + assert tools_menu is not None + + if self.log_handler: + self._event_viewer_tool = EventViewerTool( + self.log_handler, self.config_file + ) + self._event_viewer_tool.setParent(self) + tools_menu.addAction(self._event_viewer_tool.getAction()) + self.close_signal.connect(self._event_viewer_tool.close_wnd) + + self.export_tool = ExportTool(self.ert_config, self.notifier) + self.export_tool.setParent(self) + tools_menu.addAction(self.export_tool.getAction()) + + self.workflows_tool = WorkflowsTool(self.ert_config, self.notifier) + self.workflows_tool.setParent(self) + tools_menu.addAction(self.workflows_tool.getAction()) + + self.load_results_tool = LoadResultsTool(self.facade, self.notifier) + self.load_results_tool.setParent(self) + tools_menu.addAction(self.load_results_tool.getAction()) def closeEvent(self, closeEvent: Optional[QCloseEvent]) -> None: - # Use QT settings saving mechanism - # settings stored in ~/.config/Equinor/ErtGui.conf - - if closeEvent is not None and self.notifier.is_simulation_running: - closeEvent.ignore() - else: - self.__saveSettings() - self.close_signal.emit() - QMainWindow.closeEvent(self, closeEvent) - - def __fetchSettings(self) -> None: - settings = QSettings("Equinor", "Ert-Gui") - geo = settings.value("geometry") - if geo: - self.restoreGeometry(geo) - wnd = settings.value("windowState") - if wnd: - self.restoreState(wnd) - - def setWidget(self, widget: QWidget) -> None: - self.__main_widget = widget - actions = widget.getActions() - for action in actions: - self.__view_menu.addAction(action) - - self.central_layout.addWidget(widget) + if closeEvent is not None: + if self.notifier.is_simulation_running: + closeEvent.ignore() + else: + self.close_signal.emit() + QMainWindow.closeEvent(self, closeEvent) def __showAboutMessage(self) -> None: diag = AboutDialog(self) diff --git a/src/ert/gui/resources/gui/img/in_progress.svg b/src/ert/gui/resources/gui/img/in_progress.svg new file mode 100644 index 00000000000..390b28d1d8e --- /dev/null +++ b/src/ert/gui/resources/gui/img/in_progress.svg @@ -0,0 +1 @@ + diff --git a/src/ert/gui/resources/gui/img/library_add.svg b/src/ert/gui/resources/gui/img/library_add.svg new file mode 100644 index 00000000000..cd06455de73 --- /dev/null +++ b/src/ert/gui/resources/gui/img/library_add.svg @@ -0,0 +1 @@ + diff --git a/src/ert/gui/simulation/experiment_panel.py b/src/ert/gui/simulation/experiment_panel.py index 53c59ea5f29..f9e43ad56a9 100644 --- a/src/ert/gui/simulation/experiment_panel.py +++ b/src/ert/gui/simulation/experiment_panel.py @@ -34,6 +34,7 @@ get_ert_memory_usage, ) +from ..summarypanel import SummaryPanel from .combobox_with_description import QComboBoxWithDescription from .ensemble_experiment_panel import EnsembleExperimentPanel from .ensemble_smoother_panel import EnsembleSmootherPanel @@ -61,6 +62,7 @@ def create_md_table(kv: Dict[str, str], output: str) -> str: class ExperimentPanel(QWidget): experiment_type_changed = Signal(ExperimentConfigPanel) + experiment_started = Signal(object) def __init__( self, @@ -86,13 +88,11 @@ def __init__( ) experiment_type_layout = QHBoxLayout() - experiment_type_layout.addSpacing(10) + experiment_type_layout.setContentsMargins(0, 0, 0, 0) experiment_type_layout.addWidget( self._experiment_type_combo, 0, Qt.AlignmentFlag.AlignVCenter ) - experiment_type_layout.addSpacing(20) - self.run_button = QToolButton() self.run_button.setObjectName("run_experiment") self.run_button.setIcon(QIcon("img:play_circle.svg")) @@ -127,9 +127,8 @@ def __init__( experiment_type_layout.addWidget(self.run_button) experiment_type_layout.addStretch(1) - layout.addSpacing(5) + layout.setContentsMargins(10, 10, 10, 10) layout.addLayout(experiment_type_layout) - layout.addSpacing(10) self._experiment_stack = QStackedWidget() self._experiment_stack.setLineWidth(1) @@ -176,6 +175,10 @@ def __init__( ManualUpdatePanel(ensemble_size, run_path, notifier, analysis_config), experiment_type_valid, ) + + self.configuration_summary = SummaryPanel(config) + layout.addWidget(self.configuration_summary) + self.setLayout(layout) def addExperimentConfigPanel( @@ -311,11 +314,10 @@ def run_experiment(self) -> None: self.parent(), # type: ignore output_path=self.config.analysis_config.log_path, ) + self.experiment_started.emit(dialog) dialog.produce_clipboard_debug_info.connect(self.populate_clipboard_debug_info) - self.run_button.setEnabled(False) dialog.run_experiment() - dialog.show() def exit_handler() -> None: self.run_button.setEnabled(True) diff --git a/src/ert/gui/simulation/run_dialog.py b/src/ert/gui/simulation/run_dialog.py index fd193dcc07b..3c9046d00fd 100644 --- a/src/ert/gui/simulation/run_dialog.py +++ b/src/ert/gui/simulation/run_dialog.py @@ -7,8 +7,6 @@ from qtpy.QtCore import QModelIndex, QSize, Qt, QThread, QTimer, Signal, Slot from qtpy.QtGui import ( - QCloseEvent, - QKeyEvent, QMouseEvent, QMovie, QTextCursor, @@ -53,7 +51,6 @@ SnapshotModel, ) from ert.gui.tools.file import FileDialog -from ert.gui.tools.plot import PlotTool from ert.run_models import ( BaseRunModel, RunModelStatusEvent, @@ -167,9 +164,11 @@ def mouseMoveEvent(self, event: QMouseEvent | None) -> None: return super().mouseMoveEvent(event) -class RunDialog(QDialog): +class RunDialog(QFrame): simulation_done = Signal(bool, str) produce_clipboard_debug_info = Signal() + progress_update_event = Signal(dict, int) + finished = Signal() _RUN_TIME_POLL_RATE = 1000 def __init__( @@ -181,7 +180,7 @@ def __init__( parent: Optional[QWidget] = None, output_path: Optional[Path] = None, ): - QDialog.__init__(self, parent) + QFrame.__init__(self, parent) self.output_path = output_path self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose) self.setWindowFlags(Qt.WindowType.Window) @@ -194,9 +193,6 @@ def __init__( self._notifier = notifier self.fail_msg_box: Optional[ErtMessageBox] = None - self._minimum_width = 1200 - self._minimum_height = 800 - self._ticker = QTimer(self) self._ticker.timeout.connect(self._on_ticker) @@ -226,14 +222,7 @@ def __init__( self.running_time = QLabel("") self.memory_usage = QLabel("") - self.plot_tool = PlotTool(config_file, self.parent()) # type: ignore - self.plot_button = QPushButton(self.plot_tool.getName()) - self.plot_button.clicked.connect(self.plot_tool.trigger) - self.plot_button.setEnabled(True) - self.kill_button = QPushButton("Terminate experiment") - self.done_button = QPushButton("Done") - self.done_button.setHidden(True) self.restart_button = QPushButton("Rerun failed") self.restart_button.setHidden(True) self.copy_debug_info_button = QPushButton("Debug Info") @@ -248,8 +237,7 @@ def __init__( spin_movie.start() self.processing_animation = QLabel() - self.processing_animation.setMaximumSize(QSize(size, size)) - self.processing_animation.setMinimumSize(QSize(size, size)) + self.processing_animation.setFixedSize(QSize(size, size)) self.processing_animation.setMovie(spin_movie) button_layout = QHBoxLayout() @@ -259,9 +247,7 @@ def __init__( button_layout.addWidget(self.memory_usage) button_layout.addStretch() button_layout.addWidget(self.copy_debug_info_button) - button_layout.addWidget(self.plot_button) button_layout.addWidget(self.kill_button) - button_layout.addWidget(self.done_button) button_layout.addWidget(self.restart_button) button_widget_container = QWidget() @@ -299,14 +285,17 @@ def __init__( self.setLayout(layout) self.kill_button.clicked.connect(self.killJobs) # type: ignore - self.done_button.clicked.connect(self.accept) self.restart_button.clicked.connect(self.restart_failed_realizations) self.simulation_done.connect(self._on_simulation_done) - self.setMinimumSize(self._minimum_width, self._minimum_height) + self.setMinimumSize(1200, 600) self.finished.connect(self._on_finished) self._restart = False + self.flag_simulation_done = False + + def is_simulation_done(self) -> bool: + return self.flag_simulation_done def _current_tab_changed(self, index: int) -> None: widget = self._tab_widget.widget(index) @@ -353,15 +342,10 @@ def _select_real(self, index: QModelIndex) -> None: text += f", assigned to host: {exec_hosts}" self._fm_step_label.setText(text) - def closeEvent(self, a0: Optional[QCloseEvent]) -> None: - if not self._notifier.is_simulation_running: - self.accept() - elif self.killJobs() != QMessageBox.Yes and a0 is not None: - a0.ignore() - def run_experiment(self, restart: bool = False) -> None: self._restart = restart self._progress_widget.set_ensemble_running() + self.flag_simulation_done = False if restart is False: self._snapshot_model.reset() self._tab_widget.clear() @@ -408,8 +392,7 @@ def killJobs(self) -> QMessageBox.StandardButton: # Normally this slot would be invoked by the signal/slot system, # but the worker is busy tracking the evaluation. self._run_model.cancel() - self._on_finished() - self.finished.emit(-1) + self.finished.emit() return kill_job @Slot(bool, str) @@ -444,8 +427,8 @@ def _on_ticker(self) -> None: def _on_event(self, event: object) -> None: if isinstance(event, EndEvent): self.simulation_done.emit(event.failed, event.msg) + self.finished.emit() self._ticker.stop() - self.done_button.setHidden(False) elif isinstance(event, FullSnapshotEvent): if event.snapshot is not None: if self._restart: @@ -460,6 +443,7 @@ def _on_event(self, event: object) -> None: self._progress_widget.update_progress( event.status_count, event.realization_count ) + self.progress_update_event.emit(event.status_count, event.realization_count) elif isinstance(event, SnapshotUpdateEvent): if event.snapshot is not None: self._snapshot_model._update_snapshot( @@ -469,6 +453,7 @@ def _on_event(self, event: object) -> None: event.status_count, event.realization_count ) self.update_total_progress(event.progress, event.iteration_label) + self.progress_update_event.emit(event.status_count, event.realization_count) elif isinstance(event, RunModelUpdateBeginEvent): iteration = event.iteration widget = UpdateWidget(iteration) @@ -544,26 +529,13 @@ def restart_failed_realizations(self) -> None: if result == QMessageBox.Ok: self.restart_button.setVisible(False) self.kill_button.setVisible(True) - self.done_button.setVisible(False) self.run_experiment(restart=True) - def get_runtime(self) -> int: - return self._run_model.get_runtime() - def _on_finished(self) -> None: + self.flag_simulation_done = True for file_dialog in self.findChildren(FileDialog): file_dialog.close() - def keyPressEvent(self, a0: Optional[QKeyEvent]) -> None: - # QDialog on escape will close without prompting - # so call self.close() instead - if a0 is not None and a0.key() == Qt.Key.Key_Escape: - self.close() - elif a0 is not None and a0.key() == Qt.Key.Key_F1: - self.produce_clipboard_debug_info.emit() - else: - QDialog.keyPressEvent(self, a0) - # Cannot use a non-static method here as # it is called when the object is destroyed diff --git a/src/ert/gui/summarypanel.py b/src/ert/gui/summarypanel.py index e0b6b60ea20..8e345fa0733 100644 --- a/src/ert/gui/summarypanel.py +++ b/src/ert/gui/summarypanel.py @@ -64,15 +64,16 @@ def __init__(self, config: ErtConfig): self.setMinimumWidth(250) self.setMinimumHeight(150) - widget = QWidget() + widget = QWidget(self) self._layout = QHBoxLayout() widget.setLayout(self._layout) - scroll = QScrollArea() + scroll = QScrollArea(self) scroll.setWidgetResizable(True) scroll.setWidget(widget) layout = QGridLayout() + layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(scroll) self.setLayout(layout) diff --git a/src/ert/gui/tools/manage_experiments/__init__.py b/src/ert/gui/tools/manage_experiments/__init__.py index af1ac54d080..107254fc490 100644 --- a/src/ert/gui/tools/manage_experiments/__init__.py +++ b/src/ert/gui/tools/manage_experiments/__init__.py @@ -1,4 +1,3 @@ from .manage_experiments_panel import ManageExperimentsPanel -from .manage_experiments_tool import ManageExperimentsTool -__all__ = ["ManageExperimentsPanel", "ManageExperimentsTool"] +__all__ = ["ManageExperimentsPanel"] diff --git a/src/ert/gui/tools/manage_experiments/manage_experiments_tool.py b/src/ert/gui/tools/manage_experiments/manage_experiments_tool.py deleted file mode 100644 index ef5576e2522..00000000000 --- a/src/ert/gui/tools/manage_experiments/manage_experiments_tool.py +++ /dev/null @@ -1,33 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Optional - -from qtpy.QtCore import Qt -from qtpy.QtGui import QIcon - -from ert.gui.tools import Tool -from ert.gui.tools.manage_experiments import ManageExperimentsPanel - -if TYPE_CHECKING: - from ert.config import ErtConfig - from ert.gui.ertnotifier import ErtNotifier - - -class ManageExperimentsTool(Tool): - def __init__(self, config: ErtConfig, notifier: ErtNotifier, ensemble_size: int): - super().__init__("Manage experiments", QIcon("img:build_wrench.svg")) - self.notifier = notifier - self.ert_config = config - self.ensemble_size = ensemble_size - self._manage_experiments_panel: Optional[ManageExperimentsPanel] = None - - def trigger(self) -> None: - if not self._manage_experiments_panel: - self._manage_experiments_panel = ManageExperimentsPanel( - self.ert_config, self.notifier, self.ensemble_size - ) - self._manage_experiments_panel.setWindowModality( - Qt.WindowModality.ApplicationModal - ) - - self._manage_experiments_panel.show() diff --git a/src/ert/gui/tools/plot/__init__.py b/src/ert/gui/tools/plot/__init__.py index cead7bed864..e69de29bb2d 100644 --- a/src/ert/gui/tools/plot/__init__.py +++ b/src/ert/gui/tools/plot/__init__.py @@ -1,5 +0,0 @@ -from .plot_tool import PlotTool - -__all__ = [ - "PlotTool", -] diff --git a/src/ert/gui/tools/plot/plot_tool.py b/src/ert/gui/tools/plot/plot_tool.py deleted file mode 100644 index 830ea9d40c1..00000000000 --- a/src/ert/gui/tools/plot/plot_tool.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Optional - -from qtpy.QtGui import QIcon -from qtpy.QtWidgets import QWidget - -from ert.gui.tools import Tool - -from .plot_window import PlotWindow - - -class PlotTool(Tool): - def __init__(self, config_file: str, main_window: Optional[QWidget]): - super().__init__("Create plot", QIcon("img:timeline.svg")) - self._config_file = config_file - self.main_window = main_window - - def trigger(self) -> None: - plot_window = PlotWindow(self._config_file, self.main_window) - plot_window.show() diff --git a/src/ert/gui/tools/plugins/plugins_tool.py b/src/ert/gui/tools/plugins/plugins_tool.py index 937b6185ec3..0fc351e77f8 100644 --- a/src/ert/gui/tools/plugins/plugins_tool.py +++ b/src/ert/gui/tools/plugins/plugins_tool.py @@ -34,18 +34,20 @@ def __init__( self.__plugins = {} - menu = QMenu() + self.menu = QMenu("&Plugins") for plugin in plugin_handler: plugin_runner = PluginRunner(plugin, ert_config, notifier.storage) plugin_runner.setPluginFinishedCallback(self.trigger) self.__plugins[plugin] = plugin_runner - plugin_action = menu.addAction(plugin.getName()) + plugin_action = self.menu.addAction(plugin.getName()) assert plugin_action is not None + plugin_action.setIcon(QIcon("img:widgets.svg")) plugin_action.setToolTip(plugin.getDescription()) plugin_action.triggered.connect(plugin_runner.run) - self.getAction().setMenu(menu) + def get_menu(self) -> QMenu: + return self.menu def trigger(self) -> None: self.notifier.emitErtChange() # plugin may have added new cases. diff --git a/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure0-0.png b/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure0-0.png index 1bbf458f8d1..970da269a8e 100644 Binary files a/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure0-0.png and b/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure0-0.png differ diff --git a/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure1-0.png b/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure1-0.png index 6655cdb0ee7..6c3cae3cbc5 100644 Binary files a/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure1-0.png and b/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure1-0.png differ diff --git a/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure2-0.png b/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure2-0.png index 8b7e31de1f1..5005a8be1d0 100644 Binary files a/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure2-0.png and b/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure2-0.png differ diff --git a/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure3-0.png b/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure3-0.png index 3f94b6d1610..4ad6e398bc9 100644 Binary files a/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure3-0.png and b/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure3-0.png differ diff --git a/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure4-0.png b/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure4-0.png index 4ecb1dfe9d8..8af343fa2a0 100644 Binary files a/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure4-0.png and b/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure4-0.png differ diff --git a/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure5-0.png b/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure5-0.png index 04cc3061ebe..7ed2b0a7403 100644 Binary files a/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure5-0.png and b/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure5-0.png differ diff --git a/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure6-0.png b/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure6-0.png index 2c7dace9c7d..c735ecbc3ff 100644 Binary files a/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure6-0.png and b/tests/ert/ui_tests/gui/baseline/test_that_all_snake_oil_visualisations_matches_snapshot_plot_figure6-0.png differ diff --git a/tests/ert/ui_tests/gui/conftest.py b/tests/ert/ui_tests/gui/conftest.py index df913d2fcfe..1c0b1421566 100644 --- a/tests/ert/ui_tests/gui/conftest.py +++ b/tests/ert/ui_tests/gui/conftest.py @@ -14,7 +14,14 @@ import pytest from pytestqt.qtbot import QtBot from qtpy.QtCore import Qt, QTimer -from qtpy.QtWidgets import QApplication, QComboBox, QMessageBox, QPushButton, QWidget +from qtpy.QtWidgets import ( + QApplication, + QComboBox, + QMessageBox, + QPushButton, + QToolButton, + QWidget, +) from ert.config import ErtConfig from ert.gui.ertwidgets import ClosableDialog @@ -25,9 +32,7 @@ from ert.gui.simulation.run_dialog import RunDialog from ert.gui.simulation.view import RealizationWidget from ert.gui.tools.load_results.load_results_panel import LoadResultsPanel -from ert.gui.tools.manage_experiments.manage_experiments_tool import ( - ManageExperimentsTool, -) +from ert.gui.tools.manage_experiments import ManageExperimentsPanel from ert.gui.tools.manage_experiments.storage_widget import AddWidget, StorageWidget from ert.plugins import ErtPluginContext from ert.run_models import EnsembleExperiment, MultipleDataAssimilation @@ -249,7 +254,9 @@ def handle_dialog(): # The Run dialog opens, click show details and wait until done appears # then click it run_dialog = wait_for_child(gui, qtbot, RunDialog, timeout=10000) - qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=200000) + qtbot.waitUntil( + lambda: run_dialog.is_simulation_done() == True, timeout=200000 + ) qtbot.waitUntil(lambda: run_dialog._tab_widget.currentWidget() is not None) # Assert that the number of boxes in the detailed view is @@ -261,7 +268,6 @@ def handle_dialog(): list_model.rowCount() == experiment_panel.config.model_config.num_realizations ) - qtbot.mouseClick(run_dialog.done_button, Qt.LeftButton) return func @@ -338,18 +344,16 @@ def handle_popup_dialog(): dialog.close() QTimer.singleShot(1000, handle_load_results_dialog) - load_results_tool = gui.tools["Load results manually"] - load_results_tool.trigger() + gui.load_results_tool.trigger() def add_experiment_manually( qtbot, gui, experiment_name="My_experiment", ensemble_name="default" ): - manage_tool = gui.tools["Manage experiments"] - manage_tool.trigger() - - assert isinstance(manage_tool, ManageExperimentsTool) - experiments_panel = manage_tool._manage_experiments_panel + button_manage_experiments = gui.findChild(QToolButton, "button_Manage_experiments") + assert button_manage_experiments + qtbot.mouseClick(button_manage_experiments, Qt.LeftButton) + experiments_panel = gui.findChild(ManageExperimentsPanel) # Open the create new experiment tab experiments_panel.setCurrentIndex(0) diff --git a/tests/ert/ui_tests/gui/test_csv_export.py b/tests/ert/ui_tests/gui/test_csv_export.py index b40cbb0c2b1..7d53cd9a0a5 100644 --- a/tests/ert/ui_tests/gui/test_csv_export.py +++ b/tests/ert/ui_tests/gui/test_csv_export.py @@ -50,8 +50,8 @@ def handle_finished_box(): QTimer.singleShot(500, handle_export_dialog) QTimer.singleShot(3000, handle_finished_box) + gui.export_tool.trigger() - gui.tools["Export data"].trigger() assert file_name == export_path qtbot.waitUntil(lambda: os.path.exists(file_name)) @@ -101,9 +101,8 @@ def run_experiment_via_gui(gui, qtbot): qtbot.mouseClick(run_experiment, Qt.LeftButton) run_dialog = wait_for_child(gui, qtbot, RunDialog) - qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=100000) + qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=20000) qtbot.waitUntil(lambda: run_dialog._tab_widget.currentWidget() is not None) - qtbot.mouseClick(run_dialog.done_button, Qt.LeftButton) from ert.storage import open_storage diff --git a/tests/ert/ui_tests/gui/test_full_manual_update_workflow.py b/tests/ert/ui_tests/gui/test_full_manual_update_workflow.py index fbc67689515..674423ae0ee 100644 --- a/tests/ert/ui_tests/gui/test_full_manual_update_workflow.py +++ b/tests/ert/ui_tests/gui/test_full_manual_update_workflow.py @@ -5,6 +5,7 @@ from qtpy.QtCore import Qt from qtpy.QtWidgets import ( QComboBox, + QToolButton, QTreeView, QWidget, ) @@ -14,7 +15,7 @@ from ert.gui.simulation.experiment_panel import ExperimentPanel from ert.gui.simulation.manual_update_panel import ManualUpdatePanel from ert.gui.simulation.run_dialog import RunDialog -from ert.gui.tools.manage_experiments import ManageExperimentsTool +from ert.gui.tools.manage_experiments import ManageExperimentsPanel from ert.gui.tools.manage_experiments.storage_widget import StorageWidget from ert.run_models.evaluate_ensemble import EvaluateEnsemble from ert.run_models.manual_update import ManualUpdate @@ -44,16 +45,13 @@ def test_manual_analysis_workflow(ensemble_experiment_has_run, qtbot): qtbot.mouseClick(run_experiment, Qt.LeftButton) # The Run dialog opens, wait until done appears, then click done run_dialog = wait_for_child(gui, qtbot, RunDialog) - qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=100000) + qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=10000) qtbot.waitUntil(lambda: run_dialog._tab_widget.currentWidget() is not None) - qtbot.mouseClick(run_dialog.done_button, Qt.LeftButton) - # Open the manage experiments dialog - manage_tool = gui.tools["Manage experiments"] - manage_tool.trigger() - - assert isinstance(manage_tool, ManageExperimentsTool) - experiments_panel = manage_tool._manage_experiments_panel + button_manage_experiments = gui.findChild(QToolButton, "button_Manage_experiments") + assert button_manage_experiments + qtbot.mouseClick(button_manage_experiments, Qt.LeftButton) + experiments_panel = gui.findChild(ManageExperimentsPanel) assert experiments_panel # In the "create new case" tab, it should now contain "iter-1" diff --git a/tests/ert/ui_tests/gui/test_load_results_manually.py b/tests/ert/ui_tests/gui/test_load_results_manually.py index 6dcc06cd688..a28b5380456 100644 --- a/tests/ert/ui_tests/gui/test_load_results_manually.py +++ b/tests/ert/ui_tests/gui/test_load_results_manually.py @@ -48,5 +48,4 @@ def handle_load_results_dialog(): dialog.close() QTimer.singleShot(1000, handle_load_results_dialog) - load_results_tool = gui.tools["Load results manually"] - load_results_tool.trigger() + gui.load_results_tool.trigger() diff --git a/tests/ert/ui_tests/gui/test_main_window.py b/tests/ert/ui_tests/gui/test_main_window.py index f3e8d135e8f..4bdcad197c5 100644 --- a/tests/ert/ui_tests/gui/test_main_window.py +++ b/tests/ert/ui_tests/gui/test_main_window.py @@ -8,7 +8,6 @@ import numpy as np import pytest -from pytestqt.qtbot import QtBot from qtpy.QtCore import Qt, QTimer from qtpy.QtWidgets import ( QAction, @@ -16,7 +15,6 @@ QComboBox, QDoubleSpinBox, QMenuBar, - QMessageBox, QPushButton, QToolButton, QTreeView, @@ -34,12 +32,12 @@ from ert.gui.main import ErtMainWindow, GUILogHandler, _setup_main_window from ert.gui.simulation.experiment_panel import ExperimentPanel from ert.gui.simulation.run_dialog import RunDialog -from ert.gui.simulation.view import RealizationWidget from ert.gui.suggestor import Suggestor from ert.gui.suggestor._suggestor_message import SuggestorMessage from ert.gui.tools.event_viewer import add_gui_log_handler -from ert.gui.tools.file.file_dialog import FileDialog -from ert.gui.tools.manage_experiments import ManageExperimentsTool +from ert.gui.tools.manage_experiments import ( + ManageExperimentsPanel, +) from ert.gui.tools.manage_experiments.storage_widget import AddWidget, StorageWidget from ert.gui.tools.plot.data_type_keys_widget import DataTypeKeysWidget from ert.gui.tools.plot.plot_ensemble_selection_widget import ( @@ -55,11 +53,12 @@ SingleTestRun, ) from ert.services import StorageService -from ert.storage import open_storage +from ...unit_tests.gui.simulation.test_run_path_dialog import handle_run_path_dialog from .conftest import ( add_experiment_manually, get_child, + get_children, load_results_manually, wait_for_child, ) @@ -162,158 +161,6 @@ def test_gui_shows_a_warning_and_disables_update_when_parameters_are_missing( assert gui.windowTitle().startswith("ERT - poly-no-gen-kw.ert") -@pytest.mark.usefixtures("use_tmpdir", "set_site_config") -def test_that_run_dialog_can_be_closed_after_used_to_open_plots(qtbot, storage): - """ - This is a regression test for a bug where the plot window opened from run dialog - would have run dialog as parent. Because of that it would be destroyed when - run dialog was closed and end in a c++ QTObject lifetime crash. - - Also tests that the run_dialog is not modal (does not block the main_window), - but simulations cannot be clicked from the main window while the run dialog is open. - """ - config_file = Path("config.ert") - config_file.write_text( - f"NUM_REALIZATIONS 1\nENSPATH {storage.path}\n", encoding="utf-8" - ) - - args_mock = Mock() - args_mock.config = str(config_file) - - ert_config = ErtConfig.from_file(str(config_file)) - with StorageService.init_service( - project=os.path.abspath(ert_config.ens_path), - ): - gui = _setup_main_window(ert_config, args_mock, GUILogHandler(), storage) - qtbot.addWidget(gui) - simulation_mode = get_child(gui, QComboBox, name="experiment_type") - run_experiment = get_child(gui, QToolButton, name="run_experiment") - - qtbot.mouseClick(run_experiment, Qt.LeftButton) - - run_dialog = wait_for_child(gui, qtbot, RunDialog) - - # Ensure that once the run dialog is opened - # another simulation cannot be started - assert not run_experiment.isEnabled() - - # Change simulation mode and ensure that - # another experiment still cannot be started - for ind in range(simulation_mode.count()): - simulation_mode.setCurrentIndex(ind) - assert not run_experiment.isEnabled() - - # The user expects to be able to open e.g. the even viewer - # while the run dialog is open - assert not run_dialog.isModal() - - qtbot.mouseClick(run_dialog.plot_button, Qt.LeftButton) - qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=200000) - qtbot.mouseClick(run_dialog.done_button, Qt.LeftButton) - - # Ensure that once the run dialog is closed - # another simulation can be started - assert run_experiment.isEnabled() - - plot_window = wait_for_child(gui, qtbot, PlotWindow) - - # Cycle through showing all the tabs - for tab in plot_window._plot_widgets: - plot_window._central_tab.setCurrentWidget(tab) - - -def test_that_run_dialog_can_be_closed_while_file_plot_is_open( - snake_oil_case_storage: ErtConfig, qtbot: QtBot -): - """ - This is a regression test for a crash happening when - closing the RunDialog with a file open. - """ - - snake_oil_case = snake_oil_case_storage - args_mock = Mock() - args_mock.config = "snake_oil.ert" - - def handle_run_path_error_dialog(gui: ErtMainWindow, qtbot: QtBot): - mb = gui.findChild(QMessageBox, "RUN_PATH_ERROR_BOX") - - if mb is not None: - assert mb - assert isinstance(mb, QMessageBox) - # Continue without deleting the runpath - qtbot.mouseClick(mb.buttons()[0], Qt.LeftButton) - - def handle_run_path_dialog( - gui: ErtMainWindow, - qtbot: QtBot, - delete_run_path: bool = True, - expect_error: bool = False, - ): - mb = gui.findChild(QMessageBox, "RUN_PATH_WARNING_BOX") - - if mb is not None: - assert mb - assert isinstance(mb, QMessageBox) - - if delete_run_path: - qtbot.mouseClick(mb.checkBox(), Qt.LeftButton) - - qtbot.mouseClick(mb.buttons()[0], Qt.LeftButton) - if expect_error: - QTimer.singleShot( - 1000, lambda: handle_run_path_error_dialog(gui, qtbot) - ) - - with StorageService.init_service( - project=os.path.abspath(snake_oil_case.ens_path), - ), open_storage(snake_oil_case.ens_path, mode="w") as storage: - gui = _setup_main_window(snake_oil_case, args_mock, GUILogHandler(), storage) - experiment_panel = gui.findChild(ExperimentPanel) - - run_experiment = experiment_panel.findChild(QWidget, name="run_experiment") - assert run_experiment - assert isinstance(run_experiment, QToolButton) - - QTimer.singleShot( - 1000, lambda: handle_run_path_dialog(gui, qtbot, delete_run_path=True) - ) - qtbot.mouseClick(run_experiment, Qt.LeftButton) - - run_dialog = wait_for_child(gui, qtbot, RunDialog) - qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=100000) - fm_step_overview = run_dialog._fm_step_overview - - qtbot.waitUntil(fm_step_overview.isVisible, timeout=20000) - qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=200000) - - realization_widget = run_dialog.findChild(RealizationWidget) - - click_pos = realization_widget._real_view.rectForIndex( - realization_widget._real_list_model.index(0, 0) - ).center() - - with qtbot.waitSignal(realization_widget.itemClicked, timeout=30000): - qtbot.mouseClick( - realization_widget._real_view.viewport(), - Qt.LeftButton, - pos=click_pos, - ) - - click_pos = fm_step_overview.visualRect( - fm_step_overview.model().index(0, 4) - ).center() - qtbot.mouseClick(fm_step_overview.viewport(), Qt.LeftButton, pos=click_pos) - - qtbot.waitUntil(run_dialog.findChild(FileDialog).isVisible, timeout=30000) - - with qtbot.waitSignal(run_dialog.accepted, timeout=30000): - run_dialog.close() # Close the run dialog by pressing 'x' close button - - # Ensure that once the run dialog is closed - # another simulation can be started - assert run_experiment.isEnabled() - - @pytest.mark.usefixtures("set_site_config") def test_help_buttons_in_suggester_dialog(tmp_path, qtbot): """ @@ -347,8 +194,7 @@ def test_that_run_workflow_component_disabled_when_no_workflows(qapp): with add_gui_log_handler() as log_handler: gui, *_ = ert.gui.main._start_initial_gui_window(args, log_handler) assert gui.windowTitle().startswith("ERT - poly.ert") - run_workflow_button = gui.tools["Run workflow"] - assert not run_workflow_button.isEnabled() + assert not gui.workflows_tool.getAction().isEnabled() @pytest.mark.usefixtures("set_site_config") @@ -373,8 +219,7 @@ def test_that_run_workflow_component_enabled_when_workflows(qapp, tmp_path): with add_gui_log_handler() as log_handler: gui, *_ = ert.gui.main._start_initial_gui_window(args, log_handler) assert gui.windowTitle().startswith("ERT - config.ert") - run_workflow_button = gui.tools["Run workflow"] - assert run_workflow_button.isEnabled() + assert gui.workflows_tool.getAction().isEnabled() @pytest.mark.usefixtures("copy_poly_case") @@ -444,13 +289,12 @@ def test_that_the_plot_window_contains_the_expected_elements( ] # Click on Create plot after esmda has run - plot_tool = gui.tools["Create plot"] - plot_tool.trigger() - - # Then the plot window opens + button_plot_tool = gui.findChild(QToolButton, "button_Create_plot") + assert button_plot_tool + qtbot.mouseClick(button_plot_tool, Qt.LeftButton) plot_window = wait_for_child(gui, qtbot, PlotWindow) - data_types = get_child(plot_window, DataTypeKeysWidget) + data_types = get_child(plot_window, DataTypeKeysWidget) case_selection = get_child( plot_window, EnsembleSelectListWidget, "ensemble_selector" ) @@ -515,11 +359,10 @@ def test_that_the_manage_experiments_tool_can_be_used( ): gui = esmda_has_run - manage_tool = gui.tools["Manage experiments"] - manage_tool.trigger() - - assert isinstance(manage_tool, ManageExperimentsTool) - experiments_panel = manage_tool._manage_experiments_panel + button_manage_experiments = gui.findChild(QToolButton, "button_Manage_experiments") + assert button_manage_experiments + qtbot.mouseClick(button_manage_experiments, Qt.LeftButton) + experiments_panel = wait_for_child(gui, qtbot, ManageExperimentsPanel) # Open the tab experiments_panel.setCurrentIndex(0) @@ -602,11 +445,10 @@ def test_that_the_manage_experiments_tool_can_be_used_with_clean_storage( ): gui = opened_main_window_poly - manage_tool = gui.tools["Manage experiments"] - manage_tool.trigger() - - assert isinstance(manage_tool, ManageExperimentsTool) - experiments_panel = manage_tool._manage_experiments_panel + button_manage_experiments = gui.findChild(QToolButton, "button_Manage_experiments") + assert button_manage_experiments + qtbot.mouseClick(button_manage_experiments, Qt.LeftButton) + experiments_panel = wait_for_child(gui, qtbot, ManageExperimentsPanel) # Open the create new ensembles tab experiments_panel.setCurrentIndex(0) @@ -714,8 +556,7 @@ def handle_error_dialog(run_dialog): run_dialog = wait_for_child(gui, qtbot, RunDialog) QTimer.singleShot(200, lambda: handle_error_dialog(run_dialog)) - qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=100000) - qtbot.mouseClick(run_dialog.done_button, Qt.LeftButton) + qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=100000) @pytest.mark.usefixtures("use_tmpdir", "set_site_config") @@ -732,7 +573,10 @@ def test_that_gui_plotter_works_when_no_data(qtbot, storage, monkeypatch): ): gui = _setup_main_window(ert_config, args_mock, GUILogHandler(), storage) qtbot.addWidget(gui) - gui.tools["Create plot"].trigger() + + button_plot_tool = gui.findChild(QToolButton, "button_Create_plot") + assert button_plot_tool + qtbot.mouseClick(button_plot_tool, Qt.LeftButton) plot_window = wait_for_child(gui, qtbot, PlotWindow) ensemble_plot_names = get_child( @@ -827,3 +671,64 @@ def test_validation_of_experiment_names_in_run_models( experiment_field.setText("ensemble_experiment") assert not run_experiment.isEnabled() + + +def test_that_simulation_status_button_adds_menu_on_subsequent_runs( + opened_main_window_poly, qtbot +): + gui = opened_main_window_poly + + def find_and_click_button( + button_name: str, should_click: bool, expected_enabled_state: bool + ): + button = gui.findChild(QToolButton, button_name) + assert button + assert button.isEnabled() == expected_enabled_state + if should_click: + qtbot.mouseClick(button, Qt.LeftButton) + + def run_experiment(): + run_experiment_panel = wait_for_child(gui, qtbot, ExperimentPanel) + qtbot.wait_until(lambda: not run_experiment_panel.isHidden(), timeout=5000) + assert run_experiment_panel.run_button.isEnabled() + qtbot.mouseClick(run_experiment_panel.run_button, Qt.LeftButton) + + def wait_for_simulation_completed(): + run_dialogs = get_children(gui, RunDialog) + dialog = run_dialogs[-1] + qtbot.wait_until(lambda: not dialog.isHidden(), timeout=5000) + qtbot.wait_until(lambda: dialog.is_simulation_done() == True, timeout=15000) + + # not clickable since no simulations started yet + find_and_click_button("button_Simulation_status", False, False) + find_and_click_button("button_Start_simulation", True, True) + + run_experiment() + wait_for_simulation_completed() + + # just toggle to see if next button yields intended change + find_and_click_button("button_Start_simulation", True, True) + experiments_panel = wait_for_child(gui, qtbot, ExperimentPanel) + qtbot.wait_until(lambda: not experiments_panel.isHidden(), timeout=5000) + + find_and_click_button("button_Simulation_status", True, True) + run_dialog = wait_for_child(gui, qtbot, RunDialog) + qtbot.wait_until(lambda: not run_dialog.isHidden(), timeout=5000) + + # verify no drop menu + button_simulation_status = gui.findChild(QToolButton, "button_Simulation_status") + assert button_simulation_status.menu() is None + + find_and_click_button("button_Start_simulation", True, True) + QTimer.singleShot(500, lambda: handle_run_path_dialog(gui, qtbot, True)) + run_experiment() + wait_for_simulation_completed() + + # verify menu available + assert len(button_simulation_status.menu().actions()) == 2 + + find_and_click_button("button_Start_simulation", True, True) + QTimer.singleShot(500, lambda: handle_run_path_dialog(gui, qtbot, True)) + run_experiment() + wait_for_simulation_completed() + assert len(button_simulation_status.menu().actions()) == 3 diff --git a/tests/ert/ui_tests/gui/test_missing_runpath.py b/tests/ert/ui_tests/gui/test_missing_runpath.py index d7e0cdb9541..de4d5841fe3 100644 --- a/tests/ert/ui_tests/gui/test_missing_runpath.py +++ b/tests/ert/ui_tests/gui/test_missing_runpath.py @@ -1,7 +1,7 @@ import stat from contextlib import suppress -from qtpy.QtCore import Qt, QTimer +from qtpy.QtCore import QTimer from qtpy.QtWidgets import ( QLabel, ) @@ -55,14 +55,14 @@ def test_missing_runpath_has_isolated_failures( monkeypatch.chdir(tmp_path) write_config(tmp_path, "LOCAL") - def handle_message_box(run_dialog): + def handle_message_box(dialog): def inner(): qtbot.waitUntil( - lambda: run_dialog.fail_msg_box is not None, + lambda: dialog.fail_msg_box is not None, timeout=20000, ) - message_box = run_dialog.fail_msg_box + message_box = dialog.fail_msg_box assert message_box is not None assert message_box.label_text.text() == "ERT experiment failed!" message_box.accept() @@ -76,7 +76,10 @@ def inner(): run_dialog = wait_for_child(gui, qtbot, RunDialog, timeout=10000) QTimer.singleShot(100, handle_message_box(run_dialog)) - qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=200000) + qtbot.waitUntil( + lambda dialog=run_dialog: dialog.is_simulation_done() == True, + timeout=200000, + ) assert ( "9/10" in run_dialog._progress_widget.findChild( @@ -90,7 +93,6 @@ def inner(): QLabel, name="progress_label_text_Failed" ).text() ) - qtbot.mouseClick(run_dialog.done_button, Qt.LeftButton) finally: with suppress(FileNotFoundError): (tmp_path / "simulations/realization-0/iter-0").chmod(0x777) diff --git a/tests/ert/ui_tests/gui/test_plotting_of_snake_oil.py b/tests/ert/ui_tests/gui/test_plotting_of_snake_oil.py index ab3e9486df7..1af18cf5f3d 100644 --- a/tests/ert/ui_tests/gui/test_plotting_of_snake_oil.py +++ b/tests/ert/ui_tests/gui/test_plotting_of_snake_oil.py @@ -1,9 +1,8 @@ -import sys from unittest.mock import Mock import pytest from qtpy.QtCore import Qt -from qtpy.QtWidgets import QCheckBox +from qtpy.QtWidgets import QCheckBox, QToolButton from ert.gui.main import GUILogHandler, _setup_main_window from ert.gui.tools.plot.data_type_keys_widget import DataTypeKeysWidget @@ -60,9 +59,9 @@ def plot_figure(qtbot, heat_equation_storage, snake_oil_case_storage, request): gui = _setup_main_window(storage_config, args_mock, log_handler, storage) qtbot.addWidget(gui) - plot_tool = gui.tools["Create plot"] - plot_tool.trigger() - + button_plot_tool = gui.findChild(QToolButton, "button_Create_plot") + assert button_plot_tool + qtbot.mouseClick(button_plot_tool, Qt.LeftButton) plot_window = wait_for_child(gui, qtbot, PlotWindow) central_tab = plot_window._central_tab @@ -119,9 +118,6 @@ def plot_figure(qtbot, heat_equation_storage, snake_oil_case_storage, request): # The tolerance is chosen by guess, in one bug we observed a # mismatch of 58 which would fail the test by being above 10.0 @pytest.mark.mpl_image_compare(tolerance=10.0) -@pytest.mark.skipif( - sys.platform.startswith("darwin"), reason="Get different size image on mac" -) def test_that_all_snake_oil_visualisations_matches_snapshot(plot_figure): return plot_figure @@ -142,9 +138,9 @@ def test_that_all_plotter_filter_boxes_yield_expected_filter_results( gui.notifier.set_storage(storage) qtbot.addWidget(gui) - plot_tool = gui.tools["Create plot"] - plot_tool.trigger() - + button_plot_tool = gui.findChild(QToolButton, "button_Create_plot") + assert button_plot_tool + qtbot.mouseClick(button_plot_tool, Qt.LeftButton) plot_window = wait_for_child(gui, qtbot, PlotWindow) key_list = plot_window.findChild(DataTypeKeysWidget).data_type_keys_widget diff --git a/tests/ert/ui_tests/gui/test_restart_ensemble_experiment.py b/tests/ert/ui_tests/gui/test_restart_ensemble_experiment.py index 4f61212a105..a6b29efa13c 100644 --- a/tests/ert/ui_tests/gui/test_restart_ensemble_experiment.py +++ b/tests/ert/ui_tests/gui/test_restart_ensemble_experiment.py @@ -74,7 +74,7 @@ def _evaluate(coeffs, x): # The Run dialog opens, wait until restart appears and the tab is ready run_dialog = wait_for_child(gui, qtbot, RunDialog) - qtbot.waitUntil(run_dialog.restart_button.isVisible, timeout=60000) + qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=60000) qtbot.waitUntil(lambda: run_dialog._tab_widget.currentWidget() is not None) # Assert that the number of boxes in the detailed view is @@ -108,7 +108,7 @@ def handle_dialog(): write_poly_eval(failing_reals=failing_reals_second_try) qtbot.mouseClick(run_dialog.restart_button, Qt.MouseButton.LeftButton) - qtbot.waitUntil(run_dialog.restart_button.isVisible, timeout=60000) + qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=60000) qtbot.waitUntil(lambda: run_dialog._tab_widget.currentWidget() is not None) # We expect to have the same amount of realizations in list_model @@ -139,7 +139,7 @@ def handle_dialog(): write_poly_eval(failing_reals=failing_reals_third_try) qtbot.mouseClick(run_dialog.restart_button, Qt.MouseButton.LeftButton) - qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=60000) + qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=60000) qtbot.waitUntil(lambda: run_dialog._tab_widget.currentWidget() is not None) # We expect to have the same amount of realizations in list_model @@ -151,5 +151,3 @@ def handle_dialog(): assert ( list_model.rowCount() == experiment_panel.config.model_config.num_realizations ) - - qtbot.mouseClick(run_dialog.done_button, Qt.MouseButton.LeftButton) diff --git a/tests/ert/ui_tests/gui/test_restart_esmda.py b/tests/ert/ui_tests/gui/test_restart_esmda.py index 161a39cff0d..05723301520 100644 --- a/tests/ert/ui_tests/gui/test_restart_esmda.py +++ b/tests/ert/ui_tests/gui/test_restart_esmda.py @@ -33,14 +33,12 @@ def test_restart_esmda(ensemble_experiment_has_run_no_failure, qtbot): qtbot.mouseClick(run_experiment, Qt.MouseButton.LeftButton) qtbot.waitUntil(lambda: gui.findChild(RunDialog) is not None) run_dialog = gui.findChild(RunDialog) - qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=60000) + qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=60000) assert ( run_dialog._total_progress_label.text() == "Total progress 100% — Experiment completed." ) - qtbot.mouseClick(run_dialog.done_button, Qt.MouseButton.LeftButton) - def test_custom_weights_stored_and_retrieved_from_metadata_esmda( opened_main_window_minimal_realizations, qtbot @@ -71,14 +69,12 @@ def test_custom_weights_stored_and_retrieved_from_metadata_esmda( qtbot.mouseClick(run_experiment, Qt.MouseButton.LeftButton) qtbot.waitUntil(lambda: gui.findChild(RunDialog) is not None, timeout=5000) run_dialog = gui.findChild(RunDialog) - qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=20000) + qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=20000) assert ( run_dialog._total_progress_label.text() == "Total progress 100% — Experiment completed." ) - qtbot.mouseClick(run_dialog.done_button, Qt.MouseButton.LeftButton) assert wsb.text() == default_weights - restart_checkbox = es_mda_panel.findChild(QCheckBox, name="restart_checkbox_esmda") assert restart_checkbox assert not restart_checkbox.isChecked() diff --git a/tests/ert/ui_tests/gui/test_rft_export_plugin.py b/tests/ert/ui_tests/gui/test_rft_export_plugin.py index 30fbf22e192..83acb37b001 100644 --- a/tests/ert/ui_tests/gui/test_rft_export_plugin.py +++ b/tests/ert/ui_tests/gui/test_rft_export_plugin.py @@ -108,8 +108,8 @@ def handle_rft_plugin_dialog(): drop_constant.setChecked(True) qtbot.mouseClick(dialog.ok_button, Qt.LeftButton) - plugin_tool = gui.tools["Plugins"] - plugin_actions = plugin_tool.getAction().menu().actions() + plugin_tool = gui.plugins_tool + plugin_actions = plugin_tool.menu.actions() rft_plugin = next( a for a in plugin_actions if a.text() == "GEN_DATA RFT CSV Export" ) diff --git a/tests/ert/ui_tests/gui/test_single_test_run.py b/tests/ert/ui_tests/gui/test_single_test_run.py index b74f71c2e41..a1d60b178d0 100644 --- a/tests/ert/ui_tests/gui/test_single_test_run.py +++ b/tests/ert/ui_tests/gui/test_single_test_run.py @@ -32,11 +32,9 @@ def test_single_test_run_after_ensemble_experiment( run_experiment = get_child(experiment_panel, QWidget, name="run_experiment") qtbot.mouseClick(run_experiment, Qt.LeftButton) - # The Run dialog opens, wait until done appears, then click done run_dialog = wait_for_child(gui, qtbot, RunDialog) - qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=100000) + qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=100000) qtbot.waitUntil(lambda: run_dialog._tab_widget.currentWidget() is not None) - qtbot.mouseClick(run_dialog.done_button, Qt.LeftButton) storage = gui.notifier.storage assert "single_test_run" in [exp.name for exp in storage.experiments] diff --git a/tests/ert/ui_tests/gui/test_workflow_tool.py b/tests/ert/ui_tests/gui/test_workflow_tool.py index 0946e2949cb..a59354a50d5 100644 --- a/tests/ert/ui_tests/gui/test_workflow_tool.py +++ b/tests/ert/ui_tests/gui/test_workflow_tool.py @@ -67,8 +67,6 @@ def test_run_export_runpath_workflow(open_gui, qtbot, run_experiment): gui = open_gui run_experiment(EnsembleExperiment, gui) - workflow_tool = gui.tools["Run workflow"] - def handle_run_workflow_tool(): dialog = wait_for_child(gui, qtbot, ClosableDialog) workflow_widget = get_child(dialog, RunWorkflowWidget) @@ -82,6 +80,6 @@ def close_all(): qtbot.mouseClick(workflow_widget.run_button, Qt.MouseButton.LeftButton) QTimer.singleShot(1000, handle_run_workflow_tool) - workflow_tool.trigger() + gui.workflows_tool.trigger() assert os.path.isfile(".ert_runpath_list") diff --git a/tests/ert/unit_tests/gui/simulation/test_run_dialog.py b/tests/ert/unit_tests/gui/simulation/test_run_dialog.py index e8e520e8a83..569c82d3c65 100644 --- a/tests/ert/unit_tests/gui/simulation/test_run_dialog.py +++ b/tests/ert/unit_tests/gui/simulation/test_run_dialog.py @@ -69,23 +69,13 @@ def run_dialog(qtbot: QtBot, run_model, event_queue, notifier): return run_dialog -def test_that_done_button_is_not_hidden_when_the_end_event_is_given( - qtbot: QtBot, run_dialog, event_queue -): - run_dialog.run_experiment() - event_queue.put(EndEvent(failed=False, msg="")) - qtbot.waitUntil(lambda: not run_dialog.done_button.isHidden(), timeout=1000) - assert not run_dialog.done_button.isHidden() - qtbot.mouseClick(run_dialog.done_button, Qt.LeftButton) - - def test_terminating_experiment_shows_a_confirmation_dialog( qtbot: QtBot, run_dialog, event_queue ): run_dialog.run_experiment() event_queue.put(EndEvent(failed=False, msg="")) - with qtbot.waitSignal(run_dialog.finished, timeout=30000): + with qtbot.waitSignal(run_dialog.finished, timeout=10000): def handle_dialog(): confirm_terminate_dialog = wait_for_child( @@ -111,7 +101,7 @@ def test_run_dialog_polls_run_model_for_runtime( lambda: run_model.get_runtime.called, timeout=run_dialog._RUN_TIME_POLL_RATE * 2 ) event_queue.put(EndEvent(failed=False, msg="")) - qtbot.waitUntil(lambda: not run_dialog.done_button.isHidden()) + qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True) run_dialog.close() @@ -158,7 +148,7 @@ def test_large_snapshot( lambda: run_dialog._tab_widget.count() == 2, timeout=timeout_per_iter ) qtbot.waitUntil( - lambda: not run_dialog.done_button.isHidden(), timeout=timeout_per_iter + lambda: run_dialog.is_simulation_done() == True, timeout=timeout_per_iter ) @@ -364,7 +354,7 @@ def test_run_dialog(events, tab_widget_count, qtbot: QtBot, run_dialog, event_qu qtbot.waitUntil( lambda: run_dialog._tab_widget.count() == tab_widget_count, timeout=5000 ) - qtbot.waitUntil(lambda: not run_dialog.done_button.isHidden(), timeout=5000) + qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=5000) @pytest.mark.parametrize( @@ -446,7 +436,7 @@ def test_run_dialog_memory_usage_showing( qtbot.waitUntil( lambda: run_dialog._tab_widget.count() == tab_widget_count, timeout=5000 ) - qtbot.waitUntil(lambda: not run_dialog.done_button.isHidden(), timeout=5000) + qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=5000) # This is the container of realization boxes realization_box = run_dialog._tab_widget.widget(0) @@ -539,7 +529,7 @@ def test_run_dialog_fm_label_show_correct_info( qtbot.waitUntil( lambda: run_dialog._tab_widget.count() == tab_widget_count, timeout=5000 ) - qtbot.waitUntil(lambda: not run_dialog.done_button.isHidden(), timeout=5000) + qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=5000) # This is the container of realization boxes realization_box = run_dialog._tab_widget.widget(0) @@ -596,7 +586,7 @@ def handle_error_dialog(run_dialog): run_dialog = wait_for_child(gui, qtbot, RunDialog) QTimer.singleShot(100, lambda: handle_error_dialog(run_dialog)) - qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=200000) + qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=100000) run_dialog.close() @@ -624,7 +614,7 @@ def test_that_debug_info_button_provides_data_in_clipboard(qtbot: QtBot, storage qtbot.mouseClick(run_experiment, Qt.LeftButton) qtbot.waitUntil(lambda: gui.findChild(RunDialog) is not None, timeout=5000) run_dialog = gui.findChild(RunDialog) - qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=100000) + qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=10000) copy_debug_info_button = gui.findChild(QPushButton, "copy_debug_info_button") assert copy_debug_info_button @@ -635,7 +625,6 @@ def test_that_debug_info_button_provides_data_in_clipboard(qtbot: QtBot, storage for keyword in ["Single realization test-run", "Local", r"minimal\_config.ert"]: assert keyword in clipboard_text - qtbot.mouseClick(run_dialog.done_button, Qt.LeftButton) @pytest.mark.integration_test @@ -667,13 +656,13 @@ def test_that_stdout_and_stderr_buttons_react_to_file_content( 1000, lambda: handle_run_path_dialog(gui, qtbot, delete_run_path=True) ) qtbot.mouseClick(run_experiment, Qt.LeftButton) - qtbot.waitUntil(lambda: gui.findChild(RunDialog) is not None, timeout=5000) run_dialog = gui.findChild(RunDialog) - qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=100000) - fm_step_overview = run_dialog._fm_step_overview - qtbot.waitUntil(fm_step_overview.isVisible, timeout=20000) + qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=100000) + + fm_step_overview = run_dialog._fm_step_overview + qtbot.waitUntil(lambda: not fm_step_overview.isHidden(), timeout=20000) realization_widget = run_dialog.findChild(RealizationWidget) click_pos = realization_widget._real_view.rectForIndex( @@ -695,19 +684,15 @@ def test_that_stdout_and_stderr_buttons_react_to_file_content( assert ( fm_step_stdout.data(Qt.ItemDataRole.ForegroundRole) == Qt.GlobalColor.blue ) - assert fm_step_stderr.data(Qt.ItemDataRole.ForegroundRole) == None - - assert fm_step_stdout.data(Qt.ItemDataRole.FontRole).underline() == True - assert fm_step_stderr.data(Qt.ItemDataRole.FontRole) == None + assert fm_step_stderr.data(Qt.ItemDataRole.ForegroundRole) is None + assert fm_step_stdout.data(Qt.ItemDataRole.FontRole).underline() + assert fm_step_stderr.data(Qt.ItemDataRole.FontRole) is None click_pos = fm_step_overview.visualRect(fm_step_stdout).center() - qtbot.mouseClick(fm_step_overview.viewport(), Qt.LeftButton, pos=click_pos) - - qtbot.waitUntil(run_dialog.findChild(FileDialog).isVisible, timeout=30000) - - with qtbot.waitSignal(run_dialog.accepted, timeout=30000): - run_dialog.close() + file_dialog = run_dialog.findChild(FileDialog) + qtbot.waitUntil(file_dialog.isVisible, timeout=10000) + file_dialog.close() @pytest.mark.integration_test diff --git a/tests/ert/unit_tests/gui/simulation/test_run_path_dialog.py b/tests/ert/unit_tests/gui/simulation/test_run_path_dialog.py index 95670548dca..b0c52bb021c 100644 --- a/tests/ert/unit_tests/gui/simulation/test_run_path_dialog.py +++ b/tests/ert/unit_tests/gui/simulation/test_run_path_dialog.py @@ -92,10 +92,8 @@ def test_run_path_deleted_error( qtbot.waitUntil(lambda: gui.findChild(RunDialog) is not None) run_dialog = gui.findChild(RunDialog) - qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=100000) + qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=100000) qtbot.waitUntil(lambda: run_dialog._tab_widget.currentWidget() is not None) - qtbot.mouseClick(run_dialog.done_button, Qt.LeftButton) - assert os.path.exists(run_path / dummy_file.name) @@ -138,10 +136,8 @@ def test_run_path_is_deleted(snake_oil_case_storage: ErtConfig, qtbot: QtBot): qtbot.waitUntil(lambda: gui.findChild(RunDialog) is not None) run_dialog = gui.findChild(RunDialog) - qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=100000) + qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=100000) qtbot.waitUntil(lambda: run_dialog._tab_widget.currentWidget() is not None) - qtbot.mouseClick(run_dialog.done_button, Qt.LeftButton) - assert not os.path.exists(run_path / dummy_file.name) @@ -182,8 +178,6 @@ def test_run_path_is_not_deleted(snake_oil_case_storage: ErtConfig, qtbot: QtBot qtbot.waitUntil(lambda: gui.findChild(RunDialog) is not None, timeout=10000) run_dialog = gui.findChild(RunDialog) - qtbot.waitUntil(run_dialog.done_button.isVisible, timeout=100000) + qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=100000) qtbot.waitUntil(lambda: run_dialog._tab_widget.currentWidget() is not None) - qtbot.mouseClick(run_dialog.done_button, Qt.LeftButton) - assert os.path.exists(run_path / dummy_file.name)