Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
110b27351b | ||
| 37aa371e7c | |||
| eb54e9f788 | |||
|
|
482efeb340 | ||
| 99ee545e41 | |||
| cf94599c25 | |||
| b50b3a27e6 | |||
| bf6294ecbf | |||
| a3d4f5ac4b | |||
| bc264975b1 | |||
| ad07bbf85e | |||
| 9856857f4c | |||
| f9e5897900 | |||
|
|
39fb22b716 | ||
| a372925fff | |||
|
|
ec54440569 | ||
| af86860bf3 | |||
| 302ae90139 | |||
|
|
1405068925 | ||
| 5aad401ef8 |
116
CHANGELOG.md
@@ -1,5 +1,61 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v0.93.4 (2024-08-07)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix: rename DeviceBox to PositionerBox, fix test for validation ([`37aa371`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/37aa371e7c4c62d70abf37abc125db0c088790fe))
|
||||
|
||||
* fix: add validation for bec_lib.device.Positioner; closes #268 ([`eb54e9f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/eb54e9f788e97af23db8fe0c78f8facb8688bb99))
|
||||
|
||||
## v0.93.3 (2024-08-07)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(dock): properly shut down docks and temp areas ([`99ee545`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/99ee545e41c6078654958b668b5b329f85553d16))
|
||||
|
||||
* fix(settings): shut down settings dialog ([`b50b3a2`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/b50b3a27e68956e10e8169a0aa698c911d2d9642))
|
||||
|
||||
* fix(website): fixed teardown of website widgets ([`a3d4f5a`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/a3d4f5ac4bc52acfed2791a1724fade6972ed320))
|
||||
|
||||
* fix(dock): properly shut down docks and dock areas ([`bc26497`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/bc264975b1363c9dfea516621d7878c320677d15))
|
||||
|
||||
* fix(figure): cleanup pyqtgraph ([`ad07bbf`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ad07bbf85e9c8d9838bdd686f69d41c235b7db19))
|
||||
|
||||
### Test
|
||||
|
||||
* test: removed quit from teardown ([`cf94599`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/cf94599c2544d6831c8afbe7b340082077557ed1))
|
||||
|
||||
* test: removed explicit call to close the widget ([`bf6294e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/bf6294ecbfd494565d2dc215e4d7e0c280ac7745))
|
||||
|
||||
* test: use factory instead of fixture to properly cleanup widgets on teardown ([`9856857`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/9856857f4cc7fa229c10d00fbae4452464a207cb))
|
||||
|
||||
* test: ensure all toplevelwidgets are closed ([`f9e5897`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/f9e58979009cf632feea529700ad191401dd7eb8))
|
||||
|
||||
## v0.93.2 (2024-08-07)
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(scan_group_box): Scan Spinboxes limits increased to max allowed values; setting dialog for step size and decimal precision for ScanDoubleSpinBox on right click ([`a372925`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/a372925fffa787c686198ae7cb3f9c15b459c109))
|
||||
|
||||
## v0.93.1 (2024-08-06)
|
||||
|
||||
### Documentation
|
||||
|
||||
* docs: added video tutorial section with BSEG YT video ([`302ae90`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/302ae90139f6a88e2401fe29fe312387486e27a9))
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(dock): docks have more recognizable red icon for closing docks ([`af86860`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/af86860bf35474805fb1a7bc3725cf8835ed4cc7))
|
||||
|
||||
## v0.93.0 (2024-08-05)
|
||||
|
||||
### Feature
|
||||
|
||||
* feat(themes): moved themes to bec_qthemes
|
||||
|
||||
This reverts commit fd6ae91993a23a7b8dbb2cf3c4b7c3eda6d2b0f6 ([`5aad401`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/5aad401ef8774c7330784f72cd3b9d8c253e2b6a))
|
||||
|
||||
## v0.92.5 (2024-08-05)
|
||||
|
||||
### Fix
|
||||
@@ -80,10 +136,6 @@
|
||||
|
||||
* feat(dock_area): plugin added ([`a16b87a`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/a16b87ac28d164230dd2e8020f50ff3a63cd407e))
|
||||
|
||||
* feat(dock_area): Added toolbar to dock area to add widgets without CLI interactions ([`cce1367`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/cce1367a72fca7206d351894bd1831b7bbfa7ec6))
|
||||
|
||||
* feat(toolbar): expandable menu actions ([`28f26e9`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/28f26e92a46063db1a194be552156a5d3b2c43e7))
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(status_item): icons changed to material design ([`1b9c55a`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/1b9c55a46a0dfd8678c8e95ff64dd6e8cfb9233e))
|
||||
@@ -93,59 +145,3 @@
|
||||
### Test
|
||||
|
||||
* test(dock_area): tests extended ([`06fab0e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/06fab0eab926cef5677d4988fd1fce09da342dd8))
|
||||
|
||||
## v0.90.0 (2024-07-23)
|
||||
|
||||
### Feature
|
||||
|
||||
* feat(image_widget): plugin added ([`4371168`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/43711680ba253f81fb0ffe764bcaae701b02bb49))
|
||||
|
||||
* feat(image_widget): all toolbar actions added ([`501eb92`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/501eb923f12fa6aaa93f5428ca78e57694edfbc0))
|
||||
|
||||
* feat(image_widget): image_widget added ([`6a9317f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6a9317facda896ee784c7fc1db0cd3d68cdfcf73))
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(axis_setting): fix compatibility for issue with horizontal line for PyQt6 ([`1cf6e32`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/1cf6e32303f82bc7c3f3391d0e96a88bc31f29fc))
|
||||
|
||||
* fix(image_widget): image_widget autorange fixed ([`7f49893`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/7f49893d2ce3b9d02efa764f7f10442ed6ab8f3c))
|
||||
|
||||
* fix(image_widget): image widget adjusted ([`3d2ca48`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/3d2ca4855c36fe0af59a4b540caa3c8023a81773))
|
||||
|
||||
* fix(image): only single monitor image is allowed ([`fe7e542`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/fe7e542b19dc5b401523501acb74ac03edf62ad4))
|
||||
|
||||
* fix(image): raw data are saved in image item to always have precise processing ([`c15035b`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/c15035b6b769a96780a16da9e7f75af3b823654c))
|
||||
|
||||
### Refactor
|
||||
|
||||
* refactor(jupyter_console_example): added examples of standalone widgets ([`ba0d1ea`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ba0d1ea9031b4ae2e2e73bf269fbfad973b924a5))
|
||||
|
||||
### Test
|
||||
|
||||
* test(image_widget): tests added ([`70fb276`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/70fb276fdf31dffc105435d3dfe7c5caea0b10ce))
|
||||
|
||||
## v0.89.0 (2024-07-22)
|
||||
|
||||
### Feature
|
||||
|
||||
* feat(themes): moved themes to bec_qthemes ([`3798714`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/3798714369adf4023f833b7749d2f46a0ec74eee))
|
||||
|
||||
### Unknown
|
||||
|
||||
* Revert "feat(themes): moved themes to bec_qthemes"
|
||||
|
||||
This reverts commit 3798714369adf4023f833b7749d2f46a0ec74eee ([`fd6ae91`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/fd6ae91993a23a7b8dbb2cf3c4b7c3eda6d2b0f6))
|
||||
|
||||
## v0.88.1 (2024-07-22)
|
||||
|
||||
### Documentation
|
||||
|
||||
* docs: readthedocs icon path fixed ([`2bcaa42`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/2bcaa4256d6daaefacb3ead8c72458d7b1498e29))
|
||||
|
||||
### Fix
|
||||
|
||||
* fix(plot_base): set_xy autorange moved to plotbase from waveform ([`a3dff7d`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/a3dff7decc16115c12dc6b4ef1572552368da309))
|
||||
|
||||
### Refactor
|
||||
|
||||
* refactor(toolbar): generalizations of the ToolBarAction ([`ad112d1`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ad112d1f08157f6987edd48a0bacf9f669ef1997))
|
||||
|
||||
@@ -21,9 +21,9 @@ class Widgets(str, enum.Enum):
|
||||
BECQueue = "BECQueue"
|
||||
BECStatusBox = "BECStatusBox"
|
||||
BECWaveformWidget = "BECWaveformWidget"
|
||||
DeviceBox = "DeviceBox"
|
||||
DeviceComboBox = "DeviceComboBox"
|
||||
DeviceLineEdit = "DeviceLineEdit"
|
||||
PositionerBox = "PositionerBox"
|
||||
RingProgressBar = "RingProgressBar"
|
||||
ScanControl = "ScanControl"
|
||||
StopButton = "StopButton"
|
||||
@@ -2287,24 +2287,6 @@ class BECWaveformWidget(RPCBase):
|
||||
"""
|
||||
|
||||
|
||||
class DeviceBox(RPCBase):
|
||||
@property
|
||||
@rpc_call
|
||||
def _config_dict(self) -> "dict":
|
||||
"""
|
||||
Get the configuration of the widget.
|
||||
|
||||
Returns:
|
||||
dict: The configuration of the widget.
|
||||
"""
|
||||
|
||||
@rpc_call
|
||||
def _get_all_rpc(self) -> "dict":
|
||||
"""
|
||||
Get all registered RPC objects.
|
||||
"""
|
||||
|
||||
|
||||
class DeviceComboBox(RPCBase):
|
||||
@property
|
||||
@rpc_call
|
||||
@@ -2359,6 +2341,17 @@ class DeviceLineEdit(RPCBase):
|
||||
"""
|
||||
|
||||
|
||||
class PositionerBox(RPCBase):
|
||||
@rpc_call
|
||||
def set_positioner(self, positioner: str):
|
||||
"""
|
||||
Set the device
|
||||
|
||||
Args:
|
||||
positioner (Positioner | str) : Positioner to set, accepts str or the device
|
||||
"""
|
||||
|
||||
|
||||
class Ring(RPCBase):
|
||||
@rpc_call
|
||||
def _get_all_rpc(self) -> "dict":
|
||||
|
||||
@@ -106,3 +106,14 @@ class SettingsDialog(QDialog):
|
||||
Apply the changes made in the settings widget without closing the dialog.
|
||||
"""
|
||||
self.widget.accept_changes()
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
Cleanup the dialog.
|
||||
"""
|
||||
self.button_box.close()
|
||||
self.button_box.deleteLater()
|
||||
|
||||
def closeEvent(self, event):
|
||||
self.cleanup()
|
||||
super().closeEvent(event)
|
||||
|
||||
@@ -2,11 +2,10 @@ import itertools
|
||||
import re
|
||||
from typing import Literal
|
||||
|
||||
import bec_qthemes
|
||||
import numpy as np
|
||||
import pyqtgraph as pg
|
||||
import qdarkstyle
|
||||
from pydantic_core import PydanticCustomError
|
||||
from qdarkstyle import DarkPalette, LightPalette
|
||||
from qtpy.QtGui import QColor
|
||||
from qtpy.QtWidgets import QApplication
|
||||
|
||||
@@ -14,7 +13,7 @@ CURRENT_THEME = "dark"
|
||||
|
||||
|
||||
def get_theme_palette():
|
||||
return DarkPalette if CURRENT_THEME == "dark" else LightPalette
|
||||
return bec_qthemes.load_palette(CURRENT_THEME)
|
||||
|
||||
|
||||
def apply_theme(theme: Literal["dark", "light"]):
|
||||
@@ -30,7 +29,7 @@ def apply_theme(theme: Literal["dark", "light"]):
|
||||
pg_widget.setBackground("k" if theme == "dark" else "w")
|
||||
|
||||
# now define stylesheet according to theme and apply it
|
||||
style = qdarkstyle.load_stylesheet(palette=get_theme_palette())
|
||||
style = bec_qthemes.load_stylesheet(theme)
|
||||
app.setStyleSheet(style)
|
||||
|
||||
|
||||
|
||||
@@ -34,3 +34,10 @@ class ColorButton(pg.ColorButton):
|
||||
return self.color().getRgb()
|
||||
if format == "HEX":
|
||||
return self.color().name()
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
Clean up the ColorButton.
|
||||
"""
|
||||
self.colorDialog.close()
|
||||
self.colorDialog.deleteLater()
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{'files': ['device_box.py']}
|
||||
@@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Any, Literal, Optional
|
||||
|
||||
from pydantic import Field
|
||||
from pyqtgraph.dockarea import Dock, DockLabel
|
||||
from qtpy import QtCore, QtGui
|
||||
|
||||
from bec_widgets.cli.rpc_wigdet_handler import widget_handler
|
||||
from bec_widgets.utils import ConnectionConfig, GridLayoutManager
|
||||
@@ -12,8 +13,6 @@ from bec_widgets.utils.bec_widget import BECWidget
|
||||
if TYPE_CHECKING:
|
||||
from qtpy.QtWidgets import QWidget
|
||||
|
||||
from bec_widgets.widgets.dock import BECDockArea
|
||||
|
||||
|
||||
class DockConfig(ConnectionConfig):
|
||||
widgets: dict[str, Any] = Field({}, description="The widgets in the dock.")
|
||||
@@ -26,6 +25,23 @@ class DockConfig(ConnectionConfig):
|
||||
|
||||
|
||||
class CustomDockLabel(DockLabel):
|
||||
def __init__(self, text: str, closable: bool = True):
|
||||
super().__init__(text, closable)
|
||||
if closable:
|
||||
red_icon = QtGui.QIcon()
|
||||
pixmap = QtGui.QPixmap(32, 32)
|
||||
pixmap.fill(QtCore.Qt.GlobalColor.red)
|
||||
painter = QtGui.QPainter(pixmap)
|
||||
pen = QtGui.QPen(QtCore.Qt.GlobalColor.white)
|
||||
pen.setWidth(2)
|
||||
painter.setPen(pen)
|
||||
painter.drawLine(8, 8, 24, 24)
|
||||
painter.drawLine(24, 8, 8, 24)
|
||||
painter.end()
|
||||
red_icon.addPixmap(pixmap)
|
||||
|
||||
self.closeButton.setIcon(red_icon)
|
||||
|
||||
def updateStyle(self):
|
||||
r = "3px"
|
||||
if self.dim:
|
||||
@@ -137,6 +153,7 @@ class BECDock(BECWidget, Dock):
|
||||
super().dropEvent(event)
|
||||
if old_area in self.orig_area.tempAreas and old_area != self.orig_area:
|
||||
self.orig_area.removeTempArea(old_area)
|
||||
old_area.window().deleteLater()
|
||||
|
||||
def float(self):
|
||||
"""
|
||||
@@ -268,7 +285,7 @@ class BECDock(BECWidget, Dock):
|
||||
"""
|
||||
Attach the dock to the parent dock area.
|
||||
"""
|
||||
self.orig_area.removeTempArea(self.area)
|
||||
self.parent_dock_area.remove_temp_area(self.area)
|
||||
|
||||
def detach(self):
|
||||
"""
|
||||
@@ -303,6 +320,8 @@ class BECDock(BECWidget, Dock):
|
||||
if hasattr(widget, "cleanup"):
|
||||
widget.cleanup()
|
||||
self.widgets.clear()
|
||||
self.label.close()
|
||||
self.label.deleteLater()
|
||||
super().cleanup()
|
||||
|
||||
def close(self):
|
||||
|
||||
@@ -83,8 +83,8 @@ class BECDockArea(BECWidget, QWidget):
|
||||
"scan_control": IconAction(
|
||||
icon_path="scan_control.svg", tooltip="Add Scan Control"
|
||||
),
|
||||
"device_box": IconAction(
|
||||
icon_path="device_box.svg", tooltip="Add Device Box"
|
||||
"positioner_box": IconAction(
|
||||
icon_path="positioner_box.svg", tooltip="Add Device Box"
|
||||
),
|
||||
},
|
||||
),
|
||||
@@ -132,8 +132,8 @@ class BECDockArea(BECWidget, QWidget):
|
||||
self.toolbar.widgets["menu_devices"].widgets["scan_control"].triggered.connect(
|
||||
lambda: self.add_dock(widget="ScanControl", prefix="scan_control")
|
||||
)
|
||||
self.toolbar.widgets["menu_devices"].widgets["device_box"].triggered.connect(
|
||||
lambda: self.add_dock(widget="DeviceBox", prefix="device_box")
|
||||
self.toolbar.widgets["menu_devices"].widgets["positioner_box"].triggered.connect(
|
||||
lambda: self.add_dock(widget="PositionerBox", prefix="positioner_box")
|
||||
)
|
||||
|
||||
# Menu Utils
|
||||
@@ -231,6 +231,7 @@ class BECDockArea(BECWidget, QWidget):
|
||||
self.config.docks.pop(name, None)
|
||||
if dock:
|
||||
dock.close()
|
||||
dock.deleteLater()
|
||||
if len(self.dock_area.docks) <= 1:
|
||||
for dock in self.dock_area.docks.values():
|
||||
dock.hide_title_bar()
|
||||
@@ -329,7 +330,16 @@ class BECDockArea(BECWidget, QWidget):
|
||||
"""
|
||||
while self.dock_area.tempAreas:
|
||||
for temp_area in self.dock_area.tempAreas:
|
||||
self.dock_area.removeTempArea(temp_area)
|
||||
self.remove_temp_area(temp_area)
|
||||
|
||||
def remove_temp_area(self, area):
|
||||
"""
|
||||
Remove a temporary area from the dock area.
|
||||
This is a patched method of pyqtgraph's removeTempArea
|
||||
"""
|
||||
self.dock_area.tempAreas.remove(area)
|
||||
area.window().close()
|
||||
area.window().deleteLater()
|
||||
|
||||
def clear_all(self):
|
||||
"""
|
||||
@@ -345,6 +355,10 @@ class BECDockArea(BECWidget, QWidget):
|
||||
Cleanup the dock area.
|
||||
"""
|
||||
self.clear_all()
|
||||
self.toolbar.close()
|
||||
self.toolbar.deleteLater()
|
||||
self.dock_area.close()
|
||||
self.dock_area.deleteLater()
|
||||
super().cleanup()
|
||||
|
||||
def close(self):
|
||||
|
||||
@@ -513,6 +513,13 @@ class BECFigure(BECWidget, pg.GraphicsLayoutWidget):
|
||||
if widget_id in self._widgets:
|
||||
raise ValueError(f"Widget with ID '{widget_id}' already exists.")
|
||||
|
||||
# Check if position is occupied
|
||||
if row is not None and col is not None:
|
||||
if self.getItem(row, col):
|
||||
raise ValueError(f"Position at row {row} and column {col} is already occupied.")
|
||||
else:
|
||||
row, col = self._find_next_empty_position()
|
||||
|
||||
widget = self.widget_handler.create_widget(
|
||||
widget_type=widget_type,
|
||||
widget_id=widget_id,
|
||||
@@ -525,23 +532,11 @@ class BECFigure(BECWidget, pg.GraphicsLayoutWidget):
|
||||
# used otherwise multiple times
|
||||
widget.set_gui_id(widget_id)
|
||||
|
||||
# Check if position is occupied
|
||||
if row is not None and col is not None:
|
||||
if self.getItem(row, col):
|
||||
raise ValueError(f"Position at row {row} and column {col} is already occupied.")
|
||||
widget.config.row = row
|
||||
widget.config.col = col
|
||||
|
||||
widget.config.row = row
|
||||
widget.config.col = col
|
||||
|
||||
# Add widget to the figure
|
||||
self.addItem(widget, row=row, col=col)
|
||||
else:
|
||||
row, col = self._find_next_empty_position()
|
||||
widget.config.row = row
|
||||
widget.config.col = col
|
||||
|
||||
# Add widget to the figure
|
||||
self.addItem(widget, row=row, col=col)
|
||||
# Add widget to the figure
|
||||
self.addItem(widget, row=row, col=col)
|
||||
|
||||
# Update num_cols and num_rows based on the added widget
|
||||
self.config.num_rows = max(self.config.num_rows, row + 1)
|
||||
@@ -620,6 +615,7 @@ class BECFigure(BECWidget, pg.GraphicsLayoutWidget):
|
||||
"""
|
||||
if widget_id in self._widgets:
|
||||
widget = self._widgets.pop(widget_id)
|
||||
widget.cleanup_pyqtgraph()
|
||||
widget.cleanup()
|
||||
self.removeItem(widget)
|
||||
self.grid[widget.config.row][widget.config.col] = None
|
||||
@@ -745,3 +741,12 @@ class BECFigure(BECWidget, pg.GraphicsLayoutWidget):
|
||||
self.config = FigureConfig(
|
||||
widget_class=self.__class__.__name__, gui_id=self.gui_id, theme=theme
|
||||
)
|
||||
|
||||
def cleanup_pyqtgraph_all_widgets(self):
|
||||
"""Clean up the pyqtgraph widget."""
|
||||
for widget in self.widget_list:
|
||||
widget.cleanup_pyqtgraph()
|
||||
|
||||
def cleanup(self):
|
||||
"""Close the figure widget."""
|
||||
self.cleanup_pyqtgraph_all_widgets()
|
||||
|
||||
@@ -681,3 +681,17 @@ class BECImageShow(BECPlotBase):
|
||||
self.on_image_update, MessageEndpoints.device_monitor_2d(monitor)
|
||||
)
|
||||
self.images.clear()
|
||||
|
||||
def cleanup_pyqtgraph(self):
|
||||
"""Cleanup pyqtgraph items."""
|
||||
super().cleanup_pyqtgraph()
|
||||
item = self.plot_item
|
||||
if not item.items:
|
||||
return
|
||||
cbar = item.items[0].color_bar
|
||||
cbar.vb.menu.close()
|
||||
cbar.vb.menu.deleteLater()
|
||||
cbar.gradient.menu.close()
|
||||
cbar.gradient.menu.deleteLater()
|
||||
cbar.gradient.colorDialog.close()
|
||||
cbar.gradient.colorDialog.deleteLater()
|
||||
|
||||
@@ -314,3 +314,11 @@ class BECPlotBase(BECConnector, pg.GraphicsLayout):
|
||||
"""Remove the plot widget from the figure."""
|
||||
if self.figure is not None:
|
||||
self.figure.remove(widget_id=self.gui_id)
|
||||
|
||||
def cleanup_pyqtgraph(self):
|
||||
"""Cleanup pyqtgraph items."""
|
||||
item = self.plot_item
|
||||
item.vb.menu.close()
|
||||
item.vb.menu.deleteLater()
|
||||
item.ctrlMenu.close()
|
||||
item.ctrlMenu.deleteLater()
|
||||
|
||||
@@ -458,6 +458,8 @@ class BECImageWidget(BECWidget, QWidget):
|
||||
def cleanup(self):
|
||||
self.fig.cleanup()
|
||||
self.client.shutdown()
|
||||
self.toolbar.close()
|
||||
self.toolbar.deleteLater()
|
||||
return super().cleanup()
|
||||
|
||||
|
||||
|
||||
@@ -45,3 +45,12 @@ class MotorMapSettings(SettingWidget):
|
||||
self.target_widget.set_scatter_size(scatter_size)
|
||||
self.target_widget.set_background_value(background_intensity)
|
||||
self.target_widget.set_color(color)
|
||||
|
||||
def cleanup(self):
|
||||
self.ui.color.cleanup()
|
||||
self.ui.color.close()
|
||||
self.ui.color.deleteLater()
|
||||
|
||||
def closeEvent(self, event):
|
||||
self.cleanup()
|
||||
super().closeEvent(event)
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
""" Module for a PositionerBox widget to control a positioner device."""
|
||||
|
||||
import os
|
||||
import uuid
|
||||
|
||||
from bec_lib.device import Positioner
|
||||
from bec_lib.endpoints import MessageEndpoints
|
||||
from bec_lib.logger import bec_logger
|
||||
from bec_lib.messages import ScanQueueMessage
|
||||
from qtpy.QtCore import Property, Signal, Slot
|
||||
from qtpy.QtGui import QDoubleValidator
|
||||
@@ -11,12 +15,23 @@ from bec_widgets.utils import UILoader
|
||||
from bec_widgets.utils.bec_widget import BECWidget
|
||||
from bec_widgets.utils.colors import apply_theme
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
class DeviceBox(BECWidget, QWidget):
|
||||
|
||||
class PositionerBox(BECWidget, QWidget):
|
||||
"""Simple Widget to control a positioner in box form"""
|
||||
|
||||
USER_ACCESS = ["set_positioner"]
|
||||
device_changed = Signal(str, str)
|
||||
|
||||
def __init__(self, parent=None, device=None, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
def __init__(self, parent=None, device: Positioner = None, *args, **kwargs):
|
||||
"""Initialize the PositionerBox widget.
|
||||
|
||||
Args:
|
||||
parent: The parent widget.
|
||||
device (Positioner): The device to control.
|
||||
"""
|
||||
super().__init__(**kwargs)
|
||||
QWidget.__init__(self, parent=parent)
|
||||
self.get_bec_shortcuts()
|
||||
self._device = ""
|
||||
@@ -29,10 +44,11 @@ class DeviceBox(BECWidget, QWidget):
|
||||
self.init_device()
|
||||
|
||||
def init_ui(self):
|
||||
"""Init the ui"""
|
||||
self.device_changed.connect(self.on_device_change)
|
||||
|
||||
current_path = os.path.dirname(__file__)
|
||||
self.ui = UILoader(self).loader(os.path.join(current_path, "device_box.ui"))
|
||||
self.ui = UILoader(self).loader(os.path.join(current_path, "positioner_box.ui"))
|
||||
|
||||
self.layout = QVBoxLayout(self)
|
||||
self.layout.addWidget(self.ui)
|
||||
@@ -57,28 +73,73 @@ class DeviceBox(BECWidget, QWidget):
|
||||
self.ui.spinner_widget.start()
|
||||
|
||||
def init_device(self):
|
||||
if self.device in self.dev:
|
||||
"""Init the device view and readback"""
|
||||
if self._check_device_is_valid(self.device):
|
||||
data = self.dev[self.device].read()
|
||||
self.on_device_readback({"signals": data}, {})
|
||||
|
||||
def _toogle_enable_buttons(self, enable: bool) -> None:
|
||||
"""Toogle enable/disable on available buttons
|
||||
|
||||
Args:
|
||||
enable (bool): Enable buttons
|
||||
"""
|
||||
self.ui.tweak_left.setEnabled(enable)
|
||||
self.ui.tweak_right.setEnabled(enable)
|
||||
self.ui.stop.setEnabled(enable)
|
||||
self.ui.setpoint.setEnabled(enable)
|
||||
self.ui.step_size.setEnabled(enable)
|
||||
|
||||
@Property(str)
|
||||
def device(self):
|
||||
"""Property to set the device"""
|
||||
return self._device
|
||||
|
||||
@device.setter
|
||||
def device(self, value):
|
||||
def device(self, value: str):
|
||||
"""Setter, checks if device is a string"""
|
||||
if not value or not isinstance(value, str):
|
||||
return
|
||||
old_device = self._device
|
||||
self._device = value
|
||||
self.device_changed.emit(old_device, value)
|
||||
|
||||
def set_positioner(self, positioner: str):
|
||||
"""Set the device
|
||||
|
||||
Args:
|
||||
positioner (Positioner | str) : Positioner to set, accepts str or the device
|
||||
"""
|
||||
if isinstance(positioner, Positioner):
|
||||
positioner = positioner.name
|
||||
self.device = positioner
|
||||
|
||||
def _check_device_is_valid(self, device: str):
|
||||
"""Check if the device is a positioner
|
||||
|
||||
Args:
|
||||
device (str): The device name
|
||||
"""
|
||||
if device not in self.dev:
|
||||
logger.info(f"Device {device} not found in the device list")
|
||||
return False
|
||||
if not isinstance(self.dev[device], Positioner):
|
||||
logger.info(f"Device {device} is not a positioner")
|
||||
return False
|
||||
return True
|
||||
|
||||
@Slot(str, str)
|
||||
def on_device_change(self, old_device: str, new_device: str):
|
||||
if new_device not in self.dev:
|
||||
print(f"Device {new_device} not found in the device list")
|
||||
"""Upon changing the device, a check will be performed if the device is a Positioner.
|
||||
|
||||
Args:
|
||||
old_device (str): The old device name.
|
||||
new_device (str): The new device name.
|
||||
"""
|
||||
if not self._check_device_is_valid(new_device):
|
||||
return
|
||||
print(f"Device changed from {old_device} to {new_device}")
|
||||
logger.info(f"Device changed from {old_device} to {new_device}")
|
||||
self._toogle_enable_buttons(True)
|
||||
self.init_device()
|
||||
self.bec_dispatcher.disconnect_slot(
|
||||
self.on_device_readback, MessageEndpoints.device_readback(old_device)
|
||||
@@ -98,6 +159,12 @@ class DeviceBox(BECWidget, QWidget):
|
||||
|
||||
@Slot(dict, dict)
|
||||
def on_device_readback(self, msg_content: dict, metadata: dict):
|
||||
"""Callback for device readback.
|
||||
|
||||
Args:
|
||||
msg_content (dict): The message content.
|
||||
metadata (dict): The message metadata.
|
||||
"""
|
||||
signals = msg_content.get("signals", {})
|
||||
# pylint: disable=protected-access
|
||||
hinted_signals = self.dev[self.device]._hints
|
||||
@@ -134,7 +201,12 @@ class DeviceBox(BECWidget, QWidget):
|
||||
pos = (readback_val - limits[0]) / (limits[1] - limits[0])
|
||||
self.ui.position_indicator.on_position_update(pos)
|
||||
|
||||
def update_limits(self, limits):
|
||||
def update_limits(self, limits: tuple):
|
||||
"""Update limits
|
||||
|
||||
Args:
|
||||
limits (tuple): Limits of the positioner
|
||||
"""
|
||||
if limits == self._limits:
|
||||
return
|
||||
self._limits = limits
|
||||
@@ -147,6 +219,7 @@ class DeviceBox(BECWidget, QWidget):
|
||||
|
||||
@Slot()
|
||||
def on_stop(self):
|
||||
"""Stop call"""
|
||||
request_id = str(uuid.uuid4())
|
||||
params = {
|
||||
"device": self.device,
|
||||
@@ -165,18 +238,22 @@ class DeviceBox(BECWidget, QWidget):
|
||||
|
||||
@property
|
||||
def step_size(self):
|
||||
"""Step size for tweak"""
|
||||
return self.ui.step_size.value()
|
||||
|
||||
@Slot()
|
||||
def on_tweak_right(self):
|
||||
"""Tweak motor right"""
|
||||
self.dev[self.device].move(self.step_size, relative=True)
|
||||
|
||||
@Slot()
|
||||
def on_tweak_left(self):
|
||||
"""Tweak motor left"""
|
||||
self.dev[self.device].move(-self.step_size, relative=True)
|
||||
|
||||
@Slot()
|
||||
def on_setpoint_change(self):
|
||||
"""Change the setpoint for the motor"""
|
||||
self.ui.setpoint.clearFocus()
|
||||
setpoint = self.ui.setpoint.text()
|
||||
self.dev[self.device].move(float(setpoint), relative=False)
|
||||
@@ -191,7 +268,7 @@ if __name__ == "__main__": # pragma: no cover
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
apply_theme("light")
|
||||
widget = DeviceBox(device="samx")
|
||||
widget = PositionerBox(device="bpm4i")
|
||||
|
||||
widget.show()
|
||||
sys.exit(app.exec_())
|
||||
@@ -0,0 +1 @@
|
||||
{'files': ['positioner_box.py']}
|
||||
@@ -29,17 +29,24 @@
|
||||
<item>
|
||||
<widget class="QGroupBox" name="device_box">
|
||||
<property name="title">
|
||||
<string>Device Name</string>
|
||||
<string>No positioner selected</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0,0">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="step_size"/>
|
||||
<widget class="QDoubleSpinBox" name="step_size">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QToolButton" name="tweak_right">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
@@ -67,10 +74,17 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3">
|
||||
<widget class="QLineEdit" name="setpoint"/>
|
||||
<widget class="QLineEdit" name="setpoint">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QToolButton" name="tweak_left">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
@@ -99,6 +113,9 @@
|
||||
</item>
|
||||
<item row="4" column="0" colspan="3">
|
||||
<widget class="QPushButton" name="stop">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Stop</string>
|
||||
</property>
|
||||
@@ -1,44 +1,39 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
import os
|
||||
|
||||
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
||||
from qtpy.QtGui import QIcon
|
||||
|
||||
import bec_widgets
|
||||
from bec_widgets.widgets.device_box.device_box import DeviceBox
|
||||
from bec_widgets.widgets.positioner_box.positioner_box import PositionerBox
|
||||
|
||||
DOM_XML = """
|
||||
<ui language='c++'>
|
||||
<widget class='DeviceBox' name='device_box'>
|
||||
<widget class='PositionerBox' name='positioner_box'>
|
||||
</widget>
|
||||
</ui>
|
||||
"""
|
||||
|
||||
MODULE_PATH = os.path.dirname(bec_widgets.__file__)
|
||||
|
||||
|
||||
class DeviceBoxPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
||||
class PositionerBoxPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._form_editor = None
|
||||
|
||||
def createWidget(self, parent):
|
||||
t = DeviceBox(parent)
|
||||
t = PositionerBox(parent)
|
||||
return t
|
||||
|
||||
def domXml(self):
|
||||
return DOM_XML
|
||||
|
||||
def group(self):
|
||||
return "Device Control"
|
||||
return ""
|
||||
|
||||
def icon(self):
|
||||
icon_path = os.path.join(MODULE_PATH, "assets", "designer_icons", "device_box.png")
|
||||
return QIcon(icon_path)
|
||||
return QIcon()
|
||||
|
||||
def includeFile(self):
|
||||
return "device_box"
|
||||
return "positioner_box"
|
||||
|
||||
def initialize(self, form_editor):
|
||||
self._form_editor = form_editor
|
||||
@@ -50,10 +45,10 @@ class DeviceBoxPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
||||
return self._form_editor is not None
|
||||
|
||||
def name(self):
|
||||
return "DeviceBox"
|
||||
return "PositionerBox"
|
||||
|
||||
def toolTip(self):
|
||||
return "A widget for controlling a single positioner. "
|
||||
return "Simple Widget to control a positioner in box form"
|
||||
|
||||
def whatsThis(self):
|
||||
return self.toolTip()
|
||||
@@ -6,9 +6,9 @@ def main(): # pragma: no cover
|
||||
return
|
||||
from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
|
||||
|
||||
from bec_widgets.widgets.device_box.device_box_plugin import DeviceBoxPlugin
|
||||
from bec_widgets.widgets.positioner_box.positioner_box_plugin import PositionerBoxPlugin
|
||||
|
||||
QPyDesignerCustomWidgetCollection.addCustomWidget(DeviceBoxPlugin())
|
||||
QPyDesignerCustomWidgetCollection.addCustomWidget(PositionerBoxPlugin())
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
@@ -1,9 +1,13 @@
|
||||
from typing import Literal
|
||||
|
||||
from qtpy.QtCore import Qt
|
||||
from qtpy.QtWidgets import (
|
||||
QCheckBox,
|
||||
QComboBox,
|
||||
QDialog,
|
||||
QDialogButtonBox,
|
||||
QDoubleSpinBox,
|
||||
QFormLayout,
|
||||
QGridLayout,
|
||||
QGroupBox,
|
||||
QLabel,
|
||||
@@ -25,13 +29,46 @@ class ScanArgType:
|
||||
LITERALS = "dict"
|
||||
|
||||
|
||||
class SettingsDialog(QDialog):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("Settings")
|
||||
|
||||
layout = QFormLayout()
|
||||
|
||||
self.precision_spin_box = QSpinBox()
|
||||
self.precision_spin_box.setRange(
|
||||
-2147483647, 2147483647
|
||||
) # 2147483647 is the largest int which qt allows
|
||||
|
||||
self.step_size_spin_box = QDoubleSpinBox()
|
||||
self.step_size_spin_box.setRange(-float("inf"), float("inf"))
|
||||
|
||||
fixed_width = 80
|
||||
self.precision_spin_box.setFixedWidth(fixed_width)
|
||||
self.step_size_spin_box.setFixedWidth(fixed_width)
|
||||
|
||||
layout.addRow("Decimal Precision:", self.precision_spin_box)
|
||||
layout.addRow("Step Size:", self.step_size_spin_box)
|
||||
|
||||
button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
||||
button_box.accepted.connect(self.accept)
|
||||
button_box.rejected.connect(self.reject)
|
||||
layout.addWidget(button_box)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
def getValues(self):
|
||||
return self.precision_spin_box.value(), self.step_size_spin_box.value()
|
||||
|
||||
|
||||
class ScanSpinBox(QSpinBox):
|
||||
def __init__(
|
||||
self, parent=None, arg_name: str = None, default: int | None = None, *args, **kwargs
|
||||
):
|
||||
super().__init__(parent=parent, *args, **kwargs)
|
||||
self.arg_name = arg_name
|
||||
self.setRange(-9999, 9999)
|
||||
self.setRange(-2147483647, 2147483647) # 2147483647 is the largest int which qt allows
|
||||
if default is not None:
|
||||
self.setValue(default)
|
||||
|
||||
@@ -42,10 +79,25 @@ class ScanDoubleSpinBox(QDoubleSpinBox):
|
||||
):
|
||||
super().__init__(parent=parent, *args, **kwargs)
|
||||
self.arg_name = arg_name
|
||||
self.setRange(-9999, 9999)
|
||||
self.setRange(-float("inf"), float("inf"))
|
||||
if default is not None:
|
||||
self.setValue(default)
|
||||
|
||||
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
self.customContextMenuRequested.connect(self.showSettingsDialog)
|
||||
|
||||
self.setToolTip("Right click to open settings dialog for decimal precision and step size.")
|
||||
|
||||
def showSettingsDialog(self):
|
||||
dialog = SettingsDialog(self)
|
||||
dialog.precision_spin_box.setValue(self.decimals())
|
||||
dialog.step_size_spin_box.setValue(self.singleStep())
|
||||
|
||||
if dialog.exec_() == QDialog.Accepted:
|
||||
precision, step_size = dialog.getValues()
|
||||
self.setDecimals(precision)
|
||||
self.setSingleStep(step_size)
|
||||
|
||||
|
||||
class ScanLineEdit(QLineEdit):
|
||||
def __init__(
|
||||
|
||||
@@ -55,7 +55,7 @@ class SpinnerWidget(QWidget):
|
||||
|
||||
color_palette = get_theme_palette()
|
||||
|
||||
color = QColor(color_palette.COLOR_ACCENT_4)
|
||||
color = QColor(color_palette.accent().color())
|
||||
|
||||
rect.adjust(line_width, line_width, -line_width, -line_width)
|
||||
|
||||
|
||||
@@ -64,6 +64,12 @@ class WebsiteWidget(BECWidget, QWebEngineView):
|
||||
"""
|
||||
QWebEngineView.forward(self)
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
Cleanup the widget
|
||||
"""
|
||||
self.page().deleteLater()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
|
||||
@@ -11,4 +11,5 @@ hidden: true
|
||||
installation/
|
||||
quick_start/
|
||||
auto_updates/
|
||||
video_tutorials/
|
||||
```
|
||||
17
docs/user/getting_started/video_tutorials.md
Normal file
@@ -0,0 +1,17 @@
|
||||
(user.video_tutorials)=
|
||||
|
||||
# Video Tutorials
|
||||
|
||||
This section includes video tutorials that demonstrate various use cases of `bec-widgets`, including video tutorials,
|
||||
presentations, and conference talks.
|
||||
|
||||
## BSEG Meeting 24th July 2024
|
||||
|
||||
This video is a presentation of the BEC Widgets project at the BSEG meeting on the 24th July 2024. The presentation
|
||||
covers the basic interactions, including visualization of live data acquisition and how to steer experiments using
|
||||
user-friendly tools. Learn how BEC Widgets can enhance your experimental control projects with its intuitive interface
|
||||
and powerful features.
|
||||
|
||||
Used version of BEC Widgets: 0.91.0
|
||||
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/qZ8fWXRAdHE" frameborder="0" allowfullscreen></iframe>
|
||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "bec_widgets"
|
||||
version = "0.92.5"
|
||||
version = "0.93.4"
|
||||
description = "BEC Widgets"
|
||||
requires-python = ">=3.10"
|
||||
classifiers = [
|
||||
@@ -19,7 +19,7 @@ dependencies = [
|
||||
"isort~=5.13, >=5.13.2", # needed for bw-generate-cli
|
||||
"pydantic~=2.0",
|
||||
"pyqtgraph~=0.13",
|
||||
"qdarkstyle>=3.2.2",
|
||||
"bec_qthemes~=0.0",
|
||||
"qtconsole~=5.5, >=5.5.1", # needed for jupyter console
|
||||
"qtpy~=2.4",
|
||||
"pyte", # needed for vt100 console
|
||||
|
||||
@@ -12,7 +12,6 @@ def scan_control(qtbot, bec_client_lib): # , mock_dev):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
def test_scan_control_populate_scans_e2e(scan_control):
|
||||
|
||||
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 15 KiB |
@@ -1,4 +1,6 @@
|
||||
import pytest
|
||||
from pytestqt.exceptions import TimeoutError as QtBotTimeoutError
|
||||
from qtpy.QtWidgets import QApplication
|
||||
|
||||
from bec_widgets.cli.rpc_register import RPCRegister
|
||||
from bec_widgets.qt_utils import error_popups
|
||||
@@ -6,9 +8,16 @@ from bec_widgets.utils import bec_dispatcher as bec_dispatcher_module
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def qapplication(qapp): # pylint: disable=unused-argument
|
||||
def qapplication(qtbot): # pylint: disable=unused-argument
|
||||
yield
|
||||
qapp.processEvents() # make sure all events are processed before shutting down
|
||||
|
||||
qapp = QApplication.instance()
|
||||
# qapp.quit()
|
||||
qapp.processEvents()
|
||||
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)
|
||||
@@ -31,3 +40,25 @@ def bec_dispatcher(threads_check): # pylint: disable=unused-argument
|
||||
@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.
|
||||
DO NOT CREATE WIDGETS DIRECTLY IN A FIXTURE!
|
||||
|
||||
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
|
||||
|
||||
@@ -14,7 +14,6 @@ def bec_dock_area(qtbot, mocked_client):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
def test_bec_dock_area_init(bec_dock_area):
|
||||
@@ -128,10 +127,12 @@ def test_toolbar_add_plot_motor_map(bec_dock_area):
|
||||
assert bec_dock_area.panels["motor_map_1"].widgets[0].config.widget_class == "BECMotorMapWidget"
|
||||
|
||||
|
||||
def test_toolbar_add_device_device_box(bec_dock_area):
|
||||
bec_dock_area.toolbar.widgets["menu_devices"].widgets["device_box"].trigger()
|
||||
assert "device_box_1" in bec_dock_area.panels
|
||||
assert bec_dock_area.panels["device_box_1"].widgets[0].config.widget_class == "DeviceBox"
|
||||
def test_toolbar_add_device_positioner_box(bec_dock_area):
|
||||
bec_dock_area.toolbar.widgets["menu_devices"].widgets["positioner_box"].trigger()
|
||||
assert "positioner_box_1" in bec_dock_area.panels
|
||||
assert (
|
||||
bec_dock_area.panels["positioner_box_1"].widgets[0].config.widget_class == "PositionerBox"
|
||||
)
|
||||
|
||||
|
||||
def test_toolbar_add_utils_queue(bec_dock_area):
|
||||
|
||||
@@ -9,18 +9,11 @@ from bec_widgets.widgets.figure.plots.motor_map.motor_map import BECMotorMap
|
||||
from bec_widgets.widgets.figure.plots.waveform.waveform import BECWaveform
|
||||
|
||||
from .client_mocks import mocked_client
|
||||
from .conftest import create_widget
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def bec_figure(qtbot, mocked_client):
|
||||
widget = BECFigure(client=mocked_client)
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
def test_bec_figure_init(bec_figure):
|
||||
def test_bec_figure_init(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
assert bec_figure is not None
|
||||
assert bec_figure.client is not None
|
||||
assert isinstance(bec_figure, BECFigure)
|
||||
@@ -34,7 +27,8 @@ def test_bec_figure_init_with_config(mocked_client):
|
||||
assert widget.config.theme == "dark"
|
||||
|
||||
|
||||
def test_bec_figure_add_remove_plot(bec_figure):
|
||||
def test_bec_figure_add_remove_plot(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
initial_count = len(bec_figure._widgets)
|
||||
|
||||
# Adding 3 widgets - 2 WaveformBase and 1 PlotBase
|
||||
@@ -64,7 +58,8 @@ def test_bec_figure_add_remove_plot(bec_figure):
|
||||
assert bec_figure._widgets[w1.gui_id].config.widget_class == "BECWaveform"
|
||||
|
||||
|
||||
def test_add_different_types_of_widgets(bec_figure):
|
||||
def test_add_different_types_of_widgets(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
plt = bec_figure.plot(x_name="samx", y_name="bpm4i")
|
||||
im = bec_figure.image("eiger")
|
||||
motor_map = bec_figure.motor_map("samx", "samy")
|
||||
@@ -74,7 +69,8 @@ def test_add_different_types_of_widgets(bec_figure):
|
||||
assert motor_map.__class__ == BECMotorMap
|
||||
|
||||
|
||||
def test_access_widgets_access_errors(bec_figure):
|
||||
def test_access_widgets_access_errors(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
bec_figure.plot(row=0, col=0)
|
||||
|
||||
# access widget by non-existent coordinates
|
||||
@@ -96,7 +92,8 @@ def test_access_widgets_access_errors(bec_figure):
|
||||
)
|
||||
|
||||
|
||||
def test_add_plot_to_occupied_position(bec_figure):
|
||||
def test_add_plot_to_occupied_position(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
bec_figure.plot(row=0, col=0)
|
||||
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@@ -104,7 +101,8 @@ def test_add_plot_to_occupied_position(bec_figure):
|
||||
assert "Position at row 0 and column 0 is already occupied." in str(excinfo.value)
|
||||
|
||||
|
||||
def test_remove_plots(bec_figure):
|
||||
def test_remove_plots(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot(row=0, col=0)
|
||||
w2 = bec_figure.plot(row=0, col=1)
|
||||
w3 = bec_figure.plot(row=1, col=0)
|
||||
@@ -134,7 +132,8 @@ def test_remove_plots(bec_figure):
|
||||
assert len(bec_figure._widgets) == 1
|
||||
|
||||
|
||||
def test_remove_plots_by_coordinates_ints(bec_figure):
|
||||
def test_remove_plots_by_coordinates_ints(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot(row=0, col=0)
|
||||
w2 = bec_figure.plot(row=0, col=1)
|
||||
|
||||
@@ -145,7 +144,8 @@ def test_remove_plots_by_coordinates_ints(bec_figure):
|
||||
assert len(bec_figure._widgets) == 1
|
||||
|
||||
|
||||
def test_remove_plots_by_coordinates_tuple(bec_figure):
|
||||
def test_remove_plots_by_coordinates_tuple(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot(row=0, col=0)
|
||||
w2 = bec_figure.plot(row=0, col=1)
|
||||
|
||||
@@ -156,7 +156,8 @@ def test_remove_plots_by_coordinates_tuple(bec_figure):
|
||||
assert len(bec_figure._widgets) == 1
|
||||
|
||||
|
||||
def test_remove_plot_by_id_error(bec_figure):
|
||||
def test_remove_plot_by_id_error(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
bec_figure.plot()
|
||||
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@@ -164,7 +165,8 @@ def test_remove_plot_by_id_error(bec_figure):
|
||||
assert "Widget with ID 'non_existent_widget' does not exist." in str(excinfo.value)
|
||||
|
||||
|
||||
def test_remove_plot_by_coordinates_error(bec_figure):
|
||||
def test_remove_plot_by_coordinates_error(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
bec_figure.plot(row=0, col=0)
|
||||
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@@ -172,7 +174,8 @@ def test_remove_plot_by_coordinates_error(bec_figure):
|
||||
assert "No widget at coordinates (0, 1)" in str(excinfo.value)
|
||||
|
||||
|
||||
def test_remove_plot_by_providing_nothing(bec_figure):
|
||||
def test_remove_plot_by_providing_nothing(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
bec_figure.plot(row=0, col=0)
|
||||
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@@ -192,7 +195,8 @@ def test_remove_plot_by_providing_nothing(bec_figure):
|
||||
# assert bec_figure.backgroundBrush().color().name() == "#000000"
|
||||
|
||||
|
||||
def test_change_layout(bec_figure):
|
||||
def test_change_layout(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot(row=0, col=0)
|
||||
w2 = bec_figure.plot(row=0, col=1)
|
||||
w3 = bec_figure.plot(row=1, col=0)
|
||||
@@ -215,7 +219,8 @@ def test_change_layout(bec_figure):
|
||||
assert bec_figure[0, 3] == w4
|
||||
|
||||
|
||||
def test_clear_all(bec_figure):
|
||||
def test_clear_all(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
bec_figure.plot(row=0, col=0)
|
||||
bec_figure.plot(row=0, col=1)
|
||||
bec_figure.plot(row=1, col=0)
|
||||
@@ -227,7 +232,8 @@ def test_clear_all(bec_figure):
|
||||
assert np.shape(bec_figure.grid) == (0,)
|
||||
|
||||
|
||||
def test_shortcuts(bec_figure):
|
||||
def test_shortcuts(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
plt = bec_figure.plot(x_name="samx", y_name="bpm4i")
|
||||
im = bec_figure.image("eiger")
|
||||
motor_map = bec_figure.motor_map("samx", "samy")
|
||||
@@ -240,7 +246,8 @@ def test_shortcuts(bec_figure):
|
||||
assert motor_map.__class__ == BECMotorMap
|
||||
|
||||
|
||||
def test_plot_access_factory(bec_figure):
|
||||
def test_plot_access_factory(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
plt_00 = bec_figure.plot(x_name="samx", y_name="bpm4i")
|
||||
plt_01 = bec_figure.plot(x_name="samx", y_name="bpm4i", row=0, col=1)
|
||||
plt_10 = bec_figure.plot(new=True)
|
||||
|
||||
@@ -6,8 +6,10 @@ import pytest
|
||||
from bec_lib import messages
|
||||
from qtpy.QtGui import QFontInfo
|
||||
|
||||
from bec_widgets.widgets.figure import BECFigure
|
||||
|
||||
from .client_mocks import mocked_client
|
||||
from .test_bec_figure import bec_figure
|
||||
from .conftest import create_widget
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -15,7 +17,8 @@ def bec_image_show(bec_figure):
|
||||
yield bec_figure.image("eiger")
|
||||
|
||||
|
||||
def test_on_image_update(bec_image_show):
|
||||
def test_on_image_update(qtbot, mocked_client):
|
||||
bec_image_show = create_widget(qtbot, BECFigure, client=mocked_client).image("eiger")
|
||||
data = np.random.rand(100, 100)
|
||||
msg = messages.DeviceMonitor2DMessage(device="eiger", data=data, metadata={"scan_id": "12345"})
|
||||
bec_image_show.on_image_update(msg.content, msg.metadata)
|
||||
@@ -23,7 +26,8 @@ def test_on_image_update(bec_image_show):
|
||||
assert np.array_equal(img.get_data(), data)
|
||||
|
||||
|
||||
def test_autorange_on_image_update(bec_image_show):
|
||||
def test_autorange_on_image_update(qtbot, mocked_client):
|
||||
bec_image_show = create_widget(qtbot, BECFigure, client=mocked_client).image("eiger")
|
||||
# Check if autorange mode "mean" works, should be default
|
||||
data = np.random.rand(100, 100)
|
||||
msg = messages.DeviceMonitor2DMessage(device="eiger", data=data, metadata={"scan_id": "12345"})
|
||||
|
||||
@@ -15,7 +15,6 @@ def image_widget(qtbot, mocked_client):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -2,14 +2,16 @@ import numpy as np
|
||||
import pytest
|
||||
from bec_lib.messages import DeviceMessage
|
||||
|
||||
from bec_widgets.widgets.figure import BECFigure
|
||||
from bec_widgets.widgets.figure.plots.motor_map.motor_map import BECMotorMap, MotorMapConfig
|
||||
from bec_widgets.widgets.figure.plots.waveform.waveform_curve import SignalData
|
||||
|
||||
from .client_mocks import mocked_client
|
||||
from .test_bec_figure import bec_figure
|
||||
from .conftest import create_widget
|
||||
|
||||
|
||||
def test_motor_map_init(bec_figure):
|
||||
def test_motor_map_init(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
default_config = MotorMapConfig(widget_class="BECMotorMap")
|
||||
|
||||
mm = bec_figure.motor_map(config=default_config.model_dump())
|
||||
@@ -18,7 +20,8 @@ def test_motor_map_init(bec_figure):
|
||||
assert mm.config == default_config
|
||||
|
||||
|
||||
def test_motor_map_change_motors(bec_figure):
|
||||
def test_motor_map_change_motors(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
mm = bec_figure.motor_map("samx", "samy")
|
||||
|
||||
assert mm.motor_x == "samx"
|
||||
@@ -32,7 +35,8 @@ def test_motor_map_change_motors(bec_figure):
|
||||
assert mm.config.signals.y == SignalData(name="samz", entry="samz", limits=[-8, 8])
|
||||
|
||||
|
||||
def test_motor_map_get_limits(bec_figure):
|
||||
def test_motor_map_get_limits(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
mm = bec_figure.motor_map("samx", "samy")
|
||||
expected_limits = {"samx": [-10, 10], "samy": [-5, 5]}
|
||||
|
||||
@@ -41,7 +45,8 @@ def test_motor_map_get_limits(bec_figure):
|
||||
assert actual_limit == expected_limit
|
||||
|
||||
|
||||
def test_motor_map_get_init_position(bec_figure):
|
||||
def test_motor_map_get_init_position(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
mm = bec_figure.motor_map("samx", "samy")
|
||||
mm.set_precision(2)
|
||||
|
||||
@@ -57,7 +62,8 @@ def test_motor_map_get_init_position(bec_figure):
|
||||
assert actual_position == expected_position
|
||||
|
||||
|
||||
def test_motor_movement_updates_position_and_database(bec_figure):
|
||||
def test_motor_movement_updates_position_and_database(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
mm = bec_figure.motor_map("samx", "samy")
|
||||
motor_map_dev = mm.client.device_manager.devices
|
||||
|
||||
@@ -85,7 +91,8 @@ def test_motor_movement_updates_position_and_database(bec_figure):
|
||||
assert mm.database_buffer["y"] == init_positions["samy"]
|
||||
|
||||
|
||||
def test_scatter_plot_rendering(bec_figure):
|
||||
def test_scatter_plot_rendering(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
mm = bec_figure.motor_map("samx", "samy")
|
||||
motor_map_dev = mm.client.device_manager.devices
|
||||
|
||||
@@ -115,7 +122,8 @@ def test_scatter_plot_rendering(bec_figure):
|
||||
), "Scatter plot Y data should retain last known position"
|
||||
|
||||
|
||||
def test_plot_visualization_consistency(bec_figure):
|
||||
def test_plot_visualization_consistency(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
mm = bec_figure.motor_map("samx", "samy")
|
||||
mm.change_motors("samx", "samy")
|
||||
# Simulate updating the plot with new data
|
||||
@@ -133,7 +141,8 @@ def test_plot_visualization_consistency(bec_figure):
|
||||
), "Plot not updated correctly with new data"
|
||||
|
||||
|
||||
def test_change_background_value(bec_figure, qtbot):
|
||||
def test_change_background_value(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
mm = bec_figure.motor_map("samx", "samy")
|
||||
|
||||
assert mm.config.background_value == 25
|
||||
@@ -146,7 +155,8 @@ def test_change_background_value(bec_figure, qtbot):
|
||||
assert np.all(mm.plot_components["limit_map"].image == 50.0)
|
||||
|
||||
|
||||
def test_motor_map_init_from_config(bec_figure):
|
||||
def test_motor_map_init_from_config(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
config = {
|
||||
"widget_class": "BECMotorMap",
|
||||
"gui_id": "mm_id",
|
||||
@@ -200,7 +210,8 @@ def test_motor_map_init_from_config(bec_figure):
|
||||
assert mm._config_dict == config
|
||||
|
||||
|
||||
def test_motor_map_set_scatter_size(bec_figure, qtbot):
|
||||
def test_motor_map_set_scatter_size(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
mm = bec_figure.motor_map("samx", "samy")
|
||||
|
||||
assert mm.config.scatter_size == 5
|
||||
@@ -213,7 +224,8 @@ def test_motor_map_set_scatter_size(bec_figure, qtbot):
|
||||
assert mm.plot_components["scatter"].opts["size"] == 10
|
||||
|
||||
|
||||
def test_motor_map_change_precision(bec_figure):
|
||||
def test_motor_map_change_precision(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
mm = bec_figure.motor_map("samx", "samy")
|
||||
|
||||
assert mm.config.precision == 2
|
||||
@@ -221,7 +233,8 @@ def test_motor_map_change_precision(bec_figure):
|
||||
assert mm.config.precision == 10
|
||||
|
||||
|
||||
def test_motor_map_set_color(bec_figure, qtbot):
|
||||
def test_motor_map_set_color(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
mm = bec_figure.motor_map("samx", "samy")
|
||||
|
||||
assert mm.config.color == (255, 255, 255, 255)
|
||||
@@ -231,7 +244,8 @@ def test_motor_map_set_color(bec_figure, qtbot):
|
||||
assert mm.config.color == (0, 0, 0, 255)
|
||||
|
||||
|
||||
def test_motor_map_get_data_max_points(bec_figure, qtbot):
|
||||
def test_motor_map_get_data_max_points(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
mm = bec_figure.motor_map("samx", "samy")
|
||||
motor_map_dev = mm.client.device_manager.devices
|
||||
|
||||
|
||||
@@ -93,7 +93,6 @@ def bec_queue(qtbot, mocked_client):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
def test_bec_queue(bec_queue, bec_queue_msg_full):
|
||||
|
||||
@@ -20,7 +20,6 @@ def status_box(qtbot, mocked_client, service_status_fixture):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
def test_update_top_item(status_box):
|
||||
|
||||
@@ -10,7 +10,6 @@ def color_map_selector(qtbot):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
def test_color_map_selector_init(color_map_selector):
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from bec_lib.endpoints import MessageEndpoints
|
||||
from bec_lib.messages import ScanQueueMessage
|
||||
from qtpy.QtGui import QValidator
|
||||
|
||||
from bec_widgets.widgets.device_box.device_box import DeviceBox
|
||||
|
||||
from .client_mocks import mocked_client
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def device_box(qtbot, mocked_client):
|
||||
with mock.patch("bec_widgets.widgets.device_box.device_box.uuid.uuid4") as mock_uuid:
|
||||
mock_uuid.return_value = "fake_uuid"
|
||||
db = DeviceBox(device="samx", client=mocked_client)
|
||||
qtbot.addWidget(db)
|
||||
yield db
|
||||
|
||||
|
||||
def test_device_box(device_box):
|
||||
assert device_box.device == "samx"
|
||||
data = device_box.dev["samx"].read()
|
||||
|
||||
setpoint_text = device_box.ui.setpoint.text()
|
||||
# check that the setpoint is taken correctly after init
|
||||
assert float(setpoint_text) == data["samx_setpoint"]["value"]
|
||||
|
||||
# check that the precision is taken correctly after init
|
||||
precision = device_box.dev["samx"].precision
|
||||
assert setpoint_text == f"{data['samx_setpoint']['value']:.{precision}f}"
|
||||
|
||||
# check that the step size is set according to the device precision
|
||||
assert device_box.ui.step_size.value() == 10**-precision * 10
|
||||
|
||||
|
||||
def test_device_box_update_limits(device_box):
|
||||
device_box._limits = None
|
||||
device_box.update_limits([0, 10])
|
||||
assert device_box._limits == [0, 10]
|
||||
assert device_box.setpoint_validator.bottom() == 0
|
||||
assert device_box.setpoint_validator.top() == 10
|
||||
assert device_box.setpoint_validator.validate("100", 0) == (
|
||||
QValidator.State.Intermediate,
|
||||
"100",
|
||||
0,
|
||||
)
|
||||
|
||||
device_box.update_limits(None)
|
||||
assert device_box._limits is None
|
||||
assert device_box.setpoint_validator.validate("100", 0) == (
|
||||
QValidator.State.Acceptable,
|
||||
"100",
|
||||
0,
|
||||
)
|
||||
|
||||
|
||||
def test_device_box_on_stop(device_box):
|
||||
with mock.patch.object(device_box.client.connector, "send") as mock_send:
|
||||
device_box.on_stop()
|
||||
params = {"device": "samx", "rpc_id": "fake_uuid", "func": "stop", "args": [], "kwargs": {}}
|
||||
msg = ScanQueueMessage(
|
||||
scan_type="device_rpc",
|
||||
parameter=params,
|
||||
queue="emergency",
|
||||
metadata={"RID": "fake_uuid", "response": False},
|
||||
)
|
||||
mock_send.assert_called_once_with(MessageEndpoints.scan_queue_request(), msg)
|
||||
|
||||
|
||||
def test_device_box_setpoint_change(device_box):
|
||||
with mock.patch.object(device_box.dev["samx"], "move") as mock_move:
|
||||
device_box.ui.setpoint.setText("100")
|
||||
device_box.on_setpoint_change()
|
||||
mock_move.assert_called_once_with(100, relative=False)
|
||||
|
||||
|
||||
def test_device_box_on_tweak_right(device_box):
|
||||
with mock.patch.object(device_box.dev["samx"], "move") as mock_move:
|
||||
device_box.ui.step_size.setValue(0.1)
|
||||
device_box.on_tweak_right()
|
||||
mock_move.assert_called_once_with(0.1, relative=True)
|
||||
|
||||
|
||||
def test_device_box_on_tweak_left(device_box):
|
||||
with mock.patch.object(device_box.dev["samx"], "move") as mock_move:
|
||||
device_box.ui.step_size.setValue(0.1)
|
||||
device_box.on_tweak_left()
|
||||
mock_move.assert_called_once_with(-0.1, relative=True)
|
||||
|
||||
|
||||
def test_device_box_setpoint_out_of_range(device_box):
|
||||
device_box.update_limits([0, 10])
|
||||
device_box.ui.setpoint.setText("100")
|
||||
device_box.on_setpoint_change()
|
||||
assert device_box.ui.setpoint.text() == "100"
|
||||
assert device_box.ui.setpoint.hasAcceptableInput() == False
|
||||
@@ -19,7 +19,6 @@ def device_input_base(qtbot, mocked_client):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
def test_device_input_base_init(device_input_base):
|
||||
|
||||
@@ -12,7 +12,6 @@ def device_input_combobox(qtbot, mocked_client):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -28,7 +27,6 @@ def device_input_combobox_with_config(qtbot, mocked_client):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -43,7 +41,6 @@ def device_input_combobox_with_kwargs(qtbot, mocked_client):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
def test_device_input_combobox_init(device_input_combobox):
|
||||
@@ -101,7 +98,6 @@ def device_input_line_edit(qtbot, mocked_client):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -117,7 +113,6 @@ def device_input_line_edit_with_config(qtbot, mocked_client):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -132,7 +127,6 @@ def device_input_line_edit_with_kwargs(qtbot, mocked_client):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
def test_device_input_line_edit_init(device_input_line_edit):
|
||||
|
||||
@@ -16,7 +16,6 @@ def motor_map_widget(qtbot, mocked_client):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -139,7 +138,6 @@ def motor_map_settings(qtbot):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
def test_display_current_settings(motor_map_settings):
|
||||
|
||||
@@ -4,18 +4,22 @@ from unittest import mock
|
||||
import pytest
|
||||
from qtpy.QtGui import QFontInfo
|
||||
|
||||
from bec_widgets.widgets.figure import BECFigure
|
||||
|
||||
from .client_mocks import mocked_client
|
||||
from .test_bec_figure import bec_figure
|
||||
from .conftest import create_widget
|
||||
|
||||
|
||||
def test_init_plot_base(bec_figure):
|
||||
def test_init_plot_base(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
plot_base = bec_figure.add_widget(widget_type="BECPlotBase", widget_id="test_plot")
|
||||
assert plot_base is not None
|
||||
assert plot_base.config.widget_class == "BECPlotBase"
|
||||
assert plot_base.config.gui_id == "test_plot"
|
||||
|
||||
|
||||
def test_plot_base_axes_by_separate_methods(bec_figure):
|
||||
def test_plot_base_axes_by_separate_methods(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
plot_base = bec_figure.add_widget(widget_type="BECPlotBase", widget_id="test_plot")
|
||||
|
||||
plot_base.set_title("Test Title")
|
||||
@@ -65,7 +69,8 @@ def test_plot_base_axes_by_separate_methods(bec_figure):
|
||||
assert mock_set_title.call_args == call
|
||||
|
||||
|
||||
def test_plot_base_axes_added_by_kwargs(bec_figure):
|
||||
def test_plot_base_axes_added_by_kwargs(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
plot_base = bec_figure.add_widget(widget_type="BECPlotBase", widget_id="test_plot")
|
||||
|
||||
plot_base.set(
|
||||
|
||||
104
tests/unit_tests/test_positioner_box.py
Normal file
@@ -0,0 +1,104 @@
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from bec_lib.device import Positioner
|
||||
from bec_lib.endpoints import MessageEndpoints
|
||||
from bec_lib.messages import ScanQueueMessage
|
||||
from qtpy.QtGui import QValidator
|
||||
|
||||
from bec_widgets.widgets.positioner_box.positioner_box import PositionerBox
|
||||
|
||||
from .client_mocks import mocked_client
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def positioner_box(qtbot, mocked_client):
|
||||
with mock.patch("bec_widgets.widgets.positioner_box.positioner_box.uuid.uuid4") as mock_uuid:
|
||||
mock_uuid.return_value = "fake_uuid"
|
||||
with mock.patch(
|
||||
"bec_widgets.widgets.positioner_box.positioner_box.PositionerBox._check_device_is_valid",
|
||||
return_value=True,
|
||||
):
|
||||
db = PositionerBox(device="samx", client=mocked_client)
|
||||
qtbot.addWidget(db)
|
||||
yield db
|
||||
|
||||
|
||||
def test_positioner_box(positioner_box):
|
||||
assert positioner_box.device == "samx"
|
||||
data = positioner_box.dev["samx"].read()
|
||||
# Avoid check for Positioner class from BEC in _init_device
|
||||
|
||||
setpoint_text = positioner_box.ui.setpoint.text()
|
||||
# check that the setpoint is taken correctly after init
|
||||
assert float(setpoint_text) == data["samx_setpoint"]["value"]
|
||||
|
||||
# check that the precision is taken correctly after isnit
|
||||
precision = positioner_box.dev["samx"].precision
|
||||
assert setpoint_text == f"{data['samx_setpoint']['value']:.{precision}f}"
|
||||
|
||||
# check that the step size is set according to the device precision
|
||||
assert positioner_box.ui.step_size.value() == 10**-precision * 10
|
||||
|
||||
|
||||
def test_positioner_box_update_limits(positioner_box):
|
||||
positioner_box._limits = None
|
||||
positioner_box.update_limits([0, 10])
|
||||
assert positioner_box._limits == [0, 10]
|
||||
assert positioner_box.setpoint_validator.bottom() == 0
|
||||
assert positioner_box.setpoint_validator.top() == 10
|
||||
assert positioner_box.setpoint_validator.validate("100", 0) == (
|
||||
QValidator.State.Intermediate,
|
||||
"100",
|
||||
0,
|
||||
)
|
||||
|
||||
positioner_box.update_limits(None)
|
||||
assert positioner_box._limits is None
|
||||
assert positioner_box.setpoint_validator.validate("100", 0) == (
|
||||
QValidator.State.Acceptable,
|
||||
"100",
|
||||
0,
|
||||
)
|
||||
|
||||
|
||||
def test_positioner_box_on_stop(positioner_box):
|
||||
with mock.patch.object(positioner_box.client.connector, "send") as mock_send:
|
||||
positioner_box.on_stop()
|
||||
params = {"device": "samx", "rpc_id": "fake_uuid", "func": "stop", "args": [], "kwargs": {}}
|
||||
msg = ScanQueueMessage(
|
||||
scan_type="device_rpc",
|
||||
parameter=params,
|
||||
queue="emergency",
|
||||
metadata={"RID": "fake_uuid", "response": False},
|
||||
)
|
||||
mock_send.assert_called_once_with(MessageEndpoints.scan_queue_request(), msg)
|
||||
|
||||
|
||||
def test_positioner_box_setpoint_change(positioner_box):
|
||||
with mock.patch.object(positioner_box.dev["samx"], "move") as mock_move:
|
||||
positioner_box.ui.setpoint.setText("100")
|
||||
positioner_box.on_setpoint_change()
|
||||
mock_move.assert_called_once_with(100, relative=False)
|
||||
|
||||
|
||||
def test_positioner_box_on_tweak_right(positioner_box):
|
||||
with mock.patch.object(positioner_box.dev["samx"], "move") as mock_move:
|
||||
positioner_box.ui.step_size.setValue(0.1)
|
||||
positioner_box.on_tweak_right()
|
||||
mock_move.assert_called_once_with(0.1, relative=True)
|
||||
|
||||
|
||||
def test_positioner_box_on_tweak_left(positioner_box):
|
||||
with mock.patch.object(positioner_box.dev["samx"], "move") as mock_move:
|
||||
positioner_box.ui.step_size.setValue(0.1)
|
||||
positioner_box.on_tweak_left()
|
||||
mock_move.assert_called_once_with(-0.1, relative=True)
|
||||
|
||||
|
||||
def test_positioner_box_setpoint_out_of_range(positioner_box):
|
||||
positioner_box.update_limits([0, 10])
|
||||
positioner_box.ui.setpoint.setText("100")
|
||||
positioner_box.on_setpoint_change()
|
||||
assert positioner_box.ui.setpoint.text() == "100"
|
||||
assert positioner_box.ui.setpoint.hasAcceptableInput() == False
|
||||
@@ -18,7 +18,6 @@ def ring_progress_bar(qtbot, mocked_client):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
def test_bar_init(ring_progress_bar):
|
||||
|
||||
@@ -220,7 +220,6 @@ def scan_control(qtbot, mocked_client): # , mock_dev):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
def test_populate_scans(scan_control, mocked_client):
|
||||
|
||||
@@ -16,7 +16,6 @@ def setting_widget(qtbot):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
def test_setting_widget_initialization(setting_widget):
|
||||
@@ -61,8 +60,8 @@ def settings_dialog(qtbot, setting_widget):
|
||||
qtbot.addWidget(dialog)
|
||||
qtbot.waitExposed(dialog)
|
||||
yield dialog, parent_widget, setting_widget
|
||||
dialog.close()
|
||||
parent_widget.close()
|
||||
parent_widget.deleteLater()
|
||||
|
||||
|
||||
def test_settings_dialog_initialization(settings_dialog):
|
||||
|
||||
@@ -13,7 +13,6 @@ def stop_button(qtbot, mocked_client):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
def test_stop_button(stop_button):
|
||||
|
||||
@@ -14,7 +14,6 @@ def text_box_widget(qtbot, mocked_client):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
def test_textbox_widget(text_box_widget):
|
||||
|
||||
@@ -10,7 +10,6 @@ def toggle(qtbot):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
def test_toggle(toggle):
|
||||
|
||||
@@ -14,9 +14,9 @@ from .client_mocks import mocked_client
|
||||
def vscode_widget(qtbot, mocked_client):
|
||||
with mock.patch("bec_widgets.widgets.vscode.vscode.subprocess.Popen") as mock_popen:
|
||||
widget = VSCodeEditor(client=mocked_client)
|
||||
# qtbot.addWidget(widget)
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
# widget.close()
|
||||
|
||||
|
||||
def test_vscode_widget(qtbot, vscode_widget):
|
||||
|
||||
@@ -4,13 +4,15 @@ from unittest import mock
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from bec_widgets.widgets.figure import BECFigure
|
||||
from bec_widgets.widgets.figure.plots.waveform.waveform_curve import CurveConfig, Signal, SignalData
|
||||
|
||||
from .client_mocks import mocked_client
|
||||
from .test_bec_figure import bec_figure
|
||||
from .conftest import create_widget
|
||||
|
||||
|
||||
def test_adding_curve_to_waveform(bec_figure):
|
||||
def test_adding_curve_to_waveform(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot()
|
||||
|
||||
# adding curve which is in bec - only names
|
||||
@@ -38,7 +40,8 @@ def test_adding_curve_to_waveform(bec_figure):
|
||||
assert c3.config.label == "non_existent_device-non_existent_device"
|
||||
|
||||
|
||||
def test_adding_curve_with_same_id(bec_figure):
|
||||
def test_adding_curve_with_same_id(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot()
|
||||
c1 = w1.add_curve_bec(x_name="samx", y_name="bpm4i", gui_id="test_curve")
|
||||
|
||||
@@ -47,7 +50,8 @@ def test_adding_curve_with_same_id(bec_figure):
|
||||
assert "Curve with ID 'test_curve' already exists." in str(excinfo.value)
|
||||
|
||||
|
||||
def test_create_waveform1D_by_config(bec_figure):
|
||||
def test_create_waveform1D_by_config(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1_config_input = {
|
||||
"widget_class": "BECWaveform",
|
||||
"gui_id": "widget_1",
|
||||
@@ -132,7 +136,8 @@ def test_create_waveform1D_by_config(bec_figure):
|
||||
assert w1.config.axis.title == "Widget 1"
|
||||
|
||||
|
||||
def test_change_gui_id(bec_figure):
|
||||
def test_change_gui_id(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot()
|
||||
c1 = w1.add_curve_bec(x_name="samx", y_name="bpm4i")
|
||||
w1.change_gui_id("new_id")
|
||||
@@ -141,7 +146,8 @@ def test_change_gui_id(bec_figure):
|
||||
assert c1.config.parent_id == "new_id"
|
||||
|
||||
|
||||
def test_getting_curve(bec_figure):
|
||||
def test_getting_curve(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot()
|
||||
c1 = w1.add_curve_bec(x_name="samx", y_name="bpm4i", gui_id="test_curve")
|
||||
c1_expected_config = CurveConfig(
|
||||
@@ -173,7 +179,8 @@ def test_getting_curve(bec_figure):
|
||||
assert c1.get_config() == c1_expected_config.model_dump()
|
||||
|
||||
|
||||
def test_getting_curve_errors(bec_figure):
|
||||
def test_getting_curve_errors(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot()
|
||||
c1 = w1.add_curve_bec(x_name="samx", y_name="bpm4i", gui_id="test_curve")
|
||||
|
||||
@@ -190,7 +197,8 @@ def test_getting_curve_errors(bec_figure):
|
||||
)
|
||||
|
||||
|
||||
def test_add_curve(bec_figure):
|
||||
def test_add_curve(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot()
|
||||
|
||||
c1 = w1.add_curve_bec(x_name="samx", y_name="bpm4i")
|
||||
@@ -201,7 +209,8 @@ def test_add_curve(bec_figure):
|
||||
assert c1.config.source == "scan_segment"
|
||||
|
||||
|
||||
def test_change_legend_font_size(bec_figure):
|
||||
def test_change_legend_font_size(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
plot = bec_figure.plot()
|
||||
|
||||
w1 = plot.add_curve_bec(x_name="samx", y_name="bpm4i")
|
||||
@@ -213,7 +222,8 @@ def test_change_legend_font_size(bec_figure):
|
||||
assert mock_set_scale.call_args == mock.call(2)
|
||||
|
||||
|
||||
def test_remove_curve(bec_figure):
|
||||
def test_remove_curve(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot()
|
||||
|
||||
w1.add_curve_bec(x_name="samx", y_name="bpm4i")
|
||||
@@ -231,7 +241,8 @@ def test_remove_curve(bec_figure):
|
||||
)
|
||||
|
||||
|
||||
def test_change_curve_appearance_methods(bec_figure, qtbot):
|
||||
def test_change_curve_appearance_methods(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot()
|
||||
|
||||
c1 = w1.add_curve_bec(x_name="samx", y_name="bpm4i")
|
||||
@@ -260,7 +271,8 @@ def test_change_curve_appearance_methods(bec_figure, qtbot):
|
||||
}
|
||||
|
||||
|
||||
def test_change_curve_appearance_args(bec_figure):
|
||||
def test_change_curve_appearance_args(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot()
|
||||
|
||||
c1 = w1.add_curve_bec(x_name="samx", y_name="bpm4i")
|
||||
@@ -290,7 +302,8 @@ def test_change_curve_appearance_args(bec_figure):
|
||||
}
|
||||
|
||||
|
||||
def test_set_custom_curve_data(bec_figure, qtbot):
|
||||
def test_set_custom_curve_data(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot()
|
||||
|
||||
c1 = w1.add_curve_custom(
|
||||
@@ -326,7 +339,8 @@ def test_set_custom_curve_data(bec_figure, qtbot):
|
||||
assert np.array_equal(y_new, [7, 8, 9])
|
||||
|
||||
|
||||
def test_custom_data_2D_array(bec_figure, qtbot):
|
||||
def test_custom_data_2D_array(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
|
||||
data = np.random.rand(10, 2)
|
||||
|
||||
@@ -338,7 +352,8 @@ def test_custom_data_2D_array(bec_figure, qtbot):
|
||||
assert np.array_equal(y, data[:, 1])
|
||||
|
||||
|
||||
def test_get_all_data(bec_figure):
|
||||
def test_get_all_data(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot()
|
||||
|
||||
c1 = w1.add_curve_custom(
|
||||
@@ -373,7 +388,8 @@ def test_get_all_data(bec_figure):
|
||||
}
|
||||
|
||||
|
||||
def test_curve_add_by_config(bec_figure):
|
||||
def test_curve_add_by_config(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot()
|
||||
|
||||
c1_config_input = {
|
||||
@@ -413,7 +429,8 @@ def test_curve_add_by_config(bec_figure):
|
||||
assert c1.get_config(False) == CurveConfig(**c1_config_input)
|
||||
|
||||
|
||||
def test_scan_update(bec_figure, qtbot):
|
||||
def test_scan_update(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot()
|
||||
|
||||
c1 = w1.add_curve_bec(x_name="samx", y_name="bpm4i")
|
||||
@@ -447,7 +464,8 @@ def test_scan_update(bec_figure, qtbot):
|
||||
assert c1.get_data() == ([10], [5])
|
||||
|
||||
|
||||
def test_scan_history_with_val_access(bec_figure, qtbot):
|
||||
def test_scan_history_with_val_access(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot()
|
||||
|
||||
w1.plot(x_name="samx", y_name="bpm4i")
|
||||
@@ -472,7 +490,8 @@ def test_scan_history_with_val_access(bec_figure, qtbot):
|
||||
assert np.array_equal(y_data, [4, 5, 6])
|
||||
|
||||
|
||||
def test_scatter_2d_update(bec_figure, qtbot):
|
||||
def test_scatter_2d_update(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot()
|
||||
|
||||
c1 = w1.add_curve_bec(x_name="samx", y_name="samx", z_name="bpm4i")
|
||||
@@ -512,7 +531,8 @@ def test_scatter_2d_update(bec_figure, qtbot):
|
||||
assert colors == expected_z_colors
|
||||
|
||||
|
||||
def test_waveform_single_arg_inputs(bec_figure, qtbot):
|
||||
def test_waveform_single_arg_inputs(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot()
|
||||
|
||||
w1.plot("bpm4i")
|
||||
@@ -544,7 +564,8 @@ def test_waveform_single_arg_inputs(bec_figure, qtbot):
|
||||
assert np.array_equal(w1._curves_data["custom"]["np_ndarray 2D"].get_data(), data_array_2D.T)
|
||||
|
||||
|
||||
def test_waveform_set_x_sync(bec_figure, qtbot):
|
||||
def test_waveform_set_x_sync(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot()
|
||||
custom_label = "custom_label"
|
||||
w1.plot("bpm4i")
|
||||
@@ -601,7 +622,8 @@ def test_waveform_set_x_sync(bec_figure, qtbot):
|
||||
assert w1.plot_item.getAxis("bottom").labelText == custom_label + " [timestamp]"
|
||||
|
||||
|
||||
def test_waveform_async_data_update(bec_figure, qtbot):
|
||||
def test_waveform_async_data_update(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot("async_device")
|
||||
custom_label = "custom_label"
|
||||
w1.set_x_label(custom_label)
|
||||
@@ -647,7 +669,8 @@ def test_waveform_async_data_update(bec_figure, qtbot):
|
||||
assert w1.plot_item.getAxis("bottom").labelText == custom_label + " [best_effort]"
|
||||
|
||||
|
||||
def test_waveform_set_x_async(bec_figure, qtbot):
|
||||
def test_waveform_set_x_async(qtbot, mocked_client):
|
||||
bec_figure = create_widget(qtbot, BECFigure, client=mocked_client)
|
||||
w1 = bec_figure.plot("async_device")
|
||||
custom_label = "custom_label"
|
||||
w1.set_x_label(custom_label)
|
||||
|
||||
@@ -14,7 +14,6 @@ def waveform_widget(qtbot, mocked_client):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.close()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -12,8 +12,6 @@ def website_widget(qtbot, mocked_client):
|
||||
qtbot.addWidget(widget)
|
||||
qtbot.waitExposed(widget)
|
||||
yield widget
|
||||
widget.page().deleteLater()
|
||||
qtbot.wait(1000)
|
||||
|
||||
|
||||
def test_website_widget_set_url(website_widget):
|
||||
|
||||