Skip to content

Commit 9c43691

Browse files
Migrate codebase from PyQt5 to PyQt6 (#87)
* enh: update GUI dependency from PyQt5 to PyQt6 * enh: migrate codebase from pyqt5 to pyqt6 * ref: replace QSizePolicy.Expanding with QSizePolicy.Policy.Expanding * update CHANGELOG * ref: replace Qt.UserRole with Qt.ItemDataRole.UserRole * fix: install libegl1-mesa to resolve PyQt6 ImportError * ref: replace QtWidgets.QShortcut with QtGui.QShortcut * ref: update regex validation to use QRegularExpression and QRegularExpressionValidator * fix: replace QItemSelectionModel.Select with QItemSelectionModel.SelectionFlag.Select * update CHANGELOG
1 parent b13a179 commit 9c43691

30 files changed

Lines changed: 215 additions & 195 deletions

.github/workflows/check.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ jobs:
2929
- name: Setup xvfb (Linux)
3030
if: runner.os == 'Linux'
3131
run: |
32-
sudo apt-get install -y xvfb libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-shape0 libxcb-xinerama0 libxcb-xinput0 libxcb-xfixes0
32+
sudo apt-get install -y xvfb libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-shape0 libxcb-xinerama0 libxcb-xinput0 libxcb-xfixes0 libglib2.0-0 libgl1-mesa-dev
33+
sudo apt-get install '^libxcb.*-dev' libx11-xcb-dev libglu1-mesa-dev libxrender-dev libxi-dev libxkbcommon-dev libxkbcommon-x11-dev
3334
# start xvfb in the background
3435
sudo /usr/bin/Xvfb $DISPLAY -screen 0 1280x1024x24 &
3536
- name: Install Python dependencies

CHANGELOG

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
0.16.12
1+
0.17.0
2+
- BREAKING CHANGE: migrate codebase from PyQt5 to PyQt6
23
- tests: allow to use different DCOR instance for testing
34
- tests: make tests independent of testing user
45
0.16.11

dcoraid/__main__.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,33 @@ def main(splash=True):
1010
setup_logging("dclab")
1111
setup_logging("requests", level=logging.INFO)
1212

13-
from PyQt5.QtWidgets import QApplication
13+
from PyQt6.QtWidgets import QApplication
1414

1515
if platform.win32_ver()[0] == "7":
1616
# Use software OpenGL on Windows 7, because sometimes the
1717
# window content becomes plain white.
1818
# Not sure whether this actually works.
19-
from PyQt5.QtCore import Qt, QCoreApplication
20-
from PyQt5.QtGui import QGuiApplication
19+
from PyQt6.QtCore import Qt, QCoreApplication
20+
from PyQt6.QtGui import QGuiApplication
2121
QApplication.setAttribute(Qt.AA_UseSoftwareOpenGL)
2222
QCoreApplication.setAttribute(Qt.AA_UseSoftwareOpenGL)
2323
QGuiApplication.setAttribute(Qt.AA_UseSoftwareOpenGL)
2424

2525
app = QApplication(sys.argv)
2626

2727
if splash:
28-
from PyQt5.QtWidgets import QSplashScreen
29-
from PyQt5.QtGui import QPixmap
30-
from PyQt5.QtCore import QEventLoop
28+
from PyQt6.QtWidgets import QSplashScreen
29+
from PyQt6.QtGui import QPixmap
30+
from PyQt6.QtCore import QEventLoop
3131
ref_splash = resources.files("dcoraid.img") / "splash.png"
3232
with resources.as_file(ref_splash) as splash_path:
3333
splash_pix = QPixmap(str(splash_path))
3434
splash = QSplashScreen(splash_pix)
3535
splash.setMask(splash_pix.mask())
3636
splash.show()
37-
app.processEvents(QEventLoop.AllEvents, 300)
37+
app.processEvents(QEventLoop.ProcessEventsFlag.AllEvents, 300)
3838

39-
from PyQt5 import QtCore, QtGui
39+
from PyQt6 import QtCore, QtGui
4040
from .gui import DCORAid
4141

4242
# Set Application Icon
@@ -45,14 +45,14 @@ def main(splash=True):
4545
app.setWindowIcon(QtGui.QIcon(str(icon_path)))
4646

4747
# Use dots as decimal separators
48-
QtCore.QLocale.setDefault(QtCore.QLocale(QtCore.QLocale.C))
48+
QtCore.QLocale.setDefault(QtCore.QLocale(QtCore.QLocale.Language.C))
4949

5050
window = DCORAid()
5151

5252
if splash:
5353
splash.finish(window)
5454

55-
sys.exit(app.exec_())
55+
sys.exit(app.exec())
5656

5757

5858
if __name__ == "__main__":

dcoraid/gui/api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import shutil
66
import tempfile
77

8-
from PyQt5 import QtCore
8+
from PyQt6 import QtCore
99

1010
from ..api import CKANAPI
1111

dcoraid/gui/browse_public/widget_browse_public.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from importlib import resources
44

5-
from PyQt5 import uic, QtCore, QtWidgets
5+
from PyQt6 import uic, QtCore, QtWidgets
66

77
from ...common import ConnectionTimeoutErrors
88
from ...dbmodel import APIInterrogator
@@ -29,7 +29,7 @@ def __init__(self, *args, **kwargs):
2929

3030
@QtCore.pyqtSlot()
3131
def on_public_search(self):
32-
self.setCursor(QtCore.Qt.WaitCursor)
32+
self.setCursor(QtCore.Qt.CursorShape.WaitCursor)
3333
api = get_ckan_api(
3434
public=not self.checkBox_public_include_private.isChecked())
3535
try:
@@ -44,7 +44,7 @@ def on_public_search(self):
4444
self,
4545
f"Failed to connect to {api.server}",
4646
tb.format_exc(limit=1))
47-
self.setCursor(QtCore.Qt.ArrowCursor)
47+
self.setCursor(QtCore.Qt.CursorShape.ArrowCursor)
4848

