From d39845effc66d8a017d6e8c54b4fe021df697bc3 Mon Sep 17 00:00:00 2001 From: craftablescience Date: Tue, 6 May 2025 14:39:41 -0700 Subject: [PATCH] feat: allow optionally using pyside6 instead of pyqt5 --- .pre-commit-config.yaml | 2 +- pyproject.toml | 2 + src/badger/errors.py | 2 +- src/badger/gui/acr/__init__.py | 6 +- src/badger/gui/acr/components/action_bar.py | 30 +++--- .../gui/acr/components/archive_search.py | 21 ++-- src/badger/gui/acr/components/env_cbox.py | 14 +-- .../gui/acr/components/generator_cbox.py | 4 +- .../gui/acr/components/history_navigator.py | 6 +- .../gui/acr/components/routine_editor.py | 18 ++-- src/badger/gui/acr/components/routine_page.py | 16 +-- src/badger/gui/acr/components/status_bar.py | 6 +- src/badger/gui/acr/pages/home_page.py | 13 ++- src/badger/gui/acr/windows/main_window.py | 7 +- src/badger/gui/acr/windows/settings_dialog.py | 9 +- src/badger/gui/default/__init__.py | 6 +- .../default/components/analysis_extensions.py | 8 +- .../components/bo_visualizer/bo_plotter.py | 6 +- .../components/bo_visualizer/model_logic.py | 2 +- .../components/bo_visualizer/plotting_area.py | 2 +- .../components/bo_visualizer/ui_components.py | 4 +- .../gui/default/components/collapsible_box.py | 8 +- .../gui/default/components/constraint_item.py | 6 +- .../gui/default/components/create_process.py | 6 +- .../gui/default/components/data_table.py | 4 +- .../gui/default/components/eliding_label.py | 4 +- src/badger/gui/default/components/env_cbox.py | 14 +-- .../default/components/extensions_palette.py | 4 +- .../gui/default/components/filter_cbox.py | 4 +- .../gui/default/components/generator_cbox.py | 4 +- .../default/components/history_navigator.py | 4 +- .../default/components/labeled_lineedit.py | 2 +- .../gui/default/components/obj_table.py | 4 +- .../gui/default/components/process_manager.py | 4 +- .../default/components/reorderable_table.py | 2 +- .../gui/default/components/robust_spinbox.py | 4 +- .../gui/default/components/routine_editor.py | 14 +-- .../gui/default/components/routine_item.py | 10 +- .../gui/default/components/routine_page.py | 12 +-- .../gui/default/components/routine_runner.py | 14 +-- .../gui/default/components/run_monitor.py | 40 ++++---- .../gui/default/components/search_bar.py | 2 +- .../gui/default/components/state_item.py | 4 +- .../gui/default/components/status_bar.py | 6 +- src/badger/gui/default/components/syntax.py | 99 ++++++++++--------- .../gui/default/components/var_table.py | 10 +- src/badger/gui/default/pages/home_page.py | 11 +-- src/badger/gui/default/utils.py | 8 +- .../gui/default/windows/add_random_dialog.py | 6 +- src/badger/gui/default/windows/docs_window.py | 2 +- .../gui/default/windows/edit_script_dialog.py | 6 +- .../gui/default/windows/env_docs_window.py | 2 +- .../default/windows/expandable_message_box.py | 4 +- .../gui/default/windows/lim_vrange_dialog.py | 6 +- src/badger/gui/default/windows/main_window.py | 7 +- .../gui/default/windows/message_dialog.py | 4 +- .../gui/default/windows/review_dialog.py | 2 +- .../gui/default/windows/settings_dialog.py | 9 +- .../windows/terminition_condition_dialog.py | 4 +- src/badger/gui/default/windows/var_dialog.py | 4 +- src/badger/tests/test_create_process.py | 2 +- src/badger/tests/test_gui_basic.py | 2 +- src/badger/tests/test_home_page.py | 2 +- src/badger/tests/test_routine_page.py | 4 +- src/badger/tests/test_routine_runner.py | 6 +- src/badger/tests/test_run_monitor.py | 28 +++--- 66 files changed, 293 insertions(+), 295 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d484fa74..9da88b4b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks.git - rev: v4.6.0 + rev: v5.0.0 hooks: - id: no-commit-to-branch - id: trailing-whitespace diff --git a/pyproject.toml b/pyproject.toml index 9613b360..05af5b0b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,6 +25,7 @@ classifiers = [ requires-python = ">=3.10, <3.13" dependencies = [ "coolname", + "qtpy", "pyqt5", "pyqtgraph", "qdarkstyle>=3.0", @@ -38,6 +39,7 @@ version_file = "src/badger/_version.py" [project.optional-dependencies] dev = [ + "pyside6", "pytest", "pytest-cov", "pytest-qt", diff --git a/src/badger/errors.py b/src/badger/errors.py index a13fcb66..de49f981 100644 --- a/src/badger/errors.py +++ b/src/badger/errors.py @@ -1,4 +1,4 @@ -from PyQt5.QtWidgets import QMessageBox +from qtpy.QtWidgets import QMessageBox import traceback import sys diff --git a/src/badger/gui/acr/__init__.py b/src/badger/gui/acr/__init__.py index 871dc540..cad88dc6 100644 --- a/src/badger/gui/acr/__init__.py +++ b/src/badger/gui/acr/__init__.py @@ -2,9 +2,9 @@ import signal import sys import time -from PyQt5.QtWidgets import QApplication -from PyQt5.QtGui import QFont, QIcon -from PyQt5 import QtCore +from qtpy.QtWidgets import QApplication +from qtpy.QtGui import QFont, QIcon +from qtpy import QtCore from qdarkstyle import load_stylesheet, LightPalette, DarkPalette from badger.settings import init_settings diff --git a/src/badger/gui/acr/components/action_bar.py b/src/badger/gui/acr/components/action_bar.py index c3bfaf54..2d37705a 100644 --- a/src/badger/gui/acr/components/action_bar.py +++ b/src/badger/gui/acr/components/action_bar.py @@ -1,7 +1,7 @@ -from PyQt5.QtWidgets import QWidget, QHBoxLayout -from PyQt5.QtWidgets import QToolButton, QMenu, QAction -from PyQt5.QtGui import QIcon, QFont -from PyQt5.QtCore import pyqtSignal +from qtpy.QtWidgets import QWidget, QHBoxLayout +from qtpy.QtWidgets import QToolButton, QMenu +from qtpy.QtGui import QAction, QFont, QIcon +from qtpy.QtCore import Signal from importlib import resources from badger.gui.default.utils import create_button @@ -84,17 +84,17 @@ class BadgerActionBar(QWidget): - sig_start = pyqtSignal() - sig_start_until = pyqtSignal() - sig_stop = pyqtSignal() - - sig_delete_run = pyqtSignal() - sig_logbook = pyqtSignal() - sig_reset_env = pyqtSignal() - sig_jump_to_optimal = pyqtSignal() - sig_dial_in = pyqtSignal() - sig_ctrl = pyqtSignal(bool) - sig_open_extensions_palette = pyqtSignal() + sig_start = Signal() + sig_start_until = Signal() + sig_stop = Signal() + + sig_delete_run = Signal() + sig_logbook = Signal() + sig_reset_env = Signal() + sig_jump_to_optimal = Signal() + sig_dial_in = Signal() + sig_ctrl = Signal(bool) + sig_open_extensions_palette = Signal() def __init__(self, parent=None): super().__init__(parent) diff --git a/src/badger/gui/acr/components/archive_search.py b/src/badger/gui/acr/components/archive_search.py index a64e80c8..8f84b9bf 100644 --- a/src/badger/gui/acr/components/archive_search.py +++ b/src/badger/gui/acr/components/archive_search.py @@ -1,16 +1,15 @@ import logging -from typing import List -from PyQt5.QtGui import QDrag, QKeyEvent -from PyQt5.QtCore import ( +from typing import Any, List +from qtpy.QtGui import QDrag, QKeyEvent +from qtpy.QtCore import ( QAbstractTableModel, QMimeData, QModelIndex, QObject, Qt, - QVariant, - pyqtSignal, + Signal, ) -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QAbstractItemView, QHBoxLayout, QHeaderView, @@ -54,17 +53,17 @@ def columnCount(self, parent: QObject) -> int: return 0 return len(self.column_names) - def data(self, index: QModelIndex, role: int) -> QVariant: + def data(self, index: QModelIndex, role: int) -> str | None: """Return the data for the associated role. Currently only supporting DisplayRole.""" if not index.isValid(): - return QVariant() + return None if role != Qt.DisplayRole: - return QVariant() + return None return self.results_list[index.row()] - def headerData(self, section, orientation, role=Qt.DisplayRole) -> QVariant: + def headerData(self, section, orientation, role=Qt.DisplayRole) -> Any: """Return data associated with the header""" if role != Qt.DisplayRole: return super().headerData(section, orientation, role) @@ -117,7 +116,7 @@ class ArchiveSearchWidget(QWidget): The parent item of this widget """ - append_variables_requested = pyqtSignal(str) + append_variables_requested = Signal(str) def __init__(self, environment, parent: QObject = None) -> None: super().__init__(parent=parent) diff --git a/src/badger/gui/acr/components/env_cbox.py b/src/badger/gui/acr/components/env_cbox.py index 6fb7a923..38302626 100644 --- a/src/badger/gui/acr/components/env_cbox.py +++ b/src/badger/gui/acr/components/env_cbox.py @@ -1,4 +1,4 @@ -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QVBoxLayout, QHBoxLayout, QPushButton, @@ -6,13 +6,13 @@ QPlainTextEdit, QLineEdit, ) -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QCheckBox, QStyledItemDelegate, QLabel, QListWidget, ) -from PyQt5.QtCore import QRegExp, QPropertyAnimation +from qtpy.QtCore import QRegularExpression, QPropertyAnimation from badger.gui.acr.components.archive_search import ArchiveSearchWidget from badger.gui.default.components.collapsible_box import CollapsibleBox @@ -463,12 +463,12 @@ def add_var(self, name, lb, ub): def filter_var(self): keyword = self.edit_var.text() - rx = QRegExp(keyword) + rx = QRegularExpression(keyword) _variables = [] for var in self.var_table.all_variables: vname = next(iter(var)) - if rx.indexIn(vname, 0) != -1: + if rx.match(vname).hasMatch(): _variables.append(var) self.var_table.update_variables(_variables, 1) @@ -478,12 +478,12 @@ def toggle_obj_show_mode(self, _): def filter_obj(self): keyword = self.edit_obj.text() - rx = QRegExp(keyword) + rx = QRegularExpression(keyword) _objectives = [] for obj in self.obj_table.all_objectives: oname = next(iter(obj)) - if rx.indexIn(oname, 0) != -1: + if rx.match(oname).hasMatch(): _objectives.append(obj) self.obj_table.update_objectives(_objectives, 1) diff --git a/src/badger/gui/acr/components/generator_cbox.py b/src/badger/gui/acr/components/generator_cbox.py index 78c1644f..9fba5498 100644 --- a/src/badger/gui/acr/components/generator_cbox.py +++ b/src/badger/gui/acr/components/generator_cbox.py @@ -1,11 +1,11 @@ -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QVBoxLayout, QHBoxLayout, QPushButton, QWidget, QPlainTextEdit, ) -from PyQt5.QtWidgets import QComboBox, QCheckBox, QStyledItemDelegate, QLabel +from qtpy.QtWidgets import QComboBox, QCheckBox, QStyledItemDelegate, QLabel from badger.gui.default.components.collapsible_box import CollapsibleBox from badger.settings import init_settings from badger.gui.default.utils import ( diff --git a/src/badger/gui/acr/components/history_navigator.py b/src/badger/gui/acr/components/history_navigator.py index e71b747f..4481f0a2 100644 --- a/src/badger/gui/acr/components/history_navigator.py +++ b/src/badger/gui/acr/components/history_navigator.py @@ -1,6 +1,6 @@ -from PyQt5.QtWidgets import QWidget, QVBoxLayout, QTreeWidget, QTreeWidgetItem -from PyQt5.QtGui import QFont -from PyQt5.QtCore import Qt +from qtpy.QtWidgets import QWidget, QVBoxLayout, QTreeWidget, QTreeWidgetItem +from qtpy.QtGui import QFont +from qtpy.QtCore import Qt from badger.archive import get_base_run_filename from badger.utils import run_names_to_dict diff --git a/src/badger/gui/acr/components/routine_editor.py b/src/badger/gui/acr/components/routine_editor.py index 2e988c0e..83903c81 100644 --- a/src/badger/gui/acr/components/routine_editor.py +++ b/src/badger/gui/acr/components/routine_editor.py @@ -1,18 +1,18 @@ -from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QWidget, QPushButton -from PyQt5.QtWidgets import QTextEdit, QStackedWidget -from PyQt5.QtCore import pyqtSignal -from PyQt5.QtGui import QFont +from qtpy.QtWidgets import QVBoxLayout, QHBoxLayout, QWidget, QPushButton +from qtpy.QtWidgets import QTextEdit, QStackedWidget +from qtpy.QtCore import Signal +from qtpy.QtGui import QFont from badger.gui.acr.components.routine_page import BadgerRoutinePage from badger.routine import Routine class BadgerRoutineEditor(QWidget): - sig_saved = pyqtSignal() - sig_canceled = pyqtSignal() - sig_deleted = pyqtSignal() - sig_load_template = pyqtSignal(str) - sig_save_template = pyqtSignal(str) + sig_saved = Signal() + sig_canceled = Signal() + sig_deleted = Signal() + sig_load_template = Signal(str) + sig_save_template = Signal(str) def __init__(self): super().__init__() diff --git a/src/badger/gui/acr/components/routine_page.py b/src/badger/gui/acr/components/routine_page.py index cf9ddd49..473bba5f 100644 --- a/src/badger/gui/acr/components/routine_page.py +++ b/src/badger/gui/acr/components/routine_page.py @@ -7,11 +7,11 @@ import numpy as np import pandas as pd -from PyQt5.QtCore import Qt, pyqtSignal -from PyQt5.QtWidgets import QLineEdit, QLabel, QPushButton, QFileDialog -from PyQt5.QtWidgets import QListWidgetItem, QMessageBox, QWidget, QTabWidget -from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QScrollArea -from PyQt5.QtWidgets import QTableWidgetItem, QPlainTextEdit +from qtpy.QtCore import Qt, Signal +from qtpy.QtWidgets import QLineEdit, QLabel, QPushButton, QFileDialog +from qtpy.QtWidgets import QListWidgetItem, QMessageBox, QWidget, QTabWidget +from qtpy.QtWidgets import QVBoxLayout, QHBoxLayout, QScrollArea +from qtpy.QtWidgets import QTableWidgetItem, QPlainTextEdit from coolname import generate_slug from xopt import VOCS from xopt.generators import get_generator_defaults, all_generator_names @@ -59,9 +59,9 @@ class BadgerRoutinePage(QWidget): - sig_updated = pyqtSignal(str, str) # routine name, routine description - sig_load_template = pyqtSignal(str) # template path - sig_save_template = pyqtSignal(str) # template path + sig_updated = Signal(str, str) # routine name, routine description + sig_load_template = Signal(str) # template path + sig_save_template = Signal(str) # template path def __init__(self): super().__init__() diff --git a/src/badger/gui/acr/components/status_bar.py b/src/badger/gui/acr/components/status_bar.py index 1c1b67bd..60cca260 100644 --- a/src/badger/gui/acr/components/status_bar.py +++ b/src/badger/gui/acr/components/status_bar.py @@ -1,7 +1,7 @@ from importlib import resources -from PyQt5.QtWidgets import QHBoxLayout, QWidget, QPushButton -from PyQt5.QtGui import QIcon -from PyQt5.QtCore import Qt, QSize +from qtpy.QtWidgets import QHBoxLayout, QWidget, QPushButton +from qtpy.QtGui import QIcon +from qtpy.QtCore import Qt, QSize from badger.gui.acr.windows.settings_dialog import BadgerSettingsDialog from badger.gui.default.components.eliding_label import SimpleElidedLabel diff --git a/src/badger/gui/acr/pages/home_page.py b/src/badger/gui/acr/pages/home_page.py index fda100b5..e2318432 100644 --- a/src/badger/gui/acr/pages/home_page.py +++ b/src/badger/gui/acr/pages/home_page.py @@ -3,11 +3,10 @@ from importlib import resources from pandas import DataFrame -from PyQt5.QtCore import pyqtSignal, Qt -from PyQt5.QtGui import QIcon, QKeySequence -from PyQt5.QtWidgets import ( +from qtpy.QtCore import Qt, Signal +from qtpy.QtGui import QIcon, QKeySequence, QShortcut +from qtpy.QtWidgets import ( QMessageBox, - QShortcut, QSplitter, QVBoxLayout, QWidget, @@ -35,7 +34,7 @@ from badger.utils import get_header from badger.settings import init_settings -# from PyQt5.QtGui import QBrush, QColor +# from qtpy.QtGui import QBrush, QColor from badger.gui.default.windows.message_dialog import BadgerScrollableMessageBox from badger.gui.default.utils import ModalOverlay @@ -60,8 +59,8 @@ class BadgerHomePage(QWidget): - sig_routine_activated = pyqtSignal(bool) - sig_routine_invalid = pyqtSignal() + sig_routine_activated = Signal(bool) + sig_routine_invalid = Signal() def __init__(self, process_manager=None): super().__init__() diff --git a/src/badger/gui/acr/windows/main_window.py b/src/badger/gui/acr/windows/main_window.py index 53512040..c62fea95 100644 --- a/src/badger/gui/acr/windows/main_window.py +++ b/src/badger/gui/acr/windows/main_window.py @@ -2,8 +2,9 @@ from importlib import metadata from typing import Dict -from PyQt5.QtCore import QThread -from PyQt5.QtWidgets import QDesktopWidget, QMainWindow, QMessageBox, QStackedWidget +from qtpy.QtCore import QThread +from qtpy.QtGui import QGuiApplication +from qtpy.QtWidgets import QMainWindow, QMessageBox, QStackedWidget from badger.gui.default.components.create_process import CreateProcess from badger.gui.default.components.process_manager import ProcessManager @@ -86,7 +87,7 @@ def init_ui(self) -> None: def center(self) -> None: qr = self.frameGeometry() - cp = QDesktopWidget().availableGeometry().center() + cp = QGuiApplication.primaryScreen().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) diff --git a/src/badger/gui/acr/windows/settings_dialog.py b/src/badger/gui/acr/windows/settings_dialog.py index 42125255..ae98d0cf 100644 --- a/src/badger/gui/acr/windows/settings_dialog.py +++ b/src/badger/gui/acr/windows/settings_dialog.py @@ -1,6 +1,5 @@ -# from PyQt5.QtCore import QRegExp -# from PyQt5.QtGui import QRegExpValidator -from PyQt5.QtWidgets import ( +# from qtpy.QtGui import QRegularExpressionValidator +from qtpy.QtWidgets import ( # QComboBox, QGridLayout, QVBoxLayout, @@ -8,7 +7,7 @@ QLabel, QLineEdit, ) -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QDialog, QDialogButtonBox, QApplication, @@ -42,7 +41,7 @@ def init_ui(self): vbox = QVBoxLayout(self) - # validator = QRegExpValidator(QRegExp(r"^[0-9]\d*(\.\d+)?$")) + # validator = QRegularExpressionValidator(r"^[0-9]\d*(\.\d+)?$") widget_settings = QWidget(self) grid = QGridLayout(widget_settings) diff --git a/src/badger/gui/default/__init__.py b/src/badger/gui/default/__init__.py index 04332547..bd4b5770 100644 --- a/src/badger/gui/default/__init__.py +++ b/src/badger/gui/default/__init__.py @@ -2,9 +2,9 @@ import signal import sys import time -from PyQt5.QtWidgets import QApplication -from PyQt5.QtGui import QFont, QIcon -from PyQt5 import QtCore +from qtpy.QtWidgets import QApplication +from qtpy.QtGui import QFont, QIcon +from qtpy import QtCore from qdarkstyle import load_stylesheet, LightPalette, DarkPalette from badger.settings import init_settings diff --git a/src/badger/gui/default/components/analysis_extensions.py b/src/badger/gui/default/components/analysis_extensions.py index aa26c01b..cab88428 100644 --- a/src/badger/gui/default/components/analysis_extensions.py +++ b/src/badger/gui/default/components/analysis_extensions.py @@ -2,9 +2,9 @@ from typing import Optional, cast import pyqtgraph as pg -from PyQt5.QtCore import pyqtSignal -from PyQt5.QtWidgets import QDialog, QVBoxLayout, QMessageBox -from PyQt5.QtGui import QCloseEvent +from qtpy.QtCore import Signal +from qtpy.QtWidgets import QDialog, QVBoxLayout, QMessageBox +from qtpy.QtGui import QCloseEvent from badger.gui.default.components.bo_visualizer.bo_plotter import BOPlotWidget from badger.routine import Routine @@ -16,7 +16,7 @@ class AnalysisExtension(QDialog): - window_closed = pyqtSignal(object) + window_closed = Signal(object) def __init__(self, parent: Optional[QDialog] = None): super().__init__(parent=parent) diff --git a/src/badger/gui/default/components/bo_visualizer/bo_plotter.py b/src/badger/gui/default/components/bo_visualizer/bo_plotter.py index 42a842ca..a5270b61 100644 --- a/src/badger/gui/default/components/bo_visualizer/bo_plotter.py +++ b/src/badger/gui/default/components/bo_visualizer/bo_plotter.py @@ -1,14 +1,14 @@ from functools import wraps from typing import Callable, Optional, ParamSpec, cast -from PyQt5.QtWidgets import QHBoxLayout, QWidget, QVBoxLayout -from PyQt5.QtWidgets import QSizePolicy +from qtpy.QtWidgets import QHBoxLayout, QWidget, QVBoxLayout +from qtpy.QtWidgets import QSizePolicy from badger.gui.default.components.bo_visualizer.types import ConfigurableOptions from badger.routine import Routine from .ui_components import UIComponents from .plotting_area import PlottingArea from .model_logic import ModelLogic -from PyQt5.QtCore import Qt +from qtpy.QtCore import Qt from xopt.generators.bayesian.bayesian_generator import BayesianGenerator import logging diff --git a/src/badger/gui/default/components/bo_visualizer/model_logic.py b/src/badger/gui/default/components/bo_visualizer/model_logic.py index f2342e9a..0416e6ba 100644 --- a/src/badger/gui/default/components/bo_visualizer/model_logic.py +++ b/src/badger/gui/default/components/bo_visualizer/model_logic.py @@ -1,7 +1,7 @@ from typing import Optional from xopt import VOCS -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QTableWidgetItem, ) diff --git a/src/badger/gui/default/components/bo_visualizer/plotting_area.py b/src/badger/gui/default/components/bo_visualizer/plotting_area.py index 89aa4d1b..8d86d444 100644 --- a/src/badger/gui/default/components/bo_visualizer/plotting_area.py +++ b/src/badger/gui/default/components/bo_visualizer/plotting_area.py @@ -3,7 +3,7 @@ from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure from matplotlib.axes import Axes -from PyQt5.QtWidgets import QVBoxLayout, QWidget, QLayout +from qtpy.QtWidgets import QVBoxLayout, QWidget, QLayout from xopt.generators.bayesian.visualize import ( visualize_generator_model, ) diff --git a/src/badger/gui/default/components/bo_visualizer/ui_components.py b/src/badger/gui/default/components/bo_visualizer/ui_components.py index 34fab104..d154658e 100644 --- a/src/badger/gui/default/components/bo_visualizer/ui_components.py +++ b/src/badger/gui/default/components/bo_visualizer/ui_components.py @@ -1,4 +1,4 @@ -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QVBoxLayout, QHBoxLayout, QComboBox, @@ -11,7 +11,7 @@ QCheckBox, QHeaderView, ) -from PyQt5.QtCore import Qt +from qtpy.QtCore import Qt from typing import Optional, cast from badger.gui.default.components.bo_visualizer.types import ConfigurableOptions diff --git a/src/badger/gui/default/components/collapsible_box.py b/src/badger/gui/default/components/collapsible_box.py index a7b4b11c..e15c843f 100644 --- a/src/badger/gui/default/components/collapsible_box.py +++ b/src/badger/gui/default/components/collapsible_box.py @@ -1,4 +1,4 @@ -from PyQt5 import QtCore, QtGui, QtWidgets +from qtpy import QtCore, QtGui, QtWidgets stylesheet_toolbutton = """ @@ -11,7 +11,7 @@ # https://stackoverflow.com/a/56293688 class ScrollArea(QtWidgets.QScrollArea): - resized = QtCore.pyqtSignal() + resized = QtCore.Signal() def resizeEvent(self, e): self.resized.emit() @@ -71,7 +71,7 @@ def __init__(self, parent=None, title="", duration=100, tooltip=None): QtCore.QPropertyAnimation(self.content_area, b"maximumHeight") ) - @QtCore.pyqtSlot() + @QtCore.Slot() def start_animation(self): checked = self.toggle_button.isChecked() arrow_type = QtCore.Qt.DownArrow if checked else QtCore.Qt.RightArrow @@ -92,7 +92,7 @@ def expand(self): def updateContentLayout(self): if ( self.toggle_button.isChecked() - and self.toggle_animation.state() != self.toggle_animation.Running + and self.toggle_animation.state() != QtCore.QAbstractAnimation.Running ): content_height = self.content_area.layout().sizeHint().height() self.setMinimumHeight(self.collapsed_height + content_height) diff --git a/src/badger/gui/default/components/constraint_item.py b/src/badger/gui/default/components/constraint_item.py index d9babd04..d61a14f2 100644 --- a/src/badger/gui/default/components/constraint_item.py +++ b/src/badger/gui/default/components/constraint_item.py @@ -1,12 +1,12 @@ -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QHBoxLayout, QPushButton, QWidget, QDoubleSpinBox, QAbstractSpinBox, ) -from PyQt5.QtWidgets import QComboBox, QCheckBox, QStyledItemDelegate -from PyQt5.QtCore import Qt +from qtpy.QtWidgets import QComboBox, QCheckBox, QStyledItemDelegate +from qtpy.QtCore import Qt from badger.gui.default.utils import ( MouseWheelWidgetAdjustmentGuard, NoHoverFocusComboBox, diff --git a/src/badger/gui/default/components/create_process.py b/src/badger/gui/default/components/create_process.py index db0c0d91..1014314a 100644 --- a/src/badger/gui/default/components/create_process.py +++ b/src/badger/gui/default/components/create_process.py @@ -1,6 +1,6 @@ from multiprocessing import Event, Pipe, Process, Queue -from PyQt5.QtCore import pyqtSignal, QObject +from qtpy.QtCore import Signal, QObject from badger.core_subprocess import run_routine_subprocess @@ -13,8 +13,8 @@ class CreateProcess(QObject): The new process will be started, but will be holding until the wait_event is set. """ - finished = pyqtSignal() - subprocess_prepared = pyqtSignal(object) + finished = Signal() + subprocess_prepared = Signal(object) def create_subprocess(self) -> None: """ diff --git a/src/badger/gui/default/components/data_table.py b/src/badger/gui/default/components/data_table.py index bb990518..40291744 100644 --- a/src/badger/gui/default/components/data_table.py +++ b/src/badger/gui/default/components/data_table.py @@ -1,6 +1,6 @@ from pandas import DataFrame -from PyQt5.QtWidgets import QApplication, QTableWidget, QTableWidgetItem -from PyQt5.QtCore import Qt +from qtpy.QtWidgets import QApplication, QTableWidget, QTableWidgetItem +from qtpy.QtCore import Qt stylesheet = """ diff --git a/src/badger/gui/default/components/eliding_label.py b/src/badger/gui/default/components/eliding_label.py index af7acd01..98900f50 100644 --- a/src/badger/gui/default/components/eliding_label.py +++ b/src/badger/gui/default/components/eliding_label.py @@ -1,5 +1,5 @@ # https://stackoverflow.com/a/67628976/4263605 -from PyQt5 import QtCore, QtWidgets, QtGui +from qtpy import QtCore, QtWidgets, QtGui class ElidingLabel(QtWidgets.QLabel): @@ -36,7 +36,7 @@ class ElidingLabel(QtWidgets.QLabel): """ - elision_changed = QtCore.pyqtSignal(bool) + elision_changed = QtCore.Signal(bool) def __init__(self, text="", mode=QtCore.Qt.ElideMiddle, **kwargs): super().__init__(**kwargs) diff --git a/src/badger/gui/default/components/env_cbox.py b/src/badger/gui/default/components/env_cbox.py index fc8385ae..6be59ae8 100644 --- a/src/badger/gui/default/components/env_cbox.py +++ b/src/badger/gui/default/components/env_cbox.py @@ -1,4 +1,4 @@ -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QVBoxLayout, QHBoxLayout, QPushButton, @@ -6,14 +6,14 @@ QPlainTextEdit, QLineEdit, ) -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QCheckBox, QStyledItemDelegate, QLabel, QListWidget, QFrame, ) -from PyQt5.QtCore import QRegExp +from qtpy.QtCore import QRegularExpression from badger.gui.default.components.collapsible_box import CollapsibleBox from badger.gui.default.components.var_table import VariableTable @@ -364,12 +364,12 @@ def add_var(self, name, lb, ub): def filter_var(self): keyword = self.edit_var.text() - rx = QRegExp(keyword) + rx = QRegularExpression(keyword) _variables = [] for var in self.var_table.all_variables: vname = next(iter(var)) - if rx.indexIn(vname, 0) != -1: + if rx.match(vname).hasMatch(): _variables.append(var) self.var_table.update_variables(_variables, 1) @@ -379,12 +379,12 @@ def toggle_obj_show_mode(self, _): def filter_obj(self): keyword = self.edit_obj.text() - rx = QRegExp(keyword) + rx = QRegularExpression(keyword) _objectives = [] for obj in self.obj_table.all_objectives: oname = next(iter(obj)) - if rx.indexIn(oname, 0) != -1: + if rx.match(oname).hasMatch(): _objectives.append(obj) self.obj_table.update_objectives(_objectives, 1) diff --git a/src/badger/gui/default/components/extensions_palette.py b/src/badger/gui/default/components/extensions_palette.py index cd86c497..fab7d0fa 100644 --- a/src/badger/gui/default/components/extensions_palette.py +++ b/src/badger/gui/default/components/extensions_palette.py @@ -1,6 +1,6 @@ import traceback -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QMainWindow, QPushButton, QVBoxLayout, @@ -9,7 +9,7 @@ QMessageBox, QSizePolicy, ) -from PyQt5.QtCore import Qt +from qtpy.QtCore import Qt from badger.gui.default.components.analysis_extensions import ( AnalysisExtension, ParetoFrontViewer, diff --git a/src/badger/gui/default/components/filter_cbox.py b/src/badger/gui/default/components/filter_cbox.py index 032f326f..a971863a 100644 --- a/src/badger/gui/default/components/filter_cbox.py +++ b/src/badger/gui/default/components/filter_cbox.py @@ -1,5 +1,5 @@ -from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QWidget -from PyQt5.QtWidgets import QComboBox, QStyledItemDelegate, QLabel +from qtpy.QtWidgets import QVBoxLayout, QHBoxLayout, QWidget +from qtpy.QtWidgets import QComboBox, QStyledItemDelegate, QLabel from badger.gui.default.components.collapsible_box import CollapsibleBox diff --git a/src/badger/gui/default/components/generator_cbox.py b/src/badger/gui/default/components/generator_cbox.py index ef261ad0..4250476b 100644 --- a/src/badger/gui/default/components/generator_cbox.py +++ b/src/badger/gui/default/components/generator_cbox.py @@ -1,11 +1,11 @@ -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QVBoxLayout, QHBoxLayout, QPushButton, QWidget, QPlainTextEdit, ) -from PyQt5.QtWidgets import QComboBox, QCheckBox, QStyledItemDelegate, QLabel +from qtpy.QtWidgets import QComboBox, QCheckBox, QStyledItemDelegate, QLabel from badger.gui.default.components.collapsible_box import CollapsibleBox from badger.settings import init_settings from badger.gui.default.utils import ( diff --git a/src/badger/gui/default/components/history_navigator.py b/src/badger/gui/default/components/history_navigator.py index 180b32eb..fd08ad45 100644 --- a/src/badger/gui/default/components/history_navigator.py +++ b/src/badger/gui/default/components/history_navigator.py @@ -1,5 +1,5 @@ -from PyQt5.QtWidgets import QComboBox, QTreeWidget, QTreeWidgetItem -from PyQt5.QtCore import QModelIndex, Qt +from qtpy.QtWidgets import QComboBox, QTreeWidget, QTreeWidgetItem +from qtpy.QtCore import QModelIndex, Qt from badger.archive import get_base_run_filename from badger.utils import run_names_to_dict diff --git a/src/badger/gui/default/components/labeled_lineedit.py b/src/badger/gui/default/components/labeled_lineedit.py index 796a30c1..5b98cdec 100644 --- a/src/badger/gui/default/components/labeled_lineedit.py +++ b/src/badger/gui/default/components/labeled_lineedit.py @@ -1,4 +1,4 @@ -from PyQt5.QtWidgets import QHBoxLayout, QLabel, QLineEdit, QWidget +from qtpy.QtWidgets import QHBoxLayout, QLabel, QLineEdit, QWidget def labeled_lineedit(name, text, width_name=64, placeholder=None, readonly=True): diff --git a/src/badger/gui/default/components/obj_table.py b/src/badger/gui/default/components/obj_table.py index 3cfa5ae6..5b73bdfb 100644 --- a/src/badger/gui/default/components/obj_table.py +++ b/src/badger/gui/default/components/obj_table.py @@ -1,5 +1,5 @@ from typing import Any, List, Dict, Optional -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QTableWidget, QTableWidgetItem, QHeaderView, @@ -8,7 +8,7 @@ QComboBox, QStyledItemDelegate, ) -from PyQt5.QtGui import QDropEvent, QDragEnterEvent, QDragMoveEvent +from qtpy.QtGui import QDropEvent, QDragEnterEvent, QDragMoveEvent class ObjectiveTable(QTableWidget): diff --git a/src/badger/gui/default/components/process_manager.py b/src/badger/gui/default/components/process_manager.py index 30c99211..fbd74c7b 100644 --- a/src/badger/gui/default/components/process_manager.py +++ b/src/badger/gui/default/components/process_manager.py @@ -1,6 +1,6 @@ from typing import Dict, Optional -from PyQt5.QtCore import pyqtSignal, QObject +from qtpy.QtCore import Signal, QObject class ProcessManager(QObject): @@ -9,7 +9,7 @@ class ProcessManager(QObject): which can be used by Badger to run optimizations. """ - processQueueUpdated = pyqtSignal(object) + processQueueUpdated = Signal(object) def __init__(self) -> None: super().__init__() diff --git a/src/badger/gui/default/components/reorderable_table.py b/src/badger/gui/default/components/reorderable_table.py index 88f04927..7418b746 100644 --- a/src/badger/gui/default/components/reorderable_table.py +++ b/src/badger/gui/default/components/reorderable_table.py @@ -5,7 +5,7 @@ # https://creativecommons.org/publicdomain/zero/1.0/ # https://creativecommons.org/publicdomain/zero/1.0/legalcode -from PyQt5 import QtWidgets, QtGui +from qtpy import QtWidgets, QtGui class MyModel(QtGui.QStandardItemModel): diff --git a/src/badger/gui/default/components/robust_spinbox.py b/src/badger/gui/default/components/robust_spinbox.py index c384e951..88821ef4 100644 --- a/src/badger/gui/default/components/robust_spinbox.py +++ b/src/badger/gui/default/components/robust_spinbox.py @@ -1,5 +1,5 @@ -from PyQt5.QtWidgets import QDoubleSpinBox, QAbstractSpinBox -from PyQt5.QtCore import Qt +from qtpy.QtWidgets import QDoubleSpinBox, QAbstractSpinBox +from qtpy.QtCore import Qt from badger.gui.default.utils import MouseWheelWidgetAdjustmentGuard diff --git a/src/badger/gui/default/components/routine_editor.py b/src/badger/gui/default/components/routine_editor.py index c7210b96..989c864c 100644 --- a/src/badger/gui/default/components/routine_editor.py +++ b/src/badger/gui/default/components/routine_editor.py @@ -1,16 +1,16 @@ -from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QWidget, QPushButton -from PyQt5.QtWidgets import QTextEdit, QStackedWidget, QScrollArea -from PyQt5.QtCore import pyqtSignal -from PyQt5.QtGui import QFont +from qtpy.QtCore import Signal +from qtpy.QtGui import QFont +from qtpy.QtWidgets import QVBoxLayout, QHBoxLayout, QWidget, QPushButton +from qtpy.QtWidgets import QTextEdit, QStackedWidget, QScrollArea from badger.gui.default.components.routine_page import BadgerRoutinePage from badger.routine import Routine class BadgerRoutineEditor(QWidget): - sig_saved = pyqtSignal() - sig_canceled = pyqtSignal() - sig_deleted = pyqtSignal() + sig_saved = Signal() + sig_canceled = Signal() + sig_deleted = Signal() def __init__(self): super().__init__() diff --git a/src/badger/gui/default/components/routine_item.py b/src/badger/gui/default/components/routine_item.py index b075c9c8..3be1f674 100644 --- a/src/badger/gui/default/components/routine_item.py +++ b/src/badger/gui/default/components/routine_item.py @@ -1,8 +1,8 @@ from datetime import datetime -from PyQt5.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QLabel -from PyQt5.QtWidgets import QSizePolicy, QMessageBox -from PyQt5.QtCore import Qt, pyqtSignal -from PyQt5.QtGui import QFont +from qtpy.QtCore import Qt, Signal +from qtpy.QtGui import QFont +from qtpy.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QLabel +from qtpy.QtWidgets import QSizePolicy, QMessageBox from badger.gui.default.components.eliding_label import ElidingLabel from badger.gui.default.utils import create_button @@ -62,7 +62,7 @@ class BadgerRoutineItem(QWidget): # sig_del carries an id - sig_del = pyqtSignal(str) + sig_del = Signal(str) def __init__( self, id, name, timestamp, environment, env_dict, description="", parent=None diff --git a/src/badger/gui/default/components/routine_page.py b/src/badger/gui/default/components/routine_page.py index 1d27c570..19c89988 100644 --- a/src/badger/gui/default/components/routine_page.py +++ b/src/badger/gui/default/components/routine_page.py @@ -9,11 +9,11 @@ import numpy as np import pandas as pd -from PyQt5.QtCore import Qt, pyqtSignal -from PyQt5.QtWidgets import QGroupBox, QLineEdit, QLabel, QPushButton -from PyQt5.QtWidgets import QListWidgetItem, QMessageBox, QWidget -from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout -from PyQt5.QtWidgets import QTableWidgetItem, QPlainTextEdit, QSizePolicy +from qtpy.QtCore import Qt, Signal +from qtpy.QtWidgets import QGroupBox, QLineEdit, QLabel, QPushButton +from qtpy.QtWidgets import QListWidgetItem, QMessageBox, QWidget +from qtpy.QtWidgets import QVBoxLayout, QHBoxLayout +from qtpy.QtWidgets import QTableWidgetItem, QPlainTextEdit, QSizePolicy from coolname import generate_slug from pydantic import ValidationError from xopt import VOCS @@ -61,7 +61,7 @@ class BadgerRoutinePage(QWidget): - sig_updated = pyqtSignal(str, str) # routine name, routine description + sig_updated = Signal(str, str) # routine name, routine description def __init__(self): super().__init__() diff --git a/src/badger/gui/default/components/routine_runner.py b/src/badger/gui/default/components/routine_runner.py index d406b12a..bbbc6e6a 100644 --- a/src/badger/gui/default/components/routine_runner.py +++ b/src/badger/gui/default/components/routine_runner.py @@ -4,7 +4,7 @@ import pandas as pd import torch # noqa: F401. For converting dtype str to torch object. -from PyQt5.QtCore import pyqtSignal, QObject, QTimer +from qtpy.QtCore import Signal, QObject, QTimer from badger.errors import BadgerRunTerminated from badger.tests.utils import get_current_vars @@ -18,12 +18,12 @@ class BadgerRoutineSignals(QObject): - env_ready = pyqtSignal(list) - finished = pyqtSignal() - progress = pyqtSignal(object) - error = pyqtSignal(Exception) - info = pyqtSignal(str) - states = pyqtSignal(str) + env_ready = Signal(list) + finished = Signal() + progress = Signal(object) + error = Signal(Exception) + info = Signal(str) + states = Signal(str) class BadgerRoutineSubprocess: diff --git a/src/badger/gui/default/components/run_monitor.py b/src/badger/gui/default/components/run_monitor.py index 19a86353..5dff3e37 100644 --- a/src/badger/gui/default/components/run_monitor.py +++ b/src/badger/gui/default/components/run_monitor.py @@ -6,9 +6,9 @@ import numpy as np import pandas as pd import pyqtgraph as pg -from PyQt5.QtCore import pyqtSignal -from PyQt5.QtGui import QIcon -from PyQt5.QtWidgets import ( +from qtpy.QtCore import Signal +from qtpy.QtGui import QIcon +from qtpy.QtWidgets import ( QCheckBox, QComboBox, QHBoxLayout, @@ -43,23 +43,23 @@ class BadgerOptMonitor(QWidget): - sig_pause = pyqtSignal(bool) # True: pause, False: resume - sig_stop = pyqtSignal() - sig_lock = pyqtSignal(bool) # True: lock GUI, False: unlock GUI - sig_new_run = pyqtSignal() # start the new run - sig_run_started = pyqtSignal() # run started - sig_stop_run = pyqtSignal() # stop the run - sig_run_name = pyqtSignal(str) # filename of the new run - sig_status = pyqtSignal(str) # status information - sig_inspect = pyqtSignal(int) # index of the inspector - sig_progress = pyqtSignal(pd.DataFrame) # new evaluated solution - sig_del = pyqtSignal() - sig_routine_finished = pyqtSignal() - sig_lock_action = pyqtSignal() - sig_toggle_reset = pyqtSignal(bool) - sig_toggle_run = pyqtSignal(bool) - sig_toggle_other = pyqtSignal(bool) - sig_env_ready = pyqtSignal() + sig_pause = Signal(bool) # True: pause, False: resume + sig_stop = Signal() + sig_lock = Signal(bool) # True: lock GUI, False: unlock GUI + sig_new_run = Signal() # start the new run + sig_run_started = Signal() # run started + sig_stop_run = Signal() # stop the run + sig_run_name = Signal(str) # filename of the new run + sig_status = Signal(str) # status information + sig_inspect = Signal(int) # index of the inspector + sig_progress = Signal(pd.DataFrame) # new evaluated solution + sig_del = Signal() + sig_routine_finished = Signal() + sig_lock_action = Signal() + sig_toggle_reset = Signal(bool) + sig_toggle_run = Signal(bool) + sig_toggle_other = Signal(bool) + sig_env_ready = Signal() def __init__(self, process_manager=None): super().__init__() diff --git a/src/badger/gui/default/components/search_bar.py b/src/badger/gui/default/components/search_bar.py index 33a9269d..1e907bf0 100644 --- a/src/badger/gui/default/components/search_bar.py +++ b/src/badger/gui/default/components/search_bar.py @@ -1,4 +1,4 @@ -from PyQt5.QtWidgets import QLineEdit +from qtpy.QtWidgets import QLineEdit def search_bar(): diff --git a/src/badger/gui/default/components/state_item.py b/src/badger/gui/default/components/state_item.py index e3a5334e..029f0709 100644 --- a/src/badger/gui/default/components/state_item.py +++ b/src/badger/gui/default/components/state_item.py @@ -1,5 +1,5 @@ -from PyQt5.QtWidgets import QHBoxLayout, QPushButton, QWidget -from PyQt5.QtWidgets import QStyledItemDelegate +from qtpy.QtWidgets import QHBoxLayout, QPushButton, QWidget +from qtpy.QtWidgets import QStyledItemDelegate from badger.gui.default.utils import NoHoverFocusComboBox diff --git a/src/badger/gui/default/components/status_bar.py b/src/badger/gui/default/components/status_bar.py index b350d54a..bfc4d717 100644 --- a/src/badger/gui/default/components/status_bar.py +++ b/src/badger/gui/default/components/status_bar.py @@ -1,7 +1,7 @@ from importlib import resources -from PyQt5.QtWidgets import QHBoxLayout, QWidget, QPushButton -from PyQt5.QtGui import QIcon -from PyQt5.QtCore import Qt, QSize +from qtpy.QtWidgets import QHBoxLayout, QWidget, QPushButton +from qtpy.QtGui import QIcon +from qtpy.QtCore import Qt, QSize from badger.gui.default.windows.settings_dialog import BadgerSettingsDialog from badger.gui.default.components.eliding_label import SimpleElidedLabel diff --git a/src/badger/gui/default/components/syntax.py b/src/badger/gui/default/components/syntax.py index 261e6dba..84b2a012 100644 --- a/src/badger/gui/default/components/syntax.py +++ b/src/badger/gui/default/components/syntax.py @@ -1,4 +1,4 @@ -from PyQt5 import QtCore, QtGui +from qtpy import QtCore, QtGui def format(color, style=""): @@ -72,53 +72,53 @@ class PythonHighlighter(QtGui.QSyntaxHighlighter): # Python operators operators = [ - "=", + r"=", # Comparison - "==", - "!=", - "<", - "<=", - ">", - ">=", + r"==", + r"!=", + r"<", + r"<=", + r">", + r">=", # Arithmetic - "\+", - "-", - "\*", - "/", - "//", - "\%", - "\*\*", + r"\+", + r"-", + r"\*", + r"/", + r"//", + r"\%", + r"\*\*", # In-place - "\+=", - "-=", - "\*=", - "/=", - "\%=", + r"\+=", + r"-=", + r"\*=", + r"/=", + r"\%=", # Bitwise - "\^", - "\|", - "\&", - "\~", - ">>", - "<<", + r"\^", + r"\|", + r"\&", + r"\~", + r">>", + r"<<", ] # Python braces braces = [ - "\{", - "\}", - "\(", - "\)", - "\[", - "\]", + r"\{", + r"\}", + r"\(", + r"\)", + r"\[", + r"\]", ] def __init__(self, parent: QtGui.QTextDocument) -> None: super().__init__(parent) # Multi-line strings (expression, flag, style) - self.tri_single = (QtCore.QRegExp("'''"), 1, STYLES["string2"]) - self.tri_double = (QtCore.QRegExp('"""'), 2, STYLES["string2"]) + self.tri_single = (QtCore.QRegularExpression("'''"), 1, STYLES["string2"]) + self.tri_double = (QtCore.QRegularExpression('"""'), 2, STYLES["string2"]) rules = [] @@ -151,15 +151,18 @@ def __init__(self, parent: QtGui.QTextDocument) -> None: (r"#[^\n]*", 0, STYLES["comment"]), ] - # Build a QRegExp for each pattern - self.rules = [(QtCore.QRegExp(pat), index, fmt) for (pat, index, fmt) in rules] + # Build a QRegularExpression for each pattern + self.rules = [ + (QtCore.QRegularExpression(pat), index, fmt) for (pat, index, fmt) in rules + ] def highlightBlock(self, text): """Apply syntax highlighting to the given block of text.""" - self.tripleQuoutesWithinStrings = [] + self.tripleQuotesWithinStrings = [] # Do other syntax formatting for expression, nth, format in self.rules: - index = expression.indexIn(text, 0) + expression_match = expression.match(text) + index = expression_match.capturedStart(0) if index >= 0: # if there is a string we check # if there are some triple quotes within the string @@ -168,26 +171,28 @@ def highlightBlock(self, text): r'"[^"\\]*(\\.[^"\\]*)*"', r"'[^'\\]*(\\.[^'\\]*)*'", ]: - innerIndex = self.tri_single[0].indexIn(text, index + 1) + innerIndex = self.tri_single[0].match(text).capturedStart(1) if innerIndex == -1: - innerIndex = self.tri_double[0].indexIn(text, index + 1) + innerIndex = self.tri_double[0].match(text).capturedStart(1) if innerIndex != -1: tripleQuoteIndexes = range(innerIndex, innerIndex + 3) - self.tripleQuoutesWithinStrings.extend(tripleQuoteIndexes) + self.tripleQuotesWithinStrings.extend(tripleQuoteIndexes) while index >= 0: # skipping triple quotes within strings - if index in self.tripleQuoutesWithinStrings: + if ( + expression_match.capturedStart(index) + in self.tripleQuotesWithinStrings + ): index += 1 - expression.indexIn(text, index) continue # We actually want the index of the nth match - index = expression.pos(nth) - length = len(expression.cap(nth)) + index = expression_match.capturedStart(nth) + length = expression_match.capturedLength(nth) self.setFormat(index, length, format) - index = expression.indexIn(text, index + length) + index += 1 self.setCurrentBlockState(0) @@ -198,7 +203,7 @@ def highlightBlock(self, text): def match_multiline(self, text, delimiter, in_state, style): """Do highlighting of multi-line strings. ``delimiter`` should be a - ``QRegExp`` for triple-single-quotes or triple-double-quotes, and + ``QRegularExpression`` for triple-single-quotes or triple-double-quotes, and ``in_state`` should be a unique integer to represent the corresponding state changes when inside those strings. Returns True if we're still inside a multi-line string when this function is finished. diff --git a/src/badger/gui/default/components/var_table.py b/src/badger/gui/default/components/var_table.py index 260930b0..6a12f33e 100644 --- a/src/badger/gui/default/components/var_table.py +++ b/src/badger/gui/default/components/var_table.py @@ -1,4 +1,4 @@ -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QTableWidget, QTableWidgetItem, QHeaderView, @@ -6,8 +6,8 @@ QMessageBox, QAbstractItemView, ) -from PyQt5.QtCore import pyqtSignal, Qt -from PyQt5.QtGui import QColor +from qtpy.QtCore import Qt, Signal +from qtpy.QtGui import QColor from badger.gui.default.components.robust_spinbox import RobustSpinBox from badger.environment import instantiate_env @@ -15,8 +15,8 @@ class VariableTable(QTableWidget): - sig_sel_changed = pyqtSignal() - sig_pv_added = pyqtSignal() + sig_sel_changed = Signal() + sig_pv_added = Signal() def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/src/badger/gui/default/pages/home_page.py b/src/badger/gui/default/pages/home_page.py index dc18f93a..d96a472f 100644 --- a/src/badger/gui/default/pages/home_page.py +++ b/src/badger/gui/default/pages/home_page.py @@ -6,9 +6,9 @@ from typing import List from pandas import DataFrame -from PyQt5.QtCore import pyqtSignal, Qt -from PyQt5.QtGui import QIcon, QKeySequence -from PyQt5.QtWidgets import ( +from qtpy.QtCore import Qt, Signal +from qtpy.QtGui import QIcon, QKeySequence, QShortcut +from qtpy.QtWidgets import ( QFileDialog, QHBoxLayout, QLabel, @@ -16,7 +16,6 @@ QListWidgetItem, QMessageBox, QPushButton, - QShortcut, QSplitter, QTabWidget, QVBoxLayout, @@ -50,7 +49,7 @@ from badger.utils import get_header, strtobool from badger.settings import init_settings -# from PyQt5.QtGui import QBrush, QColor +# from qtpy.QtGui import QBrush, QColor from badger.gui.default.windows.message_dialog import BadgerScrollableMessageBox from badger.gui.default.utils import ModalOverlay @@ -71,7 +70,7 @@ class BadgerHomePage(QWidget): - sig_routine_activated = pyqtSignal(bool) + sig_routine_activated = Signal(bool) def __init__(self, process_manager=None): super().__init__() diff --git a/src/badger/gui/default/utils.py b/src/badger/gui/default/utils.py index 67f84a31..314b14ae 100644 --- a/src/badger/gui/default/utils.py +++ b/src/badger/gui/default/utils.py @@ -1,8 +1,8 @@ from importlib import resources -from PyQt5.QtWidgets import QWidget, QAbstractSpinBox, QPushButton, QComboBox -from PyQt5.QtWidgets import QDialog, QVBoxLayout, QLabel -from PyQt5.QtCore import Qt, QObject, QEvent, QSize -from PyQt5.QtGui import QIcon +from qtpy.QtWidgets import QWidget, QAbstractSpinBox, QPushButton, QComboBox +from qtpy.QtWidgets import QDialog, QVBoxLayout, QLabel +from qtpy.QtCore import Qt, QObject, QEvent, QSize +from qtpy.QtGui import QIcon import copy diff --git a/src/badger/gui/default/windows/add_random_dialog.py b/src/badger/gui/default/windows/add_random_dialog.py index 02e1088e..535ec849 100644 --- a/src/badger/gui/default/windows/add_random_dialog.py +++ b/src/badger/gui/default/windows/add_random_dialog.py @@ -1,6 +1,6 @@ -from PyQt5.QtWidgets import QDialog, QWidget, QHBoxLayout, QStackedWidget -from PyQt5.QtWidgets import QVBoxLayout, QSpinBox, QPushButton -from PyQt5.QtWidgets import QGroupBox, QLabel, QComboBox, QStyledItemDelegate +from qtpy.QtWidgets import QDialog, QWidget, QHBoxLayout, QStackedWidget +from qtpy.QtWidgets import QVBoxLayout, QSpinBox, QPushButton +from qtpy.QtWidgets import QGroupBox, QLabel, QComboBox, QStyledItemDelegate from badger.gui.default.components.robust_spinbox import RobustSpinBox diff --git a/src/badger/gui/default/windows/docs_window.py b/src/badger/gui/default/windows/docs_window.py index 7d20be63..e64f08b5 100644 --- a/src/badger/gui/default/windows/docs_window.py +++ b/src/badger/gui/default/windows/docs_window.py @@ -1,4 +1,4 @@ -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QTextEdit, QHBoxLayout, QVBoxLayout, diff --git a/src/badger/gui/default/windows/edit_script_dialog.py b/src/badger/gui/default/windows/edit_script_dialog.py index 839e53d7..8341ef07 100644 --- a/src/badger/gui/default/windows/edit_script_dialog.py +++ b/src/badger/gui/default/windows/edit_script_dialog.py @@ -1,6 +1,6 @@ -from PyQt5.QtWidgets import QDialog, QPlainTextEdit, QVBoxLayout, QWidget -from PyQt5.QtWidgets import QHBoxLayout, QPushButton -from PyQt5.QtGui import QFont +from qtpy.QtWidgets import QDialog, QPlainTextEdit, QVBoxLayout, QWidget +from qtpy.QtWidgets import QHBoxLayout, QPushButton +from qtpy.QtGui import QFont from badger.gui.default.components.syntax import PythonHighlighter diff --git a/src/badger/gui/default/windows/env_docs_window.py b/src/badger/gui/default/windows/env_docs_window.py index 493dd4a8..182321f0 100644 --- a/src/badger/gui/default/windows/env_docs_window.py +++ b/src/badger/gui/default/windows/env_docs_window.py @@ -1,4 +1,4 @@ -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QTextEdit, QHBoxLayout, QVBoxLayout, diff --git a/src/badger/gui/default/windows/expandable_message_box.py b/src/badger/gui/default/windows/expandable_message_box.py index 5196ba4c..d4adc26e 100644 --- a/src/badger/gui/default/windows/expandable_message_box.py +++ b/src/badger/gui/default/windows/expandable_message_box.py @@ -1,4 +1,4 @@ -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QDialog, QMessageBox, QVBoxLayout, @@ -7,7 +7,7 @@ QPushButton, QTextEdit, ) -from PyQt5.QtGui import QTextOption, QFont, QFontDatabase +from qtpy.QtGui import QTextOption, QFont, QFontDatabase class ExpandableMessageBox(QDialog): diff --git a/src/badger/gui/default/windows/lim_vrange_dialog.py b/src/badger/gui/default/windows/lim_vrange_dialog.py index 48c92f0e..1b6b813f 100644 --- a/src/badger/gui/default/windows/lim_vrange_dialog.py +++ b/src/badger/gui/default/windows/lim_vrange_dialog.py @@ -1,4 +1,4 @@ -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QDialog, QWidget, QHBoxLayout, @@ -6,14 +6,14 @@ QVBoxLayout, QDoubleSpinBox, ) -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QGroupBox, QLabel, QComboBox, QStyledItemDelegate, QStackedWidget, ) -from PyQt5.QtCore import Qt +from qtpy.QtCore import Qt class BadgerLimitVariableRangeDialog(QDialog): diff --git a/src/badger/gui/default/windows/main_window.py b/src/badger/gui/default/windows/main_window.py index 8e3a261f..cf942260 100644 --- a/src/badger/gui/default/windows/main_window.py +++ b/src/badger/gui/default/windows/main_window.py @@ -2,8 +2,9 @@ from importlib import metadata from typing import Dict -from PyQt5.QtCore import QThread -from PyQt5.QtWidgets import QDesktopWidget, QMainWindow, QMessageBox, QStackedWidget +from qtpy.QtCore import QThread +from qtpy.QtGui import QGuiApplication +from qtpy.QtWidgets import QMainWindow, QMessageBox, QStackedWidget from badger.gui.default.components.create_process import CreateProcess from badger.gui.default.components.process_manager import ProcessManager @@ -86,7 +87,7 @@ def init_ui(self) -> None: def center(self) -> None: qr = self.frameGeometry() - cp = QDesktopWidget().availableGeometry().center() + cp = QGuiApplication.primaryScreen().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) diff --git a/src/badger/gui/default/windows/message_dialog.py b/src/badger/gui/default/windows/message_dialog.py index 308f5423..f74dff20 100644 --- a/src/badger/gui/default/windows/message_dialog.py +++ b/src/badger/gui/default/windows/message_dialog.py @@ -1,4 +1,4 @@ -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QDialog, QMessageBox, QVBoxLayout, @@ -8,7 +8,7 @@ QScrollArea, QTextEdit, ) -from PyQt5.QtGui import QTextOption, QFont, QFontDatabase +from qtpy.QtGui import QTextOption, QFont, QFontDatabase # from ..components.eliding_label import ElidingLabel diff --git a/src/badger/gui/default/windows/review_dialog.py b/src/badger/gui/default/windows/review_dialog.py index 868146fa..c2ed9276 100644 --- a/src/badger/gui/default/windows/review_dialog.py +++ b/src/badger/gui/default/windows/review_dialog.py @@ -1,4 +1,4 @@ -from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QTextBrowser, QVBoxLayout +from qtpy.QtWidgets import QDialog, QDialogButtonBox, QTextBrowser, QVBoxLayout from badger.routine import Routine from badger.utils import get_yaml_string diff --git a/src/badger/gui/default/windows/settings_dialog.py b/src/badger/gui/default/windows/settings_dialog.py index d21251ca..cd003304 100644 --- a/src/badger/gui/default/windows/settings_dialog.py +++ b/src/badger/gui/default/windows/settings_dialog.py @@ -1,6 +1,5 @@ -from PyQt5.QtCore import QRegExp -from PyQt5.QtGui import QRegExpValidator -from PyQt5.QtWidgets import ( +from qtpy.QtGui import QRegularExpressionValidator +from qtpy.QtWidgets import ( QComboBox, QGridLayout, QVBoxLayout, @@ -8,7 +7,7 @@ QLabel, QLineEdit, ) -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QDialog, QDialogButtonBox, QApplication, @@ -45,7 +44,7 @@ def init_ui(self): vbox = QVBoxLayout(self) - validator = QRegExpValidator(QRegExp(r"^[0-9]\d*(\.\d+)?$")) + validator = QRegularExpressionValidator(r"^[0-9]\d*(\.\d+)?$") widget_settings = QWidget(self) grid = QGridLayout(widget_settings) diff --git a/src/badger/gui/default/windows/terminition_condition_dialog.py b/src/badger/gui/default/windows/terminition_condition_dialog.py index 3cefeaf3..76d18abe 100644 --- a/src/badger/gui/default/windows/terminition_condition_dialog.py +++ b/src/badger/gui/default/windows/terminition_condition_dialog.py @@ -1,4 +1,4 @@ -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QDialog, QWidget, QHBoxLayout, @@ -7,7 +7,7 @@ QSpinBox, QDoubleSpinBox, ) -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QGroupBox, QLabel, QComboBox, diff --git a/src/badger/gui/default/windows/var_dialog.py b/src/badger/gui/default/windows/var_dialog.py index 1ab85f22..6605482e 100644 --- a/src/badger/gui/default/windows/var_dialog.py +++ b/src/badger/gui/default/windows/var_dialog.py @@ -1,4 +1,4 @@ -from PyQt5.QtWidgets import ( +from qtpy.QtWidgets import ( QDialog, QWidget, QHBoxLayout, @@ -6,7 +6,7 @@ QPushButton, QVBoxLayout, ) -from PyQt5.QtWidgets import QGroupBox, QMessageBox +from qtpy.QtWidgets import QGroupBox, QMessageBox from badger.gui.default.components.labeled_lineedit import labeled_lineedit from badger.environment import instantiate_env diff --git a/src/badger/tests/test_create_process.py b/src/badger/tests/test_create_process.py index 87b3c4af..ac801748 100644 --- a/src/badger/tests/test_create_process.py +++ b/src/badger/tests/test_create_process.py @@ -3,7 +3,7 @@ from unittest.mock import MagicMock, patch import pytest -from PyQt5.QtWidgets import QApplication +from qtpy.QtWidgets import QApplication app = QApplication(sys.argv) diff --git a/src/badger/tests/test_gui_basic.py b/src/badger/tests/test_gui_basic.py index e9efddb8..b6d4ea28 100644 --- a/src/badger/tests/test_gui_basic.py +++ b/src/badger/tests/test_gui_basic.py @@ -3,7 +3,7 @@ from unittest.mock import patch import pytest -from PyQt5.QtCore import QEventLoop, Qt, QTimer +from qtpy.QtCore import QEventLoop, Qt, QTimer @pytest.fixture(scope="session") diff --git a/src/badger/tests/test_home_page.py b/src/badger/tests/test_home_page.py index 7bbb160e..e2c24020 100644 --- a/src/badger/tests/test_home_page.py +++ b/src/badger/tests/test_home_page.py @@ -1,7 +1,7 @@ import multiprocessing import pytest -from PyQt5.QtCore import QEventLoop, QTimer +from qtpy.QtCore import QEventLoop, QTimer @pytest.fixture(scope="session") diff --git a/src/badger/tests/test_routine_page.py b/src/badger/tests/test_routine_page.py index b197b3ac..26775017 100644 --- a/src/badger/tests/test_routine_page.py +++ b/src/badger/tests/test_routine_page.py @@ -1,7 +1,7 @@ import pandas as pd import pytest -from PyQt5.QtCore import Qt, QTimer -from PyQt5.QtWidgets import QApplication +from qtpy.QtCore import Qt, QTimer +from qtpy.QtWidgets import QApplication def test_routine_page_init(qtbot): diff --git a/src/badger/tests/test_routine_runner.py b/src/badger/tests/test_routine_runner.py index a23a5231..001ecdbb 100644 --- a/src/badger/tests/test_routine_runner.py +++ b/src/badger/tests/test_routine_runner.py @@ -1,9 +1,9 @@ import multiprocessing import pytest -from PyQt5.QtCore import QEventLoop, Qt, QTimer -from PyQt5.QtTest import QSignalSpy -from PyQt5.QtWidgets import QApplication +from qtpy.QtCore import QEventLoop, Qt, QTimer +from qtpy.QtTest import QSignalSpy +from qtpy.QtWidgets import QApplication from unittest.mock import Mock diff --git a/src/badger/tests/test_run_monitor.py b/src/badger/tests/test_run_monitor.py index 783eddb1..f3d1acc8 100644 --- a/src/badger/tests/test_run_monitor.py +++ b/src/badger/tests/test_run_monitor.py @@ -4,10 +4,10 @@ import numpy as np import pytest -from PyQt5.QtCore import QEventLoop, QPointF, Qt, QTimer -from PyQt5.QtGui import QMouseEvent -from PyQt5.QtTest import QSignalSpy -from PyQt5.QtWidgets import QApplication, QMessageBox +from qtpy.QtCore import QEventLoop, QPointF, Qt, QTimer +from qtpy.QtGui import QMouseEvent +from qtpy.QtTest import QSignalSpy +from qtpy.QtWidgets import QApplication, QMessageBox class TestRunMonitor: @@ -357,10 +357,8 @@ def test_reset_environment(self, qtbot, init_multiprocessing): monitor.inspector_objective.setValue(9) - with patch( - "PyQt5.QtWidgets.QMessageBox.question", return_value=QMessageBox.Yes - ): - # with patch("PyQt5.QtWidgets.QMessageBox.information") as mock_info: + with patch("qtpy.QtWidgets.QMessageBox.question", return_value=QMessageBox.Yes): + # with patch("qtpy.QtWidgets.QMessageBox.information") as mock_info: qtbot.mouseClick(action_bar.btn_set, Qt.MouseButton.LeftButton) # mock_info.assert_called_once() @@ -373,10 +371,8 @@ def test_reset_environment(self, qtbot, init_multiprocessing): # Reset env and confirm spy = QSignalSpy(action_bar.btn_reset.clicked) - with patch( - "PyQt5.QtWidgets.QMessageBox.question", return_value=QMessageBox.Yes - ): - # with patch("PyQt5.QtWidgets.QMessageBox.information") as mock_info: + with patch("qtpy.QtWidgets.QMessageBox.question", return_value=QMessageBox.Yes): + # with patch("qtpy.QtWidgets.QMessageBox.information") as mock_info: qtbot.mouseClick(action_bar.btn_reset, Qt.MouseButton.LeftButton) # mock_info.assert_called_once() @@ -406,9 +402,7 @@ def test_dial_in_solution(self, qtbot, home_page): monitor.inspector_objective.setValue(2) spy = QSignalSpy(action_bar.btn_set.clicked) - with patch( - "PyQt5.QtWidgets.QMessageBox.question", return_value=QMessageBox.Yes - ): + with patch("qtpy.QtWidgets.QMessageBox.question", return_value=QMessageBox.Yes): qtbot.mouseClick(action_bar.btn_set, Qt.MouseButton.LeftButton) assert len(spy) == 1 @@ -423,7 +417,7 @@ def test_dial_in_solution(self, qtbot, home_page): # monitor.plot_x_axis = False - # with patch("PyQt5.QtWidgets.QMessageBox.question", return_value=QMessageBox.Yes): + # with patch("qtpy.QtWidgets.QMessageBox.question", return_value=QMessageBox.Yes): # qtbot.mouseClick(monitor.btn_set, Qt.MouseButton.LeftButton) # not_time_x_view_range = monitor.plot_var.getViewBox().viewRange()[0] @@ -512,7 +506,7 @@ def handle_dialog(): action_bar.run_until_action.trigger() # Check if critical violation alert being triggered - with patch("PyQt5.QtWidgets.QMessageBox.warning", return_value=QMessageBox.Yes): + with patch("qtpy.QtWidgets.QMessageBox.warning", return_value=QMessageBox.Yes): while monitor.running: qtbot.wait(100)