Skip to content

Commit 952af32

Browse files
committed
Switch to PyQt6 + Python3.13 typing + formatting
1 parent 7f62637 commit 952af32

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+389
-1118
lines changed

setup.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def readme():
2727
"matplotlib==3.4.3",
2828
"numpy==1.21.0",
2929
"opencv-python",
30-
"PyQt5>=5.15.2",
30+
"PyQt6>=6.4.0",
3131
"pypylon==1.7.2",
3232
"zarr==2.10.1",
3333
"pigpio==1.78",
@@ -36,7 +36,7 @@ def readme():
3636
"adafruit-circuitpython-sht31d",
3737
"argparse",
3838
"pimoroni-ioexpander",
39-
"qimage2ndarray==1.9.0",
39+
"qimage2ndarray>=1.10.0",
4040
"py_cameras @ git+https://github.com/czbiohub/pyCameras@master",
4141
"pymotors @ git+https://github.com/czbiohub/PyMotors@master",
4242
"stats_utils @ git+https://github.com/czbiohub-sf/[email protected]",
@@ -55,7 +55,7 @@ def readme():
5555
"black==23.1.0",
5656
"mypy==1.0.1",
5757
"mypy-extensions==1.0.0",
58-
"PyQt5-stubs",
58+
"PyQt6-stubs",
5959
"ruff==0.0.253",
6060
]
6161
},

ulc_mm_package/QtGUI/acquisition.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import logging
88
import numpy as np
99

