From a71ab2e862d35eb21492efcbf32abc8ff7e4c3a0 Mon Sep 17 00:00:00 2001 From: Eivind Jahren Date: Mon, 17 Jun 2024 08:56:59 +0200 Subject: [PATCH] Type check ert.gui.ertwidgets --- .mypy.ini | 16 ++++-- src/ert/gui/ertwidgets/__init__.py | 7 +-- src/ert/gui/ertwidgets/analysismoduleedit.py | 8 ++- src/ert/gui/ertwidgets/checklist.py | 51 ++++++++++--------- src/ert/gui/ertwidgets/closabledialog.py | 20 +++++--- .../ertwidgets/create_experiment_dialog.py | 5 +- src/ert/gui/ertwidgets/ensemblelist.py | 2 +- src/ert/gui/ertwidgets/ensembleselector.py | 6 +-- src/ert/gui/ertwidgets/legend.py | 5 +- src/ert/gui/ertwidgets/message_box.py | 6 ++- src/ert/gui/ertwidgets/models/path_model.py | 4 +- .../gui/ertwidgets/models/storage_model.py | 8 +-- src/ert/gui/ertwidgets/pathchooser.py | 4 +- src/ert/gui/ertwidgets/searchbox.py | 18 +++---- src/ert/gui/ertwidgets/statusdialog.py | 22 +++++--- src/ert/gui/ertwidgets/storage_info_widget.py | 48 +++++++++-------- src/ert/gui/ertwidgets/storage_widget.py | 4 +- src/ert/gui/ertwidgets/stringbox.py | 4 +- src/ert/gui/ertwidgets/summarypanel.py | 8 +-- src/ert/gui/ertwidgets/validateddialog.py | 28 +++++----- src/ert/gui/ertwidgets/validationsupport.py | 8 +-- src/ert/gui/tools/file/file_dialog.py | 7 ++- .../gui/ertwidgets/test_vaidatedialog.py | 30 +++++++++++ 23 files changed, 202 insertions(+), 117 deletions(-) create mode 100644 tests/unit_tests/gui/ertwidgets/test_vaidatedialog.py diff --git a/.mypy.ini b/.mypy.ini index c3abf98fcbb..df699b94800 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -35,18 +35,25 @@ ignore_missing_imports = True [mypy-ert._clib.*] ignore_missing_imports = True -[mypy-ert.gui.ertwidgets.*] +[mypy-ert.gui.model.node] ignore_missing_imports = True ignore_errors = True -[mypy-ert.gui.model.node] +[mypy-ert.gui.model.snapshot] ignore_missing_imports = True ignore_errors = True -[mypy-ert.gui.model.snapshot] +[mypy-ert.gui.ertwidgets.validationsupport] ignore_missing_imports = True ignore_errors = True +[mypy-ert.gui.ertwidgets.analysismodulevariablespanel] +ignore_missing_imports = True +ignore_errors = True + +[mypy-ert.gui.ertwidgets.listeditbox] +ignore_missing_imports = True +ignore_errors = True [mypy-ert.gui.simulation.*] ignore_missing_imports = True @@ -92,6 +99,9 @@ ignore_missing_imports = True [mypy-SALib.*] ignore_missing_imports = True +[mypy-seaborn.*] +ignore_missing_imports = True + [mypy-pluggy.*] ignore_missing_imports = True diff --git a/src/ert/gui/ertwidgets/__init__.py b/src/ert/gui/ertwidgets/__init__.py index 98b21c91f18..f6f4c7a00cc 100644 --- a/src/ert/gui/ertwidgets/__init__.py +++ b/src/ert/gui/ertwidgets/__init__.py @@ -2,13 +2,14 @@ from qtpy.QtCore import Qt from qtpy.QtGui import QCursor from qtpy.QtWidgets import QApplication +from typing import Callable, Any -def showWaitCursorWhileWaiting(func): +def showWaitCursorWhileWaiting(func: Callable[..., Any]) -> Callable[..., Any]: """A function decorator to show the wait cursor while the function is working.""" - def wrapper(*arg): - QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) + def wrapper(*arg: Any) -> Any: + QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) try: res = func(*arg) return res diff --git a/src/ert/gui/ertwidgets/analysismoduleedit.py b/src/ert/gui/ertwidgets/analysismoduleedit.py index f6892727567..92270bfb0a7 100644 --- a/src/ert/gui/ertwidgets/analysismoduleedit.py +++ b/src/ert/gui/ertwidgets/analysismoduleedit.py @@ -30,7 +30,7 @@ def __init__( variables_popup_button.clicked.connect(self.showVariablesPopup) variables_popup_button.setMaximumSize(20, 20) - layout.addWidget(variables_popup_button, 0, Qt.AlignLeft) + layout.addWidget(variables_popup_button, 0, Qt.AlignmentFlag.AlignLeft) layout.setContentsMargins(QMargins(0, 0, 0, 0)) layout.addStretch() @@ -40,5 +40,9 @@ def showVariablesPopup(self) -> None: variable_dialog = AnalysisModuleVariablesPanel( self.analysis_module, self.ensemble_size ) - dialog = ClosableDialog("Edit variables", variable_dialog, self.parent()) + dialog = ClosableDialog( + "Edit variables", + variable_dialog, + self.parent(), # type: ignore + ) dialog.exec_() diff --git a/src/ert/gui/ertwidgets/checklist.py b/src/ert/gui/ertwidgets/checklist.py index 416a80f20be..5c01005d24b 100644 --- a/src/ert/gui/ertwidgets/checklist.py +++ b/src/ert/gui/ertwidgets/checklist.py @@ -1,4 +1,8 @@ -from qtpy.QtCore import QSize, Qt +from __future__ import annotations + +from typing import TYPE_CHECKING, Optional + +from qtpy.QtCore import QPoint, QSize, Qt from qtpy.QtGui import QIcon from qtpy.QtWidgets import ( QAbstractItemView, @@ -14,14 +18,21 @@ from ert.gui.ertwidgets import SearchBox +if TYPE_CHECKING: + from .models.selectable_list_model import SelectableListModel + class CheckList(QWidget): - def __init__(self, model, label: str = "", custom_filter_button=None): + def __init__( + self, + model: SelectableListModel, + label: str = "", + custom_filter_button: Optional[QToolButton] = None, + ): """ :param custom_filter_button: if needed, add a button that opens a custom filter menu. Useful when search alone isn't enough to filter the list. - :type custom_filter_button: QToolButton """ QWidget.__init__(self) @@ -32,7 +43,7 @@ def __init__(self, model, label: str = "", custom_filter_button=None): self._createCheckButtons() self._list = QListWidget() - self._list.setContextMenuPolicy(Qt.CustomContextMenu) + self._list.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) self._list.setSelectionMode(QAbstractItemView.ExtendedSelection) self._search_box = SearchBox() @@ -76,20 +87,20 @@ def _createCheckButtons(self) -> None: self._checkAllButton = QToolButton() self._checkAllButton.setIcon(QIcon("img:check.svg")) self._checkAllButton.setIconSize(QSize(16, 16)) - self._checkAllButton.setToolButtonStyle(Qt.ToolButtonIconOnly) + self._checkAllButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly) self._checkAllButton.setAutoRaise(True) self._checkAllButton.setToolTip("Select all") self._uncheckAllButton = QToolButton() self._uncheckAllButton.setIcon(QIcon("img:checkbox_outline.svg")) self._uncheckAllButton.setIconSize(QSize(16, 16)) - self._uncheckAllButton.setToolButtonStyle(Qt.ToolButtonIconOnly) + self._uncheckAllButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly) self._uncheckAllButton.setAutoRaise(True) self._uncheckAllButton.setToolTip("Unselect all") - def itemChanged(self, item: QListWidgetItem): - if item.checkState() == Qt.Checked: + def itemChanged(self, item: QListWidgetItem) -> None: + if item.checkState() == Qt.CheckState.Checked: self._model.selectValue(str(item.text())) - elif item.checkState() == Qt.Unchecked: + elif item.checkState() == Qt.CheckState.Unchecked: self._model.unselectValue(str(item.text())) else: raise AssertionError("Unhandled checkstate!") @@ -101,12 +112,12 @@ def modelChanged(self) -> None: for item in items: list_item = QListWidgetItem(item) - list_item.setFlags(list_item.flags() | Qt.ItemIsUserCheckable) + list_item.setFlags(list_item.flags() | Qt.ItemFlag.ItemIsUserCheckable) if self._model.isValueSelected(item): - list_item.setCheckState(Qt.Checked) + list_item.setCheckState(Qt.CheckState.Checked) else: - list_item.setCheckState(Qt.Unchecked) + list_item.setCheckState(Qt.CheckState.Unchecked) self._list.addItem(list_item) @@ -117,6 +128,7 @@ def filterList(self, _filter: str) -> None: for index in range(0, self._list.count()): item = self._list.item(index) + assert item is not None text = item.text().lower() if not _filter or _filter in text: @@ -130,6 +142,7 @@ def checkAll(self) -> None: """ for index in range(0, self._list.count()): item = self._list.item(index) + assert item is not None if not item.isHidden(): self._model.selectValue(str(item.text())) @@ -140,22 +153,14 @@ def uncheckAll(self) -> None: self._model.unselectAll() def checkSelected(self) -> None: - items = [] for item in self._list.selectedItems(): - items.append(str(item.text())) - - for item in items: - self._model.selectValue(item) + self._model.selectValue(str(item.text())) def uncheckSelected(self) -> None: - items = [] for item in self._list.selectedItems(): - items.append(str(item.text())) - - for item in items: - self._model.unselectValue(item) + self._model.unselectValue(str(item.text())) - def showContextMenu(self, point): + def showContextMenu(self, point: QPoint) -> None: p = self._list.mapToGlobal(point) menu = QMenu() check_selected = menu.addAction("Check selected") diff --git a/src/ert/gui/ertwidgets/closabledialog.py b/src/ert/gui/ertwidgets/closabledialog.py index 68d18cfdd4f..f02cdda8c9a 100644 --- a/src/ert/gui/ertwidgets/closabledialog.py +++ b/src/ert/gui/ertwidgets/closabledialog.py @@ -6,6 +6,7 @@ from qtpy.QtWidgets import QDialog, QHBoxLayout, QPushButton, QVBoxLayout, QWidget if TYPE_CHECKING: + from qtpy.QtGui import QKeyEvent from qtpy.QtWidgets import QT_SLOT @@ -16,9 +17,14 @@ def __init__( QDialog.__init__(self, parent) self.setWindowTitle(title) self.setModal(True) - self.setWindowFlags(self.windowFlags() | Qt.CustomizeWindowHint) - self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) - self.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint) + self.setWindowFlags(self.windowFlags() | Qt.WindowType.CustomizeWindowHint) + self.setWindowFlags( + self.windowFlags() + & ~Qt.WindowFlags(Qt.WindowType.WindowContextHelpButtonHint) + ) + self.setWindowFlags( + self.windowFlags() & ~Qt.WindowFlags(Qt.WindowType.WindowCloseButtonHint) + ) layout = QVBoxLayout() layout.addWidget(widget, stretch=1) @@ -41,9 +47,11 @@ def disableCloseButton(self) -> None: def enableCloseButton(self) -> None: self.close_button.setEnabled(True) - def keyPressEvent(self, q_key_event): - if self.close_button.isEnabled() or q_key_event.key() != Qt.Key_Escape: - QDialog.keyPressEvent(self, q_key_event) + def keyPressEvent(self, a0: Optional[QKeyEvent]) -> None: + if self.close_button.isEnabled() or ( + a0 is not None and a0.key() != Qt.Key.Key_Escape + ): + QDialog.keyPressEvent(self, a0) def addButton(self, caption: str, listener: QT_SLOT) -> None: button = QPushButton(caption) diff --git a/src/ert/gui/ertwidgets/create_experiment_dialog.py b/src/ert/gui/ertwidgets/create_experiment_dialog.py index 1cd6a75af92..9a5d8572e9a 100644 --- a/src/ert/gui/ertwidgets/create_experiment_dialog.py +++ b/src/ert/gui/ertwidgets/create_experiment_dialog.py @@ -44,8 +44,9 @@ def __init__( ) buttons.accepted.connect(self.accept) buttons.rejected.connect(self.reject) - self._ok_button = buttons.button(QDialogButtonBox.Ok) - assert self._ok_button + ok_button = buttons.button(QDialogButtonBox.Ok) + assert ok_button + self._ok_button = ok_button self._ok_button.clicked.connect( lambda: self.onDone.emit( diff --git a/src/ert/gui/ertwidgets/ensemblelist.py b/src/ert/gui/ertwidgets/ensemblelist.py index 4a9963d44e8..e944c4522b4 100644 --- a/src/ert/gui/ertwidgets/ensemblelist.py +++ b/src/ert/gui/ertwidgets/ensemblelist.py @@ -110,5 +110,5 @@ def updateList(self) -> None: item = QListWidgetItem( f"{ensemble.name} - {ensemble.started_at} ({ensemble.id})" ) - item.setData(Qt.UserRole, ensemble) + item.setData(Qt.ItemDataRole.UserRole, ensemble) self._list.addItem(item) diff --git a/src/ert/gui/ertwidgets/ensembleselector.py b/src/ert/gui/ertwidgets/ensembleselector.py index 38159cdd2f2..db0d977c449 100644 --- a/src/ert/gui/ertwidgets/ensembleselector.py +++ b/src/ert/gui/ertwidgets/ensembleselector.py @@ -81,7 +81,7 @@ def populate(self) -> None: def _ensemble_list(self) -> Iterable[Ensemble]: if self._show_only_undefined: - ensemble_list = ( + ensembles = ( ensemble for ensemble in self.notifier.storage.ensembles if all( @@ -90,8 +90,8 @@ def _ensemble_list(self) -> Iterable[Ensemble]: ) ) else: - ensemble_list = self.notifier.storage.ensembles - ensemble_list = list(ensemble_list) + ensembles = self.notifier.storage.ensembles + ensemble_list = list(ensembles) if self._show_only_no_children: parents = [ ens.parent for ens in self.notifier.storage.ensembles if ens.parent diff --git a/src/ert/gui/ertwidgets/legend.py b/src/ert/gui/ertwidgets/legend.py index bd0989b20f8..9733cf3c2e2 100644 --- a/src/ert/gui/ertwidgets/legend.py +++ b/src/ert/gui/ertwidgets/legend.py @@ -1,7 +1,7 @@ from typing import Optional from qtpy.QtCore import QSize -from qtpy.QtGui import QColor, QPainter +from qtpy.QtGui import QColor, QPainter, QPaintEvent from qtpy.QtWidgets import QHBoxLayout, QLabel, QWidget @@ -16,8 +16,7 @@ def __init__(self, color: QColor): self.color = color - def paintEvent(self, paintevent): - """Paints the box""" + def paintEvent(self, a0: Optional[QPaintEvent]) -> None: painter = QPainter(self) rect = self.contentsRect() diff --git a/src/ert/gui/ertwidgets/message_box.py b/src/ert/gui/ertwidgets/message_box.py index 6c4f9928b9a..b3aa6d495da 100644 --- a/src/ert/gui/ertwidgets/message_box.py +++ b/src/ert/gui/ertwidgets/message_box.py @@ -28,8 +28,8 @@ def __init__( super().__init__(parent) self.box = QDialogButtonBox( QDialogButtonBox.Ok, - centerButtons=True, ) + self.box.setCenterButtons(True) self.box.accepted.connect(self.accept) self.details_text = QTextEdit() @@ -39,7 +39,9 @@ def __init__( self.label_text = QLabel(text) self.label_icon = QLabel() - icon = self.style().standardIcon(QStyle.SP_MessageBoxCritical) + style = self.style() + assert style is not None + icon = style.standardIcon(QStyle.StandardPixmap.SP_MessageBoxCritical) self.label_icon.setPixmap(icon.pixmap(32)) lay = QGridLayout(self) diff --git a/src/ert/gui/ertwidgets/models/path_model.py b/src/ert/gui/ertwidgets/models/path_model.py index 8d8cedaa600..e03df7e7152 100644 --- a/src/ert/gui/ertwidgets/models/path_model.py +++ b/src/ert/gui/ertwidgets/models/path_model.py @@ -1,3 +1,5 @@ +from typing import Optional + from ert.gui.ertwidgets.models.valuemodel import ValueModel @@ -39,7 +41,7 @@ def pathMustExist(self) -> bool: def pathMustBeAbsolute(self) -> bool: return self._path_must_be_absolute - def getPath(self) -> str: + def getPath(self) -> Optional[str]: return self.getValue() def setPath(self, value: str) -> None: diff --git a/src/ert/gui/ertwidgets/models/storage_model.py b/src/ert/gui/ertwidgets/models/storage_model.py index 1061e898fbf..39720b40a53 100644 --- a/src/ert/gui/ertwidgets/models/storage_model.py +++ b/src/ert/gui/ertwidgets/models/storage_model.py @@ -51,7 +51,7 @@ def row(self) -> int: return self._parent._children.index(self) return 0 - def data(self, index: QModelIndex, role) -> Any: + def data(self, index: QModelIndex, role: Qt.ItemDataRole) -> Any: if not index.isValid(): return None @@ -78,7 +78,7 @@ def row(self) -> int: return self._parent._children.index(self) return 0 - def data(self, index: QModelIndex, role) -> Any: + def data(self, index: QModelIndex, role: Qt.ItemDataRole) -> Any: if not index.isValid(): return None @@ -111,7 +111,9 @@ def row(self) -> int: return self._parent._children.index(self) return 0 - def data(self, index: QModelIndex, role=Qt.ItemDataRole.DisplayRole) -> Any: + def data( + self, index: QModelIndex, role: Qt.ItemDataRole = Qt.ItemDataRole.DisplayRole + ) -> Any: if not index.isValid(): return None diff --git a/src/ert/gui/ertwidgets/pathchooser.py b/src/ert/gui/ertwidgets/pathchooser.py index 43eed5e1961..4875601eb2b 100644 --- a/src/ert/gui/ertwidgets/pathchooser.py +++ b/src/ert/gui/ertwidgets/pathchooser.py @@ -128,11 +128,11 @@ def selectPath(self) -> None: current_directory = self.getPath() if self._model.pathMustBeAFile(): - current_directory: tuple[str, str] = QFileDialog.getOpenFileName( + current_directory = QFileDialog.getOpenFileName( self, "Select a file path", current_directory )[0] else: - current_directory: str = QFileDialog.getExistingDirectory( + current_directory = QFileDialog.getExistingDirectory( self, "Select a directory", current_directory ) diff --git a/src/ert/gui/ertwidgets/searchbox.py b/src/ert/gui/ertwidgets/searchbox.py index 2647129fcd2..c84499e74de 100644 --- a/src/ert/gui/ertwidgets/searchbox.py +++ b/src/ert/gui/ertwidgets/searchbox.py @@ -1,7 +1,7 @@ -from typing import Any +from typing import Any, Optional from qtpy.QtCore import Qt, Signal -from qtpy.QtGui import QColor +from qtpy.QtGui import QColor, QFocusEvent, QKeyEvent from qtpy.QtWidgets import QLineEdit @@ -54,17 +54,17 @@ def exitSearch(self) -> None: if not self.text(): self.presentSearch() - def focusInEvent(self, focus_event): - QLineEdit.focusInEvent(self, focus_event) + def focusInEvent(self, a0: Optional[QFocusEvent]) -> None: + QLineEdit.focusInEvent(self, a0) self.enterSearch() - def focusOutEvent(self, focus_event): - QLineEdit.focusOutEvent(self, focus_event) + def focusOutEvent(self, a0: Optional[QFocusEvent]) -> None: + QLineEdit.focusOutEvent(self, a0) self.exitSearch() - def keyPressEvent(self, key_event): - if key_event.key() == Qt.Key_Escape: + def keyPressEvent(self, a0: Optional[QKeyEvent]) -> None: + if a0 is not None and a0.key() != Qt.Key.Key_Escape: self.clear() self.clearFocus() else: - QLineEdit.keyPressEvent(self, key_event) + QLineEdit.keyPressEvent(self, a0) diff --git a/src/ert/gui/ertwidgets/statusdialog.py b/src/ert/gui/ertwidgets/statusdialog.py index 01ea3414cd2..42ecb195d8d 100644 --- a/src/ert/gui/ertwidgets/statusdialog.py +++ b/src/ert/gui/ertwidgets/statusdialog.py @@ -1,6 +1,7 @@ from typing import Any, List, Optional, cast from qtpy.QtCore import Qt, Signal, Slot +from qtpy.QtGui import QKeyEvent from qtpy.QtWidgets import ( QDialog, QHBoxLayout, @@ -14,7 +15,7 @@ class StatusDialog(QDialog): - close = Signal() + close = Signal() # type: ignore run = Signal() def __init__( @@ -24,9 +25,14 @@ def __init__( self.setWindowTitle(title) self.setModal(True) - self.setWindowFlags(self.windowFlags() | Qt.CustomizeWindowHint) - self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) - self.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint) + self.setWindowFlags(self.windowFlags() | Qt.WindowType.CustomizeWindowHint) + self.setWindowFlags( + self.windowFlags() + & ~Qt.WindowFlags(Qt.WindowType.WindowContextHelpButtonHint) + ) + self.setWindowFlags( + self.windowFlags() & ~Qt.WindowFlags(Qt.WindowType.WindowCloseButtonHint) + ) layout = QVBoxLayout() layout.addWidget(widget) @@ -53,9 +59,11 @@ def __init__( self.setLayout(layout) - def keyPressEvent(self, q_key_event): - if self._close_button.isEnabled() or q_key_event.key() != Qt.Key_Escape: - QDialog.keyPressEvent(self, q_key_event) + def keyPressEvent(self, a0: Optional[QKeyEvent]) -> None: + if self._close_button.isEnabled() or ( + a0 is not None and a0.key() != Qt.Key.Key_Escape + ): + QDialog.keyPressEvent(self, a0) def enable_button(self, caption: Any, enabled: bool = True) -> None: button = self.findChild(QPushButton, str(caption).capitalize()) diff --git a/src/ert/gui/ertwidgets/storage_info_widget.py b/src/ert/gui/ertwidgets/storage_info_widget.py index 3ebc3795a8b..8ca06bfeb36 100644 --- a/src/ert/gui/ertwidgets/storage_info_widget.py +++ b/src/ert/gui/ertwidgets/storage_info_widget.py @@ -5,7 +5,7 @@ import numpy as np import seaborn as sns import yaml -from matplotlib.backends.backend_qt5agg import FigureCanvas +from matplotlib.backends.backend_qt5agg import FigureCanvas # type: ignore from matplotlib.figure import Figure from qtpy.QtCore import Qt, Slot from qtpy.QtWidgets import ( @@ -121,12 +121,12 @@ def __init__(self) -> None: self._name_label = QLabel() self._uuid_label = QLabel() - layout = QVBoxLayout() - layout.addWidget(self._name_label) - layout.addWidget(self._uuid_label) - layout.addStretch() + info_layout = QVBoxLayout() + info_layout.addWidget(self._name_label) + info_layout.addWidget(self._uuid_label) + info_layout.addStretch() - info_frame.setLayout(layout) + info_frame.setLayout(info_layout) self._state_text_edit = QTextEdit() self._state_text_edit.setReadOnly(True) @@ -148,10 +148,10 @@ def __init__(self) -> None: self._canvas.setFocusPolicy(Qt.FocusPolicy.StrongFocus) self._canvas.setFocus() - layout = QHBoxLayout() - layout.addWidget(self._observations_tree_widget) - layout.addWidget(self._canvas) - observations_frame.setLayout(layout) + observations_layout = QHBoxLayout() + observations_layout.addWidget(self._observations_tree_widget) + observations_layout.addWidget(self._canvas) + observations_frame.setLayout(observations_layout) self._tab_widget = QTabWidget() self._tab_widget.insertTab( @@ -187,11 +187,13 @@ def _currentItemChanged( ax.set_title(observation_name) ax.grid(True) - response_name, response_type = self._ensemble.experiment.response_info_for_obs( + ensemble = self._ensemble + assert ensemble is not None + response_name, response_type = ensemble.experiment.response_info_for_obs( observation_name ) - observation_ds = self._ensemble.experiment.get_single_obs_ds(observation_name) - response_ds = self._ensemble.load_responses( + observation_ds = ensemble.experiment.get_single_obs_ds(observation_name) + response_ds = ensemble.load_responses( response_name, ) @@ -211,7 +213,7 @@ def _currentItemChanged( ax.errorbar( x="Observation", - y=observation_ds.get("observations"), + y=observation_ds.get("observations"), # type: ignore yerr=observation_ds.get("std"), fmt=".", linewidth=1, @@ -231,7 +233,7 @@ def _currentItemChanged( ax.errorbar( x="Observation", - y=observation_ds.get("observations"), + y=observation_ds.get("observations"), # type: ignore yerr=observation_ds.get("std"), fmt=".", linewidth=1, @@ -245,7 +247,9 @@ def _currentTabChanged(self, index: int) -> None: if index == _EnsembleWidgetTabs.STATE_TAB: self._state_text_edit.clear() html = "" - for state_index, value in enumerate(self._ensemble.get_ensemble_state()): + ensemble = self._ensemble + assert ensemble is not None + for state_index, value in enumerate(ensemble.get_ensemble_state()): html += ( f"" ) @@ -257,7 +261,9 @@ def _currentTabChanged(self, index: int) -> None: self._figure.clear() self._canvas.draw() - exp = self._ensemble.experiment + ensemble = self._ensemble + assert ensemble is not None + exp = ensemble.experiment for obs_name in exp.observation_keys: response_name, response_type = exp.response_info_for_obs(obs_name) obs_ds = exp.get_single_obs_ds(obs_name) @@ -288,10 +294,10 @@ def _currentTabChanged(self, index: int) -> None: self._observations_tree_widget.sortItems(0, Qt.SortOrder.AscendingOrder) for i in range(self._observations_tree_widget.topLevelItemCount()): - if self._observations_tree_widget.topLevelItem(i).childCount() > 0: - self._observations_tree_widget.setCurrentItem( - self._observations_tree_widget.topLevelItem(i).child(0) - ) + item = self._observations_tree_widget.topLevelItem(i) + assert item is not None + if item.childCount() > 0: + self._observations_tree_widget.setCurrentItem(item.child(0)) break @Slot(Ensemble) diff --git a/src/ert/gui/ertwidgets/storage_widget.py b/src/ert/gui/ertwidgets/storage_widget.py index 565ca8e3e2d..90120ae291a 100644 --- a/src/ert/gui/ertwidgets/storage_widget.py +++ b/src/ert/gui/ertwidgets/storage_widget.py @@ -82,8 +82,8 @@ def __init__( search_bar.textChanged.connect(proxy_model.setFilterFixedString) selection_model = QItemSelectionModel(proxy_model) + selection_model.currentChanged.connect(self._currentChanged) self._tree_view.setSelectionModel(selection_model) - self._tree_view.selectionModel().currentChanged.connect(self._currentChanged) self._tree_view.setColumnWidth(0, 225) self._tree_view.setColumnWidth(1, 125) self._tree_view.setColumnWidth(2, 100) @@ -98,7 +98,7 @@ def __init__( self.setLayout(layout) def _currentChanged(self, selected: QModelIndex, previous: QModelIndex) -> None: - idx = self._tree_view.model().mapToSource(selected) + idx = self._tree_view.model().mapToSource(selected) # type: ignore cls = idx.internalPointer() if isinstance(cls, EnsembleModel): diff --git a/src/ert/gui/ertwidgets/stringbox.py b/src/ert/gui/ertwidgets/stringbox.py index 1108aa0e894..6dd4140c8c2 100644 --- a/src/ert/gui/ertwidgets/stringbox.py +++ b/src/ert/gui/ertwidgets/stringbox.py @@ -75,7 +75,7 @@ def emitChange(self, q_string: Any) -> None: def stringBoxChanged(self) -> None: """Called whenever the contents of the editline changes.""" - text = self.text() + text: Optional[str] = self.text() if not text: text = None @@ -95,7 +95,7 @@ def modelChanged(self) -> None: def model(self) -> TextModel: return self._model - def setValidator(self, validator): + def setValidator(self, validator: ArgumentDefinition) -> None: # type: ignore self._validator = validator def getValidationSupport(self) -> ValidationSupport: diff --git a/src/ert/gui/ertwidgets/summarypanel.py b/src/ert/gui/ertwidgets/summarypanel.py index f733f6a70d0..fd1551f3b89 100644 --- a/src/ert/gui/ertwidgets/summarypanel.py +++ b/src/ert/gui/ertwidgets/summarypanel.py @@ -63,8 +63,8 @@ def __init__(self, ert: "EnKFMain"): self.setMinimumHeight(150) widget = QWidget() - self.layout = QHBoxLayout() - widget.setLayout(self.layout) + self._layout = QHBoxLayout() + widget.setLayout(self._layout) scroll = QScrollArea() scroll.setWidgetResizable(True) @@ -112,11 +112,11 @@ def addColumn(self, text: str) -> None: layout = QVBoxLayout() text_widget = QLabel(text) text_widget.setWordWrap(True) - text_widget.setTextFormat(Qt.RichText) + text_widget.setTextFormat(Qt.TextFormat.RichText) layout.addWidget(text_widget) layout.addStretch(1) - self.layout.addLayout(layout) + self._layout.addLayout(layout) @staticmethod def _runlength_encode_list(strings: List[str]) -> List[Tuple[str, int]]: diff --git a/src/ert/gui/ertwidgets/validateddialog.py b/src/ert/gui/ertwidgets/validateddialog.py index 8f747d7a494..36a309db956 100644 --- a/src/ert/gui/ertwidgets/validateddialog.py +++ b/src/ert/gui/ertwidgets/validateddialog.py @@ -35,21 +35,25 @@ def __init__( self.unique_names = unique_names - self.layout = QFormLayout() - self.layout.setSizeConstraint(QLayout.SetFixedSize) + self._layout = QFormLayout() + self._layout.setSizeConstraint(QLayout.SizeConstraint.SetFixedSize) label = QLabel(description) - label.setAlignment(Qt.AlignHCenter) + label.setAlignment(Qt.AlignmentFlag.AlignHCenter) - self.layout.addRow(self.createSpace(5)) - self.layout.addRow(label) - self.layout.addRow(self.createSpace(10)) + self._layout.addRow(self.createSpace(5)) + self._layout.addRow(label) + self._layout.addRow(self.createSpace(10)) buttons = QDialogButtonBox( - QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self + QDialogButtonBox.Ok | QDialogButtonBox.Cancel, + Qt.Orientation.Horizontal, + self, ) self.cancel_button = buttons.button(QDialogButtonBox.Cancel) - self.ok_button = buttons.button(QDialogButtonBox.Ok) + ok_button = buttons.button(QDialogButtonBox.Ok) + assert ok_button is not None + self.ok_button = ok_button self.ok_button.setEnabled(False) self.param_name = QLineEdit(self) @@ -59,16 +63,16 @@ def __init__( self.param_name.backgroundRole() ) - self.layout.addRow("Name:", self.param_name) + self._layout.addRow("Name:", self.param_name) - self.layout.addRow(self.createSpace(10)) + self._layout.addRow(self.createSpace(10)) - self.layout.addRow(buttons) + self._layout.addRow(buttons) buttons.accepted.connect(self.accept) buttons.rejected.connect(self.reject) - self.setLayout(self.layout) + self.setLayout(self._layout) def notValid(self, msg: Optional[str]) -> None: """Called when the name is not valid.""" diff --git a/src/ert/gui/ertwidgets/validationsupport.py b/src/ert/gui/ertwidgets/validationsupport.py index 5b58e026bdd..8199384a893 100644 --- a/src/ert/gui/ertwidgets/validationsupport.py +++ b/src/ert/gui/ertwidgets/validationsupport.py @@ -22,8 +22,8 @@ class ErrorPopup(QWidget): "" ) - def __init__(self): - QWidget.__init__(self, None, Qt.ToolTip) + def __init__(self) -> None: + QWidget.__init__(self, None, Qt.WindowType.ToolTip) self.resize(300, 50) self.setContentsMargins(0, 0, 0, 0) @@ -35,12 +35,12 @@ def __init__(self): self._error_widget.setFrameStyle(QFrame.Box) self._error_widget.setWordWrap(True) self._error_widget.setScaledContents(True) - self._error_widget.setTextFormat(Qt.RichText) + self._error_widget.setTextFormat(Qt.TextFormat.RichText) layout.addWidget(self._error_widget) self.setLayout(layout) - def presentError(self, widget, error): + def presentError(self, widget: QWidget, error: str) -> None: assert isinstance(widget, QWidget) self._error_widget.setText(ErrorPopup.error_template % html.escape(error)) diff --git a/src/ert/gui/tools/file/file_dialog.py b/src/ert/gui/tools/file/file_dialog.py index f85b3c7b388..bd0d2af3854 100644 --- a/src/ert/gui/tools/file/file_dialog.py +++ b/src/ert/gui/tools/file/file_dialog.py @@ -16,8 +16,11 @@ from .file_update_worker import FileUpdateWorker -def calculate_screen_size_based_height(): - screen_height = QApplication.primaryScreen().geometry().height() +def calculate_screen_size_based_height() -> int: + screen = QApplication.primaryScreen() + if screen is None: + return 1024 + screen_height = screen.geometry().height() max_ratio_of_screen = 1.0 / 3.0 return floor(screen_height * max_ratio_of_screen) diff --git a/tests/unit_tests/gui/ertwidgets/test_vaidatedialog.py b/tests/unit_tests/gui/ertwidgets/test_vaidatedialog.py new file mode 100644 index 00000000000..d300e2782e8 --- /dev/null +++ b/tests/unit_tests/gui/ertwidgets/test_vaidatedialog.py @@ -0,0 +1,30 @@ +from ert.gui.ertwidgets.validateddialog import ValidatedDialog + + +def test_toggling_valid_will_toggle_ok_button_enabled(qtbot): + dialog = ValidatedDialog() + qtbot.addWidget(dialog) + + assert not dialog.ok_button.isEnabled() + + dialog.valid() + assert dialog.ok_button.isEnabled() + + dialog.notValid("Not valid") + assert not dialog.ok_button.isEnabled() + assert dialog.param_name.toolTip() == "Not valid" + + +def test_validate_name(qtbot): + dialog = ValidatedDialog(unique_names=["name1", "name2"]) + qtbot.addWidget(dialog) + + dialog.validateName("John Snow") + assert dialog.param_name.toolTip() == "No spaces allowed!" + + dialog.validateName("name1") + assert dialog.param_name.toolTip() == "Name must be unique!" + + dialog.validateName("unique_name") + assert dialog.param_name.toolTip() == "" + assert dialog.ok_button.isEnabled()
{state_index:d}.{value.name}