bec-widgets 0.81.1__py3-none-any.whl → 0.82.1__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.
Files changed (64) hide show
  1. CHANGELOG.md +44 -40
  2. PKG-INFO +1 -1
  3. bec_widgets/cli/client.py +1 -0
  4. bec_widgets/qt_utils/settings_dialog.py +107 -0
  5. bec_widgets/{widgets/toolbar → qt_utils}/toolbar.py +1 -30
  6. bec_widgets/widgets/{device_inputs → base_classes}/device_input_base.py +2 -0
  7. bec_widgets/widgets/{buttons/color_button → color_button}/color_button_plugin.py +1 -1
  8. bec_widgets/widgets/{buttons/color_button → color_button}/register_color_button.py +1 -1
  9. bec_widgets/widgets/device_combobox/assets/device_combobox_icon.png +0 -0
  10. bec_widgets/widgets/{device_inputs/device_combobox → device_combobox}/device_combobox.py +2 -2
  11. bec_widgets/widgets/device_combobox/device_combobox.pyproject +3 -0
  12. bec_widgets/widgets/{device_inputs/device_combobox → device_combobox}/device_combobox_plugin.py +6 -3
  13. bec_widgets/widgets/{device_inputs/device_combobox → device_combobox}/register_device_combobox.py +1 -3
  14. bec_widgets/widgets/device_line_edit/__init__.py +0 -0
  15. bec_widgets/widgets/device_line_edit/assets/line_edit_icon.png +0 -0
  16. bec_widgets/widgets/{device_inputs/device_line_edit → device_line_edit}/device_line_edit.py +2 -2
  17. bec_widgets/widgets/device_line_edit/device_line_edit.pyproject +3 -0
  18. bec_widgets/widgets/{device_inputs/device_line_edit → device_line_edit}/device_line_edit_plugin.py +6 -3
  19. bec_widgets/widgets/{device_inputs/device_line_edit → device_line_edit}/register_device_line_edit.py +1 -3
  20. bec_widgets/widgets/figure/plots/motor_map/motor_map.py +10 -8
  21. bec_widgets/widgets/figure/plots/waveform/waveform.py +8 -2
  22. bec_widgets/widgets/motor_map/motor_map_dialog/motor_map_settings.py +5 -31
  23. bec_widgets/widgets/motor_map/motor_map_dialog/motor_map_toolbar.py +2 -2
  24. bec_widgets/widgets/motor_map/motor_map_widget.py +6 -15
  25. bec_widgets/widgets/scan_control/scan_control.py +1 -1
  26. bec_widgets/widgets/scan_control/scan_group_box.py +1 -1
  27. bec_widgets/widgets/stop_button/__init__.py +0 -0
  28. bec_widgets/widgets/stop_button/assets/stop.png +0 -0
  29. bec_widgets/widgets/stop_button/register_stop_button.py +15 -0
  30. bec_widgets/widgets/{buttons/stop_button → stop_button}/stop_button.py +5 -12
  31. bec_widgets/widgets/stop_button/stop_button.pyproject +1 -0
  32. bec_widgets/widgets/stop_button/stop_button_plugin.py +57 -0
  33. bec_widgets/widgets/toggle/__init__.py +0 -0
  34. bec_widgets/widgets/toggle/register_toggle_switch.py +15 -0
  35. bec_widgets/widgets/toggle/toggle.py +149 -0
  36. bec_widgets/widgets/toggle/toggle_switch.pyproject +1 -0
  37. bec_widgets/widgets/toggle/toggle_switch_plugin.py +54 -0
  38. {bec_widgets-0.81.1.dist-info → bec_widgets-0.82.1.dist-info}/METADATA +1 -1
  39. {bec_widgets-0.81.1.dist-info → bec_widgets-0.82.1.dist-info}/RECORD +57 -45
  40. pyproject.toml +1 -1
  41. tests/unit_tests/client_mocks.py +8 -0
  42. tests/unit_tests/test_device_input_base.py +2 -2
  43. tests/unit_tests/test_device_input_widgets.py +4 -2
  44. tests/unit_tests/test_motor_map_widget.py +196 -0
  45. tests/unit_tests/test_setting_dialog.py +97 -0
  46. tests/unit_tests/test_stop_button.py +5 -2
  47. tests/unit_tests/test_toggle.py +38 -0
  48. bec_widgets/widgets/buttons/__init__.py +0 -1
  49. bec_widgets/widgets/device_inputs/__init__.py +0 -2
  50. bec_widgets/widgets/device_inputs/device_combobox/device_combobox.pyproject +0 -4
  51. bec_widgets/widgets/device_inputs/device_combobox/launch_device_combobox.py +0 -11
  52. bec_widgets/widgets/device_inputs/device_line_edit/device_line_edit.pyproject +0 -4
  53. bec_widgets/widgets/device_inputs/device_line_edit/launch_device_line_edit.py +0 -11
  54. bec_widgets/widgets/toolbar/__init__.py +0 -1
  55. /bec_widgets/{widgets/buttons/color_button → qt_utils}/__init__.py +0 -0
  56. /bec_widgets/widgets/{buttons/stop_button → base_classes}/__init__.py +0 -0
  57. /bec_widgets/widgets/{device_inputs/device_combobox → color_button}/__init__.py +0 -0
  58. /bec_widgets/widgets/{buttons/color_button → color_button}/assets/color_button.png +0 -0
  59. /bec_widgets/widgets/{buttons/color_button → color_button}/color_button.py +0 -0
  60. /bec_widgets/widgets/{buttons/color_button → color_button}/color_button.pyproject +0 -0
  61. /bec_widgets/widgets/{device_inputs/device_line_edit → device_combobox}/__init__.py +0 -0
  62. {bec_widgets-0.81.1.dist-info → bec_widgets-0.82.1.dist-info}/WHEEL +0 -0
  63. {bec_widgets-0.81.1.dist-info → bec_widgets-0.82.1.dist-info}/entry_points.txt +0 -0
  64. {bec_widgets-0.81.1.dist-info → bec_widgets-0.82.1.dist-info}/licenses/LICENSE +0 -0
