bec-widgets 0.82.0__py3-none-any.whl → 0.82.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- CHANGELOG.md +28 -20
- PKG-INFO +1 -1
- bec_widgets/cli/client_utils.py +5 -2
- bec_widgets/cli/server.py +24 -10
- bec_widgets/qt_utils/__init__.py +0 -0
- bec_widgets/qt_utils/settings_dialog.py +107 -0
- bec_widgets/{widgets/toolbar → qt_utils}/toolbar.py +1 -30
- bec_widgets/widgets/figure/plots/motor_map/motor_map.py +10 -8
- bec_widgets/widgets/motor_map/motor_map_dialog/motor_map_settings.py +4 -30
- bec_widgets/widgets/motor_map/motor_map_dialog/motor_map_toolbar.py +1 -1
- bec_widgets/widgets/motor_map/motor_map_widget.py +6 -3
- {bec_widgets-0.82.0.dist-info → bec_widgets-0.82.2.dist-info}/METADATA +1 -1
- {bec_widgets-0.82.0.dist-info → bec_widgets-0.82.2.dist-info}/RECORD +24 -20
- pyproject.toml +1 -1
- tests/unit_tests/client_mocks.py +8 -0
- tests/unit_tests/test_client_utils.py +47 -0
- tests/unit_tests/test_device_input_base.py +1 -1
- tests/unit_tests/test_device_input_widgets.py +2 -0
- tests/unit_tests/test_motor_map_widget.py +196 -0
- tests/unit_tests/test_rpc_server.py +42 -0
- tests/unit_tests/test_setting_dialog.py +97 -0
- bec_widgets/widgets/toolbar/__init__.py +0 -1
- {bec_widgets-0.82.0.dist-info → bec_widgets-0.82.2.dist-info}/WHEEL +0 -0
- {bec_widgets-0.82.0.dist-info → bec_widgets-0.82.2.dist-info}/entry_points.txt +0 -0
- {bec_widgets-0.82.0.dist-info → bec_widgets-0.82.2.dist-info}/licenses/LICENSE +0 -0
CHANGELOG.md
CHANGED
@@ -1,5 +1,33 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## v0.82.2 (2024-07-08)
|
4
|
+
|
5
|
+
### Fix
|
6
|
+
|
7
|
+
* fix(rpc_server): pass cli config to server ([`90178e2`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/90178e2f61fa9dac7d82c0d0db40a9767bb133e6))
|
8
|
+
|
9
|
+
## v0.82.1 (2024-07-07)
|
10
|
+
|
11
|
+
### Fix
|
12
|
+
|
13
|
+
* fix(motor_map): bug where motors without limits were selected ([`c78cd89`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/c78cd898f203f950d7cb589eb5609feaa88062cf))
|
14
|
+
|
15
|
+
### Refactor
|
16
|
+
|
17
|
+
* refactor(setting_dialog): moved to qt_utils ([`3826bb3`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/3826bb3d9e870e85709b5b20ef09a4d22641280c))
|
18
|
+
|
19
|
+
* refactor(toolbar): toolbar moved from widgets to qt_utils ([`7ffc06f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/7ffc06f3c7ddd86a1681408a75221b9bbadb236b))
|
20
|
+
|
21
|
+
### Test
|
22
|
+
|
23
|
+
* test(setting_dialog): tests added ([`74a249b`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/74a249bd065d01006cb532bfff2a9bfedb34b592))
|
24
|
+
|
25
|
+
### Unknown
|
26
|
+
|
27
|
+
* tests(motor_map_widget): tests added ([`734f4c7`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/734f4c77507a1edafd477d81b5f7401d8e759be2))
|
28
|
+
|
29
|
+
* feat(settings_dialog):apply button ([`2020953`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/2020953b933b6fcad61ecc770588d39518c26fdd))
|
30
|
+
|
3
31
|
## v0.82.0 (2024-07-07)
|
4
32
|
|
5
33
|
### Feature
|
@@ -110,12 +138,6 @@
|
|
110
138
|
|
111
139
|
## v0.77.0 (2024-07-02)
|
112
140
|
|
113
|
-
### Feature
|
114
|
-
|
115
|
-
* feat(bec_connector): export config to yaml ([`a391f30`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/a391f3018c50fee6a4a06884491b957df80c3cd3))
|
116
|
-
|
117
|
-
* feat(utils): colors added convertor for rgba to hex ([`572f2fb`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/572f2fb8110d5cb0e80f3ca45ce57ef405572456))
|
118
|
-
|
119
141
|
### Fix
|
120
142
|
|
121
143
|
* fix(waveform): scatter 2D brush error ([`215d59c`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/215d59c8bfe7fda9aff8cec8353bef9e1ce2eca1))
|
@@ -123,17 +145,3 @@
|
|
123
145
|
* fix(figure): API cleanup ([`008a33a`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/008a33a9b192473cc58e90cd6d98c5bcb5f7b8c0))
|
124
146
|
|
125
147
|
* fix(figure): if/else logic corrected in subplot_factory ([`3e78723`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/3e787234c7274b0698423d7bf9a4c54ec46bad5f))
|
126
|
-
|
127
|
-
* fix(image): processing of already displayed data; closes #106 ([`1173510`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/1173510105d2d70d7e498c2ac1e122cea3a16597))
|
128
|
-
|
129
|
-
* fix(bec_figure): full reconstruction with config from other bec figure ([`b6e1e20`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/b6e1e20b7c8549bb092e981062329e601411dda6))
|
130
|
-
|
131
|
-
* fix(motor_map): API changes updates current visualisation; motor_map can be initialised from config ([`2e2d422`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/2e2d422910685a2527a3d961a468c787f771ca44))
|
132
|
-
|
133
|
-
* fix(image): image add_custom_image fixed, closes #225 ([`f0556e4`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/f0556e44113ffee66cf735aa2dd758c62cb634f4))
|
134
|
-
|
135
|
-
* fix(figure): subplot methods consolidated; added subplot factory ([`4a97105`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/4a97105e4bd2ce77d72dfe5f8307dd9ee65b21b0))
|
136
|
-
|
137
|
-
* fix(image): image can be fully reconstructed from config ([`797f73c`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/797f73c39aa73e07d6311f3de4baea53f6c380e0))
|
138
|
-
|
139
|
-
* fix(image_item): vrange added int for pydantic model check ([`b8f796f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/b8f796fd3fcc15641e8fc6a3ca75c344ce90fc45))
|
PKG-INFO
CHANGED
bec_widgets/cli/client_utils.py
CHANGED
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import importlib
|
4
4
|
import importlib.metadata as imd
|
5
|
+
import json
|
5
6
|
import os
|
6
7
|
import select
|
7
8
|
import subprocess
|
@@ -87,7 +88,7 @@ def _get_output(process, logger) -> None:
|
|
87
88
|
print(f"Error reading process output: {str(e)}")
|
88
89
|
|
89
90
|
|
90
|
-
def _start_plot_process(gui_id, gui_class, config, logger=None) -> None:
|
91
|
+
def _start_plot_process(gui_id: str, gui_class: type, config: dict | str, logger=None) -> None:
|
91
92
|
"""
|
92
93
|
Start the plot in a new process.
|
93
94
|
|
@@ -98,6 +99,8 @@ def _start_plot_process(gui_id, gui_class, config, logger=None) -> None:
|
|
98
99
|
# pylint: disable=subprocess-run-check
|
99
100
|
command = ["bec-gui-server", "--id", gui_id, "--gui_class", gui_class.__name__]
|
100
101
|
if config:
|
102
|
+
if isinstance(config, dict):
|
103
|
+
config = json.dumps(config)
|
101
104
|
command.extend(["--config", config])
|
102
105
|
|
103
106
|
env_dict = os.environ.copy()
|
@@ -190,7 +193,7 @@ class BECGuiClientMixin:
|
|
190
193
|
if self._process is None or self._process.poll() is not None:
|
191
194
|
self._start_update_script()
|
192
195
|
self._process, self._process_output_processing_thread = _start_plot_process(
|
193
|
-
self._gui_id, self.__class__, self._client._service_config.
|
196
|
+
self._gui_id, self.__class__, self._client._service_config.config
|
194
197
|
)
|
195
198
|
while not self.gui_is_alive():
|
196
199
|
print("Waiting for GUI to start...")
|
bec_widgets/cli/server.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import inspect
|
4
|
+
import json
|
4
5
|
import signal
|
5
6
|
import sys
|
6
7
|
from contextlib import redirect_stderr, redirect_stdout
|
@@ -141,10 +142,30 @@ class SimpleFileLikeFromLogOutputFunc:
|
|
141
142
|
return
|
142
143
|
|
143
144
|
|
145
|
+
def _start_server(gui_id: str, gui_class: Union[BECFigure, BECDockArea], config: str | None = None):
|
146
|
+
if config:
|
147
|
+
try:
|
148
|
+
config = json.loads(config)
|
149
|
+
service_config = ServiceConfig(config=config)
|
150
|
+
except (json.JSONDecodeError, TypeError):
|
151
|
+
service_config = ServiceConfig(config_path=config)
|
152
|
+
else:
|
153
|
+
# if no config is provided, use the default config
|
154
|
+
service_config = ServiceConfig()
|
155
|
+
|
156
|
+
bec_logger.configure(
|
157
|
+
service_config.redis,
|
158
|
+
QtRedisConnector,
|
159
|
+
service_name="BECWidgetsCLIServer",
|
160
|
+
service_config=service_config.service_config,
|
161
|
+
)
|
162
|
+
server = BECWidgetsCLIServer(gui_id=gui_id, config=service_config, gui_class=gui_class)
|
163
|
+
return server
|
164
|
+
|
165
|
+
|
144
166
|
def main():
|
145
167
|
import argparse
|
146
168
|
import os
|
147
|
-
import sys
|
148
169
|
|
149
170
|
from qtpy.QtCore import QSize
|
150
171
|
from qtpy.QtGui import QIcon
|
@@ -159,7 +180,7 @@ def main():
|
|
159
180
|
type=str,
|
160
181
|
help="Name of the gui class to be rendered. Possible values: \n- BECFigure\n- BECDockArea",
|
161
182
|
)
|
162
|
-
parser.add_argument("--config", type=str, help="Config file")
|
183
|
+
parser.add_argument("--config", type=str, help="Config file or config string.")
|
163
184
|
|
164
185
|
args = parser.parse_args()
|
165
186
|
|
@@ -188,14 +209,7 @@ def main():
|
|
188
209
|
win = QMainWindow()
|
189
210
|
win.setWindowTitle("BEC Widgets")
|
190
211
|
|
191
|
-
|
192
|
-
bec_logger.configure(
|
193
|
-
service_config.redis,
|
194
|
-
QtRedisConnector,
|
195
|
-
service_name="BECWidgetsCLIServer",
|
196
|
-
service_config=service_config.service_config,
|
197
|
-
)
|
198
|
-
server = BECWidgetsCLIServer(gui_id=args.id, config=service_config, gui_class=gui_class)
|
212
|
+
server = _start_server(args.id, gui_class, args.config)
|
199
213
|
|
200
214
|
gui = server.gui
|
201
215
|
win.setCentralWidget(gui)
|
File without changes
|
@@ -0,0 +1,107 @@
|
|
1
|
+
from qtpy.QtCore import Slot
|
2
|
+
from qtpy.QtWidgets import QDialog, QDialogButtonBox, QHBoxLayout, QPushButton, QVBoxLayout, QWidget
|
3
|
+
|
4
|
+
|
5
|
+
class SettingWidget(QWidget):
|
6
|
+
"""
|
7
|
+
Abstract class for a settings widget to enforce the implementation of the accept_changes and display_current_settings.
|
8
|
+
Can be used for toolbar actions to display the settings of a widget.
|
9
|
+
|
10
|
+
Args:
|
11
|
+
target_widget (QWidget): The widget that the settings will be taken from and applied to.
|
12
|
+
"""
|
13
|
+
|
14
|
+
def __init__(self, parent=None, *args, **kwargs):
|
15
|
+
super().__init__(parent, *args, **kwargs)
|
16
|
+
|
17
|
+
self.target_widget = None
|
18
|
+
|
19
|
+
def set_target_widget(self, target_widget: QWidget):
|
20
|
+
self.target_widget = target_widget
|
21
|
+
|
22
|
+
@Slot()
|
23
|
+
def accept_changes(self):
|
24
|
+
"""
|
25
|
+
Accepts the changes made in the settings widget and applies them to the target widget.
|
26
|
+
"""
|
27
|
+
pass
|
28
|
+
|
29
|
+
@Slot(dict)
|
30
|
+
def display_current_settings(self, config_dict: dict):
|
31
|
+
"""
|
32
|
+
Displays the current settings of the target widget in the settings widget.
|
33
|
+
|
34
|
+
Args:
|
35
|
+
config_dict(dict): The current settings of the target widget.
|
36
|
+
"""
|
37
|
+
pass
|
38
|
+
|
39
|
+
|
40
|
+
class SettingsDialog(QDialog):
|
41
|
+
"""
|
42
|
+
Dialog to display and edit the settings of a widget with accept and cancel buttons.
|
43
|
+
|
44
|
+
Args:
|
45
|
+
parent (QWidget): The parent widget of the dialog.
|
46
|
+
target_widget (QWidget): The widget that the settings will be taken from and applied to.
|
47
|
+
settings_widget (SettingWidget): The widget that will display the settings.
|
48
|
+
"""
|
49
|
+
|
50
|
+
def __init__(
|
51
|
+
self,
|
52
|
+
parent=None,
|
53
|
+
settings_widget: SettingWidget = None,
|
54
|
+
window_title: str = "Settings",
|
55
|
+
config: dict = None,
|
56
|
+
*args,
|
57
|
+
**kwargs,
|
58
|
+
):
|
59
|
+
super().__init__(parent, *args, **kwargs)
|
60
|
+
|
61
|
+
self.setModal(False)
|
62
|
+
|
63
|
+
self.setWindowTitle(window_title)
|
64
|
+
|
65
|
+
self.widget = settings_widget
|
66
|
+
self.widget.set_target_widget(parent)
|
67
|
+
if config is None:
|
68
|
+
config = parent.get_config()
|
69
|
+
|
70
|
+
self.widget.display_current_settings(config)
|
71
|
+
|
72
|
+
self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
73
|
+
|
74
|
+
self.apply_button = QPushButton("Apply")
|
75
|
+
|
76
|
+
button_layout = QHBoxLayout()
|
77
|
+
button_layout.addWidget(self.button_box.button(QDialogButtonBox.Cancel))
|
78
|
+
button_layout.addWidget(self.apply_button)
|
79
|
+
button_layout.addWidget(self.button_box.button(QDialogButtonBox.Ok))
|
80
|
+
|
81
|
+
self.button_box.accepted.connect(self.accept)
|
82
|
+
self.button_box.rejected.connect(self.reject)
|
83
|
+
self.apply_button.clicked.connect(self.apply_changes)
|
84
|
+
|
85
|
+
self.layout = QVBoxLayout(self)
|
86
|
+
self.layout.setContentsMargins(5, 5, 5, 5)
|
87
|
+
self.layout.addWidget(self.widget)
|
88
|
+
self.layout.addLayout(button_layout)
|
89
|
+
|
90
|
+
ok_button = self.button_box.button(QDialogButtonBox.Ok)
|
91
|
+
ok_button.setDefault(True)
|
92
|
+
ok_button.setAutoDefault(True)
|
93
|
+
|
94
|
+
@Slot()
|
95
|
+
def accept(self):
|
96
|
+
"""
|
97
|
+
Accept the changes made in the settings widget and close the dialog.
|
98
|
+
"""
|
99
|
+
self.widget.accept_changes()
|
100
|
+
super().accept()
|
101
|
+
|
102
|
+
@Slot()
|
103
|
+
def apply_changes(self):
|
104
|
+
"""
|
105
|
+
Apply the changes made in the settings widget without closing the dialog.
|
106
|
+
"""
|
107
|
+
self.widget.accept_changes()
|
@@ -3,8 +3,7 @@ from collections import defaultdict
|
|
3
3
|
|
4
4
|
# pylint: disable=no-name-in-module
|
5
5
|
from qtpy.QtCore import QSize
|
6
|
-
from qtpy.
|
7
|
-
from qtpy.QtWidgets import QHBoxLayout, QLabel, QSpinBox, QToolBar, QWidget
|
6
|
+
from qtpy.QtWidgets import QToolBar, QWidget
|
8
7
|
|
9
8
|
|
10
9
|
class ToolBarAction(ABC):
|
@@ -18,34 +17,6 @@ class ToolBarAction(ABC):
|
|
18
17
|
"""
|
19
18
|
|
20
19
|
|
21
|
-
class ColumnAdjustAction(ToolBarAction):
|
22
|
-
"""Toolbar spinbox to adjust number of columns in the plot layout"""
|
23
|
-
|
24
|
-
def add_to_toolbar(self, toolbar: QToolBar, target: QWidget):
|
25
|
-
"""Creates a access history button for the toolbar.
|
26
|
-
|
27
|
-
Args:
|
28
|
-
toolbar (QToolBar): The toolbar to add the action to.
|
29
|
-
target (QWidget): The widget that the 'Access Scan History' action will be targeted.
|
30
|
-
|
31
|
-
Returns:
|
32
|
-
QAction: The 'Access Scan History' action created for the toolbar.
|
33
|
-
"""
|
34
|
-
widget = QWidget()
|
35
|
-
layout = QHBoxLayout(widget)
|
36
|
-
|
37
|
-
label = QLabel("Columns:")
|
38
|
-
spin_box = QSpinBox()
|
39
|
-
spin_box.setMinimum(1) # Set minimum value
|
40
|
-
spin_box.setMaximum(10) # Set maximum value
|
41
|
-
spin_box.setValue(target.get_column_count()) # Initial value
|
42
|
-
spin_box.valueChanged.connect(lambda value: target.set_column_count(value))
|
43
|
-
|
44
|
-
layout.addWidget(label)
|
45
|
-
layout.addWidget(spin_box)
|
46
|
-
toolbar.addWidget(widget)
|
47
|
-
|
48
|
-
|
49
20
|
class ModularToolBar(QToolBar):
|
50
21
|
"""Modular toolbar with optional automatic initialization.
|
51
22
|
Args:
|
@@ -271,11 +271,12 @@ class BECMotorMap(BECPlotBase):
|
|
271
271
|
def _swap_limit_map(self):
|
272
272
|
"""Swap the limit map."""
|
273
273
|
self.plot_item.removeItem(self.plot_components["limit_map"])
|
274
|
-
self.
|
275
|
-
self.
|
276
|
-
|
277
|
-
|
278
|
-
|
274
|
+
if self.config.signals.x.limits is not None and self.config.signals.y.limits is not None:
|
275
|
+
self.plot_components["limit_map"] = self._make_limit_map(
|
276
|
+
self.config.signals.x.limits, self.config.signals.y.limits
|
277
|
+
)
|
278
|
+
self.plot_components["limit_map"].setZValue(-1)
|
279
|
+
self.plot_item.addItem(self.plot_components["limit_map"])
|
279
280
|
|
280
281
|
def _make_motor_map(self):
|
281
282
|
"""
|
@@ -284,9 +285,10 @@ class BECMotorMap(BECPlotBase):
|
|
284
285
|
# Create limit map
|
285
286
|
motor_x_limit = self.config.signals.x.limits
|
286
287
|
motor_y_limit = self.config.signals.y.limits
|
287
|
-
|
288
|
-
|
289
|
-
|
288
|
+
if motor_x_limit is not None or motor_y_limit is not None:
|
289
|
+
self.plot_components["limit_map"] = self._make_limit_map(motor_x_limit, motor_y_limit)
|
290
|
+
self.plot_item.addItem(self.plot_components["limit_map"])
|
291
|
+
self.plot_components["limit_map"].setZValue(-1)
|
290
292
|
|
291
293
|
# Create scatter plot
|
292
294
|
scatter_size = self.config.scatter_size
|
@@ -1,19 +1,19 @@
|
|
1
1
|
import os
|
2
2
|
|
3
3
|
from qtpy.QtCore import Slot
|
4
|
-
from qtpy.QtWidgets import
|
4
|
+
from qtpy.QtWidgets import QVBoxLayout
|
5
5
|
|
6
|
+
from bec_widgets.qt_utils.settings_dialog import SettingWidget
|
6
7
|
from bec_widgets.utils import UILoader
|
7
8
|
from bec_widgets.utils.widget_io import WidgetIO
|
8
9
|
|
9
10
|
|
10
|
-
class MotorMapSettings(
|
11
|
-
def __init__(self, parent=None,
|
11
|
+
class MotorMapSettings(SettingWidget):
|
12
|
+
def __init__(self, parent=None, *args, **kwargs):
|
12
13
|
super().__init__(parent, *args, **kwargs)
|
13
14
|
current_path = os.path.dirname(__file__)
|
14
15
|
|
15
16
|
self.ui = UILoader(self).loader(os.path.join(current_path, "motor_map_settings.ui"))
|
16
|
-
self.target_widget = target_widget
|
17
17
|
|
18
18
|
self.layout = QVBoxLayout(self)
|
19
19
|
self.layout.addWidget(self.ui)
|
@@ -45,29 +45,3 @@ class MotorMapSettings(QWidget):
|
|
45
45
|
self.target_widget.set_scatter_size(scatter_size)
|
46
46
|
self.target_widget.set_background_value(background_intensity)
|
47
47
|
self.target_widget.set_color(color)
|
48
|
-
|
49
|
-
|
50
|
-
class MotorMapDialog(QDialog):
|
51
|
-
def __init__(self, parent=None, target_widget: QWidget = None, *args, **kwargs):
|
52
|
-
super().__init__(parent, *args, **kwargs)
|
53
|
-
|
54
|
-
self.setModal(False)
|
55
|
-
|
56
|
-
self.setWindowTitle("Motor Map Settings")
|
57
|
-
|
58
|
-
self.target_widget = target_widget
|
59
|
-
self.widget = MotorMapSettings(target_widget=self.target_widget)
|
60
|
-
self.widget.display_current_settings(self.target_widget._config_dict)
|
61
|
-
self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
62
|
-
|
63
|
-
self.button_box.accepted.connect(self.accept)
|
64
|
-
self.button_box.rejected.connect(self.reject)
|
65
|
-
|
66
|
-
self.layout = QVBoxLayout(self)
|
67
|
-
self.layout.addWidget(self.widget)
|
68
|
-
self.layout.addWidget(self.button_box)
|
69
|
-
|
70
|
-
@Slot()
|
71
|
-
def accept(self):
|
72
|
-
self.widget.accept_changes()
|
73
|
-
super().accept()
|
@@ -4,8 +4,8 @@ from qtpy.QtCore import QSize
|
|
4
4
|
from qtpy.QtGui import QAction, QIcon
|
5
5
|
from qtpy.QtWidgets import QHBoxLayout, QLabel, QWidget
|
6
6
|
|
7
|
+
from bec_widgets.qt_utils.toolbar import ToolBarAction
|
7
8
|
from bec_widgets.widgets.device_combobox.device_combobox import DeviceComboBox
|
8
|
-
from bec_widgets.widgets.toolbar.toolbar import ToolBarAction
|
9
9
|
|
10
10
|
|
11
11
|
class DeviceSelectionAction(ToolBarAction):
|
@@ -4,17 +4,18 @@ import sys
|
|
4
4
|
|
5
5
|
from qtpy.QtWidgets import QVBoxLayout, QWidget
|
6
6
|
|
7
|
+
from bec_widgets.qt_utils.settings_dialog import SettingsDialog
|
8
|
+
from bec_widgets.qt_utils.toolbar import ModularToolBar
|
7
9
|
from bec_widgets.utils import BECConnector
|
8
10
|
from bec_widgets.widgets.figure import BECFigure
|
9
11
|
from bec_widgets.widgets.figure.plots.motor_map.motor_map import MotorMapConfig
|
10
|
-
from bec_widgets.widgets.motor_map.motor_map_dialog.motor_map_settings import
|
12
|
+
from bec_widgets.widgets.motor_map.motor_map_dialog.motor_map_settings import MotorMapSettings
|
11
13
|
from bec_widgets.widgets.motor_map.motor_map_dialog.motor_map_toolbar import (
|
12
14
|
ConnectAction,
|
13
15
|
DeviceSelectionAction,
|
14
16
|
ResetHistoryAction,
|
15
17
|
SettingsAction,
|
16
18
|
)
|
17
|
-
from bec_widgets.widgets.toolbar import ModularToolBar
|
18
19
|
|
19
20
|
|
20
21
|
class BECMotorMapWidget(BECConnector, QWidget):
|
@@ -92,7 +93,9 @@ class BECMotorMapWidget(BECConnector, QWidget):
|
|
92
93
|
toolbar_y.setStyleSheet("QComboBox {{ background-color: " "; }}")
|
93
94
|
|
94
95
|
def show_settings(self) -> None:
|
95
|
-
dialog =
|
96
|
+
dialog = SettingsDialog(
|
97
|
+
self, settings_widget=MotorMapSettings(), window_title="Motor Map Settings"
|
98
|
+
)
|
96
99
|
dialog.exec()
|
97
100
|
|
98
101
|
###################################
|
@@ -2,11 +2,11 @@
|
|
2
2
|
.gitlab-ci.yml,sha256=vuDJPAYOK0995_H6fu0N5dIgIrOJgTvKr0HZkNWlxMw,8142
|
3
3
|
.pylintrc,sha256=eeY8YwSI74oFfq6IYIbCqnx3Vk8ZncKaatv96n_Y8Rs,18544
|
4
4
|
.readthedocs.yaml,sha256=aSOc277LqXcsTI6lgvm_JY80lMlr69GbPKgivua2cS0,603
|
5
|
-
CHANGELOG.md,sha256=
|
5
|
+
CHANGELOG.md,sha256=7VVqe14x1w6butWm_Du8rzXRFtf3RQYV3CsURU1-uT0,6428
|
6
6
|
LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
|
7
|
-
PKG-INFO,sha256=
|
7
|
+
PKG-INFO,sha256=9lGCW5x2H2CEYe7DJsHs1LlXB0Pn_hr7efNeRFUGzgo,1309
|
8
8
|
README.md,sha256=Od69x-RS85Hph0-WwWACwal4yUd67XkEn4APEfHhHFw,2649
|
9
|
-
pyproject.toml,sha256=
|
9
|
+
pyproject.toml,sha256=Jsa50E-GnKAaTBdJplPyg-B7sHQsIPL2GS-IHwugDFA,2358
|
10
10
|
.git_hooks/pre-commit,sha256=n3RofIZHJl8zfJJIUomcMyYGFi_rwq4CC19z0snz3FI,286
|
11
11
|
.gitlab/issue_templates/bug_report_template.md,sha256=gAuyEwl7XlnebBrkiJ9AqffSNOywmr8vygUFWKTuQeI,386
|
12
12
|
.gitlab/issue_templates/documentation_update_template.md,sha256=FHLdb3TS_D9aL4CYZCjyXSulbaW5mrN2CmwTaeLPbNw,860
|
@@ -18,11 +18,11 @@ bec_widgets/assets/terminal_icon.png,sha256=bJl7Tft4Fi2uxvuXI8o14uMHnI9eAWKSU2uf
|
|
18
18
|
bec_widgets/cli/__init__.py,sha256=d0Q6Fn44e7wFfLabDOBxpcJ1DPKWlFunGYDUBmO-4hA,22
|
19
19
|
bec_widgets/cli/auto_updates.py,sha256=DyBV3HnjMSH-cvVkYNcDiYKVf0Xut4Qy2qGQqkW47Bw,4833
|
20
20
|
bec_widgets/cli/client.py,sha256=MMDy1edr1j9klgVGZZmD1dzLxi74gp75Jf4FNed9al8,60084
|
21
|
-
bec_widgets/cli/client_utils.py,sha256=
|
21
|
+
bec_widgets/cli/client_utils.py,sha256=cDhabblwaP88a0jlVpbn_RWWKVbsyjhmmGtMh9gesEw,12388
|
22
22
|
bec_widgets/cli/generate_cli.py,sha256=Ea5px9KblUlcGg-1JbJBTIU7laGg2n8PM7Efw9WVVzM,5889
|
23
23
|
bec_widgets/cli/rpc_register.py,sha256=QxXUZu5XNg00Yf5O3UHWOXg3-f_pzKjjoZYMOa-MOJc,2216
|
24
24
|
bec_widgets/cli/rpc_wigdet_handler.py,sha256=6kQng2DyS6rhLJqSJ7xa0kdgSxp-35A2upcf833dJRE,1483
|
25
|
-
bec_widgets/cli/server.py,sha256=
|
25
|
+
bec_widgets/cli/server.py,sha256=FZkqsjUHIkCUFMKUFm7ls_eslXvhIFzLpINEYxeWP5s,7722
|
26
26
|
bec_widgets/examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
27
27
|
bec_widgets/examples/jupyter_console/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
28
28
|
bec_widgets/examples/jupyter_console/jupyter_console_window.py,sha256=oOVCTY68bAn9HDFd5W_xNqQhI7Nsm7TaqYYLqLWXo2w,5520
|
@@ -34,6 +34,9 @@ bec_widgets/examples/plugin_example_pyside/taskmenuextension.pyproject,sha256=O_
|
|
34
34
|
bec_widgets/examples/plugin_example_pyside/tictactoe.py,sha256=s3rCurXloVcmMdzZiSzDS7Lgj0Qe6x8-wkxCeiXYX80,4904
|
35
35
|
bec_widgets/examples/plugin_example_pyside/tictactoeplugin.py,sha256=BBt3MD8oDLUMCCY3mioJa1QRR0WQdW6DuvVmK1Taovk,1734
|
36
36
|
bec_widgets/examples/plugin_example_pyside/tictactoetaskmenu.py,sha256=LNwplI6deUdKY6FOhUuWBanotxk9asF2G-6k7lFfA8Y,2301
|
37
|
+
bec_widgets/qt_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
38
|
+
bec_widgets/qt_utils/settings_dialog.py,sha256=rR_Zk4RGTnI4dz5OEzCc13lVpxlOKuwOf4_7wqXSbRw,3373
|
39
|
+
bec_widgets/qt_utils/toolbar.py,sha256=r6H4A8_3s2AItmdV8JS9UMSM4hV8Fx_162grYL2Pwzw,2111
|
37
40
|
bec_widgets/utils/__init__.py,sha256=1930ji1Jj6dVuY81Wd2kYBhHYNV-2R0bN_L4o9zBj1U,533
|
38
41
|
bec_widgets/utils/bec_connector.py,sha256=JScGWHEt4kh6C-C0O_JV_bOuiQlBjYTAPJktqgeAj70,9534
|
39
42
|
bec_widgets/utils/bec_designer.py,sha256=ak3G8FdojUPjVBBwdPXw7tN5P2Uxr-SSoQt394jXeAA,4308
|
@@ -102,7 +105,7 @@ bec_widgets/widgets/figure/plots/image/image.py,sha256=8J-20r12FD9_Wtv-YSzJsWdq3
|
|
102
105
|
bec_widgets/widgets/figure/plots/image/image_item.py,sha256=TyarahdWEn0jgalj5fqSAmcznXSbENkqHrrlL2GVdU4,10558
|
103
106
|
bec_widgets/widgets/figure/plots/image/image_processor.py,sha256=GeTtWjbldy6VejMwPGQgM-o3d6bmLglCjdoktu19xfA,5262
|
104
107
|
bec_widgets/widgets/figure/plots/motor_map/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
105
|
-
bec_widgets/widgets/figure/plots/motor_map/motor_map.py,sha256=
|
108
|
+
bec_widgets/widgets/figure/plots/motor_map/motor_map.py,sha256=FH3ZSYThGco98jS29r9EGcIh5fYx8e5eOs_nYJNrr48,18210
|
106
109
|
bec_widgets/widgets/figure/plots/waveform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
107
110
|
bec_widgets/widgets/figure/plots/waveform/waveform.py,sha256=e401GGvUF11rZKf4onB4zYlcUWIv8Zsnm4GcysaXi6U,29226
|
108
111
|
bec_widgets/widgets/figure/plots/waveform/waveform_curve.py,sha256=yQZGPKs--3X_9Qg2pv0GUiL5WLBQVC3z_PJKRnsHqPU,8293
|
@@ -111,16 +114,16 @@ bec_widgets/widgets/jupyter_console/jupyter_console.py,sha256=ioLYJL31RdBoAOGFSS
|
|
111
114
|
bec_widgets/widgets/motor_map/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
112
115
|
bec_widgets/widgets/motor_map/bec_motor_map_widget.pyproject,sha256=NAI8s5gRKz80ED4KY7OgD2OgSH5HEsjt2ux2BYp66yg,63
|
113
116
|
bec_widgets/widgets/motor_map/bec_motor_map_widget_plugin.py,sha256=PIfDE78Zqvsu7-xwoh9DdYkH8a7eOUFSaEl0bNrHYHc,1292
|
114
|
-
bec_widgets/widgets/motor_map/motor_map_widget.py,sha256=
|
117
|
+
bec_widgets/widgets/motor_map/motor_map_widget.py,sha256=92v90z6IrxORzxYrPIt1dFXZL8cJg9viFcGzNHGOeBw,7243
|
115
118
|
bec_widgets/widgets/motor_map/register_bec_motor_map_widget.py,sha256=qRG8PtWGjso0pWbvj_DXKnbUfmQzfGqPSrnAozXfM7o,492
|
116
119
|
bec_widgets/widgets/motor_map/assets/connection.svg,sha256=czIb1BnshmxJnER8ssU3WcLENrFSIUfMwberajWOGAk,341
|
117
120
|
bec_widgets/widgets/motor_map/assets/history.svg,sha256=bd6p5saxRiNRpd5OsSwIOvRWvel0WFEHul9zw4y9vH0,392
|
118
121
|
bec_widgets/widgets/motor_map/assets/motor_map.png,sha256=xd6GFBM8gAb5c-xRgswxTZFtvo449yK57-EbkFvidOI,9746
|
119
122
|
bec_widgets/widgets/motor_map/assets/settings.svg,sha256=ro30oa9CF1YijOXoUl-hz2DilJcqTy4rlTrMYhggumQ,1473
|
120
123
|
bec_widgets/widgets/motor_map/motor_map_dialog/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
121
|
-
bec_widgets/widgets/motor_map/motor_map_dialog/motor_map_settings.py,sha256=
|
124
|
+
bec_widgets/widgets/motor_map/motor_map_dialog/motor_map_settings.py,sha256=terJ5NHRzAsiUwdqg-hTbkQ5gadnRT0Ol0_Fm66kPF4,2011
|
122
125
|
bec_widgets/widgets/motor_map/motor_map_dialog/motor_map_settings.ui,sha256=nv5vPftt6vcIl60OOZLRvwD29rdHVWOoGmz168BnwKw,2685
|
123
|
-
bec_widgets/widgets/motor_map/motor_map_dialog/motor_map_toolbar.py,sha256=
|
126
|
+
bec_widgets/widgets/motor_map/motor_map_dialog/motor_map_toolbar.py,sha256=R6pmxhB_1ouc6f6cNQQvbxTHb3Ko3K_gTGs5WIYgnRI,2194
|
124
127
|
bec_widgets/widgets/ring_progress_bar/__init__.py,sha256=_uoJKnDM2YAeUBfwc5WLbIHSJj7zm_FAurSKP3WRaCw,47
|
125
128
|
bec_widgets/widgets/ring_progress_bar/ring.py,sha256=19zFj-6ZrIPLXYqvs5EPcrmDWnfnSLlEOmzJffL4d3A,11241
|
126
129
|
bec_widgets/widgets/ring_progress_bar/ring_progress_bar.py,sha256=sU4Dur2XzBVfDYAYazI6pjOZOhzggoQIuc9VD3PWgac,24073
|
@@ -140,8 +143,6 @@ bec_widgets/widgets/toggle/register_toggle_switch.py,sha256=8pVtkeEeiDOjV4OPoZq1
|
|
140
143
|
bec_widgets/widgets/toggle/toggle.py,sha256=JzCGYoyHBrlBWCoyL94QX4zSLyEwWbCNHMegjlnSy2E,4442
|
141
144
|
bec_widgets/widgets/toggle/toggle_switch.pyproject,sha256=Msa-AS5H5XlqW65r8GlX2AxD8FnFnDyDgGnbKcXqKOw,24
|
142
145
|
bec_widgets/widgets/toggle/toggle_switch_plugin.py,sha256=8e8JjUx6T5CIx7ixWLwVdT9JOJTbQ8aWwd3_9VAc_Mw,1177
|
143
|
-
bec_widgets/widgets/toolbar/__init__.py,sha256=d-TP4_cr_VbpwreMM4ePnfZ5YXsEPQ45ibEf75nuGoE,36
|
144
|
-
bec_widgets/widgets/toolbar/toolbar.py,sha256=rloOsr3TVGHLI4OJNKYWEBb1Z9_yJ0ZYIyf9RlPlxwY,3194
|
145
146
|
bec_widgets/widgets/vscode/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
146
147
|
bec_widgets/widgets/vscode/vscode.py,sha256=ZyJJCJapYrGhqgudEt8JQn723DDqLdwjsXxXa5q3EkU,2544
|
147
148
|
bec_widgets/widgets/website/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -202,7 +203,7 @@ tests/end-2-end/test_bec_figure_rpc_e2e.py,sha256=mjg29huqTivLnukG_XyoMtjOy2P_7J
|
|
202
203
|
tests/end-2-end/test_rpc_register_e2e.py,sha256=blhMiW7HVHX1kGm5dg8Sv0PeCuJ0gnBz3evznQFz_B8,1619
|
203
204
|
tests/end-2-end/test_scan_control_e2e.py,sha256=u7oLgFyltkMW2apSZKDukMIXvYrbhHrU32p4mBdn8VE,2276
|
204
205
|
tests/unit_tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
205
|
-
tests/unit_tests/client_mocks.py,sha256=
|
206
|
+
tests/unit_tests/client_mocks.py,sha256=BTBpA75CqeJhqYCI5M5XSX2-e4wMoHxi2rnc1PnmsuE,4549
|
206
207
|
tests/unit_tests/conftest.py,sha256=KrnktXPWmZhnKNue-xGWOLD1XGEvdz9Vf7V2eO3XQ3A,596
|
207
208
|
tests/unit_tests/test_bec_connector.py,sha256=zGDfNHwLFZTbpyX6-yc7Pwzr2jWO_HGZ8T4NFCNo4IE,2444
|
208
209
|
tests/unit_tests/test_bec_dispatcher.py,sha256=rYPiRizHaswhGZw55IBMneDFxmPiCCLAZQBqjEkpdyY,3992
|
@@ -212,20 +213,23 @@ tests/unit_tests/test_bec_image.py,sha256=mjvcrHgOF_FCj6WbUyxvZH9HL63QGA5C0PNZ5d
|
|
212
213
|
tests/unit_tests/test_bec_motor_map.py,sha256=dSYopbZS8lGD9cB26Kwmqw5zBoKCZs8t7DEEr50ug-g,8532
|
213
214
|
tests/unit_tests/test_bec_queue.py,sha256=u-uc-iZeGAS8P90o6Cxy5oz_60zHpirGAu04OgQPDXw,4598
|
214
215
|
tests/unit_tests/test_bec_status_box.py,sha256=gZdjyy9DNuUP9UwleTLj2Dp5HUImiqnkHjXWiqL0Q-o,4868
|
215
|
-
tests/unit_tests/test_client_utils.py,sha256=
|
216
|
+
tests/unit_tests/test_client_utils.py,sha256=CBdWIVJ_UiyFzTJnX3XJm4PGw2uXhFvRCP_Y9ifckbw,2630
|
216
217
|
tests/unit_tests/test_color_validation.py,sha256=xbFbtFDia36XLgaNrX2IwvAX3IDC_Odpj5BGoJSgiIE,2389
|
217
218
|
tests/unit_tests/test_crosshair.py,sha256=3OMAJ2ZaISYXMOtkXf1rPdy94vCr8njeLi6uHblBL9Q,5045
|
218
|
-
tests/unit_tests/test_device_input_base.py,sha256=
|
219
|
-
tests/unit_tests/test_device_input_widgets.py,sha256=
|
219
|
+
tests/unit_tests/test_device_input_base.py,sha256=r1tI7BFAhpv7V7gf_n5gjusyrBFOfuCqIkdVg7YA7vY,2444
|
220
|
+
tests/unit_tests/test_device_input_widgets.py,sha256=Q40xNKGvJT2dvNttRH68WZi0au8PwpUgBi2EB4LXfC8,5841
|
220
221
|
tests/unit_tests/test_generate_cli_client.py,sha256=ng-eV5iF7Dhm-6YpxYo99CMY0KgqoaZBQNkMeKULDBU,3355
|
221
222
|
tests/unit_tests/test_generate_plugin.py,sha256=9603ucZChM-pYpHadzsR94U1Zec1KZT34WedX9qzgMo,4464
|
223
|
+
tests/unit_tests/test_motor_map_widget.py,sha256=3nbINg3NYvWUrrGGMRPs8SDtePjXhoehSY_CShFGvEI,7507
|
222
224
|
tests/unit_tests/test_plot_base.py,sha256=vWbt-QO5blSoE5C1392MIFha9A9JnUsx_D_9yTqhcRo,3845
|
223
225
|
tests/unit_tests/test_plugin_utils.py,sha256=ayksWdrFY7kOiA0wVEjKFmFCF3UhH3lG8tzPVOpwysk,528
|
224
226
|
tests/unit_tests/test_ring_progress_bar.py,sha256=hDlqkQho7FR7HAfM4Zrr4q1m773a3_rQ8CbM1GqDDSE,12252
|
225
227
|
tests/unit_tests/test_rpc_register.py,sha256=hECjZEimd440mwRrO0rg7L3PKN7__3DgjmESN6wx3bo,1179
|
228
|
+
tests/unit_tests/test_rpc_server.py,sha256=MvstcvqUsnGAzUxw8Et1xXXikk_VIxFPwDZD0v1QGkg,1500
|
226
229
|
tests/unit_tests/test_rpc_widget_handler.py,sha256=ceQ3BPnBIFY2Hy-sDPw0wxxREVTTphILts0gvX9qoUw,234
|
227
230
|
tests/unit_tests/test_scan_control.py,sha256=Wr6KcE8av4sEIOx5VgYbzVCem3Jgb4Kzx_oOuvwlmkE,13459
|
228
231
|
tests/unit_tests/test_scan_control_group_box.py,sha256=HNqjP10B_NonikspNwKz9upJU-t7xf6hwBerNhbC-uo,5563
|
232
|
+
tests/unit_tests/test_setting_dialog.py,sha256=QbHWwLa1VGFwYie-SN3rjS3ICo7A44S4AKN2qeNvIKY,3137
|
229
233
|
tests/unit_tests/test_stop_button.py,sha256=tpQanzBUyl7qLXjbMUQqm3U3vShbKKARcnLpgsu3P0E,789
|
230
234
|
tests/unit_tests/test_text_box_widget.py,sha256=cT0uEHt_6d-FwST0A_wE9sFW9E3F_nJbKhuBAeU4yHg,1862
|
231
235
|
tests/unit_tests/test_toggle.py,sha256=Amzgres7te0tTQIDR2WMKSx9Kce44TxMpIPR6HZygXQ,832
|
@@ -239,8 +243,8 @@ tests/unit_tests/test_configs/config_device_no_entry.yaml,sha256=hdvue9KLc_kfNzG
|
|
239
243
|
tests/unit_tests/test_configs/config_scan.yaml,sha256=vo484BbWOjA_e-h6bTjSV9k7QaQHrlAvx-z8wtY-P4E,1915
|
240
244
|
tests/unit_tests/test_msgs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
241
245
|
tests/unit_tests/test_msgs/available_scans_message.py,sha256=m_z97hIrjHXXMa2Ex-UvsPmTxOYXfjxyJaGkIY6StTY,46532
|
242
|
-
bec_widgets-0.82.
|
243
|
-
bec_widgets-0.82.
|
244
|
-
bec_widgets-0.82.
|
245
|
-
bec_widgets-0.82.
|
246
|
-
bec_widgets-0.82.
|
246
|
+
bec_widgets-0.82.2.dist-info/METADATA,sha256=9lGCW5x2H2CEYe7DJsHs1LlXB0Pn_hr7efNeRFUGzgo,1309
|
247
|
+
bec_widgets-0.82.2.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
248
|
+
bec_widgets-0.82.2.dist-info/entry_points.txt,sha256=3otEkCdDB9LZJuBLzG4pFLK5Di0CVybN_12IsZrQ-58,166
|
249
|
+
bec_widgets-0.82.2.dist-info/licenses/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
|
250
|
+
bec_widgets-0.82.2.dist-info/RECORD,,
|
pyproject.toml
CHANGED
tests/unit_tests/client_mocks.py
CHANGED
@@ -72,6 +72,13 @@ class FakePositioner(FakeDevice):
|
|
72
72
|
return MagicMock(get=MagicMock(return_value=self.read_value))
|
73
73
|
|
74
74
|
|
75
|
+
class Positioner(FakePositioner):
|
76
|
+
"""just placeholder for testing embeded isinstance check in DeviceCombobox"""
|
77
|
+
|
78
|
+
def __init__(self, name="test", limits=None, read_value=1.0):
|
79
|
+
super().__init__(name, limits, read_value)
|
80
|
+
|
81
|
+
|
75
82
|
class DMMock:
|
76
83
|
def __init__(self):
|
77
84
|
self.devices = DeviceContainer()
|
@@ -95,6 +102,7 @@ DEVICES = [
|
|
95
102
|
FakeDevice("bpm3a"),
|
96
103
|
FakeDevice("bpm3i"),
|
97
104
|
FakeDevice("eiger"),
|
105
|
+
Positioner("test", limits=[-10, 10], read_value=2.0),
|
98
106
|
]
|
99
107
|
|
100
108
|
|
@@ -3,6 +3,7 @@ from unittest import mock
|
|
3
3
|
import pytest
|
4
4
|
|
5
5
|
from bec_widgets.cli.client import BECFigure
|
6
|
+
from bec_widgets.cli.client_utils import BECGuiClientMixin, _start_plot_process
|
6
7
|
|
7
8
|
from .client_mocks import FakeDevice
|
8
9
|
|
@@ -27,3 +28,49 @@ def test_rpc_call_accepts_device_as_input(cli_figure):
|
|
27
28
|
fig, mock_rpc_call = cli_figure
|
28
29
|
fig.plot(x_name=dev1, y_name=dev2)
|
29
30
|
mock_rpc_call.assert_called_with("plot", x_name="samx", y_name="bpm4i")
|
31
|
+
|
32
|
+
|
33
|
+
@pytest.mark.parametrize(
|
34
|
+
"config, call_config",
|
35
|
+
[
|
36
|
+
(None, None),
|
37
|
+
("/path/to/config.yml", "/path/to/config.yml"),
|
38
|
+
({"key": "value"}, '{"key": "value"}'),
|
39
|
+
],
|
40
|
+
)
|
41
|
+
def test_client_utils_start_plot_process(config, call_config):
|
42
|
+
with mock.patch("bec_widgets.cli.client_utils.subprocess.Popen") as mock_popen:
|
43
|
+
_start_plot_process("gui_id", BECFigure, config)
|
44
|
+
command = ["bec-gui-server", "--id", "gui_id", "--gui_class", "BECFigure"]
|
45
|
+
if call_config:
|
46
|
+
command.extend(["--config", call_config])
|
47
|
+
mock_popen.assert_called_once_with(
|
48
|
+
command,
|
49
|
+
text=True,
|
50
|
+
start_new_session=True,
|
51
|
+
stdout=mock.ANY,
|
52
|
+
stderr=mock.ANY,
|
53
|
+
env=mock.ANY,
|
54
|
+
)
|
55
|
+
|
56
|
+
|
57
|
+
def test_client_utils_passes_client_config_to_server(bec_dispatcher):
|
58
|
+
"""
|
59
|
+
Test that the client config is passed to the server. This ensures that
|
60
|
+
changes to the client config (either through config files or plugins) are
|
61
|
+
reflected in the server.
|
62
|
+
"""
|
63
|
+
mixin = BECGuiClientMixin()
|
64
|
+
mixin._client = bec_dispatcher.client
|
65
|
+
mixin._gui_id = "gui_id"
|
66
|
+
mixin.gui_is_alive = mock.MagicMock()
|
67
|
+
mixin.gui_is_alive.side_effect = [True]
|
68
|
+
|
69
|
+
with mock.patch("bec_widgets.cli.client_utils._start_plot_process") as mock_start_plot:
|
70
|
+
with mock.patch.object(mixin, "_start_update_script") as mock_start_update:
|
71
|
+
mock_start_plot.return_value = [mock.MagicMock(), mock.MagicMock()]
|
72
|
+
mixin.show()
|
73
|
+
mock_start_plot.assert_called_once_with(
|
74
|
+
"gui_id", BECGuiClientMixin, mixin._client._service_config.config
|
75
|
+
)
|
76
|
+
mock_start_update.assert_called_once()
|
@@ -63,4 +63,4 @@ def test_device_input_base_get_device_list(device_input_base):
|
|
63
63
|
|
64
64
|
def test_device_input_base_get_filters(device_input_base):
|
65
65
|
filters = device_input_base.get_available_filters()
|
66
|
-
assert filters == {"FakePositioner", "FakeDevice"}
|
66
|
+
assert filters == {"FakePositioner", "FakeDevice", "Positioner"}
|
@@ -67,6 +67,7 @@ def test_device_input_combobox_init(device_input_combobox):
|
|
67
67
|
"bpm3a",
|
68
68
|
"bpm3i",
|
69
69
|
"eiger",
|
70
|
+
"test",
|
70
71
|
]
|
71
72
|
|
72
73
|
|
@@ -153,6 +154,7 @@ def test_device_input_line_edit_init(device_input_line_edit):
|
|
153
154
|
"bpm3a",
|
154
155
|
"bpm3i",
|
155
156
|
"eiger",
|
157
|
+
"test",
|
156
158
|
]
|
157
159
|
|
158
160
|
|
@@ -0,0 +1,196 @@
|
|
1
|
+
from unittest.mock import MagicMock, patch
|
2
|
+
|
3
|
+
import pytest
|
4
|
+
|
5
|
+
from bec_widgets.widgets.motor_map.motor_map_dialog.motor_map_settings import MotorMapSettings
|
6
|
+
from bec_widgets.widgets.motor_map.motor_map_widget import BECMotorMapWidget
|
7
|
+
|
8
|
+
from .client_mocks import mocked_client
|
9
|
+
|
10
|
+
|
11
|
+
@pytest.fixture
|
12
|
+
def motor_map_widget(qtbot, mocked_client):
|
13
|
+
widget = BECMotorMapWidget(client=mocked_client())
|
14
|
+
widget.toolbar.widgets["motor_x"].device_combobox.set_device_filter("FakePositioner")
|
15
|
+
widget.toolbar.widgets["motor_y"].device_combobox.set_device_filter("FakePositioner")
|
16
|
+
qtbot.addWidget(widget)
|
17
|
+
qtbot.waitExposed(widget)
|
18
|
+
yield widget
|
19
|
+
widget.close()
|
20
|
+
|
21
|
+
|
22
|
+
@pytest.fixture
|
23
|
+
def mock_motor_map(motor_map_widget):
|
24
|
+
motor_map_mock = MagicMock()
|
25
|
+
motor_map_widget.map = motor_map_mock
|
26
|
+
return motor_map_mock
|
27
|
+
|
28
|
+
|
29
|
+
def test_motor_map_widget_init(motor_map_widget):
|
30
|
+
assert motor_map_widget is not None
|
31
|
+
assert motor_map_widget.client is not None
|
32
|
+
assert isinstance(motor_map_widget, BECMotorMapWidget)
|
33
|
+
assert motor_map_widget.config.widget_class == "BECMotorMapWidget"
|
34
|
+
|
35
|
+
# check initial state of toolbar actions
|
36
|
+
assert motor_map_widget.toolbar.widgets["connect"].action.isEnabled() == True
|
37
|
+
assert motor_map_widget.toolbar.widgets["config"].action.isEnabled() == False
|
38
|
+
assert motor_map_widget.toolbar.widgets["history"].action.isEnabled() == False
|
39
|
+
assert (
|
40
|
+
motor_map_widget.toolbar.widgets["motor_x"].device_combobox.config.device_filter
|
41
|
+
== "FakePositioner"
|
42
|
+
)
|
43
|
+
assert (
|
44
|
+
motor_map_widget.toolbar.widgets["motor_y"].device_combobox.config.device_filter
|
45
|
+
== "FakePositioner"
|
46
|
+
)
|
47
|
+
assert motor_map_widget.map.motor_x is None
|
48
|
+
assert motor_map_widget.map.motor_y is None
|
49
|
+
|
50
|
+
|
51
|
+
###################################
|
52
|
+
# Toolbar Actions
|
53
|
+
###################################
|
54
|
+
|
55
|
+
|
56
|
+
def test_motor_map_widget_change_motors_enable_toolbar(motor_map_widget):
|
57
|
+
motor_map_widget.change_motors("samx", "samy")
|
58
|
+
assert motor_map_widget.map.motor_x == "samx"
|
59
|
+
assert motor_map_widget.map.motor_y == "samy"
|
60
|
+
assert motor_map_widget.toolbar.widgets["motor_x"].device_combobox.currentText() == "samx"
|
61
|
+
assert motor_map_widget.toolbar.widgets["motor_y"].device_combobox.currentText() == "samy"
|
62
|
+
assert motor_map_widget.toolbar.widgets["config"].action.isEnabled() == True
|
63
|
+
assert motor_map_widget.toolbar.widgets["history"].action.isEnabled() == True
|
64
|
+
|
65
|
+
|
66
|
+
###################################
|
67
|
+
# Wrapper methods for MotorMap
|
68
|
+
###################################
|
69
|
+
|
70
|
+
|
71
|
+
def test_change_motors(motor_map_widget, mock_motor_map):
|
72
|
+
motor_map_widget.change_motors("motor_x", "motor_y", "motor_x_entry", "motor_y_entry", True)
|
73
|
+
mock_motor_map.change_motors.assert_called_once_with(
|
74
|
+
"motor_x", "motor_y", "motor_x_entry", "motor_y_entry", True
|
75
|
+
)
|
76
|
+
|
77
|
+
|
78
|
+
def test_get_data(motor_map_widget, mock_motor_map):
|
79
|
+
motor_map_widget.get_data()
|
80
|
+
mock_motor_map.get_data.assert_called_once()
|
81
|
+
|
82
|
+
|
83
|
+
def test_reset_history(motor_map_widget, mock_motor_map):
|
84
|
+
motor_map_widget.reset_history()
|
85
|
+
mock_motor_map.reset_history.assert_called_once()
|
86
|
+
|
87
|
+
|
88
|
+
def test_set_color(motor_map_widget, mock_motor_map):
|
89
|
+
motor_map_widget.set_color("blue")
|
90
|
+
mock_motor_map.set_color.assert_called_once_with("blue")
|
91
|
+
|
92
|
+
|
93
|
+
def test_set_max_points(motor_map_widget, mock_motor_map):
|
94
|
+
motor_map_widget.set_max_points(100)
|
95
|
+
mock_motor_map.set_max_points.assert_called_once_with(100)
|
96
|
+
|
97
|
+
|
98
|
+
def test_set_precision(motor_map_widget, mock_motor_map):
|
99
|
+
motor_map_widget.set_precision(2)
|
100
|
+
mock_motor_map.set_precision.assert_called_once_with(2)
|
101
|
+
|
102
|
+
|
103
|
+
def test_set_num_dim_points(motor_map_widget, mock_motor_map):
|
104
|
+
motor_map_widget.set_num_dim_points(50)
|
105
|
+
mock_motor_map.set_num_dim_points.assert_called_once_with(50)
|
106
|
+
|
107
|
+
|
108
|
+
def test_set_background_value(motor_map_widget, mock_motor_map):
|
109
|
+
motor_map_widget.set_background_value(128)
|
110
|
+
mock_motor_map.set_background_value.assert_called_once_with(128)
|
111
|
+
|
112
|
+
|
113
|
+
def test_set_scatter_size(motor_map_widget, mock_motor_map):
|
114
|
+
motor_map_widget.set_scatter_size(10)
|
115
|
+
mock_motor_map.set_scatter_size.assert_called_once_with(10)
|
116
|
+
|
117
|
+
|
118
|
+
###################################
|
119
|
+
# MotorMap Dialog
|
120
|
+
###################################
|
121
|
+
|
122
|
+
|
123
|
+
def test_motor_map_widget_clicked(motor_map_widget, qtbot):
|
124
|
+
motor_map_widget.toolbar.widgets["motor_x"].device_combobox.setCurrentText("samx")
|
125
|
+
motor_map_widget.toolbar.widgets["motor_y"].device_combobox.setCurrentText("samy")
|
126
|
+
motor_map_widget.toolbar.widgets["connect"].action.trigger()
|
127
|
+
|
128
|
+
qtbot.wait(200)
|
129
|
+
|
130
|
+
assert motor_map_widget.map.motor_x == "samx"
|
131
|
+
assert motor_map_widget.map.motor_y == "samy"
|
132
|
+
assert motor_map_widget.toolbar.widgets["config"].action.isEnabled() == True
|
133
|
+
assert motor_map_widget.toolbar.widgets["history"].action.isEnabled() == True
|
134
|
+
|
135
|
+
|
136
|
+
@pytest.fixture
|
137
|
+
def motor_map_settings(qtbot):
|
138
|
+
widget = MotorMapSettings()
|
139
|
+
qtbot.addWidget(widget)
|
140
|
+
qtbot.waitExposed(widget)
|
141
|
+
yield widget
|
142
|
+
widget.close()
|
143
|
+
|
144
|
+
|
145
|
+
def test_display_current_settings(motor_map_settings):
|
146
|
+
config = {
|
147
|
+
"max_points": 100,
|
148
|
+
"num_dim_points": 50,
|
149
|
+
"precision": 2,
|
150
|
+
"scatter_size": 10,
|
151
|
+
"background_value": 128,
|
152
|
+
"color": (255, 0, 0, 255),
|
153
|
+
}
|
154
|
+
|
155
|
+
with patch("bec_widgets.utils.widget_io.WidgetIO.set_value") as mock_set_value:
|
156
|
+
with patch.object(motor_map_settings.ui.color, "setColor") as mock_set_color:
|
157
|
+
motor_map_settings.display_current_settings(config)
|
158
|
+
mock_set_value.assert_any_call(motor_map_settings.ui.max_points, config["max_points"])
|
159
|
+
mock_set_value.assert_any_call(
|
160
|
+
motor_map_settings.ui.trace_dim, config["num_dim_points"]
|
161
|
+
)
|
162
|
+
mock_set_value.assert_any_call(motor_map_settings.ui.precision, config["precision"])
|
163
|
+
mock_set_value.assert_any_call(
|
164
|
+
motor_map_settings.ui.scatter_size, config["scatter_size"]
|
165
|
+
)
|
166
|
+
mock_set_value.assert_any_call(
|
167
|
+
motor_map_settings.ui.background_value, 50
|
168
|
+
) # 128/255*100 = 50
|
169
|
+
mock_set_color.assert_called_once_with(config["color"])
|
170
|
+
|
171
|
+
|
172
|
+
def test_accept_changes(motor_map_settings):
|
173
|
+
with patch(
|
174
|
+
"bec_widgets.utils.widget_io.WidgetIO.get_value", side_effect=[100, 50, 2, 10, 50]
|
175
|
+
) as mock_get_value:
|
176
|
+
with patch.object(
|
177
|
+
motor_map_settings.ui.color, "get_color", return_value=(255, 0, 0, 255)
|
178
|
+
) as mock_get_color:
|
179
|
+
mock_target_widget = MagicMock()
|
180
|
+
motor_map_settings.set_target_widget(mock_target_widget)
|
181
|
+
|
182
|
+
motor_map_settings.accept_changes()
|
183
|
+
|
184
|
+
mock_get_value.assert_any_call(motor_map_settings.ui.max_points)
|
185
|
+
mock_get_value.assert_any_call(motor_map_settings.ui.trace_dim)
|
186
|
+
mock_get_value.assert_any_call(motor_map_settings.ui.precision)
|
187
|
+
mock_get_value.assert_any_call(motor_map_settings.ui.scatter_size)
|
188
|
+
mock_get_value.assert_any_call(motor_map_settings.ui.background_value)
|
189
|
+
mock_get_color.assert_called_once()
|
190
|
+
|
191
|
+
mock_target_widget.set_max_points.assert_called_once_with(100)
|
192
|
+
mock_target_widget.set_num_dim_points.assert_called_once_with(50)
|
193
|
+
mock_target_widget.set_precision.assert_called_once_with(2)
|
194
|
+
mock_target_widget.set_scatter_size.assert_called_once_with(10)
|
195
|
+
mock_target_widget.set_background_value.assert_called_once_with(127)
|
196
|
+
mock_target_widget.set_color.assert_called_once_with((255, 0, 0, 255))
|
@@ -0,0 +1,42 @@
|
|
1
|
+
from unittest import mock
|
2
|
+
|
3
|
+
import pytest
|
4
|
+
from bec_lib.service_config import ServiceConfig
|
5
|
+
|
6
|
+
from bec_widgets.cli.server import _start_server
|
7
|
+
from bec_widgets.widgets.figure import BECFigure
|
8
|
+
|
9
|
+
|
10
|
+
@pytest.fixture
|
11
|
+
def mocked_cli_server():
|
12
|
+
with mock.patch("bec_widgets.cli.server.BECWidgetsCLIServer") as mock_server:
|
13
|
+
with mock.patch("bec_widgets.cli.server.ServiceConfig") as mock_config:
|
14
|
+
with mock.patch("bec_lib.logger.bec_logger.configure") as mock_logger:
|
15
|
+
yield mock_server, mock_config, mock_logger
|
16
|
+
|
17
|
+
|
18
|
+
def test_rpc_server_start_server_without_service_config(mocked_cli_server):
|
19
|
+
"""
|
20
|
+
Test that the server is started with the correct arguments.
|
21
|
+
"""
|
22
|
+
mock_server, mock_config, _ = mocked_cli_server
|
23
|
+
|
24
|
+
_start_server("gui_id", BECFigure, None)
|
25
|
+
mock_server.assert_called_once_with(gui_id="gui_id", config=mock_config(), gui_class=BECFigure)
|
26
|
+
|
27
|
+
|
28
|
+
@pytest.mark.parametrize(
|
29
|
+
"config, call_config",
|
30
|
+
[
|
31
|
+
("/path/to/config.yml", {"config_path": "/path/to/config.yml"}),
|
32
|
+
({"key": "value"}, {"config": {"key": "value"}}),
|
33
|
+
],
|
34
|
+
)
|
35
|
+
def test_rpc_server_start_server_with_service_config(mocked_cli_server, config, call_config):
|
36
|
+
"""
|
37
|
+
Test that the server is started with the correct arguments.
|
38
|
+
"""
|
39
|
+
mock_server, mock_config, _ = mocked_cli_server
|
40
|
+
config = mock_config(**call_config)
|
41
|
+
_start_server("gui_id", BECFigure, config)
|
42
|
+
mock_server.assert_called_once_with(gui_id="gui_id", config=config, gui_class=BECFigure)
|
@@ -0,0 +1,97 @@
|
|
1
|
+
from unittest.mock import MagicMock, patch
|
2
|
+
|
3
|
+
import pytest
|
4
|
+
from qtpy.QtWidgets import QWidget
|
5
|
+
|
6
|
+
from bec_widgets.qt_utils.settings_dialog import SettingsDialog, SettingWidget
|
7
|
+
|
8
|
+
###################################
|
9
|
+
# SettingWidget base class tests
|
10
|
+
###################################
|
11
|
+
|
12
|
+
|
13
|
+
@pytest.fixture
|
14
|
+
def setting_widget(qtbot):
|
15
|
+
widget = SettingWidget()
|
16
|
+
qtbot.addWidget(widget)
|
17
|
+
qtbot.waitExposed(widget)
|
18
|
+
yield widget
|
19
|
+
widget.close()
|
20
|
+
|
21
|
+
|
22
|
+
def test_setting_widget_initialization(setting_widget):
|
23
|
+
assert setting_widget.target_widget is None
|
24
|
+
|
25
|
+
|
26
|
+
def test_setting_widget_set_target_widget(setting_widget):
|
27
|
+
mock_target = MagicMock(spec=QWidget)
|
28
|
+
setting_widget.set_target_widget(mock_target)
|
29
|
+
assert setting_widget.target_widget == mock_target
|
30
|
+
|
31
|
+
|
32
|
+
def test_setting_widget_accept_changes(setting_widget):
|
33
|
+
with patch.object(setting_widget, "accept_changes") as mock_accept_changes:
|
34
|
+
setting_widget.accept_changes()
|
35
|
+
mock_accept_changes.assert_called_once()
|
36
|
+
|
37
|
+
|
38
|
+
def test_setting_widget_display_current_settings(setting_widget):
|
39
|
+
config_dict = {"setting1": "value1", "setting2": "value2"}
|
40
|
+
with patch.object(setting_widget, "display_current_settings") as mock_display_current_settings:
|
41
|
+
setting_widget.display_current_settings(config_dict)
|
42
|
+
mock_display_current_settings.assert_called_once_with(config_dict)
|
43
|
+
|
44
|
+
|
45
|
+
###################################
|
46
|
+
# SettingsDialog tests
|
47
|
+
###################################
|
48
|
+
@pytest.fixture
|
49
|
+
def settings_dialog(qtbot):
|
50
|
+
parent_widget = QWidget()
|
51
|
+
settings_widget = SettingWidget()
|
52
|
+
settings_widget.set_target_widget = MagicMock()
|
53
|
+
settings_widget.display_current_settings = MagicMock()
|
54
|
+
settings_widget.accept_changes = MagicMock()
|
55
|
+
|
56
|
+
dialog = SettingsDialog(
|
57
|
+
parent=parent_widget,
|
58
|
+
settings_widget=settings_widget,
|
59
|
+
window_title="Test Settings",
|
60
|
+
config={"setting1": "value1", "setting2": "value2"},
|
61
|
+
)
|
62
|
+
qtbot.addWidget(dialog)
|
63
|
+
qtbot.waitExposed(dialog)
|
64
|
+
yield dialog, parent_widget, settings_widget
|
65
|
+
dialog.close()
|
66
|
+
|
67
|
+
|
68
|
+
def test_settings_dialog_initialization(settings_dialog):
|
69
|
+
dialog, parent_widget, settings_widget = settings_dialog
|
70
|
+
|
71
|
+
assert dialog.windowTitle() == "Test Settings"
|
72
|
+
settings_widget.set_target_widget.assert_called_once_with(parent_widget)
|
73
|
+
settings_widget.display_current_settings.assert_called_once_with(
|
74
|
+
{"setting1": "value1", "setting2": "value2"}
|
75
|
+
)
|
76
|
+
|
77
|
+
|
78
|
+
def test_settings_dialog_accept(settings_dialog, qtbot):
|
79
|
+
dialog, _, settings_widget = settings_dialog
|
80
|
+
|
81
|
+
dialog.button_box.buttons()[0].click() # OK Button
|
82
|
+
settings_widget.accept_changes.assert_called_once()
|
83
|
+
|
84
|
+
|
85
|
+
def test_settings_dialog_reject(settings_dialog, qtbot):
|
86
|
+
dialog, _, _ = settings_dialog
|
87
|
+
|
88
|
+
with patch.object(dialog, "reject", wraps=dialog.reject) as mock_reject:
|
89
|
+
dialog.button_box.buttons()[1].click() # Cancel Button
|
90
|
+
mock_reject.assert_called_once()
|
91
|
+
|
92
|
+
|
93
|
+
def test_settings_dialog_apply_changes(settings_dialog, qtbot):
|
94
|
+
dialog, _, settings_widget = settings_dialog
|
95
|
+
|
96
|
+
dialog.apply_button.click()
|
97
|
+
settings_widget.accept_changes.assert_called_once()
|
@@ -1 +0,0 @@
|
|
1
|
-
from .toolbar import ModularToolBar
|
File without changes
|
File without changes
|
File without changes
|