diff --git a/.github/actions/install_dependencies_qt/action.yml b/.github/actions/install_dependencies_qt/action.yml new file mode 100644 index 00000000000..55ae7aabc02 --- /dev/null +++ b/.github/actions/install_dependencies_qt/action.yml @@ -0,0 +1,16 @@ +name: install_dependencies_qt +description: Installs dependencies for qt + +inputs: + os: + required: true + +runs: + using: "composite" + steps: + - name: Install Ubuntu dependencies + if: inputs.os == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install libegl1 + shell: bash diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 1a0d944922f..9b9fe110b15 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -133,6 +133,10 @@ jobs: fetch-depth: 0 filter: tree:0 + - uses: ./.github/actions/install_dependencies_qt + with: + os: ${{ matrix.os }} + - name: Install pandoc run: | sudo apt install pandoc diff --git a/.github/workflows/codspeed.yml b/.github/workflows/codspeed.yml index ad51eff182a..b77b3fdb23e 100644 --- a/.github/workflows/codspeed.yml +++ b/.github/workflows/codspeed.yml @@ -20,6 +20,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - uses: ./.github/actions/install_dependencies_qt + with: + os: ubuntu-latest - uses: actions/setup-python@v5 with: python-version: '3.12' diff --git a/.github/workflows/run_ert_test_data_setups.yml b/.github/workflows/run_ert_test_data_setups.yml index c5ec7c0bf83..25da74be470 100644 --- a/.github/workflows/run_ert_test_data_setups.yml +++ b/.github/workflows/run_ert_test_data_setups.yml @@ -32,6 +32,10 @@ jobs: fetch-depth: 0 filter: tree:0 + - uses: ./.github/actions/install_dependencies_qt + with: + os: ${{ matrix.os }} + - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: diff --git a/.github/workflows/test_ert.yml b/.github/workflows/test_ert.yml index c38a0f520dc..36d06ffa54a 100644 --- a/.github/workflows/test_ert.yml +++ b/.github/workflows/test_ert.yml @@ -28,6 +28,10 @@ jobs: submodules: true lfs: true + - uses: ./.github/actions/install_dependencies_qt + with: + os: ${{ inputs.os }} + - uses: actions/setup-python@v5 id: setup_python with: diff --git a/.github/workflows/test_ert_with_flow.yml b/.github/workflows/test_ert_with_flow.yml index 47097eb46b3..3c9386136fa 100644 --- a/.github/workflows/test_ert_with_flow.yml +++ b/.github/workflows/test_ert_with_flow.yml @@ -18,6 +18,10 @@ jobs: steps: - uses: actions/checkout@v4 + - uses: ./.github/actions/install_dependencies_qt + with: + os: ${{ inputs.os }} + - uses: actions/setup-python@v5 id: setup_python with: diff --git a/.github/workflows/test_ert_with_slurm.yml b/.github/workflows/test_ert_with_slurm.yml index 80041c70bad..8975ef64dea 100644 --- a/.github/workflows/test_ert_with_slurm.yml +++ b/.github/workflows/test_ert_with_slurm.yml @@ -18,6 +18,10 @@ jobs: steps: - uses: actions/checkout@v4 + - uses: ./.github/actions/install_dependencies_qt + with: + os: ${{ inputs.os }} + - uses: actions/setup-python@v5 id: setup_python with: diff --git a/.github/workflows/test_everest.yml b/.github/workflows/test_everest.yml index 3becdf4feda..ec10e5f144b 100644 --- a/.github/workflows/test_everest.yml +++ b/.github/workflows/test_everest.yml @@ -26,6 +26,10 @@ jobs: fetch-depth: 0 filter: tree:0 + - uses: ./.github/actions/install_dependencies_qt + with: + os: ${{ inputs.os }} + - name: Set up Python ${{ inputs.python-version }} uses: actions/setup-python@v5 with: diff --git a/.github/workflows/test_semeio.yml b/.github/workflows/test_semeio.yml index de0fa6469b0..d4fde572932 100644 --- a/.github/workflows/test_semeio.yml +++ b/.github/workflows/test_semeio.yml @@ -29,6 +29,10 @@ jobs: fetch-depth: 0 filter: tree:0 + - uses: ./.github/actions/install_dependencies_qt + with: + os: ubuntu-latest + - name: Set up Python uses: actions/setup-python@v5 with: diff --git a/pyproject.toml b/pyproject.toml index c08c27b0a6e..f7643b40c08 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,15 +1,10 @@ [build-system] -requires = [ - "setuptools", - "setuptools_scm>=8.1", -] +requires = ["setuptools", "setuptools_scm>=8.1"] build-backend = "setuptools.build_meta" [project] name = "ert" -authors = [ - { name = "Equinor ASA", email = "fg_sib-scout@equinor.com" }, -] +authors = [{ name = "Equinor ASA", email = "fg_sib-scout@equinor.com" }] description = "Ensemble based Reservoir Tool (ERT)" requires-python = ">=3.11" readme = "README.md" @@ -42,7 +37,7 @@ dependencies = [ "matplotlib", "netCDF4", "numpy<2", - "openpyxl", # extra dependency for pandas (excel) + "openpyxl", # extra dependency for pandas (excel) "opentelemetry-api", "opentelemetry-sdk", "opentelemetry-instrumentation-fastapi", @@ -54,19 +49,18 @@ dependencies = [ "pluggy>=1.3.0", "polars>=1", "psutil", - "pyarrow", # extra dependency for pandas (parquet) + "pyarrow", # extra dependency for pandas (parquet) "pydantic > 2", - "PyQt5", "python-dateutil", - "python-multipart", # extra dependency for fastapi + "python-multipart", # extra dependency for fastapi "pyyaml", "pyzmq", - "qtpy", + "pyqt6", "requests", "resfo", "scipy >= 1.10.1, < 1.15", "seaborn", - "tables", # extra dependency for pandas (hdf5) + "tables", # extra dependency for pandas (hdf5) "tabulate", "tqdm>=4.62.0", "typing_extensions>=4.5", @@ -122,11 +116,9 @@ dev = [ "sphinx-autoapi", "sphinx-copybutton", "sphinxcontrib.datatemplates", - "json-schema-for-humans" -] -style = [ - "pre-commit", + "json-schema-for-humans", ] +style = ["pre-commit"] types = [ "mypy", "types-lxml", @@ -137,7 +129,7 @@ types = [ "types-docutils", "types-tqdm", "types-psutil", - "types-setuptools" + "types-setuptools", ] everest = [ "progressbar2", @@ -152,7 +144,7 @@ everest = [ ] [tool.setuptools] -package-dir = {"" = "src"} +package-dir = { "" = "src" } platforms = ["all"] [tool.setuptools.package-data] @@ -239,9 +231,7 @@ allow-dunder-method-names = [ ] [tool.ruff.lint.flake8-bugbear] -extend-immutable-calls = [ - "fastapi.Depends", -] +extend-immutable-calls = ["fastapi.Depends"] [tool.pyright] include = ["src"] @@ -252,6 +242,6 @@ pythonVersion = "3.11" [tool.pyright.defineConstant] PYSIDE6 = false -PYQT5 = true +PYQT5 = false PYSIDE2 = false -PYQT6 = false +PYQT6 = true diff --git a/src/ert/ensemble_evaluator/snapshot.py b/src/ert/ensemble_evaluator/snapshot.py index 77170810e92..5d6d3bf0d43 100644 --- a/src/ert/ensemble_evaluator/snapshot.py +++ b/src/ert/ensemble_evaluator/snapshot.py @@ -6,7 +6,7 @@ from datetime import datetime from typing import Any, TypeVar, cast, get_args -from qtpy.QtGui import QColor +from PyQt6.QtGui import QColor from typing_extensions import TypedDict from _ert.events import ( diff --git a/src/ert/gui/about_dialog.py b/src/ert/gui/about_dialog.py index 87b96959dc9..2b358379b8e 100644 --- a/src/ert/gui/about_dialog.py +++ b/src/ert/gui/about_dialog.py @@ -1,6 +1,6 @@ -from qtpy.QtCore import QSize, Qt -from qtpy.QtGui import QFont -from qtpy.QtWidgets import ( +from PyQt6.QtCore import QSize, Qt +from PyQt6.QtGui import QFont +from PyQt6.QtWidgets import ( QDialog, QHBoxLayout, QLabel, @@ -19,13 +19,8 @@ def __init__(self, parent: QWidget | None) -> None: self.setWindowTitle("About") self.setModal(True) self.setFixedSize(QSize(600, 480)) - self.setWindowFlags( - self.windowFlags() - & ~Qt.WindowFlags(Qt.WindowType.WindowContextHelpButtonHint) - ) - self.setWindowFlags( - self.windowFlags() & ~Qt.WindowFlags(Qt.WindowType.WindowCloseButtonHint) - ) + self.setWindowFlag(Qt.WindowType.WindowContextHelpButtonHint, False) + self.setWindowFlag(Qt.WindowType.WindowCloseButtonHint, False) main_layout = QVBoxLayout() diff --git a/src/ert/gui/ertnotifier.py b/src/ert/gui/ertnotifier.py index 274674c8329..f43dfb42a24 100644 --- a/src/ert/gui/ertnotifier.py +++ b/src/ert/gui/ertnotifier.py @@ -1,4 +1,6 @@ -from qtpy.QtCore import QObject, Signal, Slot +from PyQt6.QtCore import QObject +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtCore import pyqtSlot as Slot from ert.storage import Ensemble, Storage diff --git a/src/ert/gui/ertwidgets/__init__.py b/src/ert/gui/ertwidgets/__init__.py index cc1bf211dbb..75136aa0646 100644 --- a/src/ert/gui/ertwidgets/__init__.py +++ b/src/ert/gui/ertwidgets/__init__.py @@ -1,7 +1,7 @@ # isort: skip_file -from qtpy.QtCore import Qt -from qtpy.QtGui import QCursor -from qtpy.QtWidgets import QApplication +from PyQt6.QtCore import Qt +from PyQt6.QtGui import QCursor +from PyQt6.QtWidgets import QApplication from typing import Any from collections.abc import Callable diff --git a/src/ert/gui/ertwidgets/analysismoduleedit.py b/src/ert/gui/ertwidgets/analysismoduleedit.py index 92270bfb0a7..283590ac8fd 100644 --- a/src/ert/gui/ertwidgets/analysismoduleedit.py +++ b/src/ert/gui/ertwidgets/analysismoduleedit.py @@ -2,9 +2,9 @@ from typing import TYPE_CHECKING -from qtpy.QtCore import QMargins, Qt -from qtpy.QtGui import QIcon -from qtpy.QtWidgets import QHBoxLayout, QToolButton, QWidget +from PyQt6.QtCore import QMargins, Qt +from PyQt6.QtGui import QIcon +from PyQt6.QtWidgets import QHBoxLayout, QToolButton, QWidget from ert.gui.ertwidgets import ClosableDialog from ert.gui.ertwidgets.analysismodulevariablespanel import AnalysisModuleVariablesPanel @@ -45,4 +45,4 @@ def showVariablesPopup(self) -> None: variable_dialog, self.parent(), # type: ignore ) - dialog.exec_() + dialog.exec() diff --git a/src/ert/gui/ertwidgets/analysismodulevariablespanel.py b/src/ert/gui/ertwidgets/analysismodulevariablespanel.py index 87cbbc8a32b..499a746dae4 100644 --- a/src/ert/gui/ertwidgets/analysismodulevariablespanel.py +++ b/src/ert/gui/ertwidgets/analysismodulevariablespanel.py @@ -4,8 +4,8 @@ from typing import cast, get_args from annotated_types import Ge, Gt, Le -from qtpy.QtCore import Qt -from qtpy.QtWidgets import ( +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import ( QCheckBox, QComboBox, QDoubleSpinBox, @@ -75,9 +75,8 @@ def __init__(self, analysis_module: AnalysisModule, ensemble_size: int): local_checkbox.setObjectName("localization") local_checkbox.clicked.connect( partial( - self.valueChanged, + self.valueChangedCheckBox, "localization", - bool, local_checkbox, ) ) @@ -112,8 +111,8 @@ def update_inversion_algorithm(self, text: InversionTypeES) -> None: @staticmethod def create_horizontal_line() -> QFrame: hline = QFrame() - hline.setFrameShape(QFrame.HLine) - hline.setFrameShadow(QFrame.Sunken) + hline.setFrameShape(QFrame.Shape.HLine) + hline.setFrameShadow(QFrame.Shadow.Sunken) hline.setFixedHeight(20) return hline @@ -137,24 +136,11 @@ def createDoubleSpinBox( spinner.setSingleStep(step_length) spinner.setValue(variable_value) - spinner.valueChanged.connect( - partial(self.valueChanged, variable_name, float, spinner) - ) + spinner.valueChanged.connect(partial(self.valueChangedSpinner, variable_name)) return spinner - def valueChanged( - self, - variable_name: str, - variable_type: type[bool] | type[float], - variable_control: QWidget, - ) -> None: - value: bool | float | None = None - if variable_type == bool: - assert isinstance(variable_control, QCheckBox) - value = variable_control.isChecked() - elif variable_type == float: - assert isinstance(variable_control, QDoubleSpinBox) - value = variable_control.value() - - if value is not None: - self.analysis_module.__setattr__(variable_name, value) # noqa: PLC2801 + def valueChangedSpinner(self, name: str, value: float) -> None: + setattr(self.analysis_module, name, value) + + def valueChangedCheckBox(self, name: str, control: QCheckBox) -> None: + setattr(self.analysis_module, name, control.isChecked()) diff --git a/src/ert/gui/ertwidgets/checklist.py b/src/ert/gui/ertwidgets/checklist.py index 4bf1ecdac04..70c64bd840e 100644 --- a/src/ert/gui/ertwidgets/checklist.py +++ b/src/ert/gui/ertwidgets/checklist.py @@ -2,9 +2,9 @@ from typing import TYPE_CHECKING -from qtpy.QtCore import QPoint, QSize, Qt -from qtpy.QtGui import QIcon -from qtpy.QtWidgets import ( +from PyQt6.QtCore import QPoint, QSize, Qt +from PyQt6.QtGui import QIcon +from PyQt6.QtWidgets import ( QAbstractItemView, QHBoxLayout, QLabel, @@ -44,7 +44,7 @@ def __init__( self._list = QListWidget() self._list.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) - self._list.setSelectionMode(QAbstractItemView.ExtendedSelection) + self._list.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection) self._search_box = SearchBox() @@ -162,13 +162,13 @@ def uncheckSelected(self) -> None: def showContextMenu(self, point: QPoint) -> None: p = self._list.mapToGlobal(point) - menu = QMenu() + menu = QMenu(self) check_selected = menu.addAction("Check selected") uncheck_selected = menu.addAction("Uncheck selected") menu.addSeparator() clear_selection = menu.addAction("Clear selection") - selected_item = menu.exec_(p) + selected_item = menu.exec(p) if selected_item == check_selected: self.checkSelected() diff --git a/src/ert/gui/ertwidgets/closabledialog.py b/src/ert/gui/ertwidgets/closabledialog.py index c6a8cdb5df3..83773442dd8 100644 --- a/src/ert/gui/ertwidgets/closabledialog.py +++ b/src/ert/gui/ertwidgets/closabledialog.py @@ -1,13 +1,13 @@ from __future__ import annotations +from collections.abc import Callable from typing import TYPE_CHECKING -from qtpy.QtCore import Qt -from qtpy.QtWidgets import QDialog, QHBoxLayout, QPushButton, QVBoxLayout, QWidget +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QDialog, QHBoxLayout, QPushButton, QVBoxLayout, QWidget if TYPE_CHECKING: - from qtpy.QtGui import QKeyEvent - from qtpy.QtWidgets import QT_SLOT + from PyQt6.QtGui import QKeyEvent class ClosableDialog(QDialog): @@ -15,16 +15,11 @@ def __init__( self, title: str | None, widget: QWidget, parent: QWidget | None = None ) -> None: QDialog.__init__(self, parent) - self.setWindowTitle(title) + self.setWindowTitle(title if title else "") self.setModal(True) - 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) - ) + self.setWindowFlag(Qt.WindowType.CustomizeWindowHint, True) + self.setWindowFlag(Qt.WindowType.WindowContextHelpButtonHint, False) + self.setWindowFlag(Qt.WindowType.WindowCloseButtonHint, False) layout = QVBoxLayout() layout.addWidget(widget, stretch=1) @@ -51,7 +46,7 @@ def keyPressEvent(self, a0: QKeyEvent | None) -> None: if self.close_button.isEnabled() or a0 is None or a0.key() != Qt.Key.Key_Escape: QDialog.keyPressEvent(self, a0) - def addButton(self, caption: str, listener: QT_SLOT) -> QPushButton: + def addButton(self, caption: str, listener: Callable[..., None]) -> QPushButton: button = QPushButton(caption) button.setObjectName(str(caption).capitalize()) self.__button_layout.insertWidget(1, button) diff --git a/src/ert/gui/ertwidgets/copy_button.py b/src/ert/gui/ertwidgets/copy_button.py index 5ee953f11a2..10fc624597f 100644 --- a/src/ert/gui/ertwidgets/copy_button.py +++ b/src/ert/gui/ertwidgets/copy_button.py @@ -1,14 +1,14 @@ from abc import abstractmethod -from qtpy.QtCore import QTimer -from qtpy.QtGui import QIcon -from qtpy.QtWidgets import QApplication, QMessageBox, QPushButton, QSizePolicy +from PyQt6.QtCore import QTimer +from PyQt6.QtGui import QIcon +from PyQt6.QtWidgets import QApplication, QMessageBox, QPushButton, QSizePolicy class CopyButton(QPushButton): def __init__(self) -> None: super().__init__() - self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) + self.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed) self.setIcon(QIcon("img:copy.svg")) self.restore_timer = QTimer(self) @@ -32,7 +32,7 @@ def copy_text(self, text: str) -> None: None, "Error", "Cannot copy text to clipboard because your system does not have a clipboard", - QMessageBox.Ok, + QMessageBox.StandardButton.Ok, ) self.setIcon(QIcon("img:check.svg")) self.restore_timer.start(1000) diff --git a/src/ert/gui/ertwidgets/copyablelabel.py b/src/ert/gui/ertwidgets/copyablelabel.py index 02d1d47dfb8..63af5522ed4 100644 --- a/src/ert/gui/ertwidgets/copyablelabel.py +++ b/src/ert/gui/ertwidgets/copyablelabel.py @@ -1,7 +1,7 @@ from os import path -from qtpy.QtCore import Qt -from qtpy.QtWidgets import QHBoxLayout, QLabel +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QHBoxLayout, QLabel from .copy_button import CopyButton diff --git a/src/ert/gui/ertwidgets/create_experiment_dialog.py b/src/ert/gui/ertwidgets/create_experiment_dialog.py index ce234ea6005..8c38a74f34e 100644 --- a/src/ert/gui/ertwidgets/create_experiment_dialog.py +++ b/src/ert/gui/ertwidgets/create_experiment_dialog.py @@ -1,8 +1,6 @@ -from qtpy.QtCore import ( - Qt, - Signal, -) -from qtpy.QtWidgets import ( +from PyQt6.QtCore import Qt +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtWidgets import ( QDialog, QDialogButtonBox, QGridLayout, @@ -59,13 +57,13 @@ def __init__( self._iterations_field.setValidator(IntegerArgument(from_value=0)) self._iterations_field.setObjectName("iterations_field_ced") buttons = QDialogButtonBox( - QDialogButtonBox.Ok | QDialogButtonBox.Cancel, + QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel, Qt.Orientation.Horizontal, self, ) buttons.accepted.connect(self.accept) buttons.rejected.connect(self.reject) - ok_button = buttons.button(QDialogButtonBox.Ok) + ok_button = buttons.button(QDialogButtonBox.StandardButton.Ok) assert ok_button self._ok_button = ok_button diff --git a/src/ert/gui/ertwidgets/customdialog.py b/src/ert/gui/ertwidgets/customdialog.py index a2d23be78d3..4d09e34c3d9 100644 --- a/src/ert/gui/ertwidgets/customdialog.py +++ b/src/ert/gui/ertwidgets/customdialog.py @@ -1,8 +1,8 @@ from typing import Any -from qtpy.QtCore import QSize, Qt -from qtpy.QtGui import QColor -from qtpy.QtWidgets import ( +from PyQt6.QtCore import QSize, Qt +from PyQt6.QtGui import QColor +from PyQt6.QtWidgets import ( QDialog, QDialogButtonBox, QFormLayout, @@ -71,7 +71,7 @@ def showAndTell(self) -> int: Shows the dialog modally and returns the true or false (accept/reject) """ self.optionValidationChanged() - return self.exec_() + return self.exec() @staticmethod def createSpace(size: int = 5) -> QWidget: @@ -93,18 +93,18 @@ def addLabeledOption(self, label: Any, option_widget: QWidget) -> None: self._layout.addRow(f"{label}:", option_widget) - def addWidget(self, widget: QWidget | QLayout | None, label: str = "") -> None: + def addWidget(self, widget: QWidget | QLayout, label: str = "") -> None: if not label.endswith(":"): label = f"{label}:" self._layout.addRow(label, widget) def addButtons(self) -> None: buttons = QDialogButtonBox( - QDialogButtonBox.Ok | QDialogButtonBox.Cancel, + QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel, Qt.Orientation.Horizontal, self, ) - self.ok_button = buttons.button(QDialogButtonBox.Ok) + self.ok_button = buttons.button(QDialogButtonBox.StandardButton.Ok) if self.ok_button: self.ok_button.setEnabled(False) diff --git a/src/ert/gui/ertwidgets/ensembleselector.py b/src/ert/gui/ertwidgets/ensembleselector.py index 62926ddf332..ae0f9ba58d3 100644 --- a/src/ert/gui/ertwidgets/ensembleselector.py +++ b/src/ert/gui/ertwidgets/ensembleselector.py @@ -3,8 +3,9 @@ from collections.abc import Iterable from typing import TYPE_CHECKING -from qtpy.QtCore import Qt, Signal -from qtpy.QtWidgets import QComboBox +from PyQt6.QtCore import Qt +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtWidgets import QComboBox from ert.gui.ertnotifier import ErtNotifier from ert.storage.realization_storage_state import RealizationStorageState @@ -36,13 +37,13 @@ def __init__( # if the ensemble has not been used in an update, as that would # invalidate the result self._show_only_no_children = show_only_no_children - self.setSizeAdjustPolicy(QComboBox.AdjustToContents) + self.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContents) self.setEnabled(False) if update_ert: # Update ERT when this combo box is changed - self.currentIndexChanged[int].connect(self._on_current_index_changed) + self.currentIndexChanged.connect(self._on_current_index_changed) # Update this combo box when ERT is changed notifier.current_ensemble_changed.connect( diff --git a/src/ert/gui/ertwidgets/listeditbox.py b/src/ert/gui/ertwidgets/listeditbox.py index 632c0056c00..2b32c9a31dd 100644 --- a/src/ert/gui/ertwidgets/listeditbox.py +++ b/src/ert/gui/ertwidgets/listeditbox.py @@ -1,9 +1,9 @@ -from collections.abc import Iterable +from collections.abc import Sequence from uuid import UUID -from qtpy.QtCore import QSize, Qt -from qtpy.QtGui import QIcon, QKeyEvent -from qtpy.QtWidgets import ( +from PyQt6.QtCore import QSize, Qt +from PyQt6.QtGui import QIcon, QKeyEvent +from PyQt6.QtWidgets import ( QCompleter, QHBoxLayout, QInputDialog, @@ -18,14 +18,14 @@ class AutoCompleteLineEdit(QLineEdit): # http://blog.elentok.com/2011/08/autocomplete-textbox-for-multiple.html - def __init__(self, items: Iterable[str | None], parent: QWidget | None = None): + def __init__(self, items: Sequence[str], parent: QWidget | None = None): super().__init__(parent) self._separators = [",", " "] self._completer = QCompleter(items, self) self._completer.setWidget(self) - self._completer.activated[str].connect(self.__insertCompletion) + self._completer.activated.connect(self.__insertCompletion) self._completer.setCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive) self.__keysToIgnore = [ @@ -71,7 +71,7 @@ def keyPressEvent(self, a0: QKeyEvent | None) -> None: if popup is not None and len(completion_prefix) == 0: popup.hide() - def __updateCompleterPopupItems(self, completionPrefix: str | None) -> None: + def __updateCompleterPopupItems(self, completionPrefix: str) -> None: self._completer.setCompletionPrefix(completionPrefix) popup = self._completer.popup() assert popup is not None diff --git a/src/ert/gui/ertwidgets/message_box.py b/src/ert/gui/ertwidgets/message_box.py index 0eebe8c9f82..6fdece9ad0e 100644 --- a/src/ert/gui/ertwidgets/message_box.py +++ b/src/ert/gui/ertwidgets/message_box.py @@ -1,4 +1,4 @@ -from qtpy.QtWidgets import ( +from PyQt6.QtWidgets import ( QDialog, QDialogButtonBox, QGridLayout, @@ -20,12 +20,12 @@ class ErtMessageBox(QDialog): def __init__( self, text: str | None, - detailed_text: str | None, + detailed_text: str, parent: QWidget | None = None, ) -> None: super().__init__(parent) self.box = QDialogButtonBox( - QDialogButtonBox.Ok, + QDialogButtonBox.StandardButton.Ok, ) self.box.setCenterButtons(True) self.box.accepted.connect(self.accept) diff --git a/src/ert/gui/ertwidgets/models/selectable_list_model.py b/src/ert/gui/ertwidgets/models/selectable_list_model.py index 0c78cf71f54..830fce0a72d 100644 --- a/src/ert/gui/ertwidgets/models/selectable_list_model.py +++ b/src/ert/gui/ertwidgets/models/selectable_list_model.py @@ -1,4 +1,5 @@ -from qtpy.QtCore import QObject, Signal +from PyQt6.QtCore import QObject +from PyQt6.QtCore import pyqtSignal as Signal class SelectableListModel(QObject): diff --git a/src/ert/gui/ertwidgets/models/valuemodel.py b/src/ert/gui/ertwidgets/models/valuemodel.py index 42ea0087bb3..73a1d52707c 100644 --- a/src/ert/gui/ertwidgets/models/valuemodel.py +++ b/src/ert/gui/ertwidgets/models/valuemodel.py @@ -1,4 +1,6 @@ -from qtpy.QtCore import QObject, Signal, Slot +from PyQt6.QtCore import QObject +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtCore import pyqtSlot as Slot class ValueModel(QObject): diff --git a/src/ert/gui/ertwidgets/pathchooser.py b/src/ert/gui/ertwidgets/pathchooser.py index 79c9d072f04..dbdc7183547 100644 --- a/src/ert/gui/ertwidgets/pathchooser.py +++ b/src/ert/gui/ertwidgets/pathchooser.py @@ -4,9 +4,9 @@ import re from typing import TYPE_CHECKING -from qtpy.QtCore import QSize -from qtpy.QtGui import QIcon -from qtpy.QtWidgets import QFileDialog, QHBoxLayout, QLineEdit, QToolButton, QWidget +from PyQt6.QtCore import QSize +from PyQt6.QtGui import QIcon +from PyQt6.QtWidgets import QFileDialog, QHBoxLayout, QLineEdit, QToolButton, QWidget from .validationsupport import ValidationSupport diff --git a/src/ert/gui/ertwidgets/searchbox.py b/src/ert/gui/ertwidgets/searchbox.py index 473387257f0..4311a3d6946 100644 --- a/src/ert/gui/ertwidgets/searchbox.py +++ b/src/ert/gui/ertwidgets/searchbox.py @@ -1,8 +1,9 @@ from typing import Any -from qtpy.QtCore import Qt, Signal -from qtpy.QtGui import QColor, QFocusEvent, QKeyEvent -from qtpy.QtWidgets import QLineEdit +from PyQt6.QtCore import Qt +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtGui import QColor, QFocusEvent, QKeyEvent +from PyQt6.QtWidgets import QLineEdit class SearchBox(QLineEdit): @@ -63,7 +64,7 @@ def focusOutEvent(self, a0: QFocusEvent | None) -> None: self.exitSearch() def keyPressEvent(self, a0: QKeyEvent | None) -> None: - if a0 is not None and a0.key() == Qt.Key.Key_Escape: + if a0 and a0.key() == Qt.Key.Key_Escape: self.clear() self.clearFocus() else: diff --git a/src/ert/gui/ertwidgets/stringbox.py b/src/ert/gui/ertwidgets/stringbox.py index 60f56bfc634..b339597a7b2 100644 --- a/src/ert/gui/ertwidgets/stringbox.py +++ b/src/ert/gui/ertwidgets/stringbox.py @@ -2,8 +2,8 @@ from typing import TYPE_CHECKING, Any -from qtpy.QtGui import QPalette -from qtpy.QtWidgets import QLineEdit +from PyQt6.QtGui import QPalette +from PyQt6.QtWidgets import QLineEdit from .validationsupport import ValidationSupport diff --git a/src/ert/gui/ertwidgets/textbox.py b/src/ert/gui/ertwidgets/textbox.py index 5362ae4d148..3742991973e 100644 --- a/src/ert/gui/ertwidgets/textbox.py +++ b/src/ert/gui/ertwidgets/textbox.py @@ -2,8 +2,8 @@ from typing import TYPE_CHECKING, Any -from qtpy.QtGui import QPalette -from qtpy.QtWidgets import QTextEdit +from PyQt6.QtGui import QPalette +from PyQt6.QtWidgets import QTextEdit from .validationsupport import ValidationSupport diff --git a/src/ert/gui/ertwidgets/validationsupport.py b/src/ert/gui/ertwidgets/validationsupport.py index 8e7bdeaef03..9e9d85b689a 100644 --- a/src/ert/gui/ertwidgets/validationsupport.py +++ b/src/ert/gui/ertwidgets/validationsupport.py @@ -3,18 +3,14 @@ import html from typing import TYPE_CHECKING -from qtpy.QtCore import ( - QObject, - QPoint, - Qt, - Signal, -) -from qtpy.QtGui import QColor -from qtpy.QtWidgets import QFrame, QLabel, QSizePolicy, QVBoxLayout, QWidget +from PyQt6.QtCore import QObject, QPoint, Qt +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtGui import QColor, QEnterEvent +from PyQt6.QtWidgets import QFrame, QLabel, QSizePolicy, QVBoxLayout, QWidget if TYPE_CHECKING: - from qtpy.QtCore import QEvent - from qtpy.QtGui import QHideEvent + from PyQt6.QtCore import QEvent + from PyQt6.QtGui import QHideEvent class ErrorPopup(QWidget): @@ -36,8 +32,10 @@ def __init__(self) -> None: layout.setContentsMargins(0, 0, 0, 0) self._error_widget = QLabel("") - self._error_widget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum) - self._error_widget.setFrameStyle(QFrame.Box) + self._error_widget.setSizePolicy( + QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Minimum + ) + self._error_widget.setFrameStyle(QFrame.Shape.Box) self._error_widget.setWordWrap(True) self._error_widget.setScaledContents(True) self._error_widget.setTextFormat(Qt.TextFormat.RichText) @@ -84,8 +82,8 @@ def __init__(self, validation_target: QWidget) -> None: self._originalLeaveEvent = validation_target.leaveEvent self._originalHideEvent = validation_target.hideEvent - def enterEvent(a0: QEvent | None) -> None: - self._originalEnterEvent(a0) + def enterEvent(event: QEnterEvent | None) -> None: + self._originalEnterEvent(event) if not self.isValid(): self._error_popup.presentError( diff --git a/src/ert/gui/main.py b/src/ert/gui/main.py index b4d412bb84a..9c8922e4c20 100755 --- a/src/ert/gui/main.py +++ b/src/ert/gui/main.py @@ -6,9 +6,9 @@ from importlib.resources import files from signal import SIG_DFL, SIGINT, signal -from qtpy.QtCore import QDir -from qtpy.QtGui import QIcon -from qtpy.QtWidgets import QApplication, QWidget +from PyQt6.QtCore import QDir +from PyQt6.QtGui import QIcon +from PyQt6.QtWidgets import QApplication, QWidget from ert.config import ( ErrorInfo, @@ -51,7 +51,7 @@ def show_window() -> int: window.show() window.activateWindow() window.raise_() - return app.exec_() + return app.exec() # ens_path is None indicates that there was an error in the setup and # window is now just showing that error message, in which @@ -84,6 +84,8 @@ def _start_initial_gui_window( ert_config = ErtConfig.with_plugins().from_file(args.config) local_storage_set_ert_config(ert_config) + + storage = None if ert_config is not None: try: storage = open_storage(ert_config.ens_path, mode="w") @@ -105,7 +107,6 @@ def _start_initial_gui_window( ), None, ) - assert ert_config is not None counter_fm_steps = Counter(fms.name for fms in ert_config.forward_model_steps) for fm_step_name, count in counter_fm_steps.items(): @@ -118,6 +119,7 @@ def _start_initial_gui_window( for msg in validation_messages.warnings: logger.info(f"Warning shown in gui '{msg}'") + assert storage is not None main_window = _setup_main_window( ert_config, args, log_handler, storage, plugin_manager ) @@ -137,7 +139,6 @@ def continue_action() -> None: continue_action, plugin_manager.get_help_links() if plugin_manager is not None else {}, ) - suggestor.notifier = main_window.notifier return ( suggestor, ert_config.ens_path, diff --git a/src/ert/gui/main_window.py b/src/ert/gui/main_window.py index 642d6770fbd..8485584f2cc 100644 --- a/src/ert/gui/main_window.py +++ b/src/ert/gui/main_window.py @@ -4,10 +4,11 @@ import functools import webbrowser -from qtpy.QtCore import QCoreApplication, QEvent, QSize, Qt, Signal, Slot -from qtpy.QtGui import QCloseEvent, QCursor, QIcon, QMouseEvent -from qtpy.QtWidgets import ( - QAction, +from PyQt6.QtCore import QCoreApplication, QEvent, QSize, Qt +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtCore import pyqtSlot as Slot +from PyQt6.QtGui import QAction, QCloseEvent, QCursor, QIcon, QMouseEvent +from PyQt6.QtWidgets import ( QButtonGroup, QFrame, QHBoxLayout, @@ -204,7 +205,7 @@ def select_central_widget(self) -> None: def onMenuAboutToHide(self) -> None: QCoreApplication.sendEvent(self.results_button, QEvent(QEvent.Type.Leave)) - @Slot(object) + @Slot(RunDialog) def slot_add_widget(self, run_dialog: RunDialog) -> None: for widget in self.central_panels_map.values(): widget.setVisible(False) @@ -233,9 +234,11 @@ def add_sim_run_option(simulation_id: str) -> None: if self.run_dialog_counter == 2: # swap from button to menu selection self.results_button.clicked.disconnect(self.select_central_widget) - menu = QMenu() + menu = QMenu(None) self.results_button.setMenu(menu) - self.results_button.setPopupMode(QToolButton.InstantPopup) + self.results_button.setPopupMode( + QToolButton.ToolButtonPopupMode.InstantPopup + ) menu.aboutToHide.connect(self.onMenuAboutToHide) for prev_date_time, widget in self.central_panels_map.items(): @@ -254,7 +257,7 @@ def post_init(self) -> None: self.facade.get_ensemble_size(), ) experiment_panel.experiment_started.connect( - lambda: self.results_button.setChecked(True) + lambda _: self.results_button.setChecked(True) ) self.central_layout.addWidget(experiment_panel) self._experiment_panel = experiment_panel @@ -316,7 +319,7 @@ def __add_help_menu(self) -> None: help_link_item = help_menu.addAction(menu_label) assert help_link_item is not None help_link_item.setMenuRole(QAction.MenuRole.ApplicationSpecificRole) - help_link_item.triggered.connect(functools.partial(webbrowser.open, link)) # type: ignore + help_link_item.triggered.connect(functools.partial(webbrowser.open, link)) show_about = help_menu.addAction("About") assert show_about is not None diff --git a/src/ert/gui/model/fm_step_list.py b/src/ert/gui/model/fm_step_list.py index a60c6c9f4ed..5ed847d42b0 100644 --- a/src/ert/gui/model/fm_step_list.py +++ b/src/ert/gui/model/fm_step_list.py @@ -1,14 +1,13 @@ from typing import Any, overload -from qtpy.QtCore import ( +from PyQt6.QtCore import ( QAbstractItemModel, QAbstractProxyModel, QModelIndex, QObject, Qt, - QVariant, - Slot, ) +from PyQt6.QtCore import pyqtSlot as Slot from typing_extensions import override from ert.ensemble_evaluator import identifiers as ids @@ -93,7 +92,7 @@ def headerData( return header.capitalize() if orientation == Qt.Orientation.Vertical: return section - return QVariant() + return None @override def columnCount(self, parent: QModelIndex | None = None) -> int: @@ -112,9 +111,9 @@ def rowCount(self, parent: QModelIndex | None = None) -> int: @overload def parent(self, child: QModelIndex) -> QModelIndex: ... @overload - def parent(self) -> QObject | None: ... + def parent(self) -> QObject: ... @override - def parent(self, child: QModelIndex | None = None) -> QObject | None: + def parent(self, child: QModelIndex | None = None) -> QObject | QModelIndex: return QModelIndex() @override @@ -138,10 +137,10 @@ def mapToSource(self, proxyIndex: QModelIndex) -> QModelIndex: return sm.index(proxyIndex.row(), proxyIndex.column(), real_index) return QModelIndex() - def mapFromSource(self, src_index: QModelIndex) -> QModelIndex: + def mapFromSource(self, sourceIndex: QModelIndex) -> QModelIndex: return ( - self.index(src_index.row(), src_index.column(), QModelIndex()) - if src_index.isValid() and self._accept_index(src_index) + self.index(sourceIndex.row(), sourceIndex.column(), QModelIndex()) + if sourceIndex.isValid() and self._accept_index(sourceIndex) else QModelIndex() ) diff --git a/src/ert/gui/model/node.py b/src/ert/gui/model/node.py index e8baa8ee5c5..a482e0f0453 100644 --- a/src/ert/gui/model/node.py +++ b/src/ert/gui/model/node.py @@ -1,52 +1,50 @@ from __future__ import annotations -from abc import ABC, abstractmethod +from abc import ABC from dataclasses import dataclass, field -from typing import cast -from qtpy.QtGui import QColor +from PyQt6.QtGui import QColor from ert.ensemble_evaluator.snapshot import FMStepSnapshot @dataclass -class _Node(ABC): +class _NodeBase(ABC): id_: str - parent: RootNode | IterNode | RealNode | None = None - children: ( - dict[str, IterNode] | dict[str, RealNode] | dict[str, ForwardModelStepNode] - ) = field(default_factory=dict) _index: int | None = None - def __repr__(self) -> str: - parent = "no " if self.parent is None else "" - children = "no " if len(self.children) == 0 else f"{len(self.children)} " - return f"Node<{type(self).__name__}>@{self.id_} with {parent}parent and {children}children" - @abstractmethod - def add_child(self, node: _Node) -> None: - pass +def _repr(node: RootNode | IterNode | RealNode | ForwardModelStepNode) -> str: + parent = "no " if node.parent is None else "" + children = "no " if not node.children else f"{len(node.children)} " + return f"Node<{type(node).__name__}>@{node.id_} with {parent}parent and {children}children" - def row(self) -> int: - if not self._index: - if self.parent: - self._index = list(self.parent.children.keys()).index(self.id_) - else: - raise ValueError(f"{self} had no parent") - return self._index + +def _row(node: RootNode | IterNode | RealNode | ForwardModelStepNode) -> int: + if not node._index: + if node.parent: + node._index = list(node.parent.children.keys()).index(node.id_) + else: + raise ValueError(f"{node} had no parent") + return node._index @dataclass -class RootNode(_Node): +class RootNode(_NodeBase): parent: None = field(default=None, init=False) children: dict[str, IterNode] = field(default_factory=dict) max_memory_usage: int | None = None - def add_child(self, node: _Node) -> None: - node = cast(IterNode, node) + def add_child(self, node: IterNode) -> None: node.parent = self self.children[node.id_] = node + def row(self) -> int: + return _row(self) + + def __repr__(self) -> str: + return _repr(self) + @dataclass class IterNodeData: @@ -55,16 +53,21 @@ class IterNodeData: @dataclass -class IterNode(_Node): +class IterNode(_NodeBase): parent: RootNode | None = None data: IterNodeData = field(default_factory=IterNodeData) children: dict[str, RealNode] = field(default_factory=dict) - def add_child(self, node: _Node) -> None: - node = cast(RealNode, node) + def add_child(self, node: RealNode) -> None: node.parent = self self.children[node.id_] = node + def row(self) -> int: + return _row(self) + + def __repr__(self) -> str: + return _repr(self) + @dataclass class RealNodeData: @@ -80,21 +83,30 @@ class RealNodeData: @dataclass -class RealNode(_Node): +class RealNode(_NodeBase): parent: IterNode | None = None data: RealNodeData = field(default_factory=RealNodeData) children: dict[str, ForwardModelStepNode] = field(default_factory=dict) - def add_child(self, node: _Node) -> None: - node = cast(ForwardModelStepNode, node) + def add_child(self, node: ForwardModelStepNode) -> None: node.parent = self self.children[node.id_] = node + def row(self) -> int: + return _row(self) + + def __repr__(self) -> str: + return _repr(self) + @dataclass -class ForwardModelStepNode(_Node): - parent: RealNode | None +class ForwardModelStepNode(_NodeBase): + parent: RealNode | None = None data: FMStepSnapshot = field(default_factory=lambda: FMStepSnapshot()) # noqa: PLW0108 + children: dict[str, None] = field(default_factory=dict) + + def row(self) -> int: + return _row(self) - def add_child(self, node: _Node) -> None: - pass + def __repr__(self) -> str: + return _repr(self) diff --git a/src/ert/gui/model/real_list.py b/src/ert/gui/model/real_list.py index eddc60a8f51..21906cd98ef 100644 --- a/src/ert/gui/model/real_list.py +++ b/src/ert/gui/model/real_list.py @@ -1,12 +1,7 @@ from typing import overload -from qtpy.QtCore import ( - QAbstractItemModel, - QAbstractProxyModel, - QModelIndex, - QObject, - Slot, -) +from PyQt6.QtCore import QAbstractItemModel, QAbstractProxyModel, QModelIndex, QObject +from PyQt6.QtCore import pyqtSlot as Slot from typing_extensions import override from ert.gui.model.snapshot import IsEnsembleRole, IsRealizationRole, NodeRole @@ -77,9 +72,9 @@ def rowCount(self, parent: QModelIndex | None = None) -> int: @overload def parent(self, child: QModelIndex) -> QModelIndex: ... @overload - def parent(self) -> QObject | None: ... + def parent(self) -> QObject: ... @override - def parent(self, child: QModelIndex | None = None) -> QObject | None: + def parent(self, child: QModelIndex | None = None) -> QObject | QModelIndex: return QModelIndex() @override diff --git a/src/ert/gui/model/snapshot.py b/src/ert/gui/model/snapshot.py index 6521d24d101..f21f4eedd3e 100644 --- a/src/ert/gui/model/snapshot.py +++ b/src/ert/gui/model/snapshot.py @@ -3,10 +3,10 @@ from collections.abc import Sequence from contextlib import ExitStack from datetime import datetime, timedelta -from typing import Any, Final, overload +from typing import Any, Final, cast, overload -from qtpy.QtCore import QAbstractItemModel, QModelIndex, QObject, QSize, Qt, QVariant -from qtpy.QtGui import QColor, QFont +from PyQt6.QtCore import QAbstractItemModel, QModelIndex, QObject, QSize, Qt +from PyQt6.QtGui import QColor, QFont from typing_extensions import override from ert.ensemble_evaluator import EnsembleSnapshot, state @@ -45,9 +45,9 @@ IsFMStepRole = UserRole + 10 StatusRole = UserRole + 11 -DURATION = "Duration" +DURATION: Final[str] = "Duration" -FM_STEP_COLUMNS: Sequence[str] = [ +FM_STEP_COLUMNS: Final[Sequence[str]] = [ ids.NAME, ids.ERROR, ids.STATUS, @@ -172,8 +172,8 @@ def _update_snapshot(self, snapshot: EnsembleSnapshot, iter_: str) -> None: if real_id in metadata["real_status_colors"]: data.real_status_color = metadata["real_status_colors"][real_id] reals_changed.append(real_node.row()) - if real.get("message"): - data.message = real["message"] + if msg := real.get("message"): + data.message = msg fm_steps_changed_by_real: dict[str, list[int]] = defaultdict(list) for (real_id, fm_step_id), fm_step in fm_steps.items(): @@ -284,7 +284,11 @@ def columnCount(self, parent: QModelIndex | None = None) -> int: def rowCount(self, parent: QModelIndex | None = None) -> int: if parent is None: parent = QModelIndex() - parent_item = self.root if not parent.isValid() else parent.internalPointer() + parent_item = ( + self.root + if not parent.isValid() + else cast(RootNode | IterNode | RealNode, parent.internalPointer()) + ) if parent.column() > 0: return 0 @@ -294,27 +298,30 @@ def rowCount(self, parent: QModelIndex | None = None) -> int: @overload def parent(self, child: QModelIndex) -> QModelIndex: ... @overload - def parent(self) -> QObject | None: ... + def parent(self) -> QObject: ... @override - def parent(self, child: QModelIndex | None = None) -> QObject | None: + def parent(self, child: QModelIndex | None = None) -> QObject | QModelIndex: if child is None or not child.isValid(): return QModelIndex() - parent_item = child.internalPointer().parent + parent_item = cast( + IterNode | RealNode | ForwardModelStepNode, child.internalPointer() + ).parent if parent_item == self.root: return QModelIndex() + assert parent_item return self.createIndex(parent_item.row(), 0, parent_item) @override def data(self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) -> Any: if not index.isValid(): - return QVariant() + return None if role == Qt.ItemDataRole.TextAlignmentRole: return Qt.AlignmentFlag.AlignCenter - node: IterNode | RealNode | ForwardModelStepNode = index.internalPointer() + node = cast(IterNode | RealNode | ForwardModelStepNode, index.internalPointer()) if role == NodeRole: return node @@ -326,9 +333,9 @@ def data(self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) -> A return isinstance(node, ForwardModelStepNode) if isinstance(node, ForwardModelStepNode): - return self._fm_step_data(index, node, role) + return self._fm_step_data(index, node, Qt.ItemDataRole(role)) if isinstance(node, RealNode): - return self._real_data(index, node, role) + return self._real_data(node, role) if role == Qt.ItemDataRole.DisplayRole: if index.column() == 0: @@ -356,10 +363,10 @@ def data(self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) -> A }: return QColor() - return QVariant() + return None @staticmethod - def _real_data(_: QModelIndex, node: RealNode, role: int) -> Any: + def _real_data(node: RealNode, role: int) -> Any: if role == FMStepColorHint: total_count = len(node.data.fm_step_status_color_by_id) finished_count = sum( @@ -383,13 +390,11 @@ def _real_data(_: QModelIndex, node: RealNode, role: int) -> Any: if role == CallbackStatusMessageRole: return node.data.message - return QVariant() + return None @staticmethod def _fm_step_data( - index: QModelIndex, - node: ForwardModelStepNode, - role: int, # Qt.ItemDataRole + index: QModelIndex, node: ForwardModelStepNode, role: Qt.ItemDataRole ) -> Any: node_id = str(node.id_) @@ -418,21 +423,21 @@ def _fm_step_data( if role == Qt.ItemDataRole.DisplayRole: data_name = FM_STEP_COLUMNS[index.column()] - if data_name in {ids.MAX_MEMORY_USAGE}: + if data_name == ids.MAX_MEMORY_USAGE: data = node.data - bytes_: str | None = data.get(data_name) # type: ignore + bytes_ = cast(str | None, data.get(data_name)) if bytes_: return byte_with_unit(float(bytes_)) if data_name in {ids.STDOUT, ids.STDERR}: if not file_has_content(index.data(FileRole)): return "-" - return "View" if data_name in node.data else QVariant() + return "View" if data_name in node.data else None - if data_name in {DURATION}: + if data_name == DURATION: start_time = node.data.get(ids.START_TIME) if start_time is None: - return QVariant() + return None delta = _estimate_duration( start_time, end_time=node.data.get(ids.END_TIME) ) @@ -445,7 +450,7 @@ def _fm_step_data( if role == FileRole: data_name = FM_STEP_COLUMNS[index.column()] if data_name in {ids.STDOUT, ids.STDERR}: - return node.data.get(data_name, QVariant()) + return node.data.get(data_name) if role == RealIens: return node.parent.id_ if node.parent else None @@ -470,7 +475,7 @@ def _fm_step_data( if tt_text is not None: return str(tt_text) - return QVariant() + return None @override def index( diff --git a/src/ert/gui/simulation/combobox_with_description.py b/src/ert/gui/simulation/combobox_with_description.py index de393bdc564..b32c9bf38ec 100644 --- a/src/ert/gui/simulation/combobox_with_description.py +++ b/src/ert/gui/simulation/combobox_with_description.py @@ -1,8 +1,8 @@ from typing import Any -from qtpy.QtCore import QModelIndex, QPoint, QSize -from qtpy.QtGui import QColor, QRegion -from qtpy.QtWidgets import ( +from PyQt6.QtCore import QModelIndex, QPoint, QSize +from PyQt6.QtGui import QColor, QRegion +from PyQt6.QtWidgets import ( QComboBox, QLabel, QStyle, @@ -85,11 +85,11 @@ def paint(self, painter: Any, option: Any, index: Any) -> None: description = index.data(DESCRIPTION_ROLE) group = index.data(GROUP_TITLE_ROLE) - is_enabled = option.state & QStyle.State_Enabled # type: ignore + is_enabled = option.state & QStyle.StateFlag.State_Enabled if is_enabled and ( - option.state & QStyle.State_Selected # type: ignore - or option.state & QStyle.State_MouseOver # type: ignore + option.state & QStyle.StateFlag.State_Selected + or option.state & QStyle.StateFlag.State_MouseOver ): color = COLOR_HIGHLIGHT_LIGHT if option.palette.text().color().value() > 150: @@ -120,7 +120,7 @@ def __init__(self, parent: QWidget | None = None) -> None: self.setItemDelegate(_ComboBoxWithDescriptionDelegate(self)) def addDescriptionItem( - self, label: str | None, description: Any, group: str | None = None + self, label: str, description: Any, group: str | None = None ) -> None: super().addItem(label) model = self.model() diff --git a/src/ert/gui/simulation/ensemble_experiment_panel.py b/src/ert/gui/simulation/ensemble_experiment_panel.py index 11e59340f26..342f703d9fc 100644 --- a/src/ert/gui/simulation/ensemble_experiment_panel.py +++ b/src/ert/gui/simulation/ensemble_experiment_panel.py @@ -1,8 +1,8 @@ from dataclasses import dataclass -from qtpy import QtCore -from qtpy.QtCore import Slot -from qtpy.QtWidgets import QFormLayout, QHBoxLayout, QLabel, QPushButton +from PyQt6.QtCore import Qt +from PyQt6.QtCore import pyqtSlot as Slot +from PyQt6.QtWidgets import QFormLayout, QHBoxLayout, QLabel, QPushButton, QWidget from ert.config import AnalysisConfig, DesignMatrix from ert.gui.ertnotifier import ErtNotifier @@ -44,7 +44,7 @@ def __init__( layout = QFormLayout() lab = QLabel(" ".join(EnsembleExperiment.__doc__.split())) # type: ignore lab.setWordWrap(True) - lab.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeft) + lab.setAlignment(Qt.AlignmentFlag.AlignLeft) layout.addRow(lab) self._experiment_name_field = StringBox( @@ -123,10 +123,10 @@ def on_show_dm_params_clicked(self, design_matrix: DesignMatrix) -> None: viewer.setMinimumHeight(500) viewer.setMinimumWidth(1000) viewer.adjustSize() - viewer.exec_() + viewer.exec() - @Slot(ExperimentConfigPanel) - def experimentTypeChanged(self, w: ExperimentConfigPanel) -> None: + @Slot(QWidget) + def experimentTypeChanged(self, w: QWidget) -> None: if isinstance(w, EnsembleExperimentPanel): self._update_experiment_name_placeholder() diff --git a/src/ert/gui/simulation/ensemble_smoother_panel.py b/src/ert/gui/simulation/ensemble_smoother_panel.py index 8cabfd1daee..e0ee6ba73e5 100644 --- a/src/ert/gui/simulation/ensemble_smoother_panel.py +++ b/src/ert/gui/simulation/ensemble_smoother_panel.py @@ -3,8 +3,8 @@ from dataclasses import dataclass from typing import TYPE_CHECKING -from qtpy.QtCore import Slot -from qtpy.QtWidgets import QFormLayout, QLabel +from PyQt6.QtCore import pyqtSlot as Slot +from PyQt6.QtWidgets import QFormLayout, QLabel, QWidget from ert.gui.ertnotifier import ErtNotifier from ert.gui.ertwidgets import ( @@ -103,8 +103,8 @@ def __init__( self.notifier.ertChanged.connect(self._update_experiment_name_placeholder) - @Slot(ExperimentConfigPanel) - def experimentTypeChanged(self, w: ExperimentConfigPanel) -> None: + @Slot(QWidget) + def experimentTypeChanged(self, w: QWidget) -> None: if isinstance(w, EnsembleSmootherPanel): self._update_experiment_name_placeholder() diff --git a/src/ert/gui/simulation/evaluate_ensemble_panel.py b/src/ert/gui/simulation/evaluate_ensemble_panel.py index a81b40ad15c..c345e1aacc6 100644 --- a/src/ert/gui/simulation/evaluate_ensemble_panel.py +++ b/src/ert/gui/simulation/evaluate_ensemble_panel.py @@ -1,8 +1,8 @@ from dataclasses import dataclass import numpy as np -from qtpy import QtCore -from qtpy.QtWidgets import QFormLayout, QLabel +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QFormLayout, QLabel from ert.gui.ertnotifier import ErtNotifier from ert.gui.ertwidgets import ( @@ -33,7 +33,7 @@ def __init__(self, ensemble_size: int, run_path: str, notifier: ErtNotifier): layout = QFormLayout() lab = QLabel(" ".join(EvaluateEnsemble.__doc__.split())) # type: ignore lab.setWordWrap(True) - lab.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeft) + lab.setAlignment(Qt.AlignmentFlag.AlignLeft) layout.addRow(lab) self._ensemble_selector = EnsembleSelector(notifier, show_only_no_children=True) layout.addRow("Ensemble:", self._ensemble_selector) diff --git a/src/ert/gui/simulation/experiment_config_panel.py b/src/ert/gui/simulation/experiment_config_panel.py index 08e8fe2be52..54bc33c504f 100644 --- a/src/ert/gui/simulation/experiment_config_panel.py +++ b/src/ert/gui/simulation/experiment_config_panel.py @@ -2,8 +2,9 @@ from typing import TYPE_CHECKING, Any -from qtpy.QtCore import Signal, Slot -from qtpy.QtWidgets import QWidget +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtCore import pyqtSlot as Slot +from PyQt6.QtWidgets import QWidget if TYPE_CHECKING: from ert.run_models import BaseRunModel diff --git a/src/ert/gui/simulation/experiment_panel.py b/src/ert/gui/simulation/experiment_panel.py index 25a22ab8722..01e74842415 100644 --- a/src/ert/gui/simulation/experiment_panel.py +++ b/src/ert/gui/simulation/experiment_panel.py @@ -9,10 +9,10 @@ from queue import SimpleQueue from typing import TYPE_CHECKING, Any -from qtpy.QtCore import QSize, Qt, Signal -from qtpy.QtGui import QIcon, QStandardItemModel -from qtpy.QtWidgets import ( - QAction, +from PyQt6.QtCore import QSize, Qt +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtGui import QAction, QIcon, QStandardItemModel +from PyQt6.QtWidgets import ( QApplication, QCheckBox, QFrame, @@ -63,7 +63,7 @@ def create_md_table(kv: dict[str, str], output: str) -> str: class ExperimentPanel(QWidget): experiment_type_changed = Signal(ExperimentConfigPanel) - experiment_started = Signal(object) + experiment_started = Signal(RunDialog) def __init__( self, @@ -134,11 +134,13 @@ def __init__( self._experiment_stack = QStackedWidget() self._experiment_stack.setLineWidth(1) - self._experiment_stack.setFrameStyle(QFrame.StyledPanel) + self._experiment_stack.setFrameStyle(QFrame.Shape.StyledPanel) layout.addWidget(self._experiment_stack) - self._experiment_widgets: dict[type[BaseRunModel], QWidget] = OrderedDict() + self._experiment_widgets: dict[type[BaseRunModel], ExperimentConfigPanel] = ( + OrderedDict() + ) self.addExperimentConfigPanel( SingleTestRunPanel(run_path, notifier), True, @@ -223,8 +225,7 @@ def get_current_experiment_type(self) -> Any: def get_experiment_arguments(self) -> Any: simulation_widget = self._experiment_widgets[self.get_current_experiment_type()] - args = simulation_widget.get_experiment_arguments() - return args + return simulation_widget.get_experiment_arguments() def getExperimentName(self) -> str: """Get the experiment name as provided by the user. Defaults to run mode if not set.""" @@ -244,7 +245,10 @@ def run_experiment(self) -> None: except ValueError as e: QMessageBox.warning( - self, "ERROR: Failed to create experiment", str(e), QMessageBox.Ok + self, + "ERROR: Failed to create experiment", + str(e), + QMessageBox.StandardButton.Ok, ) return @@ -255,7 +259,7 @@ def run_experiment(self) -> None: msg_box = QMessageBox(self) msg_box.setObjectName("RUN_PATH_WARNING_BOX") - msg_box.setIcon(QMessageBox.Warning) + msg_box.setIcon(QMessageBox.Icon.Warning) msg_box.setText("Run experiments") msg_box.setInformativeText( @@ -274,13 +278,15 @@ def run_experiment(self) -> None: delete_runpath_checkbox.setText("Delete run_path") msg_box.setCheckBox(delete_runpath_checkbox) - msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No) - msg_box.setDefaultButton(QMessageBox.No) + msg_box.setStandardButtons( + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No + ) + msg_box.setDefaultButton(QMessageBox.StandardButton.No) msg_box.setWindowModality(Qt.WindowModality.ApplicationModal) msg_box_res = msg_box.exec() - if msg_box_res == QMessageBox.No: + if msg_box_res == QMessageBox.StandardButton.No: return if delete_runpath_checkbox.checkState() == Qt.CheckState.Checked: @@ -291,20 +297,22 @@ def run_experiment(self) -> None: QApplication.restoreOverrideCursor() msg_box = QMessageBox(self) msg_box.setObjectName("RUN_PATH_ERROR_BOX") - msg_box.setIcon(QMessageBox.Warning) + msg_box.setIcon(QMessageBox.Icon.Warning) msg_box.setText("ERT could not delete the existing runpath") msg_box.setInformativeText( f"{e}\n\nContinue without deleting the runpath?" ) - msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No) - msg_box.setDefaultButton(QMessageBox.No) + msg_box.setStandardButtons( + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No + ) + msg_box.setDefaultButton(QMessageBox.StandardButton.No) msg_box.setWindowModality(Qt.WindowModality.ApplicationModal) msg_box_res = msg_box.exec() - if msg_box_res == QMessageBox.No: + if msg_box_res == QMessageBox.StandardButton.No: return QApplication.restoreOverrideCursor() - dialog = RunDialog( + self._dialog = RunDialog( self._config_file, model, event_queue, @@ -312,11 +320,13 @@ 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.experiment_started.emit(self._dialog) + self._dialog.produce_clipboard_debug_info.connect( + self.populate_clipboard_debug_info + ) self._simulation_done = False self.run_button.setEnabled(self._simulation_done) - dialog.run_experiment() + self._dialog.run_experiment() def simulation_done_handler() -> None: self._simulation_done = True @@ -324,7 +334,7 @@ def simulation_done_handler() -> None: self.toggleExperimentType() self._notifier.emitErtChange() - dialog.simulation_done.connect(simulation_done_handler) + self._dialog.simulation_done.connect(simulation_done_handler) def toggleExperimentType(self) -> None: current_model = self.get_current_experiment_type() diff --git a/src/ert/gui/simulation/manual_update_panel.py b/src/ert/gui/simulation/manual_update_panel.py index 4a7d2a93be5..6cb855d1f7d 100644 --- a/src/ert/gui/simulation/manual_update_panel.py +++ b/src/ert/gui/simulation/manual_update_panel.py @@ -1,8 +1,8 @@ from dataclasses import dataclass import numpy as np -from qtpy import QtCore -from qtpy.QtWidgets import QFormLayout, QLabel +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QFormLayout, QLabel from ert.config import AnalysisConfig from ert.gui.ertnotifier import ErtNotifier @@ -43,7 +43,7 @@ def __init__( layout = QFormLayout() lab = QLabel(" ".join(ManualUpdate.__doc__.split())) # type: ignore lab.setWordWrap(True) - lab.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeft) + lab.setAlignment(Qt.AlignmentFlag.AlignLeft) layout.addRow(lab) self._ensemble_selector = EnsembleSelector(notifier) layout.addRow("Ensemble:", self._ensemble_selector) diff --git a/src/ert/gui/simulation/multiple_data_assimilation_panel.py b/src/ert/gui/simulation/multiple_data_assimilation_panel.py index a629c77f09a..04dc731527b 100644 --- a/src/ert/gui/simulation/multiple_data_assimilation_panel.py +++ b/src/ert/gui/simulation/multiple_data_assimilation_panel.py @@ -3,9 +3,9 @@ from dataclasses import dataclass from typing import TYPE_CHECKING, Any -from qtpy.QtCore import Slot -from qtpy.QtGui import QFont -from qtpy.QtWidgets import QCheckBox, QFormLayout, QLabel +from PyQt6.QtCore import pyqtSlot as Slot +from PyQt6.QtGui import QFont +from PyQt6.QtWidgets import QCheckBox, QFormLayout, QLabel, QWidget from ert.gui.ertnotifier import ErtNotifier from ert.gui.ertwidgets import ( @@ -139,8 +139,8 @@ def __init__( self.notifier.ertChanged.connect(self._update_experiment_name_placeholder) - @Slot(ExperimentConfigPanel) - def experimentTypeChanged(self, w: ExperimentConfigPanel) -> None: + @Slot(QWidget) + def experimentTypeChanged(self, w: QWidget) -> None: if isinstance(w, MultipleDataAssimilationPanel): self._update_experiment_name_placeholder() @@ -276,7 +276,7 @@ def __init__(self, model: ValueModel) -> None: self._model = model font = self.font() - font.setWeight(QFont.Bold) + font.setWeight(QFont.Weight.Bold) self.setFont(font) self._model.valueChanged.connect(self.updateLabel) diff --git a/src/ert/gui/simulation/queue_emitter.py b/src/ert/gui/simulation/queue_emitter.py index dd07a5ff2fd..f8bec5148b5 100644 --- a/src/ert/gui/simulation/queue_emitter.py +++ b/src/ert/gui/simulation/queue_emitter.py @@ -5,7 +5,9 @@ from queue import Empty, SimpleQueue from time import sleep -from qtpy.QtCore import QObject, Signal, Slot +from PyQt6.QtCore import QObject +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtCore import pyqtSlot as Slot from ert.ensemble_evaluator import EndEvent, FullSnapshotEvent, SnapshotUpdateEvent from ert.gui.model.snapshot import SnapshotModel diff --git a/src/ert/gui/simulation/run_dialog.py b/src/ert/gui/simulation/run_dialog.py index c0a06ff404b..3c08ddd6367 100644 --- a/src/ert/gui/simulation/run_dialog.py +++ b/src/ert/gui/simulation/run_dialog.py @@ -4,15 +4,13 @@ from collections.abc import Callable from pathlib import Path from queue import SimpleQueue +from typing import cast -from qtpy.QtCore import QModelIndex, QSize, Qt, QThread, QTimer, Signal, Slot -from qtpy.QtGui import ( - QMouseEvent, - QMovie, - QTextCursor, - QTextOption, -) -from qtpy.QtWidgets import ( +from PyQt6.QtCore import QModelIndex, QSize, Qt, QThread, QTimer +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtCore import pyqtSlot as Slot +from PyQt6.QtGui import QMouseEvent, QMovie, QTextCursor, QTextOption +from PyQt6.QtWidgets import ( QAbstractItemView, QDialog, QDialogButtonBox, @@ -43,6 +41,8 @@ from ert.gui.ertnotifier import ErtNotifier from ert.gui.ertwidgets.message_box import ErtMessageBox from ert.gui.model.fm_step_list import FMStepListProxyModel +from ert.gui.model.node import IterNode +from ert.gui.model.real_list import RealListModel from ert.gui.model.snapshot import ( FM_STEP_COLUMNS, FileRole, @@ -81,9 +81,9 @@ def __init__(self, snapshot_model: SnapshotModel, parent: QWidget | None) -> Non self._fm_step_model = FMStepListProxyModel(self, 0, 0) self._fm_step_model.setSourceModel(snapshot_model) - self.setVerticalScrollMode(QAbstractItemView.ScrollPerItem) - self.setSelectionBehavior(QAbstractItemView.SelectRows) - self.setSelectionMode(QAbstractItemView.SingleSelection) + self.setVerticalScrollMode(QAbstractItemView.ScrollMode.ScrollPerItem) + self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) + self.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) self.clicked.connect(self._fm_step_clicked) self.setModel(self._fm_step_model) @@ -99,9 +99,9 @@ def __init__(self, snapshot_model: SnapshotModel, parent: QWidget | None) -> Non # Only last section should be stretch horizontal_header.setSectionResizeMode( section, - QHeaderView.Stretch + QHeaderView.ResizeMode.Stretch if section == horizontal_header.count() - 1 - else QHeaderView.Interactive, + else QHeaderView.ResizeMode.Interactive, ) vertical_header = self.verticalHeader() @@ -139,20 +139,20 @@ def _fm_step_clicked(self, index: QModelIndex) -> None: error_textedit = QPlainTextEdit() error_textedit.setReadOnly(True) - error_textedit.setWordWrapMode(QTextOption.NoWrap) + error_textedit.setWordWrapMode(QTextOption.WrapMode.NoWrap) error_textedit.appendPlainText(index.data()) layout.addWidget(error_textedit) - dialog_button = QDialogButtonBox(QDialogButtonBox.Ok) + dialog_button = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok) dialog_button.accepted.connect(error_dialog.accept) layout.addWidget(dialog_button) error_dialog.resize(700, 300) - error_textedit.moveCursor(QTextCursor.Start) - error_dialog.exec_() + error_textedit.moveCursor(QTextCursor.MoveOperation.Start) + error_dialog.exec() - def mouseMoveEvent(self, event: QMouseEvent | None) -> None: - if event: - index = self.indexAt(event.pos()) + def mouseMoveEvent(self, e: QMouseEvent | None) -> None: + if e: + index = self.indexAt(e.pos()) if index.isValid(): data_name = FM_STEP_COLUMNS[index.column()] if data_name in {ids.STDOUT, ids.STDERR} and file_has_content( @@ -162,7 +162,7 @@ def mouseMoveEvent(self, event: QMouseEvent | None) -> None: else: self.setCursor(Qt.CursorShape.ArrowCursor) - return super().mouseMoveEvent(event) + return super().mouseMoveEvent(e) class RunDialog(QFrame): @@ -180,11 +180,11 @@ def __init__( parent: QWidget | None = None, output_path: Path | None = None, ): - QFrame.__init__(self, parent) + super().__init__(parent) self.output_path = output_path self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose) self.setWindowFlags(Qt.WindowType.Window) - self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) # type: ignore + self.setWindowFlag(Qt.WindowType.WindowContextHelpButtonHint, False) self.setWindowTitle(f"Experiment - {config_file} {find_ert_info()}") self._snapshot_model = SnapshotModel(self) @@ -289,7 +289,7 @@ def __init__( self.setLayout(layout) - self.kill_button.clicked.connect(self.killJobs) # type: ignore + self.kill_button.clicked.connect(self.killJobs) self.restart_button.clicked.connect(self.restart_failed_realizations) self.simulation_done.connect(self._on_simulation_done) @@ -313,9 +313,10 @@ def on_snapshot_new_iteration( ) -> None: if not parent.isValid(): index = self._snapshot_model.index(start, 0, parent) + iteration = cast(IterNode, index.internalPointer()).id_ iter_row = start self._iteration_progress_label.setText( - f"Progress for iteration {index.internalPointer().id_}" + f"Progress for iteration {iteration}" ) widget = RealizationWidget(iter_row) @@ -323,7 +324,7 @@ def on_snapshot_new_iteration( widget.itemClicked.connect(self._select_real) self._select_real(widget._real_list_model.index(0, 0)) tab_index = self._tab_widget.addTab( - widget, f"Realizations for iteration {index.internalPointer().id_}" + widget, f"Realizations for iteration {iteration}" ) if self._tab_widget.currentIndex() == self._tab_widget.count() - 2: self._tab_widget.setCurrentIndex(tab_index) @@ -332,7 +333,7 @@ def on_snapshot_new_iteration( def _select_real(self, index: QModelIndex) -> None: if index.isValid(): real = index.row() - iter_ = index.model().get_iter() # type: ignore + iter_ = cast(RealListModel, index.model()).get_iter() exec_hosts = None iter_node = self._snapshot_model.root.children.get(str(iter_), None) @@ -374,13 +375,14 @@ def run() -> None: ) self._worker_thread = QThread(parent=self) - self.destroyed.connect(lambda: _stop_worker(self)) self._worker = QueueEmitter(self._event_queue) self._worker.done.connect(self._worker_thread.quit) self._worker.new_event.connect(self._on_event) self._worker.moveToThread(self._worker_thread) + self.destroyed.connect(lambda: _stop_worker(self._worker_thread, self._worker)) + self.simulation_done.connect(self._worker.stop) self._worker_thread.started.connect(self._worker.consume_and_emit) @@ -393,10 +395,13 @@ def run() -> None: def killJobs(self) -> QMessageBox.StandardButton: msg = "Are you sure you want to terminate the currently running experiment?" kill_job = QMessageBox.question( - self, "Terminate experiment", msg, QMessageBox.Yes | QMessageBox.No + self, + "Terminate experiment", + msg, + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, ) - if kill_job == QMessageBox.Yes: + if kill_job == QMessageBox.StandardButton.Yes: # Normally this slot would be invoked by the signal/slot system, # but the worker is busy tracking the evaluation. self._run_model.cancel() @@ -506,17 +511,19 @@ def update_total_progress( def restart_failed_realizations(self) -> None: msg = QMessageBox(self) - msg.setIcon(QMessageBox.Information) + msg.setIcon(QMessageBox.Icon.Information) msg.setText( "Note that workflows will only be executed on the restarted " "realizations and that this might have unexpected consequences." ) msg.setWindowTitle("Restart failed realizations") - msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) + msg.setStandardButtons( + QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel + ) msg.setObjectName("restart_prompt") - result = msg.exec_() + result = msg.exec() - if result == QMessageBox.Ok: + if result == QMessageBox.StandardButton.Ok: self.restart_button.setVisible(False) self.kill_button.setVisible(True) self.run_experiment(restart=True) @@ -551,13 +558,13 @@ def _alternate_button_text(self) -> None: # Cannot use a non-static method here as # it is called when the object is destroyed # https://stackoverflow.com/questions/16842955 -def _stop_worker(run_dialog: RunDialog) -> None: - if run_dialog._worker_thread.isRunning(): - run_dialog._worker.stop() - run_dialog._worker_thread.wait(3000) - if run_dialog._worker_thread.isRunning(): - run_dialog._worker_thread.quit() - run_dialog._worker_thread.wait(3000) - if run_dialog._worker_thread.isRunning(): - run_dialog._worker_thread.terminate() - run_dialog._worker_thread.wait(3000) +def _stop_worker(worker_thread: QThread, worker: QueueEmitter) -> None: + if worker_thread.isRunning(): + worker.stop() + worker_thread.wait(3000) + if worker_thread.isRunning(): + worker_thread.quit() + worker_thread.wait(3000) + if worker_thread.isRunning(): + worker_thread.terminate() + worker_thread.wait(3000) diff --git a/src/ert/gui/simulation/single_test_run_panel.py b/src/ert/gui/simulation/single_test_run_panel.py index 23ecc40490a..13e906499f8 100644 --- a/src/ert/gui/simulation/single_test_run_panel.py +++ b/src/ert/gui/simulation/single_test_run_panel.py @@ -1,7 +1,7 @@ from dataclasses import dataclass -from qtpy import QtCore -from qtpy.QtWidgets import QFormLayout, QLabel +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QFormLayout, QLabel from ert.gui.ertnotifier import ErtNotifier from ert.gui.ertwidgets import CopyableLabel @@ -27,7 +27,7 @@ def __init__(self, run_path: str, notifier: ErtNotifier): layout = QFormLayout() lab = QLabel(" ".join(SingleTestRun.__doc__.split())) # type: ignore lab.setWordWrap(True) - lab.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeft) + lab.setAlignment(Qt.AlignmentFlag.AlignLeft) layout.addRow(lab) runpath_label = CopyableLabel(text=run_path) diff --git a/src/ert/gui/simulation/view/disk_space_widget.py b/src/ert/gui/simulation/view/disk_space_widget.py index e1324d709b6..247c3690d4d 100644 --- a/src/ert/gui/simulation/view/disk_space_widget.py +++ b/src/ert/gui/simulation/view/disk_space_widget.py @@ -2,8 +2,8 @@ import shutil from pathlib import Path -from qtpy.QtCore import Qt -from qtpy.QtWidgets import QHBoxLayout, QLabel, QProgressBar, QWidget +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QHBoxLayout, QLabel, QProgressBar, QWidget from ert.shared.status.utils import byte_with_unit @@ -31,7 +31,7 @@ def __init__(self, mount_path: Path, parent: QWidget | None = None) -> None: self.progress_bar.setRange(0, 100) self.progress_bar.setTextVisible(True) self.progress_bar.setFixedWidth(100) - self.progress_bar.setAlignment(Qt.AlignCenter) # type: ignore + self.progress_bar.setAlignment(Qt.AlignmentFlag.AlignCenter) layout.addWidget(self.usage_label) layout.addWidget(self.progress_bar) diff --git a/src/ert/gui/simulation/view/progress_widget.py b/src/ert/gui/simulation/view/progress_widget.py index 1a01fef930e..c18eafde088 100644 --- a/src/ert/gui/simulation/view/progress_widget.py +++ b/src/ert/gui/simulation/view/progress_widget.py @@ -1,15 +1,12 @@ from __future__ import annotations -from typing import Any - -from qtpy.QtGui import QColor -from qtpy.QtWidgets import ( +from PyQt6.QtGui import QColor, QResizeEvent +from PyQt6.QtWidgets import ( QFrame, QHBoxLayout, QLabel, QProgressBar, QVBoxLayout, - QWidget, ) from ert.ensemble_evaluator.state import ENSEMBLE_STATE_FAILED, REAL_STATE_TO_COLOR @@ -17,7 +14,7 @@ class ProgressWidget(QFrame): def __init__(self) -> None: - QWidget.__init__(self) + super().__init__() self.setFixedHeight(70) self._vertical_layout = QVBoxLayout(self) @@ -110,5 +107,5 @@ def update_progress(self, status: dict[str, int], realization_count: int) -> Non self.stop_waiting_progress_bar() self.repaint_components() - def resizeEvent(self, a0: Any, event: Any = None) -> None: + def resizeEvent(self, a0: QResizeEvent | None) -> None: self.repaint_components() diff --git a/src/ert/gui/simulation/view/realization.py b/src/ert/gui/simulation/view/realization.py index 00cd593962d..fe64e3f1d71 100644 --- a/src/ert/gui/simulation/view/realization.py +++ b/src/ert/gui/simulation/view/realization.py @@ -1,16 +1,18 @@ -from qtpy.QtCore import ( +from typing import cast + +from PyQt6.QtCore import ( QAbstractItemModel, QEvent, QItemSelectionModel, QModelIndex, QObject, - QPoint, + QPointF, QSize, Qt, - Signal, ) -from qtpy.QtGui import QColor, QColorConstants, QPainter, QPalette, QPen -from qtpy.QtWidgets import ( +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtGui import QColor, QMouseEvent, QPainter, QPalette, QPen +from PyQt6.QtWidgets import ( QAbstractItemView, QListView, QStyle, @@ -39,18 +41,20 @@ def __init__(self, it: int, parent: QWidget | None = None) -> None: self._delegate_size = QSize(90, 90) self._real_view = QListView(self) - self._real_view.setViewMode(QListView.IconMode) + self._real_view.setViewMode(QListView.ViewMode.IconMode) self._real_view.setGridSize(self._delegate_size) real_delegate = RealizationDelegate(self._delegate_size, self) self._real_view.setMouseTracking(True) self._real_view.setItemDelegate(real_delegate) - self._real_view.setSelectionMode(QAbstractItemView.SingleSelection) - self._real_view.setFlow(QListView.LeftToRight) + self._real_view.setSelectionMode( + QAbstractItemView.SelectionMode.SingleSelection + ) + self._real_view.setFlow(QListView.Flow.LeftToRight) self._real_view.setWrapping(True) - self._real_view.setResizeMode(QListView.Adjust) + self._real_view.setResizeMode(QListView.ResizeMode.Adjust) self._real_view.setUniformItemSizes(True) self._real_view.setStyleSheet( - f"QListView {{ background-color: {self.palette().color(QPalette.Window).name()}; }}" + f"QListView {{ background-color: {self.palette().color(QPalette.ColorRole.Window).name()}; }}" ) self._real_view.clicked.connect(self._item_clicked) @@ -91,17 +95,14 @@ def __init__(self, size: QSize, parent: QObject) -> None: super().__init__(parent) self._size = size parent.installEventFilter(self) - self.adjustment_point_for_job_rect_margin = QPoint(-20, -20) + self.adjustment_point_for_job_rect_margin = QPointF(-20, -20) self._color_black = QColor(0, 0, 0, 180) self._color_progress = QColor(50, 173, 230, 200) - self._color_lightgray = QColor(QColorConstants.LightGray).lighter(120) + self._color_lightgray = QColor("LightGray").lighter(120) self._pen_black = QPen(self._color_black, 2, Qt.PenStyle.SolidLine) def paint( - self, - painter: QPainter | None, - option: QStyleOptionViewItem, - index: QModelIndex, + self, painter: QPainter | None, option: QStyleOptionViewItem, index: QModelIndex ) -> None: if painter is None: return @@ -109,8 +110,8 @@ def paint( selected_color, finished_count, total_count = tuple(index.data(FMStepColorHint)) painter.save() - painter.setRenderHint(QPainter.TextAntialiasing, True) - painter.setRenderHint(QPainter.Antialiasing, True) + painter.setRenderHint(QPainter.RenderHint.TextAntialiasing, True) + painter.setRenderHint(QPainter.RenderHint.Antialiasing, True) percentage_done = ( 100 if total_count < 1 else int((finished_count * 100.0) / total_count) @@ -152,9 +153,11 @@ def sizeHint(self, option: QStyleOptionViewItem, index: QModelIndex) -> QSize: return self._size def eventFilter(self, object: QObject | None, event: QEvent | None) -> bool: - if event.type() == QEvent.Type.ToolTip: # type: ignore - mouse_pos = event.pos() + self.adjustment_point_for_job_rect_margin # type: ignore - parent: RealizationWidget = self.parent() # type: ignore + if event and event.type() == QEvent.Type.ToolTip and type(event) is QMouseEvent: + mouse_pos = ( + event.position() + self.adjustment_point_for_job_rect_margin + ).toPoint() + parent: RealizationWidget = cast(RealizationWidget, self.parent()) view = parent._real_view index = view.indexAt(mouse_pos) if index.isValid(): diff --git a/src/ert/gui/simulation/view/update.py b/src/ert/gui/simulation/view/update.py index 1fe262cafad..ff58be02f95 100644 --- a/src/ert/gui/simulation/view/update.py +++ b/src/ert/gui/simulation/view/update.py @@ -5,9 +5,10 @@ from datetime import timedelta import humanize -from qtpy.QtCore import Qt, Slot -from qtpy.QtGui import QColor, QKeyEvent, QKeySequence -from qtpy.QtWidgets import ( +from PyQt6.QtCore import Qt +from PyQt6.QtCore import pyqtSlot as Slot +from PyQt6.QtGui import QColor, QKeyEvent, QKeySequence +from PyQt6.QtWidgets import ( QAbstractItemView, QApplication, QGridLayout, @@ -46,17 +47,17 @@ def __init__(self, data: DataSection, parent: QWidget | None = None): self.setRowCount(len(data.data)) self.setHorizontalHeaderLabels(data.header) self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) - self.setEditTriggers(QAbstractItemView.NoEditTriggers) + self.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers) horizontal_header = self.horizontalHeader() assert horizontal_header is not None - horizontal_header.setSectionResizeMode(QHeaderView.ResizeToContents) + horizontal_header.setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents) self.setSortingEnabled(True) for i, row in enumerate(data.data): for j, val in enumerate(row): self.setItem(i, j, QTableWidgetItem(str(val))) def keyPressEvent(self, e: QKeyEvent | None) -> None: - if e is not None and e.matches(QKeySequence.Copy): + if e is not None and e.matches(QKeySequence.StandardKey.Copy): stream = "" for i in self.selectedIndexes(): item = self.itemFromIndex(i) @@ -71,7 +72,7 @@ def keyPressEvent(self, e: QKeyEvent | None) -> None: None, "Error", "Cannot copy text to clipboard because your system does not have a clipboard", - QMessageBox.Ok, + QMessageBox.StandardButton.Ok, ) else: super().keyPressEvent(e) @@ -127,7 +128,7 @@ def iteration(self) -> int: def _insert_status_message(self, message: str) -> None: item = QListWidgetItem() item.setText(message) - item.setFlags(item.flags() & ~Qt.ItemFlags(Qt.ItemFlag.ItemIsEnabled)) + item.setFlags(item.flags() & ~Qt.ItemFlag.ItemIsEnabled) self._msg_list.addItem(item) def _insert_table_tab( diff --git a/src/ert/gui/suggestor/_suggestor_message.py b/src/ert/gui/suggestor/_suggestor_message.py index e786340a836..3e5e077d770 100644 --- a/src/ert/gui/suggestor/_suggestor_message.py +++ b/src/ert/gui/suggestor/_suggestor_message.py @@ -2,10 +2,10 @@ from typing import Any, Self -from qtpy import QtSvg -from qtpy.QtCore import Qt -from qtpy.QtGui import QColor -from qtpy.QtWidgets import ( +from PyQt6.QtCore import Qt +from PyQt6.QtGui import QColor +from PyQt6.QtSvgWidgets import QSvgWidget +from PyQt6.QtWidgets import ( QGraphicsDropShadowEffect, QHBoxLayout, QLabel, @@ -24,9 +24,9 @@ ) -def _svg_icon(image_name: str) -> QtSvg.QSvgWidget: - widget = QtSvg.QSvgWidget(f"img:{image_name}.svg") - widget.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) +def _svg_icon(image_name: str) -> QSvgWidget: + widget = QSvgWidget(f"img:{image_name}.svg") + widget.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) return widget @@ -73,7 +73,9 @@ def __init__( self.lbl = QLabel(self._collapsed_text()) self.lbl.setOpenExternalLinks(False) - self.lbl.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + self.lbl.setSizePolicy( + QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding + ) self.lbl.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse) self.lbl.setWordWrap(True) self._expanded = False diff --git a/src/ert/gui/suggestor/suggestor.py b/src/ert/gui/suggestor/suggestor.py index 99221baf2ab..071e7aae41e 100644 --- a/src/ert/gui/suggestor/suggestor.py +++ b/src/ert/gui/suggestor/suggestor.py @@ -7,9 +7,9 @@ from collections.abc import Callable, Sequence from typing import TYPE_CHECKING -from qtpy.QtCore import Qt -from qtpy.QtGui import QCursor -from qtpy.QtWidgets import ( +from PyQt6.QtCore import Qt +from PyQt6.QtGui import QCursor +from PyQt6.QtWidgets import ( QFrame, QGridLayout, QHBoxLayout, @@ -166,7 +166,7 @@ def _help_panel(self, help_links: dict[str, str]) -> QFrame: help_buttons_layout.addWidget(help_header, alignment=Qt.AlignmentFlag.AlignTop) separator = QFrame(parent=self) - separator.setFrameShape(QFrame.HLine) + separator.setFrameShape(QFrame.Shape.HLine) separator.setStyleSheet(f"color: {HEAVY_GREY};") separator.setFixedWidth(388) help_buttons_layout.addWidget(separator) @@ -219,7 +219,7 @@ def run_pressed() -> None: run.setObjectName("run_ert_button") run.pressed.connect(run_pressed) - give_up.pressed.connect(self.close) # type: ignore + give_up.pressed.connect(self.close) buttons = QWidget(parent=self) buttons_layout = QHBoxLayout() buttons_layout.insertStretch(-1, -1) diff --git a/src/ert/gui/summarypanel.py b/src/ert/gui/summarypanel.py index 3eebbae6578..8cccf54cbb6 100644 --- a/src/ert/gui/summarypanel.py +++ b/src/ert/gui/summarypanel.py @@ -2,8 +2,8 @@ from typing import TYPE_CHECKING, Any -from qtpy.QtCore import Qt -from qtpy.QtWidgets import ( +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import ( QFrame, QGridLayout, QHBoxLayout, diff --git a/src/ert/gui/tools/design_matrix/design_matrix_panel.py b/src/ert/gui/tools/design_matrix/design_matrix_panel.py index e92e81063c6..0d94f166962 100644 --- a/src/ert/gui/tools/design_matrix/design_matrix_panel.py +++ b/src/ert/gui/tools/design_matrix/design_matrix_panel.py @@ -1,6 +1,6 @@ import pandas as pd -from qtpy.QtGui import QStandardItem, QStandardItemModel -from qtpy.QtWidgets import QDialog, QTableView, QVBoxLayout, QWidget +from PyQt6.QtGui import QStandardItem, QStandardItemModel +from PyQt6.QtWidgets import QDialog, QTableView, QVBoxLayout, QWidget class DesignMatrixPanel(QDialog): @@ -15,7 +15,7 @@ def __init__( self.setWindowTitle(f"Design matrix parameters from {filename}") table_view = QTableView(self) - table_view.setEditTriggers(QTableView.NoEditTriggers) + table_view.setEditTriggers(QTableView.EditTrigger.NoEditTriggers) self.model = self.create_model(design_matrix_df) table_view.setModel(self.model) diff --git a/src/ert/gui/tools/event_viewer/panel.py b/src/ert/gui/tools/event_viewer/panel.py index 3dfd06fb654..3a4f59edaff 100644 --- a/src/ert/gui/tools/event_viewer/panel.py +++ b/src/ert/gui/tools/event_viewer/panel.py @@ -2,9 +2,10 @@ from collections.abc import Iterator from contextlib import contextmanager -from qtpy import QtCore -from qtpy.QtCore import QObject -from qtpy.QtWidgets import QPlainTextEdit, QVBoxLayout +from PyQt6.QtCore import QObject +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtCore import pyqtSlot as Slot +from PyQt6.QtWidgets import QPlainTextEdit, QVBoxLayout from ert.gui.tools.search_bar import SearchBar @@ -14,7 +15,7 @@ class _Signaler(QObject): - append_log_statement = QtCore.Signal(str) + append_log_statement = Signal(str) class _GUILogHandler(logging.Handler): @@ -70,7 +71,7 @@ def __init__(self, log_handler: GUILogHandler): self.setLayout(layout) log_handler.append_log_statement.connect(self.val_changed) - @QtCore.Slot(str) + @Slot(str) def val_changed(self, value: str) -> None: self.text_box.appendPlainText(value) diff --git a/src/ert/gui/tools/event_viewer/tool.py b/src/ert/gui/tools/event_viewer/tool.py index c083b06a79d..0e739cd083a 100644 --- a/src/ert/gui/tools/event_viewer/tool.py +++ b/src/ert/gui/tools/event_viewer/tool.py @@ -1,5 +1,6 @@ -from qtpy.QtCore import QObject, Slot -from qtpy.QtGui import QIcon +from PyQt6.QtCore import QObject +from PyQt6.QtCore import pyqtSlot as Slot +from PyQt6.QtGui import QIcon from ert.gui.tools import Tool diff --git a/src/ert/gui/tools/export/export_panel.py b/src/ert/gui/tools/export/export_panel.py index 1086f5ae66e..623d74b9d2a 100644 --- a/src/ert/gui/tools/export/export_panel.py +++ b/src/ert/gui/tools/export/export_panel.py @@ -3,7 +3,7 @@ import json from typing import TYPE_CHECKING -from qtpy.QtWidgets import QCheckBox, QWidget +from PyQt6.QtWidgets import QCheckBox, QWidget from ert.gui.ertwidgets import CustomDialog, ListEditBox, PathChooser, PathModel diff --git a/src/ert/gui/tools/export/export_tool.py b/src/ert/gui/tools/export/export_tool.py index ad277b756fb..0072abc40d3 100644 --- a/src/ert/gui/tools/export/export_tool.py +++ b/src/ert/gui/tools/export/export_tool.py @@ -3,8 +3,8 @@ import logging from typing import TYPE_CHECKING, Any, cast, no_type_check -from qtpy.QtGui import QIcon -from qtpy.QtWidgets import QMessageBox, QWidget +from PyQt6.QtGui import QIcon +from PyQt6.QtWidgets import QMessageBox, QWidget if TYPE_CHECKING: from ert.config import ErtConfig @@ -54,7 +54,7 @@ def _run_export(self, params: list[Any]) -> None: cast(QWidget, self.parent()), "Success", """Export completed!""", - QMessageBox.Ok, + QMessageBox.StandardButton.Ok, ) except UserWarning as usrwarning: logger.error(str(usrwarning)) @@ -62,5 +62,5 @@ def _run_export(self, params: list[Any]) -> None: cast(QWidget, self.parent()), "Failure", f"Export failed with the following message:\n{usrwarning}", - QMessageBox.Ok, + QMessageBox.StandardButton.Ok, ) diff --git a/src/ert/gui/tools/file/file_dialog.py b/src/ert/gui/tools/file/file_dialog.py index 8ab5d21d60b..b085544bce3 100644 --- a/src/ert/gui/tools/file/file_dialog.py +++ b/src/ert/gui/tools/file/file_dialog.py @@ -1,8 +1,8 @@ from math import floor -from qtpy.QtCore import QSize, Qt, QThread -from qtpy.QtGui import QClipboard, QFontDatabase, QTextCursor, QTextOption -from qtpy.QtWidgets import ( +from PyQt6.QtCore import QSize, Qt, QThread +from PyQt6.QtGui import QClipboard, QFontDatabase, QTextCursor, QTextOption +from PyQt6.QtWidgets import ( QApplication, QDialog, QDialogButtonBox, @@ -60,10 +60,10 @@ def __init__( self._file = open(file_name, encoding="utf-8") # noqa: SIM115 except OSError as error: self._mb = QMessageBox( - QMessageBox.Critical, + QMessageBox.Icon.Critical, "Error opening file", - error.strerror, - QMessageBox.Ok, + error.strerror if error.strerror else "", + QMessageBox.StandardButton.Ok, self, ) self._mb.finished.connect(self.accept) @@ -72,7 +72,7 @@ def __init__( self._view = QPlainTextEdit() self._view.setReadOnly(True) - self._view.setWordWrapMode(QTextOption.NoWrap) + self._view.setWordWrapMode(QTextOption.WrapMode.NoWrap) # for moving the actual slider scroll_bar = self._view.verticalScrollBar() assert scroll_bar is not None @@ -80,7 +80,7 @@ def __init__( # for mouse wheel and keyboard arrows scroll_bar.valueChanged.connect(self._update_cursor) - self._view.setFont(QFontDatabase.systemFont(QFontDatabase.FixedFont)) + self._view.setFont(QFontDatabase.systemFont(QFontDatabase.SystemFont.FixedFont)) self._search_bar = SearchBar(self._view) self._follow_mode = False @@ -95,19 +95,19 @@ def _quit_thread(self) -> None: self._file.close() def _init_layout(self) -> None: - dialog_buttons = QDialogButtonBox(QDialogButtonBox.Ok) + dialog_buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok) dialog_buttons.accepted.connect(self.accept) self._copy_all_button = dialog_buttons.addButton( "Copy all", - QDialogButtonBox.ActionRole, + QDialogButtonBox.ButtonRole.ActionRole, ) assert self._copy_all_button is not None self._copy_all_button.clicked.connect(self._copy_all) self._follow_button = dialog_buttons.addButton( "Follow", - QDialogButtonBox.ActionRole, + QDialogButtonBox.ButtonRole.ActionRole, ) assert self._follow_button is not None self._follow_button.setCheckable(True) @@ -151,13 +151,13 @@ def _enable_follow_mode(self, enable: bool) -> None: vertical_scroll_bar.setDisabled(enable) self._follow_mode = enable if enable: - self._view.moveCursor(QTextCursor.End) + self._view.moveCursor(QTextCursor.MoveOperation.End) self._view.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self._view.setTextInteractionFlags(Qt.TextInteractionFlag.NoTextInteraction) else: self._view.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded) self._view.setTextInteractionFlags( - Qt.TextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse) + Qt.TextInteractionFlag.TextSelectableByMouse | Qt.TextInteractionFlag.TextSelectableByKeyboard ) @@ -166,7 +166,7 @@ def _append_text(self, text: str) -> None: if text[-1:] == "\n": text = text[:-1] if self._follow_mode: - self._view.moveCursor(QTextCursor.End) + self._view.moveCursor(QTextCursor.MoveOperation.End) self._view.appendPlainText(text) self.adjustSize() diff --git a/src/ert/gui/tools/file/file_update_worker.py b/src/ert/gui/tools/file/file_update_worker.py index 25b9343853d..4234e1ed8cf 100644 --- a/src/ert/gui/tools/file/file_update_worker.py +++ b/src/ert/gui/tools/file/file_update_worker.py @@ -1,6 +1,8 @@ from io import TextIOWrapper -from qtpy.QtCore import QObject, QTimer, Signal, Slot +from PyQt6.QtCore import QObject, QTimer +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtCore import pyqtSlot as Slot class FileUpdateWorker(QObject): diff --git a/src/ert/gui/tools/load_results/load_results_panel.py b/src/ert/gui/tools/load_results/load_results_panel.py index a0cb44e0936..1512291c4fc 100644 --- a/src/ert/gui/tools/load_results/load_results_panel.py +++ b/src/ert/gui/tools/load_results/load_results_panel.py @@ -1,7 +1,8 @@ from __future__ import annotations -from qtpy.QtCore import Qt, Signal -from qtpy.QtWidgets import QFormLayout, QLabel, QMessageBox, QWidget +from PyQt6.QtCore import Qt +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtWidgets import QFormLayout, QLabel, QMessageBox, QWidget from ert.gui.ertnotifier import ErtNotifier from ert.gui.ertwidgets import ( @@ -112,10 +113,10 @@ def load(self) -> int: msg = ErtMessageBox( f"Successfully loaded {loaded} realizations", "\n".join(messages) ) - msg.exec_() + msg.exec() else: msg = ErtMessageBox("No realizations loaded", "\n".join(messages)) - msg.exec_() + msg.exec() return loaded def refresh(self) -> None: diff --git a/src/ert/gui/tools/load_results/load_results_tool.py b/src/ert/gui/tools/load_results/load_results_tool.py index faf5a4b58bd..e40de9ea15e 100644 --- a/src/ert/gui/tools/load_results/load_results_tool.py +++ b/src/ert/gui/tools/load_results/load_results_tool.py @@ -1,6 +1,6 @@ from typing import Any -from qtpy.QtGui import QIcon +from PyQt6.QtGui import QIcon from ert.gui.ertnotifier import ErtNotifier from ert.gui.ertwidgets import ClosableDialog @@ -41,7 +41,7 @@ def trigger(self) -> None: self._loadButton.setEnabled(False) self._loadButton.setToolTip("Must load into a ensemble") assert self._dialog is not None - self._dialog.exec_() + self._dialog.exec() def load(self, _: Any) -> None: assert self._dialog is not None diff --git a/src/ert/gui/tools/manage_experiments/manage_experiments_panel.py b/src/ert/gui/tools/manage_experiments/manage_experiments_panel.py index 4fe9d8b34bb..b85d429eebe 100644 --- a/src/ert/gui/tools/manage_experiments/manage_experiments_panel.py +++ b/src/ert/gui/tools/manage_experiments/manage_experiments_panel.py @@ -1,9 +1,9 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING -from qtpy.QtCore import QEvent, QObject, Qt -from qtpy.QtWidgets import ( +from PyQt6.QtCore import QEvent, QObject, Qt +from PyQt6.QtWidgets import ( QHBoxLayout, QLabel, QPushButton, @@ -110,7 +110,7 @@ def _add_initialize_from_scratch_tab(self) -> None: initialize_button.setMaximumWidth(150) @showWaitCursorWhileWaiting - def initialize_from_scratch(_: Any) -> None: + def initialize_from_scratch(_: bool) -> None: parameters = parameter_model.getSelectedItems() sample_prior( ensemble=ensemble_selector.currentData(), @@ -126,7 +126,7 @@ def update_button_state() -> None: ensemble_selector.ensemble_populated.connect(update_button_state) initialize_button.clicked.connect(initialize_from_scratch) initialize_button.clicked.connect( - lambda: self._storage_info_widget.setEnsemble( + lambda _: self._storage_info_widget.setEnsemble( ensemble_selector.currentData() ) ) diff --git a/src/ert/gui/tools/manage_experiments/storage_info_widget.py b/src/ert/gui/tools/manage_experiments/storage_info_widget.py index 2d845312f4f..a250563f4c1 100644 --- a/src/ert/gui/tools/manage_experiments/storage_info_widget.py +++ b/src/ert/gui/tools/manage_experiments/storage_info_widget.py @@ -6,8 +6,9 @@ import yaml from matplotlib.backends.backend_qt5agg import FigureCanvas # type: ignore from matplotlib.figure import Figure -from qtpy.QtCore import Qt, Slot -from qtpy.QtWidgets import ( +from PyQt6.QtCore import Qt +from PyQt6.QtCore import pyqtSlot as Slot +from PyQt6.QtWidgets import ( QFrame, QHBoxLayout, QLabel, diff --git a/src/ert/gui/tools/manage_experiments/storage_model.py b/src/ert/gui/tools/manage_experiments/storage_model.py index 54ac392adfa..b57cf50b7db 100644 --- a/src/ert/gui/tools/manage_experiments/storage_model.py +++ b/src/ert/gui/tools/manage_experiments/storage_model.py @@ -1,10 +1,11 @@ from enum import IntEnum -from typing import Any, overload +from typing import Any, Self, cast, overload from uuid import UUID import humanize -from qtpy.QtCore import QAbstractItemModel, QModelIndex, QObject, Qt, Slot -from qtpy.QtWidgets import QApplication +from PyQt6.QtCore import QAbstractItemModel, QModelIndex, QObject, Qt +from PyQt6.QtCore import pyqtSlot as Slot +from PyQt6.QtWidgets import QApplication from typing_extensions import override from ert.storage import Ensemble, Experiment, Storage @@ -132,6 +133,9 @@ def data( return None +ChildModel = ExperimentModel | EnsembleModel | RealizationModel + + class StorageModel(QAbstractItemModel): def __init__(self, storage: Storage): super().__init__(None) @@ -144,7 +148,7 @@ def reloadStorage(self, storage: Storage) -> None: self._load_storage(storage) self.endResetModel() - @Slot() + @Slot(ExperimentModel) def add_experiment(self, experiment: ExperimentModel) -> None: idx = QModelIndex() self.beginInsertRows(idx, 0, 0) @@ -169,25 +173,22 @@ def columnCount(self, parent: QModelIndex | None = None) -> int: @override def rowCount(self, parent: QModelIndex | None = None) -> int: - if parent is None: - parent = QModelIndex() - if parent.isValid(): - if isinstance(parent.internalPointer(), RealizationModel): - return 0 - return len(parent.internalPointer()._children) + if parent is not None and parent.isValid(): + data = cast(ChildModel | Self, parent.internalPointer()) + return 0 if isinstance(data, RealizationModel) else len(data._children) else: return len(self._children) @overload def parent(self, child: QModelIndex) -> QModelIndex: ... @overload - def parent(self) -> QObject | None: ... + def parent(self) -> QObject: ... @override - def parent(self, child: QModelIndex | None = None) -> QObject | None: + def parent(self, child: QModelIndex | None = None) -> QObject | QModelIndex: if child is None or not child.isValid(): return QModelIndex() - child_item = child.internalPointer() + child_item = cast(ChildModel, child.internalPointer()) parentItem = child_item._parent if parentItem == self: @@ -212,7 +213,9 @@ def data(self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) -> A if not index.isValid(): return None - return index.internalPointer().data(index, role) + return cast(ChildModel | Self, index.internalPointer()).data( + index, Qt.ItemDataRole(role) + ) @override def index( @@ -220,11 +223,17 @@ def index( ) -> QModelIndex: if parent is None: parent = QModelIndex() - parentItem = parent.internalPointer() if parent.isValid() else self - try: - childItem = parentItem._children[row] - except KeyError: - childItem = None - if childItem: - return self.createIndex(row, column, childItem) + + model = ( + cast(ChildModel | Self, parent.internalPointer()) + if parent.isValid() + else self + ) + if type(model) is not RealizationModel: + model = cast(Self | EnsembleModel | ExperimentModel, model) + try: + childItem = model._children[row] + return self.createIndex(row, column, childItem) + except KeyError: + pass return QModelIndex() diff --git a/src/ert/gui/tools/manage_experiments/storage_widget.py b/src/ert/gui/tools/manage_experiments/storage_widget.py index a062254607a..a0f02c3ace1 100644 --- a/src/ert/gui/tools/manage_experiments/storage_widget.py +++ b/src/ert/gui/tools/manage_experiments/storage_widget.py @@ -1,16 +1,16 @@ from collections.abc import Callable -from qtpy.QtCore import ( +from PyQt6.QtCore import ( QAbstractItemModel, QItemSelectionModel, QModelIndex, QSize, QSortFilterProxyModel, Qt, - Signal, ) -from qtpy.QtGui import QIcon -from qtpy.QtWidgets import ( +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtGui import QIcon +from PyQt6.QtWidgets import ( QHBoxLayout, QLineEdit, QToolButton, @@ -114,9 +114,9 @@ def __init__( self._tree_view.setModel(proxy_model) 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._sel_model = QItemSelectionModel(proxy_model) + self._sel_model.currentChanged.connect(self._currentChanged) + self._tree_view.setSelectionModel(self._sel_model) self._tree_view.setColumnWidth(0, 225) self._tree_view.setColumnWidth(1, 125) self._tree_view.setColumnWidth(2, 100) @@ -147,7 +147,7 @@ def _currentChanged(self, selected: QModelIndex, previous: QModelIndex) -> None: def _addItem(self) -> None: create_experiment_dialog = CreateExperimentDialog(self._notifier, parent=self) create_experiment_dialog.show() - if create_experiment_dialog.exec_(): + if create_experiment_dialog.exec(): ensemble = self._notifier.storage.create_experiment( parameters=self._ert_config.ensemble_config.parameter_configuration, responses=self._ert_config.ensemble_config.response_configuration, diff --git a/src/ert/gui/tools/plot/customize/color_chooser.py b/src/ert/gui/tools/plot/customize/color_chooser.py index de8f7495915..4f97bb88cc7 100644 --- a/src/ert/gui/tools/plot/customize/color_chooser.py +++ b/src/ert/gui/tools/plot/customize/color_chooser.py @@ -1,6 +1,8 @@ -from qtpy.QtCore import QRect, QSize, Signal, Slot -from qtpy.QtGui import QColor, QMouseEvent, QPainter, QPaintEvent -from qtpy.QtWidgets import QColorDialog, QFrame +from PyQt6.QtCore import QRect, QSize +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtCore import pyqtSlot as Slot +from PyQt6.QtGui import QColor, QMouseEvent, QPainter, QPaintEvent +from PyQt6.QtWidgets import QColorDialog, QFrame class ColorBox(QFrame): @@ -11,7 +13,7 @@ class ColorBox(QFrame): def __init__(self, size: int = 15) -> None: QFrame.__init__(self) - self.setFrameStyle(QFrame.Panel | QFrame.Sunken) + self.setFrameStyle(QFrame.Shape.Panel | QFrame.Shadow.Sunken) self.setMaximumSize(QSize(size, size)) self.setMinimumSize(QSize(size, size)) @@ -30,7 +32,7 @@ def update_color(self, color: QColor) -> None: def show_color_dialog(self) -> None: color_dialog = QColorDialog(self._color, self) color_dialog.setWindowTitle("Select color") - color_dialog.setOption(QColorDialog.ShowAlphaChannel) + color_dialog.setOption(QColorDialog.ColorDialogOption.ShowAlphaChannel) color_dialog.accepted.connect( lambda: self.colorChanged.emit(color_dialog.selectedColor()) ) @@ -47,7 +49,7 @@ def color(self, color: tuple[str, float]) -> None: self._color = new_color self.update() - def paintEvent(self, event: QPaintEvent | None) -> None: + def paintEvent(self, a0: QPaintEvent | None) -> None: """Paints the box""" painter = QPainter(self) rect = self.contentsRect() @@ -65,9 +67,9 @@ def paintEvent(self, event: QPaintEvent | None) -> None: painter.restore() painter.fillRect(rect, self._color) - QFrame.paintEvent(self, event) + QFrame.paintEvent(self, a0) - def mouseReleaseEvent(self, event: QMouseEvent | None) -> None: - if event: + def mouseReleaseEvent(self, a0: QMouseEvent | None) -> None: + if a0: self.mouseRelease.emit() - return super().mouseReleaseEvent(event) + return super().mouseReleaseEvent(a0) diff --git a/src/ert/gui/tools/plot/customize/customization_view.py b/src/ert/gui/tools/plot/customize/customization_view.py index 24dd5530e00..3105532ca90 100644 --- a/src/ert/gui/tools/plot/customize/customization_view.py +++ b/src/ert/gui/tools/plot/customize/customization_view.py @@ -3,7 +3,7 @@ from collections.abc import Callable from typing import TYPE_CHECKING, Any -from qtpy.QtWidgets import ( +from PyQt6.QtWidgets import ( QCheckBox, QFormLayout, QHBoxLayout, @@ -28,7 +28,7 @@ def __init__(self) -> None: self.setLayout(self._layout) self._widgets: dict[str, QWidget] = {} - def addRow(self, title: str | None, widget: QWidget | None) -> None: + def addRow(self, title: str, widget: QWidget) -> None: self._layout.addRow(title, widget) def addLineEdit( diff --git a/src/ert/gui/tools/plot/customize/customize_plot_dialog.py b/src/ert/gui/tools/plot/customize/customize_plot_dialog.py index ca4bbf520a4..afb18208bbc 100644 --- a/src/ert/gui/tools/plot/customize/customize_plot_dialog.py +++ b/src/ert/gui/tools/plot/customize/customize_plot_dialog.py @@ -3,9 +3,10 @@ from collections.abc import Iterable, Iterator from typing import TYPE_CHECKING -from qtpy.QtCore import QObject, Qt, Signal -from qtpy.QtGui import QIcon, QKeyEvent -from qtpy.QtWidgets import ( +from PyQt6.QtCore import QObject, Qt +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtGui import QIcon, QKeyEvent +from PyQt6.QtWidgets import ( QDialog, QHBoxLayout, QLayout, @@ -197,15 +198,16 @@ def __init__( key: str | None = "", ) -> None: QDialog.__init__(self, parent) - self.setWindowTitle(title) + if title is not None: + self.setWindowTitle(title) self.current_key = key self._key_defs = key_defs - self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) # type: ignore - self.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint) # type: ignore + self.setWindowFlag(Qt.WindowType.WindowContextHelpButtonHint, False) + self.setWindowFlag(Qt.WindowType.WindowCloseButtonHint, False) - self._tab_map: dict[str, QWidget] = {} + self._tab_map: dict[str, CustomizationView] = {} self._tab_order: list[str] = [] layout = QVBoxLayout() @@ -235,13 +237,15 @@ def __init__( self._copy_from_button = QToolButton() self._copy_from_button.setIcon(QIcon("img:download.svg")) self._copy_from_button.setToolTip("Copy settings from another key") - self._copy_from_button.setPopupMode(QToolButton.InstantPopup) + self._copy_from_button.setPopupMode( + QToolButton.ToolButtonPopupMode.InstantPopup + ) self._copy_from_button.setEnabled(False) self._copy_to_button = QToolButton() self._copy_to_button.setIcon(QIcon("img:upload.svg")) self._copy_to_button.setToolTip("Copy current plot settings to other keys") - self._copy_to_button.setPopupMode(QToolButton.InstantPopup) + self._copy_to_button.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup) self._copy_to_button.clicked.connect(self.initiateCopyStyleToDialog) self._copy_to_button.setEnabled(True) @@ -280,10 +284,10 @@ def __init__( def initiateCopyStyleToDialog(self) -> None: dialog = CopyStyleToDialog(self, self.current_key, self._key_defs) - if dialog.exec_(): + if dialog.exec(): self.copySettingsToOthers.emit(dialog.getSelectedKeys()) - def addCopyableKey(self, key: str | QListWidgetItem | None) -> None: + def addCopyableKey(self, key: str | QListWidgetItem) -> None: self._popup_list.addItem(key) def keySelected(self, list_widget_item: QListWidgetItem) -> None: @@ -295,12 +299,14 @@ def currentPlotKeyChanged(self, new_key: str | None) -> None: def keyPressEvent(self, a0: QKeyEvent | None) -> None: # Hide when pressing Escape instead of QDialog.keyPressEvent(KeyEscape) # which closes the dialog - if a0 is not None and a0.key() == Qt.Key.Key_Escape: + if a0 and a0.key() == Qt.Key.Key_Escape: self.hide() else: QDialog.keyPressEvent(self, a0) - def addTab(self, attribute_name: str, title: str, widget: QWidget) -> None: + def addTab( + self, attribute_name: str, title: str, widget: CustomizationView + ) -> None: self._tabs.addTab(widget, title) self._tab_map[attribute_name] = widget self._tab_order.append(attribute_name) @@ -308,7 +314,7 @@ def addTab(self, attribute_name: str, title: str, widget: QWidget) -> None: def __getitem__(self, item: str) -> CustomizationView: return self._tab_map[item] - def __iter__(self) -> Iterator[QWidget]: + def __iter__(self) -> Iterator[CustomizationView]: for attribute_name in self._tab_order: yield self._tab_map[attribute_name] diff --git a/src/ert/gui/tools/plot/customize/limits_customization_view.py b/src/ert/gui/tools/plot/customize/limits_customization_view.py index fec3e58cccf..ebfd5059b76 100644 --- a/src/ert/gui/tools/plot/customize/limits_customization_view.py +++ b/src/ert/gui/tools/plot/customize/limits_customization_view.py @@ -2,10 +2,10 @@ from copy import copy from datetime import date -from typing import TYPE_CHECKING, Any, ClassVar +from typing import TYPE_CHECKING, Any, ClassVar, cast -from qtpy.QtGui import QDoubleValidator, QIntValidator -from qtpy.QtWidgets import QLabel, QStackedWidget, QWidget +from PyQt6.QtGui import QDoubleValidator, QIntValidator +from PyQt6.QtWidgets import QLabel, QLineEdit, QStackedWidget from ert.gui.tools.plot.plottery import PlotContext, PlotLimits from ert.gui.tools.plot.widgets import ClearableLineEdit, CustomDateEdit @@ -19,12 +19,14 @@ class StackedInput(QStackedWidget): def __init__(self) -> None: QStackedWidget.__init__(self) - self._inputs: dict[str | None, QWidget] = {} + self._inputs: dict[str | None, QLineEdit | QLabel | CustomDateEdit] = {} self._index_map: dict[str | None, int] = {} self.addInput(PlotContext.UNKNOWN_AXIS, QLabel("Fixed")) self._current_name: str | None = PlotContext.UNKNOWN_AXIS - def addInput(self, name: str | None, widget: QWidget) -> None: + def addInput( + self, name: str | None, widget: QLineEdit | QLabel | CustomDateEdit + ) -> None: index = self.addWidget(widget) self._inputs[name] = widget self._index_map[name] = index @@ -102,28 +104,27 @@ def createIntegerLineEdit( def setValue(self, axis_name: str | None, value: Any) -> None: input_ = self._inputs[axis_name] - if axis_name in LimitsStack.NUMBER_AXIS: - if value is None: - input_.setText("") - else: - input_.setText(str(value)) - elif axis_name == PlotContext.DATE_AXIS: + if axis_name in LimitsStack.NUMBER_AXIS and ( + issubclass(type(input_), QLineEdit) or issubclass(type(input_), QLabel) + ): + input_ = cast(QLineEdit | QLabel, input_) + input_.setText(str(value) if value is not None else "") + elif axis_name == PlotContext.DATE_AXIS and type(input_) is CustomDateEdit: input_.setDate(value) def getValue(self, axis_name: str | None) -> float | int | date | None: input_ = self._inputs[axis_name] - result = None - if axis_name in LimitsStack.FLOAT_AXIS: + result: float | int | date | None = None + if issubclass(type(input_), QLineEdit) or issubclass(type(input_), QLabel): try: - result = float(input_.text()) + input_ = cast(QLineEdit | QLabel, input_) + if axis_name in LimitsStack.FLOAT_AXIS: + result = float(input_.text()) + elif axis_name in LimitsStack.INT_AXIS: + result = int(input_.text()) except ValueError: result = None - elif axis_name in LimitsStack.INT_AXIS: - try: - result = int(input_.text()) - except ValueError: - result = None - elif axis_name == PlotContext.DATE_AXIS: + elif axis_name == PlotContext.DATE_AXIS and type(input_) is CustomDateEdit: result = input_.date() return result diff --git a/src/ert/gui/tools/plot/customize/statistics_customization_view.py b/src/ert/gui/tools/plot/customize/statistics_customization_view.py index 9fbd4c991db..fdf8c4e7979 100644 --- a/src/ert/gui/tools/plot/customize/statistics_customization_view.py +++ b/src/ert/gui/tools/plot/customize/statistics_customization_view.py @@ -1,11 +1,11 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, cast -from qtpy.QtWidgets import QComboBox, QHBoxLayout +from PyQt6.QtWidgets import QComboBox, QHBoxLayout from .customization_view import CustomizationView, WidgetProperty -from .style_chooser import STYLESET_AREA +from .style_chooser import STYLESET_AREA, StyleChooser if TYPE_CHECKING: from ert.gui.tools.plot.plottery import PlotConfig @@ -80,7 +80,8 @@ def __init__(self) -> None: "Toggle distribution connection lines visibility.", ) - self["mean_style"].createLabelLayout(layout) + style = cast(StyleChooser, self["mean_style"]) + style.createLabelLayout(layout) def createPresets(self) -> QComboBox: preset_combo = QComboBox() diff --git a/src/ert/gui/tools/plot/customize/style_chooser.py b/src/ert/gui/tools/plot/customize/style_chooser.py index 46bd7a0fa9b..2b084f6b0ff 100644 --- a/src/ert/gui/tools/plot/customize/style_chooser.py +++ b/src/ert/gui/tools/plot/customize/style_chooser.py @@ -1,6 +1,6 @@ from collections.abc import Iterator -from qtpy.QtWidgets import ( +from PyQt6.QtWidgets import ( QComboBox, QDoubleSpinBox, QHBoxLayout, diff --git a/src/ert/gui/tools/plot/customize/style_customization_view.py b/src/ert/gui/tools/plot/customize/style_customization_view.py index db611287f8e..3cdd2502f15 100644 --- a/src/ert/gui/tools/plot/customize/style_customization_view.py +++ b/src/ert/gui/tools/plot/customize/style_customization_view.py @@ -1,10 +1,10 @@ -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, cast -from qtpy.QtWidgets import QHBoxLayout +from PyQt6.QtWidgets import QHBoxLayout from .color_chooser import ColorBox from .customization_view import CustomizationView, WidgetProperty -from .style_chooser import STYLESET_TOGGLE +from .style_chooser import STYLESET_TOGGLE, StyleChooser if TYPE_CHECKING: from ert.gui.tools.plot.plottery import PlotConfig @@ -36,7 +36,8 @@ def __init__(self) -> None: line_style_set=STYLESET_TOGGLE, ) - self["default_style"].createLabelLayout(layout) + style = cast(StyleChooser, self["default_style"]) + style.createLabelLayout(layout) self.addSpacing(10) diff --git a/src/ert/gui/tools/plot/data_type_keys_list_model.py b/src/ert/gui/tools/plot/data_type_keys_list_model.py index cc7aae62b75..d75e3e907a7 100644 --- a/src/ert/gui/tools/plot/data_type_keys_list_model.py +++ b/src/ert/gui/tools/plot/data_type_keys_list_model.py @@ -1,7 +1,7 @@ from typing import Any, overload -from qtpy.QtCore import QAbstractItemModel, QModelIndex, QObject, Qt -from qtpy.QtGui import QColor, QIcon +from PyQt6.QtCore import QAbstractItemModel, QModelIndex, QObject, Qt +from PyQt6.QtGui import QColor, QIcon from typing_extensions import override from .plot_api import PlotApiKeyDefinition @@ -26,9 +26,9 @@ def index( @overload def parent(self, child: QModelIndex) -> QModelIndex: ... @overload - def parent(self) -> QObject | None: ... + def parent(self) -> QObject: ... @override - def parent(self, child: QModelIndex | None = None) -> QObject | None: + def parent(self, child: QModelIndex | None = None) -> QObject | QModelIndex: return QModelIndex() @override diff --git a/src/ert/gui/tools/plot/data_type_keys_widget.py b/src/ert/gui/tools/plot/data_type_keys_widget.py index 31e9dc26671..34c578cc790 100644 --- a/src/ert/gui/tools/plot/data_type_keys_widget.py +++ b/src/ert/gui/tools/plot/data_type_keys_widget.py @@ -1,6 +1,7 @@ -from qtpy.QtCore import QSize, Signal -from qtpy.QtGui import QColor, QIcon, QPainter, QPaintEvent -from qtpy.QtWidgets import ( +from PyQt6.QtCore import QSize +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtGui import QColor, QIcon, QPainter, QPaintEvent +from PyQt6.QtWidgets import ( QHBoxLayout, QLabel, QListView, @@ -56,7 +57,7 @@ def __init__(self, legend: str | None, color: QColor): layout.setContentsMargins(0, 0, 0, 0) self.legend_marker = _LegendMarker(color) - self.legend_marker.setToolTip(legend) + self.legend_marker.setToolTip(legend if legend else "") layout.addWidget(self.legend_marker) self.legend_label = QLabel(legend) @@ -94,9 +95,9 @@ def __init__(self, key_defs: list[PlotApiKeyDefinition]): self.data_type_keys_widget = QListView() self.data_type_keys_widget.setModel(self.filter_model) - selection_model = self.data_type_keys_widget.selectionModel() - assert selection_model is not None - selection_model.selectionChanged.connect(self.itemSelected) + self._sel_model = self.data_type_keys_widget.selectionModel() + assert self._sel_model is not None + self._sel_model.selectionChanged.connect(self.itemSelected) layout.addSpacing(15) layout.addWidget(self.data_type_keys_widget, 2) @@ -127,7 +128,7 @@ def selectDefault(self) -> None: self.data_type_keys_widget.setCurrentIndex(self.filter_model.index(0, 0)) def setSearchString(self, filter_: str | None) -> None: - self.filter_model.setFilterFixedString(filter_) + self.filter_model.setFilterFixedString(filter_ if filter_ else "") def showFilterPopup(self) -> None: self.__filter_popup.show() diff --git a/src/ert/gui/tools/plot/data_type_proxy_model.py b/src/ert/gui/tools/plot/data_type_proxy_model.py index 09a18b77d76..e322f72b77e 100644 --- a/src/ert/gui/tools/plot/data_type_proxy_model.py +++ b/src/ert/gui/tools/plot/data_type_proxy_model.py @@ -2,7 +2,7 @@ from typing import TYPE_CHECKING -from qtpy.QtCore import QModelIndex, QObject, QSortFilterProxyModel, Qt +from PyQt6.QtCore import QModelIndex, QObject, QSortFilterProxyModel, Qt if TYPE_CHECKING: from .data_type_keys_list_model import DataTypeKeysListModel diff --git a/src/ert/gui/tools/plot/plot_ensemble_selection_widget.py b/src/ert/gui/tools/plot/plot_ensemble_selection_widget.py index e72147d93ff..3a39effd490 100644 --- a/src/ert/gui/tools/plot/plot_ensemble_selection_widget.py +++ b/src/ert/gui/tools/plot/plot_ensemble_selection_widget.py @@ -1,8 +1,13 @@ from collections.abc import Iterator from typing import Any -from qtpy.QtCore import QModelIndex, QSize, Qt, Signal -from qtpy.QtGui import ( +from PyQt6.QtCore import ( + QModelIndex, + QSize, + Qt, +) +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtGui import ( QBrush, QColor, QCursor, @@ -12,7 +17,7 @@ QPainter, QPen, ) -from qtpy.QtWidgets import ( +from PyQt6.QtWidgets import ( QAbstractItemView, QListWidget, QListWidgetItem, @@ -67,7 +72,7 @@ def __init__(self, ensembles: list[EnsembleObject]): if (viewport := self.viewport()) is not None: viewport.setMouseTracking(True) - self.setDragDropMode(QAbstractItemView.InternalMove) + self.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove) self.setItemDelegate(CustomItemDelegate()) self.itemClicked.connect(self.slot_toggle_plot) @@ -113,14 +118,11 @@ def sizeHint(self, option: Any, index: Any) -> QSize: return QSize(-1, 30) def paint( - self, - painter: QPainter | None, - option: QStyleOptionViewItem, - index: QModelIndex, + self, painter: QPainter | None, option: QStyleOptionViewItem, index: QModelIndex ) -> None: if painter is None: return - painter.setRenderHint(QPainter.Antialiasing) + painter.setRenderHint(QPainter.RenderHint.Antialiasing) pen_color = QColor("black") background_color = QColor("lightgray") diff --git a/src/ert/gui/tools/plot/plot_widget.py b/src/ert/gui/tools/plot/plot_widget.py index a94e5f60633..8e5c66d674a 100644 --- a/src/ert/gui/tools/plot/plot_widget.py +++ b/src/ert/gui/tools/plot/plot_widget.py @@ -10,9 +10,11 @@ NavigationToolbar2QT, ) from matplotlib.figure import Figure -from qtpy.QtCore import QStringListModel, Qt, Signal, Slot -from qtpy.QtGui import QIcon -from qtpy.QtWidgets import QAction, QComboBox, QVBoxLayout, QWidget, QWidgetAction +from PyQt6.QtCore import QStringListModel, Qt +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtCore import pyqtSlot as Slot +from PyQt6.QtGui import QAction, QIcon +from PyQt6.QtWidgets import QComboBox, QVBoxLayout, QWidget, QWidgetAction from .plot_api import EnsembleObject diff --git a/src/ert/gui/tools/plot/plot_window.py b/src/ert/gui/tools/plot/plot_window.py index e19efb380ec..b92bdb8e6cd 100644 --- a/src/ert/gui/tools/plot/plot_window.py +++ b/src/ert/gui/tools/plot/plot_window.py @@ -1,13 +1,14 @@ import logging import time -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, cast import numpy as np import pandas as pd from httpx import RequestError from pandas import DataFrame -from qtpy.QtCore import Qt, Slot -from qtpy.QtWidgets import QDockWidget, QMainWindow, QTabWidget, QWidget +from PyQt6.QtCore import Qt +from PyQt6.QtCore import pyqtSlot as Slot +from PyQt6.QtWidgets import QDockWidget, QMainWindow, QTabWidget, QWidget from ert.gui.ertwidgets import showWaitCursorWhileWaiting @@ -41,7 +42,7 @@ logger = logging.getLogger(__name__) -from qtpy.QtWidgets import ( +from PyQt6.QtWidgets import ( QApplication, QDialog, QHBoxLayout, @@ -97,7 +98,7 @@ def open_error_dialog(title: str, content: str) -> None: class PlotWindow(QMainWindow): def __init__(self, config_file: str, parent: QWidget | None): - QMainWindow.__init__(self, parent) + super().__init__(parent) t = time.perf_counter() logger.info("PlotWindow __init__") @@ -191,8 +192,7 @@ def updatePlot(self, layer: int | None = None) -> None: return key = key_def.key - plot_widget = self._central_tab.currentWidget() - assert plot_widget is not None + plot_widget = cast(PlotWidget, self._central_tab.currentWidget()) if plot_widget._plotter.dimensionality == key_def.dimensionality: selected_ensembles = ( @@ -329,7 +329,8 @@ def addDock( dock_widget.setWidget(widget) dock_widget.setAllowedAreas(allowed_areas) dock_widget.setFeatures( - QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable + QDockWidget.DockWidgetFeature.DockWidgetFloatable + | QDockWidget.DockWidgetFeature.DockWidgetMovable ) self.addDockWidget(area, dock_widget) diff --git a/src/ert/gui/tools/plot/plottery/plots/std_dev.py b/src/ert/gui/tools/plot/plottery/plots/std_dev.py index 6c44bd654aa..a54217fa7b3 100644 --- a/src/ert/gui/tools/plot/plottery/plots/std_dev.py +++ b/src/ert/gui/tools/plot/plottery/plots/std_dev.py @@ -59,7 +59,7 @@ def plot( im = ax_heat.imshow(data, cmap="viridis", aspect="equal") heatmaps.append(im) - ax_box.boxplot(data.flatten(), vert=True, widths=0.5) + ax_box.boxplot(data.flatten(), orientation="vertical", widths=0.5) boxplot_axes.append(ax_box) min_value = np.min(data) diff --git a/src/ert/gui/tools/plot/widgets/clearable_line_edit.py b/src/ert/gui/tools/plot/widgets/clearable_line_edit.py index 63cfb1120be..417e95aae81 100644 --- a/src/ert/gui/tools/plot/widgets/clearable_line_edit.py +++ b/src/ert/gui/tools/plot/widgets/clearable_line_edit.py @@ -1,6 +1,6 @@ -from qtpy.QtCore import QSize, Qt -from qtpy.QtGui import QColor, QFocusEvent, QIcon, QKeyEvent, QResizeEvent -from qtpy.QtWidgets import QLineEdit, QPushButton, QStyle +from PyQt6.QtCore import QSize, Qt +from PyQt6.QtGui import QColor, QFocusEvent, QIcon, QKeyEvent, QResizeEvent +from PyQt6.QtWidgets import QLineEdit, QPushButton, QStyle class ClearableLineEdit(QLineEdit): diff --git a/src/ert/gui/tools/plot/widgets/copy_style_to_dialog.py b/src/ert/gui/tools/plot/widgets/copy_style_to_dialog.py index 059a5500566..1049b9f883b 100644 --- a/src/ert/gui/tools/plot/widgets/copy_style_to_dialog.py +++ b/src/ert/gui/tools/plot/widgets/copy_style_to_dialog.py @@ -2,8 +2,8 @@ from typing import TYPE_CHECKING, Any -from qtpy.QtGui import QIcon -from qtpy.QtWidgets import ( +from PyQt6.QtGui import QIcon +from PyQt6.QtWidgets import ( QDialog, QFormLayout, QHBoxLayout, diff --git a/src/ert/gui/tools/plot/widgets/custom_date_edit.py b/src/ert/gui/tools/plot/widgets/custom_date_edit.py index 27779469f46..e2ef65084c2 100644 --- a/src/ert/gui/tools/plot/widgets/custom_date_edit.py +++ b/src/ert/gui/tools/plot/widgets/custom_date_edit.py @@ -1,8 +1,8 @@ import datetime -from qtpy.QtCore import QDate -from qtpy.QtGui import QIcon -from qtpy.QtWidgets import ( +from PyQt6.QtCore import QDate +from PyQt6.QtGui import QIcon +from PyQt6.QtWidgets import ( QCalendarWidget, QHBoxLayout, QMenu, @@ -20,7 +20,7 @@ def __init__(self) -> None: self._line_edit = ClearableLineEdit() self._calendar_button = QToolButton() - self._calendar_button.setPopupMode(QToolButton.InstantPopup) + self._calendar_button.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup) self._calendar_button.setFixedSize(26, 26) self._calendar_button.setAutoRaise(True) self._calendar_button.setIcon(QIcon("img:calendar_date_range.svg")) @@ -45,7 +45,7 @@ def __init__(self) -> None: def setDate(self, date: datetime.date | QDate) -> None: if isinstance(date, datetime.date): - date = QDate(date.year, date.month, date.day) # type: ignore + date = QDate(date.year, date.month, date.day) if date is not None and date.isValid(): self._line_edit.setText(str(date.toString("yyyy-MM-dd"))) diff --git a/src/ert/gui/tools/plot/widgets/filter_popup.py b/src/ert/gui/tools/plot/widgets/filter_popup.py index fb4a0a91fce..c6dd533b469 100644 --- a/src/ert/gui/tools/plot/widgets/filter_popup.py +++ b/src/ert/gui/tools/plot/widgets/filter_popup.py @@ -2,9 +2,10 @@ from typing import TYPE_CHECKING -from qtpy.QtCore import QEvent, Qt, Signal -from qtpy.QtGui import QCursor -from qtpy.QtWidgets import ( +from PyQt6.QtCore import QEvent, Qt +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtGui import QCursor +from PyQt6.QtWidgets import ( QCheckBox, QDialog, QFrame, @@ -27,9 +28,9 @@ def __init__( QDialog.__init__( self, parent, - Qt.WindowStaysOnTopHint # type: ignore - | Qt.X11BypassWindowManagerHint # type: ignore - | Qt.FramelessWindowHint, # type: ignore + Qt.WindowType.WindowStaysOnTopHint + | Qt.WindowType.X11BypassWindowManagerHint + | Qt.WindowType.FramelessWindowHint, ) self.setVisible(False) @@ -38,7 +39,7 @@ def __init__( layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) frame = QFrame() - frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised) + frame.setFrameStyle(QFrame.Shape.StyledPanel | QFrame.Shadow.Raised) layout.addWidget(frame) self.__layout = QVBoxLayout() @@ -69,9 +70,9 @@ def toggleItem(checked: bool) -> None: self.__layout.addWidget(check_box) - def leaveEvent(self, event: QEvent | None) -> None: + def leaveEvent(self, a0: QEvent | None) -> None: self.hide() - QWidget.leaveEvent(self, event) + QWidget.leaveEvent(self, a0) def show(self) -> None: QWidget.show(self) diff --git a/src/ert/gui/tools/plugins/plugin.py b/src/ert/gui/tools/plugins/plugin.py index c3407720d29..3795cb2b77b 100644 --- a/src/ert/gui/tools/plugins/plugin.py +++ b/src/ert/gui/tools/plugins/plugin.py @@ -6,7 +6,7 @@ from ert import ErtScript if TYPE_CHECKING: - from qtpy.QtWidgets import QWidget + from PyQt6.QtWidgets import QWidget from ert.config import ErtPlugin, WorkflowJob from ert.gui.ertnotifier import ErtNotifier diff --git a/src/ert/gui/tools/plugins/plugin_handler.py b/src/ert/gui/tools/plugins/plugin_handler.py index fbced1ad385..009648bf102 100644 --- a/src/ert/gui/tools/plugins/plugin_handler.py +++ b/src/ert/gui/tools/plugins/plugin_handler.py @@ -6,7 +6,7 @@ from .plugin import Plugin if TYPE_CHECKING: - from qtpy.QtWidgets import QWidget + from PyQt6.QtWidgets import QWidget from ert.config import WorkflowJob from ert.gui.ertnotifier import ErtNotifier diff --git a/src/ert/gui/tools/plugins/plugins_tool.py b/src/ert/gui/tools/plugins/plugins_tool.py index 519d120d959..b1153553836 100644 --- a/src/ert/gui/tools/plugins/plugins_tool.py +++ b/src/ert/gui/tools/plugins/plugins_tool.py @@ -2,8 +2,8 @@ from typing import TYPE_CHECKING -from qtpy.QtGui import QIcon -from qtpy.QtWidgets import QMenu +from PyQt6.QtGui import QIcon +from PyQt6.QtWidgets import QMenu from ert.gui.tools import Tool diff --git a/src/ert/gui/tools/plugins/process_job_dialog.py b/src/ert/gui/tools/plugins/process_job_dialog.py index 38198f8cb89..cd722f16bbf 100644 --- a/src/ert/gui/tools/plugins/process_job_dialog.py +++ b/src/ert/gui/tools/plugins/process_job_dialog.py @@ -1,8 +1,9 @@ from typing import cast -from qtpy.QtCore import QSize, Qt, Signal -from qtpy.QtGui import QCloseEvent, QKeyEvent, QMovie -from qtpy.QtWidgets import ( +from PyQt6.QtCore import QSize, Qt +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtGui import QCloseEvent, QKeyEvent, QMovie +from PyQt6.QtWidgets import ( QDialog, QGridLayout, QHBoxLayout, @@ -31,13 +32,8 @@ def __init__(self, title: str, parent: QWidget | None = None) -> None: self.__parent = parent self.setWindowTitle(title) self.setModal(True) - self.setWindowFlags( - self.windowFlags() - & ~Qt.WindowFlags(Qt.WindowType.WindowContextHelpButtonHint) - ) - self.setWindowFlags( - self.windowFlags() & ~Qt.WindowFlags(Qt.WindowType.WindowCloseButtonHint) - ) + self.setWindowFlag(Qt.WindowType.WindowContextHelpButtonHint, False) + self.setWindowFlag(Qt.WindowType.WindowCloseButtonHint, False) layout = QVBoxLayout() layout.setSizeConstraint(QLayout.SizeConstraint.SetFixedSize) @@ -91,11 +87,7 @@ def enableCloseButton(self) -> None: def keyPressEvent(self, a0: QKeyEvent | None) -> None: # disallow pressing escape to close # when close button is not enabled - if ( - self._close_button.isEnabled() - or a0 is None - or a0.key() != Qt.Key.Key_Escape - ): + if self.close_button.isEnabled() or a0 is None or a0.key() != Qt.Key.Key_Escape: QDialog.keyPressEvent(self, a0) def closeEvent(self, a0: QCloseEvent | None) -> None: @@ -103,9 +95,7 @@ def closeEvent(self, a0: QCloseEvent | None) -> None: a0.ignore() self.closeButtonPressed.emit() - def __createMsgBox( - self, title: str | None, message: str | None, details: str - ) -> QMessageBox: + def __createMsgBox(self, title: str, message: str, details: str) -> QMessageBox: msg_box = QMessageBox(cast(QWidget | None, self.parent())) msg_box.setText(title) msg_box.setInformativeText(message) @@ -114,38 +104,36 @@ def __createMsgBox( msg_box.setDetailedText(details) horizontal_spacer = QSpacerItem( - 500, 0, QSizePolicy.MinimumExpanding, QSizePolicy.Expanding + 500, 0, QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Expanding ) layout = cast(QGridLayout, msg_box.layout()) layout.addItem(horizontal_spacer, layout.rowCount(), 0, 1, layout.columnCount()) return msg_box - def __presentInformation( - self, title: str | None, message: str | None, details: str - ) -> None: + def __presentInformation(self, title: str, message: str, details: str) -> None: self._msg_box = self.__createMsgBox(title, message, details) - self._msg_box.setIcon(QMessageBox.Information) + self._msg_box.setIcon(QMessageBox.Icon.Information) - self._msg_box.exec_() + self._msg_box.exec() - def __presentError( - self, title: str | None, message: str | None, details: str - ) -> None: + def __presentError(self, title: str, message: str, details: str) -> None: self._msg_box = self.__createMsgBox(title, message, details) - self._msg_box.setIcon(QMessageBox.Critical) + self._msg_box.setIcon(QMessageBox.Icon.Critical) - self._msg_box.exec_() + self._msg_box.exec() def __confirmCancel(self) -> None: cancel_box = self.__createMsgBox( "Confirm cancel", "Are you sure you want to cancel the running job?", "" ) - cancel_box.setIcon(QMessageBox.Question) - cancel_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No) - cancel_box.exec_() + cancel_box.setIcon(QMessageBox.Icon.Question) + cancel_box.setStandardButtons( + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No + ) + cancel_box.exec() cancel = cancel_box.result() - if cancel == QMessageBox.Yes: + if cancel == QMessageBox.StandardButton.Yes: self.cancelConfirmed.emit() diff --git a/src/ert/gui/tools/search_bar/search_bar.py b/src/ert/gui/tools/search_bar/search_bar.py index 59bb5ad6547..fdaadb3e859 100644 --- a/src/ert/gui/tools/search_bar/search_bar.py +++ b/src/ert/gui/tools/search_bar/search_bar.py @@ -1,6 +1,6 @@ -from qtpy import QtCore -from qtpy.QtGui import QBrush, QColor, QTextCharFormat, QTextCursor -from qtpy.QtWidgets import QBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPlainTextEdit +from PyQt6.QtCore import pyqtSlot as Slot +from PyQt6.QtGui import QBrush, QColor, QTextCharFormat, QTextCursor +from PyQt6.QtWidgets import QBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPlainTextEdit class SearchBar(QLineEdit): @@ -11,7 +11,7 @@ def __init__(self, text_box: QPlainTextEdit, label: str = "Find"): self.textChanged.connect(self.search_bar_changed) self._cursor = self._text_box.textCursor() - @QtCore.Slot(str) + @Slot(str) def search_bar_changed(self, value: str) -> None: self.clear_selection() if not value: @@ -33,11 +33,14 @@ def search_bar_changed(self, value: str) -> None: ): # Check if the entire term matches self._cursor.movePosition( - QTextCursor.Right, QTextCursor.KeepAnchor, len(value) + QTextCursor.MoveOperation.Right, + QTextCursor.MoveMode.KeepAnchor, + len(value), ) self._cursor.mergeCharFormat(text_format) self._cursor.movePosition( - QTextCursor.NextCharacter, QTextCursor.MoveAnchor + QTextCursor.MoveOperation.NextCharacter, + QTextCursor.MoveMode.MoveAnchor, ) def get_layout(self) -> QBoxLayout: @@ -48,13 +51,17 @@ def get_layout(self) -> QBoxLayout: def select_text(self, start: int, length: int) -> None: self._cursor.setPosition(start) - self._cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, length) + self._cursor.movePosition( + QTextCursor.MoveOperation.Right, QTextCursor.MoveMode.KeepAnchor, length + ) self._text_box.setTextCursor(self._cursor) def clear_selection(self) -> None: text_format = QTextCharFormat() - self._cursor.setPosition(QTextCursor.Start) - self._cursor.movePosition(QTextCursor.End, QTextCursor.KeepAnchor) + self._cursor.setPosition(0, QTextCursor.MoveMode.MoveAnchor) + self._cursor.movePosition( + QTextCursor.MoveOperation.End, QTextCursor.MoveMode.KeepAnchor + ) text_format.setBackground(QBrush(QColor("white"))) self._cursor.mergeCharFormat(text_format) self._cursor.clearSelection() diff --git a/src/ert/gui/tools/tool.py b/src/ert/gui/tools/tool.py index fc24e4c6f07..d8eda941cd1 100644 --- a/src/ert/gui/tools/tool.py +++ b/src/ert/gui/tools/tool.py @@ -1,6 +1,5 @@ -from qtpy.QtCore import QObject -from qtpy.QtGui import QIcon -from qtpy.QtWidgets import QAction +from PyQt6.QtCore import QObject +from PyQt6.QtGui import QAction, QIcon class Tool: @@ -39,8 +38,8 @@ def setParent(self, parent: QObject | None) -> None: self.__parent = parent self.__action.setParent(parent) - def parent(self) -> QObject | None: - return self.__parent + def parent(self) -> QObject: + return self.__parent if self.__parent else QObject() def isEnabled(self) -> bool: return self.__enabled diff --git a/src/ert/gui/tools/workflows/run_workflow_widget.py b/src/ert/gui/tools/workflows/run_workflow_widget.py index 811d7b72a49..2fe3157f2c7 100644 --- a/src/ert/gui/tools/workflows/run_workflow_widget.py +++ b/src/ert/gui/tools/workflows/run_workflow_widget.py @@ -4,9 +4,10 @@ from collections.abc import Iterable from typing import TYPE_CHECKING -from qtpy.QtCore import QSize, Qt, Signal -from qtpy.QtGui import QIcon, QMovie -from qtpy.QtWidgets import ( +from PyQt6.QtCore import QSize, Qt +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtGui import QIcon, QMovie +from PyQt6.QtWidgets import ( QComboBox, QFormLayout, QHBoxLayout, @@ -40,7 +41,8 @@ def __init__(self, config: ErtConfig, notifier: ErtNotifier): layout = QFormLayout() self._workflow_combo = QComboBox() - self._workflow_combo.addItems(sorted(config.workflows.keys(), key=str.lower)) # type: ignore + sorted_items = sorted(config.workflows.keys(), key=str.lower) + self._workflow_combo.addItems(sorted_items) layout.addRow("Workflow", self._workflow_combo) @@ -97,10 +99,10 @@ def cancelWorkflow(self) -> None: self, "Confirm cancel", "Are you sure you want to cancel the running workflow?", - QMessageBox.Yes | QMessageBox.No, + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, ) - if cancel == QMessageBox.Yes: + if cancel == QMessageBox.StandardButton.Yes: self._workflow_runner.cancel() if self._running_workflow_dialog is not None: self._running_workflow_dialog.disableCloseButton() diff --git a/src/ert/gui/tools/workflows/workflow_dialog.py b/src/ert/gui/tools/workflows/workflow_dialog.py index 0927b922f4c..a573764d6b5 100644 --- a/src/ert/gui/tools/workflows/workflow_dialog.py +++ b/src/ert/gui/tools/workflows/workflow_dialog.py @@ -1,6 +1,7 @@ -from qtpy.QtCore import Qt, Signal -from qtpy.QtGui import QKeyEvent -from qtpy.QtWidgets import ( +from PyQt6.QtCore import Qt +from PyQt6.QtCore import pyqtSignal as Signal +from PyQt6.QtGui import QKeyEvent +from PyQt6.QtWidgets import ( QDialog, QHBoxLayout, QLayout, @@ -20,13 +21,8 @@ def __init__( self.setWindowTitle(title) self.setModal(True) - self.setWindowFlags( - self.windowFlags() - & ~Qt.WindowFlags(Qt.WindowType.WindowContextHelpButtonHint) - ) - self.setWindowFlags( - self.windowFlags() & ~Qt.WindowFlags(Qt.WindowType.WindowCloseButtonHint) - ) + self.setWindowFlag(Qt.WindowType.WindowContextHelpButtonHint, False) + self.setWindowFlag(Qt.WindowType.WindowCloseButtonHint, False) layout = QVBoxLayout() layout.setSizeConstraint( @@ -54,9 +50,5 @@ def enableCloseButton(self) -> None: def keyPressEvent(self, a0: QKeyEvent | None) -> None: # disallow pressing escape to close # when close button is not enabled - if ( - self._close_button.isEnabled() - or a0 is None - or a0.key() != Qt.Key.Key_Escape - ): + if self.close_button.isEnabled() or a0 is None or a0.key() != Qt.Key.Key_Escape: QDialog.keyPressEvent(self, a0) diff --git a/src/ert/gui/tools/workflows/workflows_tool.py b/src/ert/gui/tools/workflows/workflows_tool.py index 5cc87f44d5f..15307127a34 100644 --- a/src/ert/gui/tools/workflows/workflows_tool.py +++ b/src/ert/gui/tools/workflows/workflows_tool.py @@ -2,7 +2,7 @@ from typing import TYPE_CHECKING -from qtpy.QtGui import QIcon +from PyQt6.QtGui import QIcon from ert.gui.ertwidgets import ClosableDialog from ert.gui.tools import Tool @@ -27,5 +27,5 @@ def __init__(self, config: ErtConfig, notifier: ErtNotifier) -> None: def trigger(self) -> None: run_workflow_widget = RunWorkflowWidget(self.config, self.notifier) dialog = ClosableDialog("Run workflow", run_workflow_widget, self.parent()) # type: ignore - dialog.exec_() + dialog.exec() self.notifier.emitErtChange() # workflow may have added new cases. diff --git a/src/ert/plugins/hook_implementations/workflows/gen_data_rft_export.py b/src/ert/plugins/hook_implementations/workflows/gen_data_rft_export.py index 0b603d9b413..529a1d2d852 100644 --- a/src/ert/plugins/hook_implementations/workflows/gen_data_rft_export.py +++ b/src/ert/plugins/hook_implementations/workflows/gen_data_rft_export.py @@ -7,7 +7,7 @@ import numpy import pandas as pd import polars -from qtpy.QtWidgets import QCheckBox, QWidget +from PyQt6.QtWidgets import QCheckBox, QWidget from ert.config import CancelPluginException, ErtPlugin from ert.storage import Storage diff --git a/tests/ert/conftest.py b/tests/ert/conftest.py index 7073b6c3190..790b5f15741 100644 --- a/tests/ert/conftest.py +++ b/tests/ert/conftest.py @@ -13,8 +13,8 @@ import pytest from hypothesis import HealthCheck, settings from hypothesis import strategies as st -from qtpy.QtCore import QDir -from qtpy.QtWidgets import QApplication +from PyQt6.QtCore import QDir +from PyQt6.QtWidgets import QApplication import _ert.forward_model_runner.cli from _ert.threading import set_signal_handler diff --git a/tests/ert/ui_tests/gui/conftest.py b/tests/ert/ui_tests/gui/conftest.py index 2100ced7685..4867785ba3c 100644 --- a/tests/ert/ui_tests/gui/conftest.py +++ b/tests/ert/ui_tests/gui/conftest.py @@ -13,9 +13,8 @@ from unittest.mock import MagicMock, Mock import pytest -from pytestqt.qtbot import QtBot -from qtpy.QtCore import Qt, QTimer -from qtpy.QtWidgets import ( +from PyQt6.QtCore import Qt, QTimer +from PyQt6.QtWidgets import ( QApplication, QComboBox, QMessageBox, @@ -23,6 +22,7 @@ QToolButton, QWidget, ) +from pytestqt.qtbot import QtBot from ert.config import ErtConfig from ert.gui.ertwidgets import ClosableDialog @@ -260,7 +260,7 @@ def handle_dialog(): "Evaluate ensemble", }: QTimer.singleShot(500, handle_dialog) - qtbot.mouseClick(run_experiment, Qt.LeftButton) + qtbot.mouseClick(run_experiment, Qt.MouseButton.LeftButton) if click_done: # The Run dialog opens, click show details and wait until done appears @@ -348,11 +348,11 @@ def handle_popup_dialog(): messagebox = QApplication.activeModalWidget() assert isinstance(messagebox, QMessageBox) assert messagebox.text() == "Successfully loaded all realisations" - ok_button = messagebox.button(QMessageBox.Ok) - qtbot.mouseClick(ok_button, Qt.LeftButton) + ok_button = messagebox.button(QMessageBox.StandardButton.Ok) + qtbot.mouseClick(ok_button, Qt.MouseButton.LeftButton) QTimer.singleShot(2000, handle_popup_dialog) - qtbot.mouseClick(load_button, Qt.LeftButton) + qtbot.mouseClick(load_button, Qt.MouseButton.LeftButton) dialog.close() QTimer.singleShot(1000, handle_load_results_dialog) @@ -364,7 +364,7 @@ def add_experiment_manually( ): button_manage_experiments = gui.findChild(QToolButton, "button_Manage_experiments") assert button_manage_experiments - qtbot.mouseClick(button_manage_experiments, Qt.LeftButton) + qtbot.mouseClick(button_manage_experiments, Qt.MouseButton.LeftButton) experiments_panel = gui.findChild(ManageExperimentsPanel) # Open the create new experiment tab diff --git a/tests/ert/ui_tests/gui/test_csv_export.py b/tests/ert/ui_tests/gui/test_csv_export.py index 263b0278cd8..fc13e4aec33 100644 --- a/tests/ert/ui_tests/gui/test_csv_export.py +++ b/tests/ert/ui_tests/gui/test_csv_export.py @@ -5,8 +5,8 @@ import pandas as pd import pytest -from qtpy.QtCore import Qt, QTimer -from qtpy.QtWidgets import QComboBox, QMessageBox, QWidget +from PyQt6.QtCore import Qt, QTimer +from PyQt6.QtWidgets import QComboBox, QMessageBox, QWidget from ert.gui.ertwidgets.listeditbox import ListEditBox from ert.gui.ertwidgets.pathchooser import PathChooser @@ -45,7 +45,8 @@ def handle_finished_box(): finished_message = wait_for_child(gui, qtbot, QMessageBox) assert "completed" in finished_message.text() qtbot.mouseClick( - finished_message.button(QMessageBox.Ok), Qt.MouseButton.LeftButton + finished_message.button(QMessageBox.StandardButton.Ok), + Qt.MouseButton.LeftButton, ) QTimer.singleShot(500, handle_export_dialog) @@ -98,7 +99,7 @@ def run_experiment_via_gui(gui, qtbot): shutil.rmtree("poly_out") run_experiment = get_child(experiment_panel, QWidget, name="run_experiment") - qtbot.mouseClick(run_experiment, Qt.LeftButton) + qtbot.mouseClick(run_experiment, Qt.MouseButton.LeftButton) run_dialog = wait_for_child(gui, qtbot, RunDialog) qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=20000) 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 b70b18bbd65..e27663e3b8c 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 @@ -2,8 +2,8 @@ import shutil import numpy as np -from qtpy.QtCore import Qt -from qtpy.QtWidgets import QComboBox, QToolButton, QTreeView, QWidget +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QComboBox, QToolButton, QTreeView, QWidget from ert.data import MeasuredData from ert.gui.simulation.evaluate_ensemble_panel import EvaluateEnsemblePanel @@ -37,7 +37,7 @@ def test_manual_analysis_workflow(ensemble_experiment_has_run, qtbot): # Click start simulation and agree to the message run_experiment = get_child(experiment_panel, QWidget, name="run_experiment") - qtbot.mouseClick(run_experiment, Qt.LeftButton) + qtbot.mouseClick(run_experiment, Qt.MouseButton.LeftButton) # The Run dialog opens, wait until done appears, then click done run_dialog = wait_for_child(gui, qtbot, RunDialog) qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=10000) @@ -45,7 +45,7 @@ def test_manual_analysis_workflow(ensemble_experiment_has_run, qtbot): button_manage_experiments = gui.findChild(QToolButton, "button_Manage_experiments") assert button_manage_experiments - qtbot.mouseClick(button_manage_experiments, Qt.LeftButton) + qtbot.mouseClick(button_manage_experiments, Qt.MouseButton.LeftButton) experiments_panel = gui.findChild(ManageExperimentsPanel) assert experiments_panel @@ -70,7 +70,9 @@ def test_manual_analysis_workflow(ensemble_experiment_has_run, qtbot): simulation_mode_combo.setCurrentText(EvaluateEnsemble.name()) idx = simulation_settings._ensemble_selector.findData( - "ensemble_experiment : iter-0_1", Qt.MatchStartsWith + "ensemble_experiment : iter-0_1", + Qt.ItemDataRole.DisplayRole, + Qt.MatchFlag.MatchStartsWith, ) assert idx != -1 simulation_settings._ensemble_selector.setCurrentIndex(idx) 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 8b72648fb61..fde29347de3 100644 --- a/tests/ert/ui_tests/gui/test_load_results_manually.py +++ b/tests/ert/ui_tests/gui/test_load_results_manually.py @@ -1,5 +1,5 @@ -from qtpy.QtCore import Qt, QTimer -from qtpy.QtWidgets import QPushButton +from PyQt6.QtCore import Qt, QTimer +from PyQt6.QtWidgets import QPushButton from ert.gui.ertwidgets import ClosableDialog, StringBox, TextBox from ert.gui.ertwidgets.ensembleselector import EnsembleSelector diff --git a/tests/ert/ui_tests/gui/test_main_window.py b/tests/ert/ui_tests/gui/test_main_window.py index 6dd099de325..c57a3d720f7 100644 --- a/tests/ert/ui_tests/gui/test_main_window.py +++ b/tests/ert/ui_tests/gui/test_main_window.py @@ -8,9 +8,9 @@ import numpy as np import pytest -from qtpy.QtCore import Qt, QTimer -from qtpy.QtWidgets import ( - QAction, +from PyQt6.QtCore import Qt, QTimer +from PyQt6.QtGui import QAction +from PyQt6.QtWidgets import ( QCheckBox, QComboBox, QDoubleSpinBox, @@ -191,7 +191,7 @@ def test_help_buttons_in_suggester_dialog(tmp_path, qtbot): with patch("webbrowser.open", MagicMock(return_value=True)) as browser_open: github_button = get_child(gui, QWidget, name="GitHub page") - qtbot.mouseClick(github_button, Qt.LeftButton) + qtbot.mouseClick(github_button, Qt.MouseButton.LeftButton) assert browser_open.called @@ -299,7 +299,7 @@ def test_that_the_plot_window_contains_the_expected_elements( # Click on Create plot after esmda has run button_plot_tool = gui.findChild(QToolButton, "button_Create_plot") assert button_plot_tool - qtbot.mouseClick(button_plot_tool, Qt.LeftButton) + qtbot.mouseClick(button_plot_tool, Qt.MouseButton.LeftButton) plot_window = wait_for_child(gui, qtbot, PlotWindow) data_types = get_child(plot_window, DataTypeKeysWidget) @@ -318,7 +318,7 @@ def test_that_the_plot_window_contains_the_expected_elements( data_keys = data_types.data_type_keys_widget for i in range(data_keys.model().rowCount()): index = data_keys.model().index(i, 0) - data_names.append(str(index.data(Qt.DisplayRole))) + data_names.append(str(index.data(Qt.ItemDataRole.DisplayRole))) expected_data_names = [ "POLY_RES@0", @@ -351,12 +351,12 @@ def click_plotter_item(pos: int) -> None: viewport = data_keys.viewport() center = viewport.mapToGlobal(center) local_pos = viewport.mapFromGlobal(center) - qtbot.mouseClick(data_keys.viewport(), Qt.LeftButton, pos=local_pos) + qtbot.mouseClick(data_keys.viewport(), Qt.MouseButton.LeftButton, pos=local_pos) def click_tab_index(pos: int) -> None: tab_bar = plot_window._central_tab.tabBar() tab_center = tab_bar.tabRect(pos).center() - qtbot.mouseClick(tab_bar, Qt.LeftButton, pos=tab_center) + qtbot.mouseClick(tab_bar, Qt.MouseButton.LeftButton, pos=tab_center) # make sure plotter remembers plot types selected previously response_index = 0 @@ -398,7 +398,7 @@ def test_that_the_manage_experiments_tool_can_be_used(esmda_has_run, qtbot): button_manage_experiments = gui.findChild(QToolButton, "button_Manage_experiments") assert button_manage_experiments - qtbot.mouseClick(button_manage_experiments, Qt.LeftButton) + qtbot.mouseClick(button_manage_experiments, Qt.MouseButton.LeftButton) experiments_panel = wait_for_child(gui, qtbot, ManageExperimentsPanel) # Open the tab @@ -437,7 +437,7 @@ def handle_add_dialog(): QTimer.singleShot(1000, handle_add_dialog) create_widget = get_child(storage_widget, AddWidget) - qtbot.mouseClick(create_widget.addButton, Qt.LeftButton) + qtbot.mouseClick(create_widget.addButton, Qt.MouseButton.LeftButton) assert experiments_panel.notifier.current_ensemble.iteration == 42 @@ -452,14 +452,14 @@ def handle_add_dialog(): QPushButton, name="initialize_from_scratch_button", ) - qtbot.mouseClick(initialize_button, Qt.LeftButton) + qtbot.mouseClick(initialize_button, Qt.MouseButton.LeftButton) def test_that_inversion_type_can_be_set_from_gui(qtbot, opened_main_window_poly): gui = opened_main_window_poly sim_mode = get_child(gui, QWidget, name="experiment_type") - qtbot.keyClick(sim_mode, Qt.Key_Down) + qtbot.keyClick(sim_mode, Qt.Key.Key_Down) es_panel = get_child(gui, QWidget, name="ensemble_smoother_panel") es_edit = get_child(es_panel, QWidget, name="ensemble_smoother_edit") @@ -481,7 +481,9 @@ def handle_analysis_module_panel(): var_panel.parent().close() QTimer.singleShot(500, handle_analysis_module_panel) - qtbot.mouseClick(get_child(es_edit, QToolButton), Qt.LeftButton, delay=1) + qtbot.mouseClick( + get_child(es_edit, QToolButton), Qt.MouseButton.LeftButton, delay=1 + ) def test_that_the_manage_experiments_tool_can_be_used_with_clean_storage( @@ -491,7 +493,7 @@ def test_that_the_manage_experiments_tool_can_be_used_with_clean_storage( button_manage_experiments = gui.findChild(QToolButton, "button_Manage_experiments") assert button_manage_experiments - qtbot.mouseClick(button_manage_experiments, Qt.LeftButton) + qtbot.mouseClick(button_manage_experiments, Qt.MouseButton.LeftButton) experiments_panel = wait_for_child(gui, qtbot, ManageExperimentsPanel) # Open the create new ensembles tab @@ -533,7 +535,7 @@ def handle_add_dialog(): initialize_button = get_child( current_tab, QPushButton, name="initialize_from_scratch_button" ) - qtbot.mouseClick(initialize_button, Qt.LeftButton) + qtbot.mouseClick(initialize_button, Qt.MouseButton.LeftButton) @pytest.mark.usefixtures("use_tmpdir") @@ -595,7 +597,7 @@ def handle_error_dialog(run_dialog): assert substring in text error_dialog.accept() - qtbot.mouseClick(run_experiment, Qt.LeftButton) + qtbot.mouseClick(run_experiment, Qt.MouseButton.LeftButton) run_dialog = wait_for_child(gui, qtbot, RunDialog) @@ -620,7 +622,7 @@ def test_that_gui_plotter_works_when_no_data(qtbot, storage, monkeypatch): button_plot_tool = gui.findChild(QToolButton, "button_Create_plot") assert button_plot_tool - qtbot.mouseClick(button_plot_tool, Qt.LeftButton) + qtbot.mouseClick(button_plot_tool, Qt.MouseButton.LeftButton) plot_window = wait_for_child(gui, qtbot, PlotWindow) ensemble_plot_names = get_child( @@ -644,7 +646,7 @@ def test_right_click_plot_button_opens_external_plotter(qtbot, storage, monkeypa gui = _setup_main_window(ert_config, args_mock, GUILogHandler(), storage) qtbot.addWidget(gui) - button_plot_tool = gui.findChild(SidebarToolButton, "button_Create_plot") + button_plot_tool = gui.findChild(QToolButton, "button_Create_plot") assert button_plot_tool def top_level_plotter_windows() -> list[PlotWindow]: @@ -658,7 +660,7 @@ def top_level_plotter_windows() -> list[PlotWindow]: def right_click_plotter_button() -> None: top_level_windows = len(top_level_plotter_windows()) - qtbot.mouseClick(button_plot_tool, Qt.RightButton) + qtbot.mouseClick(button_plot_tool, Qt.MouseButton.RightButton) qtbot.wait_until( lambda: len(top_level_plotter_windows()) > top_level_windows, timeout=5000, @@ -676,7 +678,7 @@ def right_click_plotter_button() -> None: qtbot.wait_until(lambda: not top_level_plotter_windows(), timeout=5000) - qtbot.mouseClick(button_plot_tool, Qt.LeftButton) + qtbot.mouseClick(button_plot_tool, Qt.MouseButton.LeftButton) plot_window = wait_for_child(gui, qtbot, PlotWindow) assert plot_window assert "Plotting" in plot_window.windowTitle() @@ -737,7 +739,8 @@ def test_help_menu(qtbot): about_dialog = wait_for_child(gui, qtbot, AboutDialog) assert about_dialog.windowTitle() == "About" qtbot.mouseClick( - get_child(about_dialog, QPushButton, name="close_button"), Qt.LeftButton + get_child(about_dialog, QPushButton, name="close_button"), + Qt.MouseButton.LeftButton, ) @@ -786,7 +789,7 @@ def find_and_click_button( assert button assert button.isEnabled() == expected_enabled_state if should_click: - qtbot.mouseClick(button, Qt.LeftButton) + qtbot.mouseClick(button, Qt.MouseButton.LeftButton) def find_and_check_selected(button_name: str, expected_selected_state: bool): button = gui.findChild(SidebarToolButton, button_name) @@ -797,7 +800,7 @@ 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) + qtbot.mouseClick(run_experiment_panel.run_button, Qt.MouseButton.LeftButton) def wait_for_simulation_completed(): run_dialogs = get_children(gui, RunDialog) diff --git a/tests/ert/ui_tests/gui/test_manage_experiments_tool.py b/tests/ert/ui_tests/gui/test_manage_experiments_tool.py index ed2d28a42d7..507fba7620f 100644 --- a/tests/ert/ui_tests/gui/test_manage_experiments_tool.py +++ b/tests/ert/ui_tests/gui/test_manage_experiments_tool.py @@ -3,8 +3,8 @@ import polars import pytest -from qtpy.QtCore import Qt -from qtpy.QtWidgets import QPushButton, QTextEdit +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QPushButton, QTextEdit from ert.config import ErtConfig, SummaryConfig from ert.gui.ertnotifier import ErtNotifier @@ -13,6 +13,7 @@ _EnsembleWidget, _EnsembleWidgetTabs, _ExperimentWidget, + _RealizationWidget, _WidgetType, ) from ert.gui.tools.manage_experiments.storage_widget import StorageWidget @@ -436,6 +437,7 @@ def test_realization_view( ) realization_widget = tool._storage_info_widget._content_layout.currentWidget() + assert type(realization_widget) is _RealizationWidget assert ( realization_widget._state_label.text() diff --git a/tests/ert/ui_tests/gui/test_missing_parameters_to_update.py b/tests/ert/ui_tests/gui/test_missing_parameters_to_update.py index c2cae6dbf5b..9ac08e1f791 100644 --- a/tests/ert/ui_tests/gui/test_missing_parameters_to_update.py +++ b/tests/ert/ui_tests/gui/test_missing_parameters_to_update.py @@ -1,8 +1,8 @@ import fileinput import pytest -from qtpy.QtCore import Qt -from qtpy.QtWidgets import QComboBox +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QComboBox from ert.gui.simulation.experiment_panel import ExperimentPanel from ert.run_models import ( diff --git a/tests/ert/ui_tests/gui/test_missing_runpath.py b/tests/ert/ui_tests/gui/test_missing_runpath.py index e6118037a85..6bfb881d7a6 100644 --- a/tests/ert/ui_tests/gui/test_missing_runpath.py +++ b/tests/ert/ui_tests/gui/test_missing_runpath.py @@ -1,8 +1,8 @@ import stat from contextlib import suppress -from qtpy.QtCore import QTimer -from qtpy.QtWidgets import QLabel +from PyQt6.QtCore import QTimer +from PyQt6.QtWidgets import QLabel from ert.ensemble_evaluator.state import ENSEMBLE_STATE_FAILED from ert.gui.simulation.run_dialog import RunDialog 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 1e5691bc290..85ee86e2bcd 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,8 +1,8 @@ from unittest.mock import Mock import pytest -from qtpy.QtCore import Qt -from qtpy.QtWidgets import QCheckBox, QToolButton +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QCheckBox, QToolButton from ert.gui.main import GUILogHandler, _setup_main_window from ert.gui.tools.plot.data_type_keys_widget import DataTypeKeysWidget @@ -64,7 +64,7 @@ def plot_figure(qtbot, heat_equation_storage, snake_oil_case_storage, request): button_plot_tool = gui.findChild(QToolButton, "button_Create_plot") assert button_plot_tool - qtbot.mouseClick(button_plot_tool, Qt.LeftButton) + qtbot.mouseClick(button_plot_tool, Qt.MouseButton.LeftButton) plot_window = wait_for_child(gui, qtbot, PlotWindow) central_tab = plot_window._central_tab @@ -147,7 +147,7 @@ def test_that_all_plotter_filter_boxes_yield_expected_filter_results( button_plot_tool = gui.findChild(QToolButton, "button_Create_plot") assert button_plot_tool - qtbot.mouseClick(button_plot_tool, Qt.LeftButton) + qtbot.mouseClick(button_plot_tool, Qt.MouseButton.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 04910bb8890..4113a1efe22 100644 --- a/tests/ert/ui_tests/gui/test_restart_ensemble_experiment.py +++ b/tests/ert/ui_tests/gui/test_restart_ensemble_experiment.py @@ -3,8 +3,8 @@ import stat from textwrap import dedent -from qtpy.QtCore import Qt, QTimer -from qtpy.QtWidgets import QComboBox, QMessageBox, QWidget +from PyQt6.QtCore import Qt, QTimer +from PyQt6.QtWidgets import QComboBox, QMessageBox, QWidget from ert.gui.simulation.experiment_panel import ExperimentPanel from ert.gui.simulation.run_dialog import RunDialog @@ -99,12 +99,12 @@ def _evaluate(coeffs, x): assert set(failed_realizations) == failing_reals_first_try def handle_dialog(): - message_box = wait_for_child(gui, qtbot, QMessageBox, name="restart_prompt") + message_box = gui.findChildren(QMessageBox, name="restart_prompt")[-1] qtbot.mouseClick(message_box.buttons()[0], Qt.MouseButton.LeftButton) - QTimer.singleShot(500, handle_dialog) failing_reals_second_try = {*random.sample(list(failing_reals_first_try), 5)} write_poly_eval(failing_reals=failing_reals_second_try) + QTimer.singleShot(500, handle_dialog) qtbot.mouseClick(run_dialog.restart_button, Qt.MouseButton.LeftButton) qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=60000) diff --git a/tests/ert/ui_tests/gui/test_restart_esmda.py b/tests/ert/ui_tests/gui/test_restart_esmda.py index e99f39e4350..a3ac45ed663 100644 --- a/tests/ert/ui_tests/gui/test_restart_esmda.py +++ b/tests/ert/ui_tests/gui/test_restart_esmda.py @@ -1,5 +1,5 @@ -from qtpy.QtCore import Qt -from qtpy.QtWidgets import QCheckBox, QComboBox, QWidget +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QCheckBox, QComboBox, QWidget from ert.gui.ertwidgets import StringBox from ert.gui.simulation.experiment_panel import ExperimentPanel diff --git a/tests/ert/ui_tests/gui/test_restart_no_responses_and_parameters.py b/tests/ert/ui_tests/gui/test_restart_no_responses_and_parameters.py index 0cc9cc1cc37..ac8bf8046ff 100644 --- a/tests/ert/ui_tests/gui/test_restart_no_responses_and_parameters.py +++ b/tests/ert/ui_tests/gui/test_restart_no_responses_and_parameters.py @@ -6,10 +6,8 @@ from unittest.mock import Mock import pytest -from qtpy.QtCore import Qt -from qtpy.QtWidgets import ( - QComboBox, -) +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QComboBox from ert.config import ErtConfig from ert.gui.main import _setup_main_window @@ -107,7 +105,9 @@ def test_sensitivity_restart(open_gui, qtbot, run_experiment): simulation_mode_combo.setCurrentText(EvaluateEnsemble.name()) idx = simulation_settings._ensemble_selector.findData( - "ensemble_experiment : iter-0", Qt.MatchStartsWith + "ensemble_experiment : iter-0", + Qt.ItemDataRole.DisplayRole, + Qt.MatchFlag.MatchStartsWith, ) assert idx != -1 simulation_settings._ensemble_selector.setCurrentIndex(idx) 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 444f1b1cb16..5e4ef977fb2 100644 --- a/tests/ert/ui_tests/gui/test_rft_export_plugin.py +++ b/tests/ert/ui_tests/gui/test_rft_export_plugin.py @@ -3,8 +3,8 @@ from unittest.mock import Mock import pytest -from qtpy.QtCore import Qt, QTimer -from qtpy.QtWidgets import QCheckBox, QMessageBox +from PyQt6.QtCore import Qt, QTimer +from PyQt6.QtWidgets import QCheckBox, QMessageBox from ert.config import ErtConfig from ert.gui.ertwidgets import CustomDialog, ListEditBox, PathChooser @@ -89,11 +89,14 @@ def test_rft_csv_export_plugin_exports_rft_data( def handle_finished_box(): """ - Click on the plugin finised dialog once it pops up + Click on the plugin finished dialog once it pops up """ finished_message = wait_for_child(gui, qtbot, QMessageBox) assert "completed" in finished_message.text() - qtbot.mouseClick(finished_message.button(QMessageBox.Ok), Qt.LeftButton) + qtbot.mouseClick( + finished_message.button(QMessageBox.StandardButton.Ok), + Qt.MouseButton.LeftButton, + ) def handle_rft_plugin_dialog(): dialog = wait_for_child(gui, qtbot, CustomDialog) @@ -105,7 +108,7 @@ def handle_rft_plugin_dialog(): dialog, QCheckBox, name="drop_const_columns_check" ) drop_constant.setChecked(True) - qtbot.mouseClick(dialog.ok_button, Qt.LeftButton) + qtbot.mouseClick(dialog.ok_button, Qt.MouseButton.LeftButton) plugin_tool = gui.plugins_tool plugin_actions = plugin_tool.menu.actions() 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 536808c355e..a94d6b779a0 100644 --- a/tests/ert/ui_tests/gui/test_single_test_run.py +++ b/tests/ert/ui_tests/gui/test_single_test_run.py @@ -1,8 +1,8 @@ import contextlib import shutil -from qtpy.QtCore import Qt -from qtpy.QtWidgets import QComboBox, QWidget +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QComboBox, QWidget from ert.gui.simulation.experiment_panel import ExperimentPanel from ert.gui.simulation.run_dialog import RunDialog @@ -28,7 +28,7 @@ def test_single_test_run_after_ensemble_experiment( simulation_mode_combo.setCurrentText("Single realization test-run") run_experiment = get_child(experiment_panel, QWidget, name="run_experiment") - qtbot.mouseClick(run_experiment, Qt.LeftButton) + qtbot.mouseClick(run_experiment, Qt.MouseButton.LeftButton) run_dialog = wait_for_child(gui, qtbot, RunDialog) qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=100000) qtbot.waitUntil(lambda: run_dialog._tab_widget.currentWidget() is not None) diff --git a/tests/ert/ui_tests/gui/test_workflow_tool.py b/tests/ert/ui_tests/gui/test_workflow_tool.py index dc348b6e02b..6f0b5492ac7 100644 --- a/tests/ert/ui_tests/gui/test_workflow_tool.py +++ b/tests/ert/ui_tests/gui/test_workflow_tool.py @@ -5,7 +5,7 @@ from unittest.mock import Mock import pytest -from qtpy.QtCore import Qt, QTimer +from PyQt6.QtCore import Qt, QTimer from ert.config import ErtConfig from ert.gui.ertwidgets import ClosableDialog @@ -75,7 +75,8 @@ def handle_run_workflow_tool(): workflow_widget = get_child(dialog, RunWorkflowWidget) def close_all(): - workflow_widget._running_workflow_dialog.accept() + if running_dlg := workflow_widget._running_workflow_dialog: + running_dlg.accept() dialog.close() workflow_widget.workflowSucceeded.disconnect() diff --git a/tests/ert/unit_tests/gui/ertwidgets/test_checklist.py b/tests/ert/unit_tests/gui/ertwidgets/test_checklist.py index 89e21160f0b..952dc3b50ca 100644 --- a/tests/ert/unit_tests/gui/ertwidgets/test_checklist.py +++ b/tests/ert/unit_tests/gui/ertwidgets/test_checklist.py @@ -1,4 +1,4 @@ -from qtpy.QtCore import Qt +from PyQt6.QtCore import Qt from ert.gui.ertwidgets.checklist import CheckList from ert.gui.ertwidgets.models.selectable_list_model import SelectableListModel @@ -8,12 +8,12 @@ def test_checklist(qtbot): checklist = CheckList(SelectableListModel(items=["1", "2", "3"])) qtbot.addWidget(checklist) - qtbot.mouseClick(checklist._checkAllButton, Qt.LeftButton) + qtbot.mouseClick(checklist._checkAllButton, Qt.MouseButton.LeftButton) for item in checklist._model.getList(): assert checklist._model.isValueSelected(item) - qtbot.mouseClick(checklist._uncheckAllButton, Qt.LeftButton) + qtbot.mouseClick(checklist._uncheckAllButton, Qt.MouseButton.LeftButton) for item in checklist._model.getList(): assert not checklist._model.isValueSelected(item) diff --git a/tests/ert/unit_tests/gui/ertwidgets/test_closabledialog.py b/tests/ert/unit_tests/gui/ertwidgets/test_closabledialog.py index 47e22506868..6040aae26fd 100644 --- a/tests/ert/unit_tests/gui/ertwidgets/test_closabledialog.py +++ b/tests/ert/unit_tests/gui/ertwidgets/test_closabledialog.py @@ -1,6 +1,6 @@ +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QPushButton from pytestqt.qtbot import QtBot -from qtpy.QtCore import Qt -from qtpy.QtWidgets import QPushButton from ert.gui.ertwidgets import ClosableDialog diff --git a/tests/ert/unit_tests/gui/ertwidgets/test_copy_debug_info_button.py b/tests/ert/unit_tests/gui/ertwidgets/test_copy_debug_info_button.py index d85d68e9592..ffa39a0a21c 100644 --- a/tests/ert/unit_tests/gui/ertwidgets/test_copy_debug_info_button.py +++ b/tests/ert/unit_tests/gui/ertwidgets/test_copy_debug_info_button.py @@ -1,5 +1,5 @@ +from PyQt6.QtCore import Qt from pytestqt.qtbot import QtBot -from qtpy.QtCore import Qt from ert.gui.simulation.run_dialog import CopyDebugInfoButton diff --git a/tests/ert/unit_tests/gui/ertwidgets/test_copyablelabel.py b/tests/ert/unit_tests/gui/ertwidgets/test_copyablelabel.py index 2dbc36c9ab8..984fbd7fcae 100644 --- a/tests/ert/unit_tests/gui/ertwidgets/test_copyablelabel.py +++ b/tests/ert/unit_tests/gui/ertwidgets/test_copyablelabel.py @@ -1,6 +1,6 @@ import pytest -from qtpy.QtCore import Qt -from qtpy.QtWidgets import QApplication, QWidget +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QApplication, QWidget from ert.gui.ertwidgets.copyablelabel import ( CopyableLabel, diff --git a/tests/ert/unit_tests/gui/ertwidgets/test_pathchooser.py b/tests/ert/unit_tests/gui/ertwidgets/test_pathchooser.py index b051533ff6a..5e84b0a72c2 100644 --- a/tests/ert/unit_tests/gui/ertwidgets/test_pathchooser.py +++ b/tests/ert/unit_tests/gui/ertwidgets/test_pathchooser.py @@ -1,4 +1,4 @@ -from qtpy.QtWidgets import QFileDialog +from PyQt6.QtWidgets import QFileDialog from ert.gui.ertwidgets.models.path_model import PathModel from ert.gui.ertwidgets.pathchooser import PathChooser diff --git a/tests/ert/unit_tests/gui/ertwidgets/test_plot_case_selection_widget.py b/tests/ert/unit_tests/gui/ertwidgets/test_plot_case_selection_widget.py index 938741ac4cc..a5351e5a8d3 100644 --- a/tests/ert/unit_tests/gui/ertwidgets/test_plot_case_selection_widget.py +++ b/tests/ert/unit_tests/gui/ertwidgets/test_plot_case_selection_widget.py @@ -1,5 +1,5 @@ +from PyQt6.QtCore import Qt from pytestqt.qtbot import QtBot -from qtpy.QtCore import Qt from ert.gui.tools.plot.plot_api import EnsembleObject from ert.gui.tools.plot.plot_ensemble_selection_widget import ( @@ -24,7 +24,7 @@ def test_ensemble_selection_widget_max_min_selection(qtbot: QtBot): qtbot.mouseClick( list_widget.viewport(), - Qt.LeftButton, + Qt.MouseButton.LeftButton, pos=list_widget.visualItemRect(list_widget.item(0)).center(), ) # deselect the only item selected @@ -36,7 +36,7 @@ def test_ensemble_selection_widget_max_min_selection(qtbot: QtBot): it = list_widget.item(index) qtbot.mouseClick( list_widget.viewport(), - Qt.LeftButton, + Qt.MouseButton.LeftButton, pos=list_widget.visualItemRect(it).center(), ) @@ -46,7 +46,7 @@ def test_ensemble_selection_widget_max_min_selection(qtbot: QtBot): it = list_widget.item(index) qtbot.mouseClick( list_widget.viewport(), - Qt.LeftButton, + Qt.MouseButton.LeftButton, pos=list_widget.visualItemRect(it).center(), ) diff --git a/tests/ert/unit_tests/gui/ertwidgets/test_search_bar.py b/tests/ert/unit_tests/gui/ertwidgets/test_search_bar.py index ce6181ab907..5bf4fd78d7e 100644 --- a/tests/ert/unit_tests/gui/ertwidgets/test_search_bar.py +++ b/tests/ert/unit_tests/gui/ertwidgets/test_search_bar.py @@ -1,7 +1,7 @@ import pytest +from PyQt6.QtGui import QColor +from PyQt6.QtWidgets import QPlainTextEdit from pytestqt.qtbot import QtBot -from qtpy.QtGui import QColor -from qtpy.QtWidgets import QPlainTextEdit from ert.gui.tools.search_bar import SearchBar diff --git a/tests/ert/unit_tests/gui/model/test_job_list.py b/tests/ert/unit_tests/gui/model/test_job_list.py index 0bf1a211069..9b077ffb96c 100644 --- a/tests/ert/unit_tests/gui/model/test_job_list.py +++ b/tests/ert/unit_tests/gui/model/test_job_list.py @@ -3,8 +3,8 @@ import pytest from dateutil import tz +from PyQt6.QtCore import QModelIndex from pytestqt.qt_compat import qt_api -from qtpy.QtCore import QModelIndex from ert.ensemble_evaluator import identifiers as ids from ert.ensemble_evaluator.snapshot import FMStepSnapshot diff --git a/tests/ert/unit_tests/gui/model/test_real_list.py b/tests/ert/unit_tests/gui/model/test_real_list.py index d0f6c304b6b..1f4f0e4cf07 100644 --- a/tests/ert/unit_tests/gui/model/test_real_list.py +++ b/tests/ert/unit_tests/gui/model/test_real_list.py @@ -1,5 +1,5 @@ +from PyQt6.QtCore import QModelIndex from pytestqt.qt_compat import qt_api -from qtpy.QtCore import QModelIndex from ert.ensemble_evaluator.state import ( REALIZATION_STATE_FINISHED, diff --git a/tests/ert/unit_tests/gui/model/test_snapshot.py b/tests/ert/unit_tests/gui/model/test_snapshot.py index 13a29eb1019..938ba7d4e8b 100644 --- a/tests/ert/unit_tests/gui/model/test_snapshot.py +++ b/tests/ert/unit_tests/gui/model/test_snapshot.py @@ -1,7 +1,7 @@ import pytest +from PyQt6.QtCore import QModelIndex +from PyQt6.QtGui import QColor from pytestqt.qt_compat import qt_api -from qtpy.QtCore import QModelIndex -from qtpy.QtGui import QColor from ert.ensemble_evaluator.state import COLOR_FAILED from ert.gui.model.snapshot import FMStepColorHint, SnapshotModel diff --git a/tests/ert/unit_tests/gui/run_analysis/test_analysispanel.py b/tests/ert/unit_tests/gui/run_analysis/test_analysispanel.py index 03896f2655d..aca873be454 100644 --- a/tests/ert/unit_tests/gui/run_analysis/test_analysispanel.py +++ b/tests/ert/unit_tests/gui/run_analysis/test_analysispanel.py @@ -1,20 +1,21 @@ import math import pytest -from qtpy.QtCore import Qt -from qtpy.QtWidgets import QCheckBox, QDoubleSpinBox +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QCheckBox, QDoubleSpinBox +from pytestqt.qtbot import QtBot from ert.config import ESSettings from ert.gui.ertwidgets.analysismodulevariablespanel import AnalysisModuleVariablesPanel @pytest.fixture -def panel_with_localization_on(qtbot): +def panel_with_localization_on(qtbot: QtBot): def func(settings, ensemble_size): widget = AnalysisModuleVariablesPanel(settings, ensemble_size) qtbot.addWidget(widget) check_box = widget.findChild(QCheckBox, name="localization") - qtbot.mouseClick(check_box, Qt.LeftButton) + qtbot.mouseClick(check_box, Qt.MouseButton.LeftButton) return settings, widget yield func diff --git a/tests/ert/unit_tests/gui/run_analysis/test_update_widget.py b/tests/ert/unit_tests/gui/run_analysis/test_update_widget.py index f8176643fd6..8bab56409d3 100644 --- a/tests/ert/unit_tests/gui/run_analysis/test_update_widget.py +++ b/tests/ert/unit_tests/gui/run_analysis/test_update_widget.py @@ -1,8 +1,8 @@ from uuid import uuid4 import numpy as np +from PyQt6.QtWidgets import QTableWidget from pytestqt.qtbot import QtBot -from qtpy.QtWidgets import QTableWidget from ert.analysis.event import DataSection from ert.gui.simulation.view import UpdateWidget 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 39f8d629e6d..75e55d5be16 100644 --- a/tests/ert/unit_tests/gui/simulation/test_run_dialog.py +++ b/tests/ert/unit_tests/gui/simulation/test_run_dialog.py @@ -4,19 +4,20 @@ import pandas as pd import pytest -from pytestqt.qtbot import QtBot -from qtpy import QtWidgets -from qtpy.QtCore import Qt, QTimer -from qtpy.QtWidgets import ( +from PyQt6.QtCore import Qt, QTimer +from PyQt6.QtWidgets import ( QApplication, QComboBox, + QDialogButtonBox, QLabel, + QMessageBox, QPushButton, QToolButton, - QWidget, ) +from pytestqt.qtbot import QtBot import ert +import ert.run_models from ert.config import ErtConfig from ert.ensemble_evaluator import state from ert.ensemble_evaluator.event import ( @@ -70,32 +71,22 @@ def notifier(): def run_dialog(qtbot: QtBot, run_model, event_queue, notifier): run_dialog = RunDialog("mock.ert", run_model, event_queue, notifier) qtbot.addWidget(run_dialog) - - # Teardown yield run_dialog - run_dialog.close() -def test_terminating_experiment_shows_a_confirmation_dialog( - qtbot: QtBot, run_dialog, event_queue -): +def test_terminating_experiment_shows_a_confirmation_dialog(qtbot: QtBot, run_dialog): run_dialog.run_experiment() - event_queue.put(EndEvent(failed=False, msg="")) with qtbot.waitSignal(run_dialog.simulation_done, timeout=10000): def handle_dialog(): - confirm_terminate_dialog = wait_for_child( - run_dialog, qtbot, QtWidgets.QMessageBox - ) - dialog_buttons = confirm_terminate_dialog.findChild( - QtWidgets.QDialogButtonBox - ).buttons() + terminate_dialog = wait_for_child(run_dialog, qtbot, QMessageBox) + dialog_buttons = terminate_dialog.findChild(QDialogButtonBox).buttons() yes_button = next(b for b in dialog_buttons if "Yes" in b.text()) - qtbot.mouseClick(yes_button, Qt.LeftButton) + qtbot.mouseClick(yes_button, Qt.MouseButton.LeftButton) QTimer.singleShot(100, handle_dialog) - qtbot.mouseClick(run_dialog.kill_button, Qt.LeftButton) + qtbot.mouseClick(run_dialog.kill_button, Qt.MouseButton.LeftButton) @pytest.mark.integration_test @@ -434,7 +425,7 @@ def test_run_dialog_memory_usage_showing( realization_box = run_dialog._tab_widget.widget(0) assert type(realization_box) == RealizationWidget # Click the first realization box - qtbot.mouseClick(realization_box, Qt.LeftButton) + qtbot.mouseClick(realization_box, Qt.MouseButton.LeftButton) fm_step_model = run_dialog._fm_step_overview.model() assert fm_step_model._real == 0 @@ -444,7 +435,9 @@ def test_run_dialog_memory_usage_showing( max_memory_column_proxy_index = fm_step_model.index( fm_step_number, max_memory_column_index ) - max_memory_value = fm_step_model.data(max_memory_column_proxy_index, Qt.DisplayRole) + max_memory_value = fm_step_model.data( + max_memory_column_proxy_index, Qt.ItemDataRole.DisplayRole + ) assert max_memory_value == "60.00 KB" @@ -537,7 +530,7 @@ def test_run_dialog_fm_label_show_correct_info( realization_box = run_dialog._tab_widget.widget(0) assert type(realization_box) == RealizationWidget # Click the first realization box - qtbot.mouseClick(realization_box, Qt.LeftButton) + qtbot.mouseClick(realization_box, Qt.MouseButton.LeftButton) fm_step_model = run_dialog._fm_step_overview.model() assert fm_step_model._real == 0 @@ -586,11 +579,11 @@ def handle_error_dialog(run_dialog): assert error_dialog text = error_dialog.details_text.toPlainText() assert "I failed :(" in text - qtbot.mouseClick(error_dialog.box.buttons()[0], Qt.LeftButton) + qtbot.mouseClick(error_dialog.box.buttons()[0], Qt.MouseButton.LeftButton) simulation_mode_combo = gui.findChild(QComboBox) simulation_mode_combo.setCurrentText("Single realization test-run") - qtbot.mouseClick(run_experiment, Qt.LeftButton) + qtbot.mouseClick(run_experiment, Qt.MouseButton.LeftButton) run_dialog = wait_for_child(gui, qtbot, RunDialog) QTimer.singleShot(100, lambda: handle_error_dialog(run_dialog)) @@ -612,21 +605,19 @@ def test_that_debug_info_button_provides_data_in_clipboard(qtbot: QtBot, storage ): gui = _setup_main_window(ert_config, args_mock, GUILogHandler(), storage) experiment_panel = gui.findChild(ExperimentPanel) - assert isinstance(experiment_panel, ExperimentPanel) + assert experiment_panel - run_experiment = experiment_panel.findChild(QWidget, name="run_experiment") + run_experiment = experiment_panel.findChild(QToolButton, name="run_experiment") assert run_experiment - assert isinstance(run_experiment, QToolButton) - qtbot.mouseClick(run_experiment, Qt.LeftButton) + qtbot.mouseClick(run_experiment, Qt.MouseButton.LeftButton) qtbot.waitUntil(lambda: gui.findChild(RunDialog) is not None, timeout=5000) run_dialog = gui.findChild(RunDialog) - assert run_dialog is not None + assert run_dialog qtbot.waitUntil(lambda: run_dialog.is_simulation_done() == True, timeout=100000) copy_debug_info_button = gui.findChild(QPushButton, "copy_debug_info_button") assert copy_debug_info_button - assert isinstance(copy_debug_info_button, QPushButton) - qtbot.mouseClick(copy_debug_info_button, Qt.LeftButton) + qtbot.mouseClick(copy_debug_info_button, Qt.MouseButton.LeftButton) clipboard_text = QApplication.clipboard().text() @@ -655,22 +646,20 @@ def test_that_stdout_and_stderr_buttons_react_to_file_content( ): gui = _setup_main_window(snake_oil_case, args_mock, GUILogHandler(), storage) experiment_panel = gui.findChild(ExperimentPanel) - - assert isinstance(experiment_panel, ExperimentPanel) + assert experiment_panel simulation_mode_combo = experiment_panel.findChild(QComboBox) - assert isinstance(simulation_mode_combo, QComboBox) + assert simulation_mode_combo simulation_mode_combo.setCurrentText(EnsembleExperiment.name()) simulation_settings = gui.findChild(EnsembleExperimentPanel) simulation_settings._experiment_name_field.setText("new_experiment_name") - run_experiment = experiment_panel.findChild(QWidget, name="run_experiment") + run_experiment = experiment_panel.findChild(QToolButton, 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) + qtbot.mouseClick(run_experiment, Qt.MouseButton.LeftButton) qtbot.waitUntil(lambda: gui.findChild(RunDialog) is not None, timeout=5000) run_dialog = gui.findChild(RunDialog) @@ -687,7 +676,7 @@ def test_that_stdout_and_stderr_buttons_react_to_file_content( with qtbot.waitSignal(realization_widget.itemClicked, timeout=30000): qtbot.mouseClick( realization_widget._real_view.viewport(), - Qt.LeftButton, + Qt.MouseButton.LeftButton, pos=click_pos, ) @@ -704,7 +693,9 @@ def test_that_stdout_and_stderr_buttons_react_to_file_content( 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.mouseClick( + fm_step_overview.viewport(), Qt.MouseButton.LeftButton, pos=click_pos + ) file_dialog = run_dialog.findChild(FileDialog) qtbot.waitUntil(file_dialog.isVisible, timeout=10000) file_dialog.close() @@ -750,10 +741,10 @@ def test_that_design_matrix_show_parameters_button_is_visible( ): gui = _setup_main_window(ert_config, args_mock, GUILogHandler(), storage) experiment_panel = gui.findChild(ExperimentPanel) - assert isinstance(experiment_panel, ExperimentPanel) + assert experiment_panel simulation_mode_combo = experiment_panel.findChild(QComboBox) - assert isinstance(simulation_mode_combo, QComboBox) + assert simulation_mode_combo simulation_mode_combo.setCurrentText(EnsembleExperiment.name()) simulation_settings = gui.findChild(EnsembleExperimentPanel) @@ -761,7 +752,7 @@ def test_that_design_matrix_show_parameters_button_is_visible( QPushButton, "show-dm-parameters" ) if design_matrix_entry: - assert isinstance(show_dm_parameters, QPushButton) + assert show_dm_parameters else: assert show_dm_parameters is None @@ -827,13 +818,13 @@ def qt_bot_click_realization(realization_index: int, iteration: int) -> None: view.scrollTo(model_index) rect = view.visualRect(model_index) click_pos = rect.center() - qtbot.mouseClick(view.viewport(), Qt.LeftButton, pos=click_pos) + qtbot.mouseClick(view.viewport(), Qt.MouseButton.LeftButton, pos=click_pos) def qt_bot_click_tab_index(tab_index: int) -> None: tab_bar = run_dialog._tab_widget.tabBar() tab_rect = tab_bar.tabRect(tab_index) click_pos = tab_rect.center() - qtbot.mouseClick(tab_bar, Qt.LeftButton, pos=click_pos) + qtbot.mouseClick(tab_bar, Qt.MouseButton.LeftButton, pos=click_pos) # verify two tabs present qtbot.waitUntil( 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 ad4fde67f3c..f86141e9157 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 @@ -3,9 +3,9 @@ from unittest.mock import Mock, patch import pytest +from PyQt6.QtCore import Qt, QTimer +from PyQt6.QtWidgets import QComboBox, QMessageBox, QToolButton, QWidget from pytestqt.qtbot import QtBot -from qtpy.QtCore import Qt, QTimer -from qtpy.QtWidgets import QComboBox, QMessageBox, QToolButton, QWidget from ert.config import ErtConfig from ert.gui.main import _setup_main_window @@ -25,16 +25,17 @@ def handle_run_path_dialog( delete_run_path: bool = True, expect_error: bool = False, ): - mb = gui.findChild(QMessageBox, "RUN_PATH_WARNING_BOX") + mb = gui.findChildren(QMessageBox, "RUN_PATH_WARNING_BOX") + mb = mb[-1] if mb else None if mb is not None: assert mb assert isinstance(mb, QMessageBox) if delete_run_path: - qtbot.mouseClick(mb.checkBox(), Qt.LeftButton) + qtbot.mouseClick(mb.checkBox(), Qt.MouseButton.LeftButton) - qtbot.mouseClick(mb.buttons()[0], Qt.LeftButton) + qtbot.mouseClick(mb.buttons()[0], Qt.MouseButton.LeftButton) if expect_error: QTimer.singleShot(1000, lambda: handle_run_path_error_dialog(gui, qtbot)) @@ -46,7 +47,7 @@ def handle_run_path_error_dialog(gui: ErtMainWindow, qtbot: QtBot): assert mb assert isinstance(mb, QMessageBox) # Continue without deleting the runpath - qtbot.mouseClick(mb.buttons()[0], Qt.LeftButton) + qtbot.mouseClick(mb.buttons()[0], Qt.MouseButton.LeftButton) @pytest.mark.integration_test @@ -91,7 +92,7 @@ def test_run_path_deleted_error( 1000, lambda: handle_run_path_dialog(gui, qtbot, expect_error=True) ) with patch("shutil.rmtree", side_effect=PermissionError("Not allowed!")): - qtbot.mouseClick(run_experiment, Qt.LeftButton) + qtbot.mouseClick(run_experiment, Qt.MouseButton.LeftButton) qtbot.waitUntil(lambda: gui.findChild(RunDialog) is not None) run_dialog = gui.findChild(RunDialog) @@ -138,7 +139,7 @@ def test_run_path_is_deleted(snake_oil_case_storage: ErtConfig, qtbot: QtBot): QTimer.singleShot( 1000, lambda: handle_run_path_dialog(gui, qtbot, delete_run_path=True) ) - qtbot.mouseClick(run_experiment, Qt.LeftButton) + qtbot.mouseClick(run_experiment, Qt.MouseButton.LeftButton) qtbot.waitUntil(lambda: gui.findChild(RunDialog) is not None) run_dialog = gui.findChild(RunDialog) @@ -183,7 +184,7 @@ def test_run_path_is_not_deleted(snake_oil_case_storage: ErtConfig, qtbot: QtBot QTimer.singleShot( 500, lambda: handle_run_path_dialog(gui, qtbot, delete_run_path=False) ) - qtbot.mouseClick(run_experiment, Qt.LeftButton) + qtbot.mouseClick(run_experiment, Qt.MouseButton.LeftButton) qtbot.waitUntil(lambda: gui.findChild(RunDialog) is not None, timeout=10000) run_dialog = gui.findChild(RunDialog) diff --git a/tests/ert/unit_tests/gui/simulation/view/test_legend.py b/tests/ert/unit_tests/gui/simulation/view/test_legend.py index 40730621c2f..9df620edc7d 100644 --- a/tests/ert/unit_tests/gui/simulation/view/test_legend.py +++ b/tests/ert/unit_tests/gui/simulation/view/test_legend.py @@ -1,7 +1,7 @@ import hypothesis.strategies as st import pytest from hypothesis import HealthCheck, given, settings -from qtpy.QtWidgets import QLabel +from PyQt6.QtWidgets import QLabel from ert.ensemble_evaluator.state import REAL_STATE_TO_COLOR from ert.gui.simulation.view import ProgressWidget diff --git a/tests/ert/unit_tests/gui/simulation/view/test_realization.py b/tests/ert/unit_tests/gui/simulation/view/test_realization.py index 4de9ecab378..2e08c1c0e1b 100644 --- a/tests/ert/unit_tests/gui/simulation/view/test_realization.py +++ b/tests/ert/unit_tests/gui/simulation/view/test_realization.py @@ -1,9 +1,8 @@ from datetime import datetime as dt import pytest -from qtpy import QtCore -from qtpy.QtCore import QModelIndex, QSize -from qtpy.QtWidgets import QStyledItemDelegate, QStyleOptionViewItem +from PyQt6.QtCore import QModelIndex, QSize, Qt +from PyQt6.QtWidgets import QStyledItemDelegate, QStyleOptionViewItem from ert.ensemble_evaluator.snapshot import ( EnsembleSnapshot, @@ -12,7 +11,7 @@ FORWARD_MODEL_STATE_START, REALIZATION_STATE_UNKNOWN, ) -from ert.gui.model.node import _Node +from ert.gui.model.node import ForwardModelStepNode, IterNode, RealNode, RootNode from ert.gui.model.snapshot import SnapshotModel from ert.gui.simulation.view.realization import RealizationWidget from tests.ert import SnapshotBuilder @@ -104,13 +103,15 @@ def test_selection_success(large_snapshot, qtbot): def check_selection_cb(index): node = index.internalPointer() - return isinstance(node, _Node) and str(node.id_) == str(selection_id) + return isinstance( + node, ForwardModelStepNode | RealNode | IterNode | RootNode + ) and str(node.id_) == str(selection_id) with qtbot.waitSignal( widget.itemClicked, timeout=30000, check_params_cb=check_selection_cb ): qtbot.mouseClick( widget._real_view.viewport(), - QtCore.Qt.LeftButton, + Qt.MouseButton.LeftButton, pos=selection_rect.center(), ) diff --git a/tests/ert/unit_tests/gui/test_suggestor.py b/tests/ert/unit_tests/gui/test_suggestor.py index a04366e07cc..1125d5b1515 100644 --- a/tests/ert/unit_tests/gui/test_suggestor.py +++ b/tests/ert/unit_tests/gui/test_suggestor.py @@ -1,5 +1,5 @@ import pytest -from qtpy.QtWidgets import QWidget +from PyQt6.QtWidgets import QWidget from ert.config import ErrorInfo from ert.gui.suggestor import Suggestor diff --git a/tests/ert/unit_tests/gui/tools/file/test_filedialog.py b/tests/ert/unit_tests/gui/tools/file/test_filedialog.py index fcb8d4dec2a..94e8bb68846 100644 --- a/tests/ert/unit_tests/gui/tools/file/test_filedialog.py +++ b/tests/ert/unit_tests/gui/tools/file/test_filedialog.py @@ -2,7 +2,7 @@ from os import path import pytest -from qtpy.QtWidgets import QApplication +from PyQt6.QtWidgets import QApplication from ert.gui.tools.file.file_dialog import FileDialog diff --git a/tests/ert/unit_tests/gui/tools/plot/test_plot_window.py b/tests/ert/unit_tests/gui/tools/plot/test_plot_window.py index 0d23a9d4dcb..306ecf9db96 100644 --- a/tests/ert/unit_tests/gui/tools/plot/test_plot_window.py +++ b/tests/ert/unit_tests/gui/tools/plot/test_plot_window.py @@ -1,6 +1,6 @@ +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QApplication, QPushButton from pytestqt.qtbot import QtBot -from qtpy.QtCore import Qt -from qtpy.QtWidgets import QApplication, QPushButton from ert.gui.tools.plot.plot_window import create_error_dialog diff --git a/tests/everest/dialogs_mocker.py b/tests/everest/dialogs_mocker.py index 5361465ab3d..703421599e9 100644 --- a/tests/everest/dialogs_mocker.py +++ b/tests/everest/dialogs_mocker.py @@ -1,4 +1,4 @@ -from qtpy.QtWidgets import QFileDialog, QMessageBox +from PyQt6.QtWidgets import QFileDialog, QMessageBox def mock_dialogs( @@ -57,10 +57,10 @@ def mock_dialogs_all( open_file_name="", open_file_names="", save_file_name="", - information_button=QMessageBox.Ok, - warning_button=QMessageBox.Ok, - critical_button=QMessageBox.Ok, - question_button=QMessageBox.Ok | QMessageBox.Yes, + information_button=QMessageBox.StandardButton.Ok, + warning_button=QMessageBox.StandardButton.Ok, + critical_button=QMessageBox.StandardButton.Ok, + question_button=QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Yes, ): """Same as mock_dialog but with some acceptable default""" mock_dialogs(