4949
@staticmethod
5050
def find_main_window():

dcoraid/gui/dbview/drag_table_widget.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from PyQt5 import QtWidgets, QtCore, QtGui
2-
from PyQt5.QtCore import Qt
1+
from PyQt6 import QtWidgets, QtCore, QtGui
2+
from PyQt6.QtCore import Qt
33

44

55
class DragTableWidget(QtWidgets.QTableWidget):
@@ -9,7 +9,7 @@ def mouseMoveEvent(self, e):
99

1010
urls = []
1111
for item in self.selectedItems():
12-
data = item.data(Qt.UserRole + 1)
12+
data = item.data(Qt.ItemDataRole.UserRole + 1)
1313
urls.append(QtCore.QUrl(data))
1414

1515
mime_data = QtCore.QMimeData()
@@ -20,4 +20,4 @@ def mouseMoveEvent(self, e):
2020
drag.setHotSpot(e.pos() - self.rect().topLeft())
2121

2222
# This magic is somehow required to get drag working.
23-
dropAction = drag.exec_(Qt.CopyAction) # noqa: F841
23+
dropAction = drag.exec(Qt.CopyAction) # noqa: F841

dcoraid/gui/dbview/filter_base.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import copy
22
from importlib import resources
33

4-
from PyQt5 import QtCore, QtGui, QtWidgets, uic
4+
from PyQt6 import QtCore, QtGui, QtWidgets, uic
55

66

77
class FilterBase(QtWidgets.QWidget):
@@ -22,7 +22,8 @@ def __init__(self, *args, **kwargs):
2222

2323
# resize first column
2424
header = self.tableWidget.horizontalHeader()
25-
header.setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch)
25+
header.setSectionResizeMode(0,
26+
QtWidgets.QHeaderView.ResizeMode.Stretch)
2627

2728
# trigger user selection change signal
2829
self.tableWidget.itemSelectionChanged.connect(self.on_entry_selected)
@@ -38,9 +39,10 @@ def __init__(self, *args, **kwargs):
3839
self.tableWidget.setDragEnabled(False) # disable drag
3940
self.tableWidget.setDragDropOverwriteMode(False) # don't overwrite
4041
self.tableWidget.setDragDropMode(
41-
QtWidgets.QAbstractItemView.NoDragDrop) # drag & drop disabled
42+
# drag & drop disabled
43+
QtWidgets.QAbstractItemView.DragDropMode.NoDragDrop)
4244
self.tableWidget.setDefaultDropAction(
43-
QtCore.Qt.IgnoreAction) # no drop by default
45+
QtCore.Qt.DropAction.IgnoreAction) # no drop by default
4446

4547
def get_entry_actions(self, row, entry):
4648
"""This is defined in the subclasses (Circle, Collection, etc)"""
@@ -87,8 +89,8 @@ def set_entry(self, row, entry):
8789
horz_layout.setContentsMargins(2, 0, 2, 0)
8890

8991
spacer = QtWidgets.QSpacerItem(0, 0,
90-
QtWidgets.QSizePolicy.Expanding,
91-
QtWidgets.QSizePolicy.Minimum)
92+
QtWidgets.QSizePolicy.Policy.Expanding,
93+
QtWidgets.QSizePolicy.Policy.Minimum)
9294
horz_layout.addItem(spacer)
9395

9496
for action in self.get_entry_actions(row, entry):

dcoraid/gui/dbview/filter_chain.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from importlib import resources
44

5-
from PyQt5 import QtCore, QtWidgets, uic
5+
from PyQt6 import QtCore, QtWidgets, uic
66

77
from ..tools import ShowWaitCursor
88
from ..api import get_ckan_api

dcoraid/gui/dbview/filter_views.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from functools import partial
22
import webbrowser
33

4-
from PyQt5 import QtCore, QtWidgets
5-
from PyQt5.QtCore import Qt
4+
from PyQt6 import QtCore, QtWidgets
5+
from PyQt6.QtCore import Qt
66