@@ -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,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()
@@ -2,7 +2,7 @@
2
2
 
3
3
  import pytest
4
4
 
5
- from bec_widgets.widgets.buttons import StopButton
5
+ from bec_widgets.widgets.stop_button.stop_button import StopButton
6
6
 
7
7
  from .client_mocks import mocked_client
8
8
 
@@ -18,7 +18,10 @@ def stop_button(qtbot, mocked_client):
18
18
 
19
19
  def test_stop_button(stop_button):
20
20
  assert stop_button.text() == "Stop"
21
- assert stop_button.styleSheet() == "background-color: #cc181e; color: white"
21
+ assert (
22
+ stop_button.styleSheet()
23
+ == "background-color: #cc181e; color: white; font-weight: bold; font-size: 12px;"
24
+ )
22
25
  stop_button.click()
23
26
  assert stop_button.queue.request_scan_abortion.called
24
27
  assert stop_button.queue.request_queue_reset.called
@@ -0,0 +1,38 @@
1
+ import pytest
2
+ from qtpy.QtCore import QPointF, Qt
3
+
4
+ from bec_widgets.widgets.toggle.toggle import ToggleSwitch
5
+
6
+
7
+ @pytest.fixture
8
+ def toggle(qtbot):
9
+ widget = ToggleSwitch()
10
+ qtbot.addWidget(widget)
11
+ qtbot.waitExposed(widget)
12
+ yield widget
13
+
14
+
15
+ def test_toggle(toggle):
16
+ toggle.checked = False
17
+ assert toggle.checked is False
18
+
19
+ assert toggle.thumb_pos == QPointF(3, 2)
20
+
21
+ toggle.checked = True
22
+ assert toggle.checked is True
23
+
24
+ assert toggle.thumb_pos == QPointF(22, 2)
25
+
26
+
27
+ def test_toggle_click(qtbot, toggle):
28
+ init_state = toggle.checked
29
+
30
+ qtbot.mouseClick(toggle, Qt.LeftButton)
31
+ toggle.paintEvent(None)
32
+ assert toggle.checked is not init_state
33
+
34
+ init_state = toggle.checked
35
+
36
+ qtbot.mouseClick(toggle, Qt.LeftButton)
37
+ toggle.paintEvent(None)
38
+ assert toggle.checked is not init_state
@@ -1 +0,0 @@
1
- from .stop_button.stop_button import StopButton
@@ -1,2 +0,0 @@
1
- from .device_combobox.device_combobox import DeviceComboBox
2
- from .device_line_edit.device_line_edit import DeviceLineEdit
@@ -1,4 +0,0 @@
1
- {
2
- "files": ["device_combobox.py", "launch_device_combobox.py",
3
- ]
4
- }
@@ -1,11 +0,0 @@
1
- from bec_widgets.widgets.device_inputs import DeviceComboBox
2
-
3
- if __name__ == "__main__": # pragma: no cover
4
- import sys
5
-
6
- from qtpy.QtWidgets import QApplication
7
-
8
- app = QApplication(sys.argv)
9
- w = DeviceComboBox()
10
- w.show()
11
- sys.exit(app.exec_())
@@ -1,4 +0,0 @@
1
- {
2
- "files": ["device_line_edit.py", "launch_device_line_edit.py",
3
- ]
4
- }
@@ -1,11 +0,0 @@
1
- from bec_widgets.widgets.device_inputs import DeviceLineEdit
2
-
3
- if __name__ == "__main__": # pragma: no cover
4
- import sys
5
-
6
- from qtpy.QtWidgets import QApplication
7
-
8
- app = QApplication(sys.argv)
9
- w = DeviceLineEdit()
10
- w.show()
11
- sys.exit(app.exec_())
@@ -1 +0,0 @@
1
- from .toolbar import ModularToolBar