10-
from PyQt5.QtCore import (
10+
from PyQt6.QtCore import (
1111
QObject,
1212
QTimer,
1313
pyqtSignal,
@@ -40,11 +40,11 @@ def __init__(self):
4040
@pyqtSlot()
4141
def create_timers(self):
4242
self.acquisition_timer = QTimer()
43-
self.acquisition_timer.setTimerType(Qt.PreciseTimer)
43+
self.acquisition_timer.setTimerType(Qt.TimerType.PreciseTimer)
4444
self.acquisition_timer.timeout.connect(self.get_img)
4545

4646
self.liveview_timer = QTimer()
47-
self.liveview_timer.setTimerType(Qt.PreciseTimer)
47+
self.liveview_timer.setTimerType(Qt.TimerType.PreciseTimer)
4848
self.liveview_timer.timeout.connect(self.send_img)
4949

5050
self.logger.info("Created acquisition and liveview timers.")

ulc_mm_package/QtGUI/clickablelineedit.py

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

44

55
class ClickableLineEdit(QLineEdit):

ulc_mm_package/QtGUI/dev_run.py

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
import sys
66
import traceback
77
import subprocess
8-
from typing import Dict
98
from time import perf_counter, sleep
109

1110
import cv2
1211
import numpy as np
13-
from PyQt5 import QtWidgets, uic # type: ignore
14-
from PyQt5.QtCore import Qt, QThread, pyqtSignal, pyqtSlot
15-
from PyQt5.QtGui import QImage, QPixmap
12+
from PyQt6 import QtWidgets, uic # type: ignore
13+
from PyQt6.QtCore import QThread, pyqtSignal, pyqtSlot
14+
from PyQt6.QtGui import QImage, QPixmap
1615
from qimage2ndarray import gray2qimage
1716
from gpiozero import CPUTemperature
1817

@@ -64,8 +63,6 @@
6463

6564
cpu = CPUTemperature()
6665

67-
QtWidgets.QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
68-
6966
# Qt GUI Files
7067
curr_dir = Path(__file__).parent.resolve() # Get full path
7168
os.chdir(curr_dir)
@@ -149,7 +146,7 @@ def _initializeAttributes(self, external_dir: str, mscope: MalariaScope):
149146
self.autofocus_model = AutoFocus()
150147
except RuntimeError as e:
151148
raise RuntimeError(
152-
f'got {str(e)}:\n {subprocess.getoutput("lsusb | grep Myriad")}'
149+
f"got {str(e)}:\n {subprocess.getoutput('lsusb | grep Myriad')}"
153150
)
154151
self.active_autofocus = False
155152
self.prev_autofocus_time = 0.0
@@ -182,7 +179,7 @@ def run(self):
182179
print(e)
183180
print(traceback.format_exc())
184181

185-
def getMetadata(self) -> Dict:
182+
def getMetadata(self) -> dict:
186183
"""Required metadata:
187184
- Measurement type (actual diagnostic experiment or data collection)
188185
- Sample type / sample name (i.e dataset name)
@@ -466,7 +463,7 @@ def __init__(self, *args, **kwargs):
466463
"ERROR! No external harddrive / SSD detected. Press OK to continue, cancel to quit.",
467464
cancel=True,
468465
)
469-
if retval == QtWidgets.QMessageBox.Ok:
466+
if retval == QtWidgets.QMessageBox.StandardButton.Ok:
470467
self.external_dir = None
471468
else:
472469
quit()
@@ -646,10 +643,11 @@ def _displayMessageBox(self, icon, title, text, cancel):
646643
msgBox.setText(f"{text}")
647644
if cancel:
648645
msgBox.setStandardButtons(
649-
QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel
646+
QtWidgets.QMessageBox.StandardButton.Ok
647+
| QtWidgets.QMessageBox.StandardButton.Cancel
650648
)
651649
else:
652-
msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok)
650+
msgBox.setStandardButtons(QtWidgets.QMessageBox.StandardButton.Ok)
653651
return msgBox.exec()
654652

655653
def txtBoxFocusGotFocus(self):
@@ -700,7 +698,7 @@ def btnSnapHandler(self):
700698
start_time = self.acquisitionThread.start_time
701699
num_images = self.acquisitionThread.im_counter
702700
print(
703-
f"{num_images} images taken in {end_time - start_time:.2f}s ({num_images / (end_time-start_time):.2f} fps)"
701+
f"{num_images} images taken in {end_time - start_time:.2f}s ({num_images / (end_time - start_time):.2f} fps)"
704702
)
705703

706704
return
@@ -947,7 +945,7 @@ def btnFullZStackHandler(self):
947945
cancel=True,
948946
)
949947

950-
if retval == QtWidgets.QMessageBox.Ok:
948+
if retval == QtWidgets.QMessageBox.StandardButton.Ok:
951949
self.disableMotorUIElements()
952950
self.acquisitionThread.runFullZStack()
953951

@@ -967,7 +965,7 @@ def btnLocalZStackHandler(self):
967965
cancel=True,
968966
)
969967

970-
if retval == QtWidgets.QMessageBox.Ok:
968+
if retval == QtWidgets.QMessageBox.StandardButton.Ok:
971969
self.disableMotorUIElements()
972970
self.acquisitionThread.runLocalZStack()
973971

@@ -1142,7 +1140,7 @@ def exit(self):
11421140
cancel=True,
11431141
)
11441142

1145-
if retval == QtWidgets.QMessageBox.Ok:
1143+
if retval == QtWidgets.QMessageBox.StandardButton.Ok:
11461144
# Move syringe back and de-energize
11471145
self.pneumatic_module.close()
11481146

@@ -1171,7 +1169,7 @@ def main():
11711169
app = QtWidgets.QApplication(sys.argv)
11721170
main_window = MalariaScopeGUI()
11731171
main_window.show()
1174-
app.exec_()
1172+
app.exec()
11751173
finally:
11761174
main_window.mscope.shutoff()
11771175

ulc_mm_package/QtGUI/dev_run.ui

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,7 @@
788788
<customwidget>
789789
<class>ClickableLineEdit</class>
790790
<extends>QLineEdit</extends>
791-
<header>clickablelineedit.h</header>
791+
<header>clickablelineedit</header>
792792
</customwidget>
793793
</customwidgets>
794794
<resources/>

ulc_mm_package/QtGUI/form_gui.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
import sys
88

9-
from PyQt5.QtWidgets import (
9+
from PyQt6.QtCore import QRect, pyqtSignal
10+
from PyQt6.QtGui import QIcon
11+
from PyQt6.QtWidgets import (
1012
QApplication,
1113
QDialog,
1214
QGridLayout,
@@ -15,10 +17,7 @@
1517
QLineEdit,
1618
QPlainTextEdit,
1719
QComboBox,
18-
QDesktopWidget,
1920
)
20-
from PyQt5.QtGui import QIcon
21-
from PyQt5.QtCore import pyqtSignal
2221

2322
from ulc_mm_package.scope_constants import EXPERIMENT_METADATA_KEYS
2423
from ulc_mm_package.image_processing.processing_constants import TARGET_FLOWRATE
@@ -60,13 +59,20 @@ def _load_ui(self):
6059
self.setWindowTitle("Experiment form")
6160

6261
# Get screen parameters
63-
self.screen = QDesktopWidget().screenGeometry()
62+
screen = QApplication.primaryScreen()
63+
if screen is not None:
64+
self.screen = screen.geometry()
65+
available_geometry = screen.availableGeometry()
66+
else:
67+
self.screen = QRect(0, 0, 800, 480)
68+
available_geometry = self.screen
69+
6470
if self.screen.height() > 480:
6571
self.setGeometry(0, 0, 675, 500)
6672

6773
# Move window to middle of screen
6874
window_geometry = self.frameGeometry()
69-
centerpoint = QDesktopWidget().availableGeometry().center()
75+
centerpoint = available_geometry.center()
7076
window_geometry.moveCenter(centerpoint)
7177
self.move(window_geometry.topLeft())
7278
else:
@@ -196,4 +202,4 @@ def sf(self) -> None:
196202
print(gui.get_form_input())
197203

198204
gui.show()
199-
sys.exit(app.exec_())
205+
sys.exit(app.exec())

ulc_mm_package/QtGUI/liveview_gui.py

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44

55
import sys
66
from functools import partial
7-
from typing import List, NamedTuple, Dict, Tuple
7+
from typing import NamedTuple
88
from time import strftime, gmtime
99

1010
from qimage2ndarray import gray2qimage
1111
import numpy as np
1212

13-
from PyQt5.QtWidgets import (
13+
from PyQt6.QtCore import Qt, pyqtSlot, pyqtSignal, QSize, QRect
14+
from PyQt6.QtGui import QPixmap, QIcon
15+
from PyQt6.QtWidgets import (
1416
QApplication,
1517
QMainWindow,
1618
QGridLayout,
@@ -27,10 +29,7 @@
2729
QPlainTextEdit,
2830
QPushButton,
2931
QScrollBar,
30-
QDesktopWidget,
3132
)
32-
from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal, QSize
33-
from PyQt5.QtGui import QPixmap, QIcon
3433

3534
from ulc_mm_package.image_processing.flow_control import get_flow_error
3635

@@ -59,8 +58,8 @@ class ThumbnailDisplay(NamedTuple):
5958
class_name: str
6059
class_id: int
6160
list_widget: QListWidget
62-
list_widget_conf_labels: List[QLabel]
63-
list_widget_img_labels: List[QLabel]
61+
list_widget_conf_labels: list[QLabel]
62+
list_widget_img_labels: list[QLabel]
6463

6564

6665
class LiveviewGUI(QMainWindow):
@@ -72,7 +71,12 @@ def __init__(self):
7271
self.target_flowrate = None
7372

7473
# Get screen parameters
75-
self.screen = QDesktopWidget().screenGeometry()
74+
screen = QApplication.primaryScreen()
75+
if screen is not None:
76+
self.screen = screen.geometry()
77+
else:
78+
self.screen = QRect(0, 0, 800, 480)
79+
7680
if self.screen.height() > 480:
7781
self.big_screen = True
7882
else:
@@ -225,8 +229,8 @@ def clear_thumbnails(self):
225229
@pyqtSlot(object)
226230
def update_thumbnails(
227231
self,
228-
tuple_of_dict_of_thumbnails: Tuple[
229-
Dict[int, List[Thumbnail]], Dict[int, List[Thumbnail]]
232+
tuple_of_dict_of_thumbnails: tuple[
233+
dict[int, list[Thumbnail]], dict[int, list[Thumbnail]]
230234
],
231235
):
232236
max_confs = tuple_of_dict_of_thumbnails[0]
@@ -350,14 +354,14 @@ def _load_infopanel_ui(self):
350354
self.flowrate_val = QLabel("-")
351355

352356
# Set title alignments
353-
self.state_lbl.setAlignment(Qt.AlignCenter)
354-
self.cell_count_title.setAlignment(Qt.AlignCenter)
355-
self.focus_title.setAlignment(Qt.AlignCenter)
356-
self.flowrate_title.setAlignment(Qt.AlignCenter)
357-
self.tcp_lbl.setAlignment(Qt.AlignCenter)
358-
self.end_of_run_progress_bar.setAlignment(Qt.AlignCenter)
357+
self.state_lbl.setAlignment(Qt.AlignmentFlag.AlignCenter)
358+
self.cell_count_title.setAlignment(Qt.AlignmentFlag.AlignCenter)
359+
self.focus_title.setAlignment(Qt.AlignmentFlag.AlignCenter)
360+
self.flowrate_title.setAlignment(Qt.AlignmentFlag.AlignCenter)
361+
self.tcp_lbl.setAlignment(Qt.AlignmentFlag.AlignCenter)
362+
self.end_of_run_progress_bar.setAlignment(Qt.AlignmentFlag.AlignCenter)
359363
self.end_of_run_progress_bar.setStyleSheet(
360-
"QProgressBar::chunk " "{" "background-color: green;" "}"
364+
"QProgressBar::chunk {background-color: green;}"
361365
)
362366

363367
# Setup column size
@@ -429,7 +433,7 @@ def _load_liveview_ui(self):
429433
# Populate liveview tab
430434
self.liveview_img = QLabel()
431435

432-
self.liveview_img.setAlignment(Qt.AlignCenter)
436+
self.liveview_img.setAlignment(Qt.AlignmentFlag.AlignCenter)
433437
self.liveview_img.setMinimumSize(1, 1)
434438
self.liveview_img.setScaledContents(True)
435439

@@ -443,22 +447,27 @@ def _load_thumbnail_ui(self):
443447

444448
# Populate thumbnail tab
445449
class_labels = [QLabel(c.capitalize()) for c in CLASSES_TO_DISPLAY]
446-
[label.setAlignment(Qt.AlignVCenter | Qt.AlignLeft) for label in class_labels]
450+
[
451+
label.setAlignment(
452+
Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignLeft
453+
)
454+
for label in class_labels
455+
]
447456

448-
self.max_and_min_conf_thumbnail_displays: Dict[str, List[ThumbnailDisplay]] = {
457+
self.max_and_min_conf_thumbnail_displays: dict[str, list[ThumbnailDisplay]] = {
449458
"max_conf": [],
450459
"min_conf": [],
451460
}
452461
for k in self.max_and_min_conf_thumbnail_displays.keys():
453-
thumbnail_lists: List[ThumbnailDisplay] = []
462+
thumbnail_lists: list[ThumbnailDisplay] = []
454463
for i, c in enumerate(CLASSES_TO_DISPLAY):
455464
class_id = CLASS_IDS[i]
456465
class_name = c
457-
conf_labels: List[QLabel] = []
458-
img_labels: List[QLabel] = []
466+
conf_labels: list[QLabel] = []
467+
img_labels: list[QLabel] = []
459468

460469
list_widget = QListWidget()
461-
list_widget.setFlow(QListView.LeftToRight)
470+
list_widget.setFlow(QListView.Flow.LeftToRight)
462471
list_widget.setContentsMargins(0, 0, 0, 0)
463472

464473
for i in range(MAX_THUMBNAILS):
@@ -470,19 +479,21 @@ def _load_thumbnail_ui(self):
470479
)
471480

472481
conf_label = QLabel()
473-
conf_label.setAlignment(Qt.AlignBottom | Qt.AlignHCenter)
482+
conf_label.setAlignment(
483+
Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignHCenter
484+
)
474485

475486
img_label = QLabel()
476487
conf_labels.append(conf_label)
477488
img_labels.append(img_label)
478489

479490
layout.addWidget(conf_label)
480491
layout.addWidget(img_label)
481-
layout.setAlignment(Qt.AlignVCenter)
492+
layout.setAlignment(Qt.AlignmentFlag.AlignVCenter)
482493
w.setLayout(layout)
483494

484495
v = QListWidgetItem()
485-
v.setFlags(Qt.NoItemFlags)
496+
v.setFlags(Qt.ItemFlag.NoItemFlags)
486497
qs = QSize()
487498
qs.setHeight(MIN_THUMBNAIL_DISPLAY_SIZE)
488499
qs.setWidth(MIN_THUMBNAIL_DISPLAY_SIZE)
@@ -617,4 +628,4 @@ def _load_metadata_ui(self):
617628

618629
gui.showMaximized()
619630
gui.exit_btn.clicked.connect(gui.close)
620-
sys.exit(app.exec_())
631+
sys.exit(app.exec())

0 commit comments

Comments
 (0)