77
from ..api import get_ckan_api
88
from ..tools import ShowWaitCursor
@@ -64,7 +64,7 @@ def download_collection(self, collection_name, condensed=False):
6464
for res_dict in ds_dict.get("resources", []):
6565
self.download_resource.emit(res_dict["id"], condensed)
6666
QtWidgets.QApplication.processEvents(
67-
QtCore.QEventLoop.AllEvents,
67+
QtCore.QEventLoop.ProcessEventsFlag.AllEvents,
6868
300)
6969

7070
def get_entry_actions(self, row, entry):
@@ -108,7 +108,7 @@ def download_dataset(self, dataset_id, condensed=False):
108108
for res_dict in ds_dict.get("resources", []):
109109
self.download_resource.emit(res_dict["id"], condensed)
110110
QtWidgets.QApplication.processEvents(
111-
QtCore.QEventLoop.AllEvents,
111+
QtCore.QEventLoop.ProcessEventsFlag.AllEvents,
112112
300)
113113

114114
def get_entry_actions(self, row, entry):
@@ -139,7 +139,7 @@ def __init__(self, *args, **kwargs):
139139
self.checkBox.setChecked(True)
140140
self.tableWidget.setDragEnabled(True)
141141
self.tableWidget.setDragDropMode(
142-
QtWidgets.QAbstractItemView.DragOnly)
142+
QtWidgets.QAbstractItemView.DragDropMode.DragOnly)
143143
self.label_info.setText("<i>Tip: You can drag and drop your selection "
144144
"from the resources list to Shape-Out!</i>")
145145

@@ -172,4 +172,4 @@ def set_entry_label(self, row, entry):
172172
item = self.tableWidget.item(row, 0)
173173
api = get_ckan_api()
174174
dcor_url = f"{api.server}/api/3/action/dcserv?id={entry['id']}"
175-
item.setData(Qt.UserRole + 1, dcor_url)
175+
item.setData(Qt.ItemDataRole.UserRole + 1, dcor_url)

dcoraid/gui/download/widget_download.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
import subprocess
1010
import webbrowser
1111

12-
from PyQt5 import uic, QtCore, QtGui, QtWidgets
13-
from PyQt5.QtCore import QStandardPaths
12+
from PyQt6 import uic, QtCore, QtGui, QtWidgets
13+
from PyQt6.QtCore import QStandardPaths
1414

1515
from ...download import DownloadQueue
1616

@@ -37,7 +37,7 @@ def __init__(self, *args, **kwargs):
3737
#: path to persistent shelf to be able to resume uploads on startup
3838
self.shelf_path = os_path.join(
3939
QStandardPaths.writableLocation(
40-
QStandardPaths.AppLocalDataLocation),
40+
QStandardPaths.StandardLocation.AppLocalDataLocation),
4141
"persistent_download_jobs")
4242

4343
#: DownloadQueue instance
@@ -85,7 +85,7 @@ def initialize(self):
8585
@QtCore.pyqtSlot(str, bool)
8686
def download_resource(self, resource_id, condensed=False):
8787
fallback = QStandardPaths.writableLocation(
88-
QStandardPaths.DownloadLocation)
88+
QStandardPaths.StandardLocation.DownloadLocation)
8989
dl_path = self.settings.value("downloads/default path", fallback)
9090
self.widget_jobs.jobs.new_job(resource_id, dl_path, condensed)
9191

@@ -182,14 +182,14 @@ def update_job_status(self):
182182
job.traceback = traceback.format_exc()
183183

184184
QtWidgets.QApplication.processEvents(
185-
QtCore.QEventLoop.AllEvents,
186-
300)
185+
QtCore.QEventLoop.ProcessEventsFlag.AllEvents, 300)
187186

188187
# spacing (did not work in __init__)
189188
header = self.horizontalHeader()
190189
header.setSectionResizeMode(
191-
0, QtWidgets.QHeaderView.ResizeToContents)
192-
header.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
190+
0, QtWidgets.QHeaderView.ResizeMode.ResizeToContents)
191+
header.setSectionResizeMode(
192+
1, QtWidgets.QHeaderView.ResizeMode.Stretch)
193193

194194
self._busy_updating_widgets = False
195195

@@ -219,9 +219,11 @@ def set_actions_item(self, row, col, job):
219219
horz_layout = QtWidgets.QHBoxLayout(widact)
220220
horz_layout.setContentsMargins(2, 0, 2, 0)
221221

222-
spacer = QtWidgets.QSpacerItem(0, 0,
223-
QtWidgets.QSizePolicy.Expanding,
224-
QtWidgets.QSizePolicy.Minimum)
222+
spacer = QtWidgets.QSpacerItem(
223+
0, 0,
224+
QtWidgets.QSizePolicy.Policy.Expanding,
225+
QtWidgets.QSizePolicy.Policy.Minimum
226+
)
225227
horz_layout.addItem(spacer)
226228
if job.state == "error":
227229
actions = [

0 commit comments

Comments
 (0)