WIP: Draft: refactor(omny_alignment_widget): improve type hints #75
@@ -1,33 +1,52 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
from typing import TypedDict
|
||||
from bec_widgets.utils.error_popups import SafeSlot
|
||||
import os
|
||||
from bec_widgets.utils.bec_widget import BECWidget
|
||||
from bec_widgets.utils.ui_loader import UILoader
|
||||
from qtpy.QtWidgets import QWidget, QPushButton, QLineEdit, QLabel, QVBoxLayout
|
||||
from bec_qthemes import material_icon
|
||||
from typing import TYPE_CHECKING, TypedDict
|
||||
|
||||
from bec_lib.logger import bec_logger
|
||||
from bec_qthemes import material_icon
|
||||
from bec_widgets.utils.bec_widget import BECWidget
|
||||
from bec_widgets.utils.error_popups import SafeSlot
|
||||
from bec_widgets.utils.ui_loader import UILoader
|
||||
from qtpy.QtWidgets import QVBoxLayout, QWidget
|
||||
|
||||
logger = bec_logger.logger
|
||||
logger = bec_logger.logger
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from bec_widgets.widgets.plots.image.image import Image
|
||||
from bec_widgets.widgets.utility.toggle.toggle import ToggleSwitch
|
||||
from qtpy.QtWidgets import QLineEdit, QPushButton
|
||||
|
||||
|
||||
# class OmnyAlignmentUIComponents(TypedDict):
|
||||
# moveRightButton: QPushButton
|
||||
# moveLeftButton: QPushButton
|
||||
# moveUpButton: QPushButton
|
||||
# moveDownButton: QPushButton
|
||||
# image: Image
|
||||
class OmnyAlignmentUIComponents(TypedDict):
|
||||
moveRightButton: QPushButton
|
||||
moveLeftButton: QPushButton
|
||||
moveUpButton: QPushButton
|
||||
moveDownButton: QPushButton
|
||||
confirmButton: QPushButton
|
||||
image: Image
|
||||
sampleLineEdit: QLineEdit
|
||||
messageLineEdit: QLineEdit
|
||||
liveViewSwitch: ToggleSwitch
|
||||
|
||||
|
||||
class OmnyAlignment(BECWidget, QWidget):
|
||||
USER_ACCESS = ["enable_live_view", "enable_live_view.setter", "user_message", "user_message.setter","sample_name", "sample_name.setter", "enable_move_buttons", "enable_move_buttons.setter"]
|
||||
USER_ACCESS = [
|
||||
"enable_live_view",
|
||||
"enable_live_view.setter",
|
||||
"user_message",
|
||||
"user_message.setter",
|
||||
"sample_name",
|
||||
"sample_name.setter",
|
||||
"enable_move_buttons",
|
||||
"enable_move_buttons.setter",
|
||||
]
|
||||
PLUGIN = True
|
||||
ui_file = "./omny_alignment.ui"
|
||||
components: OmnyAlignmentUIComponents
|
||||
|
||||
def __init__(self, parent=None, **kwargs):
|
||||
super().__init__(parent=parent, **kwargs)
|
||||
|
||||
self._load_ui()
|
||||
|
||||
def _load_ui(self):
|
||||
@@ -38,102 +57,107 @@ class OmnyAlignment(BECWidget, QWidget):
|
||||
self.setLayout(layout)
|
||||
|
||||
icon_options = {"size": (16, 16), "convert_to_pixmap": False}
|
||||
self.ui.moveRightButton.setText("")
|
||||
self.ui.moveRightButton.setIcon(
|
||||
|
||||
self.components: OmnyAlignmentUIComponents = {
|
||||
"moveRightButton": self.ui.moveRightButton,
|
||||
"moveLeftButton": self.ui.moveLeftButton,
|
||||
"moveUpButton": self.ui.moveUpButton,
|
||||
"moveDownButton": self.ui.moveDownButton,
|
||||
"confirmButton": self.ui.confirmButton,
|
||||
"image": self.ui.image,
|
||||
"sampleLineEdit": self.ui.sampleLineEdit,
|
||||
"messageLineEdit": self.ui.messageLineEdit,
|
||||
"liveViewSwitch": self.ui.liveViewSwitch,
|
||||
}
|
||||
self.components["moveRightButton"].setText("")
|
||||
self.components["moveRightButton"].setIcon(
|
||||
material_icon(icon_name="keyboard_arrow_right", **icon_options)
|
||||
)
|
||||
|
||||
self.ui.moveLeftButton.setText("")
|
||||
self.ui.moveLeftButton.setIcon(
|
||||
self.components["moveLeftButton"].setText("")
|
||||
self.components["moveLeftButton"].setIcon(
|
||||
material_icon(icon_name="keyboard_arrow_left", **icon_options)
|
||||
)
|
||||
|
||||
self.ui.moveUpButton.setText("")
|
||||
self.ui.moveUpButton.setIcon(
|
||||
self.components["moveUpButton"].setText("")
|
||||
self.components["moveUpButton"].setIcon(
|
||||
material_icon(icon_name="keyboard_arrow_up", **icon_options)
|
||||
)
|
||||
|
||||
self.ui.moveDownButton.setText("")
|
||||
self.ui.moveDownButton.setIcon(
|
||||
self.components["moveDownButton"].setText("")
|
||||
self.components["moveDownButton"].setIcon(
|
||||
material_icon(icon_name="keyboard_arrow_down", **icon_options)
|
||||
)
|
||||
|
||||
self.ui.confirmButton.setText("OK")
|
||||
|
||||
|
||||
self.ui.liveViewSwitch.enabled.connect(self.on_live_view_enabled)
|
||||
self.components["confirmButton"].setText("OK")
|
||||
|
||||
self.components["liveViewSwitch"].enabled.connect(self.on_live_view_enabled)
|
||||
|
||||
@property
|
||||
def enable_live_view(self):
|
||||
return self.ui.liveViewSwitch.checked
|
||||
|
||||
@enable_live_view.setter
|
||||
def enable_live_view(self, enable:bool):
|
||||
self.ui.liveViewSwitch.checked = enable
|
||||
return self.components["liveViewSwitch"].checked
|
||||
|
||||
@enable_live_view.setter
|
||||
def enable_live_view(self, enable: bool):
|
||||
self.components["liveViewSwitch"].checked = enable
|
||||
|
||||
@property
|
||||
def user_message(self):
|
||||
return self.ui.messageLineEdit.text()
|
||||
|
||||
return self.components["messageLineEdit"].text()
|
||||
|
||||
@user_message.setter
|
||||
def user_message(self, message:str):
|
||||
self.ui.messageLineEdit.setText(message)
|
||||
def user_message(self, message: str):
|
||||
self.components["messageLineEdit"].setText(message)
|
||||
|
||||
@property
|
||||
def sample_name(self):
|
||||
return self.ui.sampleLineEdit.text()
|
||||
|
||||
@sample_name.setter
|
||||
def sample_name(self, message:str):
|
||||
self.ui.sampleLineEdit.setText(message)
|
||||
return self.components["sampleLineEdit"].text()
|
||||
|
||||
@sample_name.setter
|
||||
def sample_name(self, message: str):
|
||||
self.components["sampleLineEdit"].setText(message)
|
||||
|
||||
@SafeSlot(bool)
|
||||
def on_live_view_enabled(self, enabled:bool):
|
||||
from bec_widgets.widgets.plots.image.image import Image
|
||||
def on_live_view_enabled(self, enabled: bool):
|
||||
logger.info(f"Live view is enabled: {enabled}")
|
||||
image: Image = self.ui.image
|
||||
image = self.components["image"]
|
||||
if enabled:
|
||||
image.image("cam200")
|
||||
return
|
||||
|
||||
|
||||
image.disconnect_monitor("cam200")
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def enable_move_buttons(self):
|
||||
move_up:QPushButton = self.ui.moveUpButton
|
||||
move_down:QPushButton = self.ui.moveDownButton
|
||||
move_left:QPushButton = self.ui.moveLeftButton
|
||||
move_right:QPushButton = self.ui.moveRightButton
|
||||
return move_up.isEnabled() and move_down.isEnabled() and move_left.isEnabled() and move_right.isEnabled()
|
||||
|
||||
move_up: QPushButton = self.components["moveUpButton"]
|
||||
move_down: QPushButton = self.components["moveDownButton"]
|
||||
move_left: QPushButton = self.components["moveLeftButton"]
|
||||
move_right: QPushButton = self.components["moveRightButton"]
|
||||
return (
|
||||
move_up.isEnabled()
|
||||
and move_down.isEnabled()
|
||||
and move_left.isEnabled()
|
||||
and move_right.isEnabled()
|
||||
)
|
||||
|
||||
@enable_move_buttons.setter
|
||||
def enable_move_buttons(self, enabled:bool):
|
||||
move_up:QPushButton = self.ui.moveUpButton
|
||||
move_down:QPushButton = self.ui.moveDownButton
|
||||
move_left:QPushButton = self.ui.moveLeftButton
|
||||
move_right:QPushButton = self.ui.moveRightButton
|
||||
def enable_move_buttons(self, enabled: bool):
|
||||
move_up: QPushButton = self.components["moveUpButton"]
|
||||
move_down: QPushButton = self.components["moveDownButton"]
|
||||
move_left: QPushButton = self.components["moveLeftButton"]
|
||||
move_right: QPushButton = self.components["moveRightButton"]
|
||||
|
||||
move_up.setEnabled(enabled)
|
||||
move_down.setEnabled(enabled)
|
||||
move_left.setEnabled(enabled)
|
||||
move_right.setEnabled(enabled)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from qtpy.QtWidgets import QApplication
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
import sys
|
||||
|
||||
from qtpy.QtWidgets import QApplication
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
widget = OmnyAlignment()
|
||||
|
||||
widget.show()
|
||||
sys.exit(app.exec_())
|
||||
sys.exit(app.exec_())
|
||||
|
||||
@@ -34,6 +34,7 @@ dev = [
|
||||
"pytest",
|
||||
"pytest-random-order",
|
||||
"pytest-redis",
|
||||
"pytest-qt",
|
||||
]
|
||||
|
||||
[project.entry-points."bec"]
|
||||
@@ -55,6 +56,9 @@ plugin_ipython_client_post = "csaxs_bec.bec_ipython_client.startup"
|
||||
[project.entry-points."bec.widgets.user_widgets"]
|
||||
plugin_widgets = "csaxs_bec.bec_widgets.widgets"
|
||||
|
||||
[project.entry-points."bec.widgets.auto_updates"]
|
||||
plugin_widgets_update = "csaxs_bec.bec_widgets.auto_updates"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
include = ["*"]
|
||||
|
||||
|
||||
83
tests/tests_bec_widgets/conftest.py
Normal file
83
tests/tests_bec_widgets/conftest.py
Normal file
@@ -0,0 +1,83 @@
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from bec_widgets.cli.rpc.rpc_register import RPCRegister
|
||||
from bec_widgets.utils import bec_dispatcher as bec_dispatcher_module
|
||||
from bec_widgets.utils import error_popups
|
||||
from pytestqt.exceptions import TimeoutError as QtBotTimeoutError
|
||||
from qtpy.QtWidgets import QApplication
|
||||
|
||||
|
||||
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
|
||||
def pytest_runtest_makereport(item, call):
|
||||
# execute all other hooks to obtain the report object
|
||||
outcome = yield
|
||||
rep = outcome.get_result()
|
||||
|
||||
item.stash["failed"] = rep.failed
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def qapplication(qtbot, request): # pylint: disable=unused-argument
|
||||
yield
|
||||
|
||||
# if the test failed, we don't want to check for open widgets as
|
||||
# it simply pollutes the output
|
||||
if request.node.stash._storage.get("failed"):
|
||||
print("Test failed, skipping cleanup checks")
|
||||
return
|
||||
bec_dispatcher = bec_dispatcher_module.BECDispatcher()
|
||||
bec_dispatcher.stop_cli_server()
|
||||
|
||||
qapp = QApplication.instance()
|
||||
qapp.processEvents()
|
||||
if hasattr(qapp, "os_listener") and qapp.os_listener:
|
||||
qapp.removeEventFilter(qapp.os_listener)
|
||||
try:
|
||||
qtbot.waitUntil(lambda: qapp.topLevelWidgets() == [])
|
||||
except QtBotTimeoutError as exc:
|
||||
raise TimeoutError(f"Failed to close all widgets: {qapp.topLevelWidgets()}") from exc
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def rpc_register():
|
||||
yield RPCRegister()
|
||||
RPCRegister.reset_singleton()
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def bec_dispatcher(threads_check): # pylint: disable=unused-argument
|
||||
bec_dispatcher = bec_dispatcher_module.BECDispatcher()
|
||||
yield bec_dispatcher
|
||||
bec_dispatcher.disconnect_all()
|
||||
# clean BEC client
|
||||
bec_dispatcher.client.shutdown()
|
||||
# stop the cli server
|
||||
bec_dispatcher.stop_cli_server()
|
||||
# reinitialize singleton for next test
|
||||
bec_dispatcher_module.BECDispatcher.reset_singleton()
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def clean_singleton():
|
||||
error_popups._popup_utility_instance = None
|
||||
|
||||
|
||||
def create_widget(qtbot, widget, *args, **kwargs):
|
||||
"""
|
||||
Create a widget and add it to the qtbot for testing. This is a helper function that
|
||||
should be used in all tests that require a widget to be created.
|
||||
|
||||
Args:
|
||||
qtbot (fixture): pytest-qt fixture
|
||||
widget (QWidget): widget class to be created
|
||||
*args: positional arguments for the widget
|
||||
**kwargs: keyword arguments for the widget
|
||||
|
||||
Returns:
|
||||
QWidget: the created widget
|
||||
"""
|
||||
widget = widget(*args, **kwargs)
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
return widget
|
||||
35
tests/tests_bec_widgets/test_omny_alignment.py
Normal file
35
tests/tests_bec_widgets/test_omny_alignment.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import pytest
|
||||
|
||||
from csaxs_bec.bec_widgets.widgets.omny_alignment.omny_alignment import OmnyAlignment
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def omny_alignment(qtbot):
|
||||
widget = OmnyAlignment()
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
return widget
|
||||
|
||||
|
||||
def test_omny_alignment_set_user_message(omny_alignment):
|
||||
"""
|
||||
Test the set_user_message method of the OmnyAlignment widget.
|
||||
"""
|
||||
# Set a message
|
||||
message = "Test message"
|
||||
omny_alignment.user_message = message
|
||||
|
||||
# Check if the message is set correctly
|
||||
assert omny_alignment.components["messageLineEdit"].text() == message
|
||||
|
||||
|
||||
def test_omny_alignment_set_sample_name(omny_alignment):
|
||||
"""
|
||||
Test the set_sample_name method of the OmnyAlignment widget.
|
||||
"""
|
||||
# Set a sample name
|
||||
sample_name = "Test sample"
|
||||
omny_alignment.sample_name = sample_name
|
||||
|
||||
# Check if the sample name is set correctly
|
||||
assert omny_alignment.components["sampleLineEdit"].text() == sample_name
|
||||
Reference in New Issue
Block a user