bec-widgets 0.44.5__py3-none-any.whl → 0.46.0__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.
- bec_widgets/cli/client.py +123 -1
- bec_widgets/cli/generate_cli.py +4 -3
- bec_widgets/cli/server.py +2 -2
- bec_widgets/widgets/__init__.py +1 -2
- bec_widgets/widgets/figure/figure.py +148 -22
- bec_widgets/widgets/plots/__init__.py +2 -1
- bec_widgets/widgets/plots/motor_map.py +423 -0
- bec_widgets/widgets/plots/plot_base.py +1 -1
- bec_widgets/widgets/plots/{waveform1d.py → waveform.py} +77 -11
- {bec_widgets-0.44.5.dist-info → bec_widgets-0.46.0.dist-info}/METADATA +1 -1
- {bec_widgets-0.44.5.dist-info → bec_widgets-0.46.0.dist-info}/RECORD +23 -24
- tests/client_mocks.py +76 -31
- tests/test_bec_dispatcher.py +2 -2
- tests/test_bec_figure.py +28 -4
- tests/test_bec_monitor.py +2 -66
- tests/test_bec_motor_map.py +125 -0
- tests/test_config_dialog.py +2 -63
- tests/test_motor_control.py +17 -83
- tests/test_motor_map.py +9 -66
- tests/test_waveform1d.py +75 -10
- bec_widgets/widgets/monitor_scatter_2D/__init__.py +0 -1
- bec_widgets/widgets/monitor_scatter_2D/monitor_scatter_2D.py +0 -374
- tests/test_bec_monitor_scatter2D.py +0 -162
- {bec_widgets-0.44.5.dist-info → bec_widgets-0.46.0.dist-info}/LICENSE +0 -0
- {bec_widgets-0.44.5.dist-info → bec_widgets-0.46.0.dist-info}/WHEEL +0 -0
- {bec_widgets-0.44.5.dist-info → bec_widgets-0.46.0.dist-info}/top_level.txt +0 -0
@@ -1,9 +1,9 @@
|
|
1
1
|
bec_widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
2
|
bec_widgets/cli/__init__.py,sha256=yFyAmDteCcndbReunhnrfDib6JujQ7-BKWeVvuU0Ylw,30
|
3
|
-
bec_widgets/cli/client.py,sha256=
|
3
|
+
bec_widgets/cli/client.py,sha256=rIK2W4rh6dSnrDkbw-qPOdE34r2sTwpOEhHR_QG81bM,38222
|
4
4
|
bec_widgets/cli/client_utils.py,sha256=8tVOmAMo5x0tUywTfivvCt8n0tJoT5WzoCa3GtsZ-qE,9694
|
5
|
-
bec_widgets/cli/generate_cli.py,sha256=
|
6
|
-
bec_widgets/cli/server.py,sha256=
|
5
|
+
bec_widgets/cli/generate_cli.py,sha256=JLqUlUgfz_f_4KHPRUAN-Xli-K7uNOc8-F-LkAC7Scw,4004
|
6
|
+
bec_widgets/cli/server.py,sha256=IqpFG7FnsTejnq-4reAqk5mBpynk1jZgoTn7O43N_6I,4717
|
7
7
|
bec_widgets/examples/__init__.py,sha256=WWQ0cu7m8sA4Ehy-DWdTIqSISjaHsbxhsNmNrMnhDZU,202
|
8
8
|
bec_widgets/examples/eiger_plot/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
9
|
bec_widgets/examples/eiger_plot/eiger_plot.py,sha256=Uxl2Usf8jEzaX7AT8zVqa1x8ZIEgI1HmazSlb-tRFWE,10359
|
@@ -36,19 +36,17 @@ bec_widgets/utils/widget_io.py,sha256=JKl508VnqQSxcaHqKaoBQ1TWSOm3pXhxQGx7iF_pRA
|
|
36
36
|
bec_widgets/utils/yaml_dialog.py,sha256=soZI8BOjlqYGfYDga70MEvkxJTsktq4y7B3uog2cSik,1851
|
37
37
|
bec_widgets/validation/__init__.py,sha256=ismd1bU5FhFb0zFPwNKuq7oT48G4Y2GfaMZOdNKUtGk,132
|
38
38
|
bec_widgets/validation/monitor_config_validator.py,sha256=M9p8K_nvxicnqJB4X7j90R377WHYVH4wMCtSXsRI51M,8150
|
39
|
-
bec_widgets/widgets/__init__.py,sha256=
|
39
|
+
bec_widgets/widgets/__init__.py,sha256=GptryTiWJ4yWZZVBG_03guISJabSOzVpOMRkgW0LdTg,383
|
40
40
|
bec_widgets/widgets/editor/__init__.py,sha256=5mBdFYi_IpygCz81kbLEZUWhd1b6oqiO3nASejuV_ug,30
|
41
41
|
bec_widgets/widgets/editor/editor.py,sha256=pIIYLPqqqhXqT11Xj10cyGEiy-ieNGE4ZujN5lf0e68,15110
|
42
42
|
bec_widgets/widgets/figure/__init__.py,sha256=3hGx_KOV7QHCYAV06aNuUgKq4QIYCjUTad-DrwkUaBM,44
|
43
|
-
bec_widgets/widgets/figure/figure.py,sha256=
|
43
|
+
bec_widgets/widgets/figure/figure.py,sha256=7kcHjkml3roJCVqMvlrDI3h_b4gSt2GNHm-JcTWHnDk,34361
|
44
44
|
bec_widgets/widgets/figure/figure_debug_minimal.ui,sha256=GodXBvBvs5QAUsHbo3pcxR4o51Tvce4DTqpTluk3hOs,742
|
45
45
|
bec_widgets/widgets/monitor/__init__.py,sha256=afXuZcBOxNAuYdCkIQXX5J60R5A3Q_86lNEW2vpFtPI,32
|
46
46
|
bec_widgets/widgets/monitor/config_dialog.py,sha256=Z1a4WRIVlfEGdwC-QG25kba2EHCZWi5J843tBVZlWiI,20275
|
47
47
|
bec_widgets/widgets/monitor/config_dialog.ui,sha256=ISMcF7CLTAMXhfZh2Yv5yezzAjMtb9fxY1pmX4B_jCg,5932
|
48
48
|
bec_widgets/widgets/monitor/monitor.py,sha256=ET5O48kqRlwd8_jCMCrp8QwnL8LvoNgb5nQmVw36pKg,30219
|
49
49
|
bec_widgets/widgets/monitor/tab_template.ui,sha256=JVB5fkzVhTjxMn9EdZCXsnfzBkeZpFMdTRuqTNSDSSo,4904
|
50
|
-
bec_widgets/widgets/monitor_scatter_2D/__init__.py,sha256=hgiRKV5PBdesYLFbLmYb-qfqNTIGwzpdQFvkLi6-qnE,52
|
51
|
-
bec_widgets/widgets/monitor_scatter_2D/monitor_scatter_2D.py,sha256=AKx3SUKxbyUxpXAHG5T-_horr02coKHbcMQppRZ_eEY,13108
|
52
50
|
bec_widgets/widgets/motor_control/__init__.py,sha256=_4-G9AKcEnOyS6qVE26meRw3grEohNeMzACNMU5Sig0,153
|
53
51
|
bec_widgets/widgets/motor_control/motor_control.py,sha256=sfH_uGes4B3mOFPP9BYVMtqMSCFD5fWJNQwNxV06288,42458
|
54
52
|
bec_widgets/widgets/motor_control/motor_control_absolute.ui,sha256=nR3p6oevAkIBTLW5wM_zYOVWsCAUgeMZdRm10Q77COE,4126
|
@@ -57,40 +55,41 @@ bec_widgets/widgets/motor_control/motor_control_selection.ui,sha256=vXXpvNWuL6xy
|
|
57
55
|
bec_widgets/widgets/motor_control/motor_control_table.ui,sha256=t6aRKiSmutMfp0AyupavbCs0cal-FANEnlKQiPzC9PQ,2792
|
58
56
|
bec_widgets/widgets/motor_map/__init__.py,sha256=K3c-3A_LbxK0UJ0_bV3opL-wGLTwBLendsJXsg8GAqE,32
|
59
57
|
bec_widgets/widgets/motor_map/motor_map.py,sha256=A7VOs8RAiXaLZF4_oxOYJX5BwMhRvir0k0u5eEPFtLc,21909
|
60
|
-
bec_widgets/widgets/plots/__init__.py,sha256=
|
58
|
+
bec_widgets/widgets/plots/__init__.py,sha256=kGQTORTr-2M9vmVCK-T7AFre4bY5LVVzGxcIzT81-ZU,237
|
61
59
|
bec_widgets/widgets/plots/image.py,sha256=Ty-8etIYBQl1MJLcuwCtlLUcAuXbxBq4RLDikbTL34c,31748
|
62
|
-
bec_widgets/widgets/plots/
|
63
|
-
bec_widgets/widgets/plots/
|
60
|
+
bec_widgets/widgets/plots/motor_map.py,sha256=wNluFsen4y68HMOu3XJu3tzmtJ4xilmOh8scuRiGUqw,15113
|
61
|
+
bec_widgets/widgets/plots/plot_base.py,sha256=tF0oamgCVIXFrfD8jnMVTltkzYLLSQ0Dq9HAG57Ji3E,8446
|
62
|
+
bec_widgets/widgets/plots/waveform.py,sha256=xSvq9N296L0JryV8quz0MpLIG37E-3hjgfWn_EeMkaw,28504
|
64
63
|
bec_widgets/widgets/scan_control/__init__.py,sha256=IOfHl15vxb_uC6KN62-PeUzbBha_vQyqkkXbJ2HU674,38
|
65
64
|
bec_widgets/widgets/scan_control/scan_control.py,sha256=tbO9tbVynRvs4VCxTZ4ZFBDTVAojIr-zkl70vuHbWgw,17116
|
66
65
|
bec_widgets/widgets/toolbar/__init__.py,sha256=d-TP4_cr_VbpwreMM4ePnfZ5YXsEPQ45ibEf75nuGoE,36
|
67
66
|
bec_widgets/widgets/toolbar/toolbar.py,sha256=sxz7rbc8XNPS6n2WMObF4-2PqdYfPxVtsOZEGV6mqa0,5124
|
68
67
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
69
|
-
tests/client_mocks.py,sha256=
|
68
|
+
tests/client_mocks.py,sha256=925yW3vFnS8h6ym_4kpgX299WGVeObkGneuiXNWRE7s,3596
|
70
69
|
tests/conftest.py,sha256=wMFVnerrLZjpi-OnPf7Ugah_DCb51QD1WWcbR4e_M6k,1055
|
71
70
|
tests/test_bec_connector.py,sha256=f2XXGGw3NoZLIUrDuZuEWwF_ttOYmmquCgUrV5XkIOY,1951
|
72
|
-
tests/test_bec_dispatcher.py,sha256=
|
73
|
-
tests/test_bec_figure.py,sha256=
|
74
|
-
tests/test_bec_monitor.py,sha256=
|
75
|
-
tests/
|
76
|
-
tests/test_config_dialog.py,sha256=
|
71
|
+
tests/test_bec_dispatcher.py,sha256=aX4ngQEslgxqYb0wpIYAz2_WUfGO6jJxYrPRy5Y4Xo8,9239
|
72
|
+
tests/test_bec_figure.py,sha256=4vOVZMRb50aoQaSjry-oomcjgG3lAQXtZJIq-FwkM5I,7908
|
73
|
+
tests/test_bec_monitor.py,sha256=mN7gBY7oXY6j65zzihpy8r-FvwVoCQlie3F6SoVq0mo,7042
|
74
|
+
tests/test_bec_motor_map.py,sha256=IXSfitUGxOPqmngwVNPK5nwi2QDcXWjBkGNb0dBZDxQ,4611
|
75
|
+
tests/test_config_dialog.py,sha256=5uNGcpvrx8qDdMwFCTXr8HMzFZF4rFi-ZHoDpMxGMf8,6955
|
77
76
|
tests/test_crosshair.py,sha256=d7fX-ymboZPALNqqiAj86PZ96llmGZ_3jf0yjVP0S94,5039
|
78
77
|
tests/test_editor.py,sha256=TED5k1xFJHRZ4KDAg2VxSRu_hMJnra-lbAmVwsDicsM,6784
|
79
78
|
tests/test_eiger_plot.py,sha256=bWnKBQid0YcLMQeBLy6ojb4ZpwTG-rFVT0kMg9Y08p8,4427
|
80
79
|
tests/test_generate_cli_client.py,sha256=BdpTZMNUFOBJa2e-rme9AJUoXfueYyLiUCOpGi3SNvc,2400
|
81
|
-
tests/test_motor_control.py,sha256=
|
82
|
-
tests/test_motor_map.py,sha256=
|
80
|
+
tests/test_motor_control.py,sha256=jdTG35z3jOL9XCAIDNIGfdv60vcwGLHa3KJjKqJkoZw,20322
|
81
|
+
tests/test_motor_map.py,sha256=UEjmtIYI2mxq9BUeopqoqNNy7UiPJEts9h45ufsFcrA,5979
|
83
82
|
tests/test_plot_base.py,sha256=bOdlgAxh9oKk5PwiQ_MSFmzr44uJ61Tlg242RCIhl5c,2610
|
84
83
|
tests/test_scan_control.py,sha256=e6_YpyxcayK35jXBSfxinGNL_8G-jcrWap25eg3z4QI,7560
|
85
84
|
tests/test_stream_plot.py,sha256=LNCYIj9CafremGaz-DwDktCRJRrjgfOdVewCUwwZE5s,5843
|
86
85
|
tests/test_validator_errors.py,sha256=NFxyv0TIOXeZKZRRUBfVQ7bpunwY4KkG95yTUdQmvns,3532
|
87
|
-
tests/test_waveform1d.py,sha256
|
86
|
+
tests/test_waveform1d.py,sha256=-YfBi_m91sR_v4oj8rshARk4G6AOxqQB_gbVqJ3iXvY,15003
|
88
87
|
tests/test_widget_io.py,sha256=FeL3ZYSBQnRt6jxj8VGYw1cmcicRQyHKleahw7XIyR0,3475
|
89
88
|
tests/test_yaml_dialog.py,sha256=HNrqferkdg02-9ieOhhI2mr2Qvt7GrYgXmQ061YCTbg,5794
|
90
89
|
tests/test_msgs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
91
90
|
tests/test_msgs/available_scans_message.py,sha256=m_z97hIrjHXXMa2Ex-UvsPmTxOYXfjxyJaGkIY6StTY,46532
|
92
|
-
bec_widgets-0.
|
93
|
-
bec_widgets-0.
|
94
|
-
bec_widgets-0.
|
95
|
-
bec_widgets-0.
|
96
|
-
bec_widgets-0.
|
91
|
+
bec_widgets-0.46.0.dist-info/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
|
92
|
+
bec_widgets-0.46.0.dist-info/METADATA,sha256=DMGzNpuWh8HzUrKOPVwMYr_5AsH5dVyGStDXZr85pqs,3714
|
93
|
+
bec_widgets-0.46.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
94
|
+
bec_widgets-0.46.0.dist-info/top_level.txt,sha256=EXCwhJYmXmd1DjYYL3hrGsddX-97IwYSiIHrf27FFVk,18
|
95
|
+
bec_widgets-0.46.0.dist-info/RECORD,,
|
tests/client_mocks.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
# pylint: disable = no-name-in-module,missing-class-docstring, missing-module-docstring
|
2
|
-
|
3
|
-
from unittest.mock import MagicMock
|
2
|
+
from unittest.mock import MagicMock, patch
|
4
3
|
|
5
4
|
import pytest
|
5
|
+
from bec_lib.device import Positioner
|
6
|
+
from bec_lib.devicemanager import DeviceContainer
|
6
7
|
|
7
8
|
|
8
9
|
class FakeDevice:
|
@@ -12,7 +13,7 @@ class FakeDevice:
|
|
12
13
|
self.name = name
|
13
14
|
self.enabled = enabled
|
14
15
|
self.signals = {self.name: {"value": 1.0}}
|
15
|
-
self.description = {self.name: {"source": self.name}}
|
16
|
+
self.description = {self.name: {"source": self.name, "dtype": "number", "shape": []}}
|
16
17
|
|
17
18
|
def __contains__(self, item):
|
18
19
|
return item == self.name
|
@@ -38,41 +39,85 @@ class FakeDevice:
|
|
38
39
|
return self.description
|
39
40
|
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
42
|
+
class FakePositioner(FakeDevice):
|
43
|
+
def __init__(self, name, enabled=True, limits=None, read_value=1.0):
|
44
|
+
super().__init__(name, enabled)
|
45
|
+
self.limits = limits if limits is not None else [0, 0]
|
46
|
+
self.read_value = read_value
|
47
|
+
|
48
|
+
def set_read_value(self, value):
|
49
|
+
self.read_value = value
|
50
|
+
|
51
|
+
def read(self):
|
52
|
+
return {self.name: {"value": self.read_value}}
|
53
|
+
|
54
|
+
def set_limits(self, limits):
|
55
|
+
self.limits = limits
|
56
|
+
|
57
|
+
def move(self, value, relative=False):
|
58
|
+
"""Simulates moving the device to a new position."""
|
59
|
+
if relative:
|
60
|
+
self.read_value += value
|
61
|
+
else:
|
62
|
+
self.read_value = value
|
63
|
+
# Respect the limits
|
64
|
+
self.read_value = max(min(self.read_value, self.limits[1]), self.limits[0])
|
65
|
+
|
66
|
+
@property
|
67
|
+
def readback(self):
|
68
|
+
return MagicMock(get=MagicMock(return_value=self.read_value))
|
69
|
+
|
70
|
+
|
71
|
+
class DMMock:
|
72
|
+
def __init__(self):
|
73
|
+
self.devices = DeviceContainer()
|
74
|
+
|
75
|
+
def add_devives(self, devices: list):
|
76
|
+
for device in devices:
|
77
|
+
self.devices[device.name] = device
|
78
|
+
|
79
|
+
|
80
|
+
DEVICES = [
|
81
|
+
FakePositioner("samx", limits=[-10, 10], read_value=2.0),
|
82
|
+
FakePositioner("samy", limits=[-5, 5], read_value=3.0),
|
83
|
+
FakePositioner("aptrx", limits=None, read_value=4.0),
|
84
|
+
FakePositioner("aptry", limits=None, read_value=5.0),
|
85
|
+
FakeDevice("gauss_bpm"),
|
86
|
+
FakeDevice("gauss_adc1"),
|
87
|
+
FakeDevice("gauss_adc2"),
|
88
|
+
FakeDevice("gauss_adc3"),
|
89
|
+
FakeDevice("bpm4i"),
|
90
|
+
FakeDevice("bpm3a"),
|
91
|
+
FakeDevice("bpm3i"),
|
92
|
+
]
|
48
93
|
|
49
94
|
|
50
95
|
@pytest.fixture(scope="function")
|
51
96
|
def mocked_client():
|
52
|
-
# Create a dictionary of mocked devices
|
53
|
-
device_names = [
|
54
|
-
"samx",
|
55
|
-
"samy",
|
56
|
-
"gauss_bpm",
|
57
|
-
"gauss_adc1",
|
58
|
-
"gauss_adc2",
|
59
|
-
"gauss_adc3",
|
60
|
-
"bpm4i",
|
61
|
-
"bpm3a",
|
62
|
-
"bpm3i",
|
63
|
-
]
|
64
|
-
mocked_devices = {name: get_mocked_device(name) for name in device_names}
|
65
|
-
|
66
97
|
# Create a MagicMock object
|
67
98
|
client = MagicMock()
|
68
99
|
|
69
100
|
# Mock the device_manager.devices attribute
|
70
|
-
client.device_manager
|
71
|
-
client.device_manager.
|
72
|
-
|
101
|
+
client.device_manager = DMMock()
|
102
|
+
client.device_manager.add_devives(DEVICES)
|
103
|
+
|
104
|
+
def mock_mv(*args, relative=False):
|
105
|
+
# Extracting motor and value pairs
|
106
|
+
for i in range(0, len(args), 2):
|
107
|
+
motor = args[i]
|
108
|
+
value = args[i + 1]
|
109
|
+
motor.move(value, relative=relative)
|
110
|
+
return MagicMock(wait=MagicMock())
|
111
|
+
|
112
|
+
client.scans = MagicMock(mv=mock_mv)
|
113
|
+
|
114
|
+
# Ensure isinstance check for Positioner passes
|
115
|
+
original_isinstance = isinstance
|
73
116
|
|
74
|
-
|
75
|
-
|
76
|
-
|
117
|
+
def isinstance_mock(obj, class_info):
|
118
|
+
if class_info == Positioner and isinstance(obj, FakePositioner):
|
119
|
+
return True
|
120
|
+
return original_isinstance(obj, class_info)
|
77
121
|
|
78
|
-
|
122
|
+
with patch("builtins.isinstance", new=isinstance_mock):
|
123
|
+
yield client
|
tests/test_bec_dispatcher.py
CHANGED
@@ -5,7 +5,7 @@ import pytest
|
|
5
5
|
from bec_lib.connector import MessageObject
|
6
6
|
from bec_lib.messages import ScanMessage
|
7
7
|
|
8
|
-
msg = MessageObject(topic="", value=ScanMessage(point_id=0, scan_id=
|
8
|
+
msg = MessageObject(topic="", value=ScanMessage(point_id=0, scan_id="scan_id", data={}))
|
9
9
|
|
10
10
|
|
11
11
|
@pytest.fixture(name="consumer")
|
@@ -205,7 +205,7 @@ def test_connect_one_slot_multiple_topics_single_callback(bec_dispatcher, consum
|
|
205
205
|
# Simulate messages being published on each topic
|
206
206
|
for topic in topics:
|
207
207
|
msg_with_topic = MessageObject(
|
208
|
-
topic=topic, value=ScanMessage(point_id=0, scan_id=
|
208
|
+
topic=topic, value=ScanMessage(point_id=0, scan_id="scan_id", data={})
|
209
209
|
)
|
210
210
|
consumer.register.call_args.kwargs["cb"](msg_with_topic)
|
211
211
|
|
tests/test_bec_figure.py
CHANGED
@@ -5,7 +5,8 @@ from unittest.mock import MagicMock
|
|
5
5
|
import numpy as np
|
6
6
|
import pytest
|
7
7
|
|
8
|
-
from bec_widgets.widgets import BECFigure
|
8
|
+
from bec_widgets.widgets import BECFigure, BECMotorMap, BECWaveform
|
9
|
+
from bec_widgets.widgets.plots import BECImageShow
|
9
10
|
|
10
11
|
from .client_mocks import mocked_client
|
11
12
|
|
@@ -49,8 +50,8 @@ def test_bec_figure_add_remove_plot(bec_figure):
|
|
49
50
|
assert "widget_1" in bec_figure._widgets
|
50
51
|
assert "widget_2" in bec_figure._widgets
|
51
52
|
assert "widget_3" in bec_figure._widgets
|
52
|
-
assert bec_figure._widgets["widget_1"].config.widget_class == "
|
53
|
-
assert bec_figure._widgets["widget_2"].config.widget_class == "
|
53
|
+
assert bec_figure._widgets["widget_1"].config.widget_class == "BECWaveform"
|
54
|
+
assert bec_figure._widgets["widget_2"].config.widget_class == "BECWaveform"
|
54
55
|
assert bec_figure._widgets["widget_3"].config.widget_class == "BECPlotBase"
|
55
56
|
|
56
57
|
# Check accessing positions by the grid in figure
|
@@ -63,7 +64,17 @@ def test_bec_figure_add_remove_plot(bec_figure):
|
|
63
64
|
assert len(bec_figure._widgets) == initial_count + 2
|
64
65
|
assert "widget_1" not in bec_figure._widgets
|
65
66
|
assert "widget_3" in bec_figure._widgets
|
66
|
-
assert bec_figure._widgets["widget_2"].config.widget_class == "
|
67
|
+
assert bec_figure._widgets["widget_2"].config.widget_class == "BECWaveform"
|
68
|
+
|
69
|
+
|
70
|
+
def test_add_different_types_of_widgets(bec_figure):
|
71
|
+
plt = bec_figure.plot("samx", "bpm4i")
|
72
|
+
im = bec_figure.image("eiger")
|
73
|
+
motor_map = bec_figure.motor_map("samx", "samy")
|
74
|
+
|
75
|
+
assert plt.__class__ == BECWaveform
|
76
|
+
assert im.__class__ == BECImageShow
|
77
|
+
assert motor_map.__class__ == BECMotorMap
|
67
78
|
|
68
79
|
|
69
80
|
def test_access_widgets_access_errors(bec_figure):
|
@@ -217,3 +228,16 @@ def test_clear_all(bec_figure):
|
|
217
228
|
|
218
229
|
assert len(bec_figure._widgets) == 0
|
219
230
|
assert np.shape(bec_figure.grid) == (0,)
|
231
|
+
|
232
|
+
|
233
|
+
def test_shortcuts(bec_figure):
|
234
|
+
plt = bec_figure.plot("samx", "bpm4i")
|
235
|
+
im = bec_figure.image("eiger")
|
236
|
+
motor_map = bec_figure.motor_map("samx", "samy")
|
237
|
+
|
238
|
+
assert plt.config.widget_class == "BECWaveform"
|
239
|
+
assert plt.__class__ == BECWaveform
|
240
|
+
assert im.config.widget_class == "BECImageShow"
|
241
|
+
assert im.__class__ == BECImageShow
|
242
|
+
assert motor_map.config.widget_class == "BECMotorMap"
|
243
|
+
assert motor_map.__class__ == BECMotorMap
|
tests/test_bec_monitor.py
CHANGED
@@ -7,6 +7,8 @@ import yaml
|
|
7
7
|
|
8
8
|
from bec_widgets.widgets import BECMonitor
|
9
9
|
|
10
|
+
from .client_mocks import mocked_client
|
11
|
+
|
10
12
|
|
11
13
|
def load_test_config(config_name):
|
12
14
|
"""Helper function to load config from yaml file."""
|
@@ -16,69 +18,6 @@ def load_test_config(config_name):
|
|
16
18
|
return config
|
17
19
|
|
18
20
|
|
19
|
-
class FakeDevice:
|
20
|
-
"""Fake minimal positioner class for testing."""
|
21
|
-
|
22
|
-
def __init__(self, name, enabled=True):
|
23
|
-
self.name = name
|
24
|
-
self.enabled = enabled
|
25
|
-
self.signals = {self.name: {"value": 1.0}}
|
26
|
-
self.description = {self.name: {"source": self.name}}
|
27
|
-
|
28
|
-
def __contains__(self, item):
|
29
|
-
return item == self.name
|
30
|
-
|
31
|
-
@property
|
32
|
-
def _hints(self):
|
33
|
-
return [self.name]
|
34
|
-
|
35
|
-
def set_value(self, fake_value: float = 1.0) -> None:
|
36
|
-
"""
|
37
|
-
Setup fake value for device readout
|
38
|
-
Args:
|
39
|
-
fake_value(float): Desired fake value
|
40
|
-
"""
|
41
|
-
self.signals[self.name]["value"] = fake_value
|
42
|
-
|
43
|
-
def describe(self) -> dict:
|
44
|
-
"""
|
45
|
-
Get the description of the device
|
46
|
-
Returns:
|
47
|
-
dict: Description of the device
|
48
|
-
"""
|
49
|
-
return self.description
|
50
|
-
|
51
|
-
|
52
|
-
def get_mocked_device(device_name: str):
|
53
|
-
"""
|
54
|
-
Helper function to mock the devices
|
55
|
-
Args:
|
56
|
-
device_name(str): Name of the device to mock
|
57
|
-
"""
|
58
|
-
return FakeDevice(name=device_name, enabled=True)
|
59
|
-
|
60
|
-
|
61
|
-
@pytest.fixture(scope="function")
|
62
|
-
def mocked_client():
|
63
|
-
# Create a dictionary of mocked devices
|
64
|
-
device_names = ["samx", "gauss_bpm", "gauss_adc1", "gauss_adc2", "gauss_adc3", "bpm4i"]
|
65
|
-
mocked_devices = {name: get_mocked_device(name) for name in device_names}
|
66
|
-
|
67
|
-
# Create a MagicMock object
|
68
|
-
client = MagicMock()
|
69
|
-
|
70
|
-
# Mock the device_manager.devices attribute
|
71
|
-
client.device_manager.devices = MagicMock()
|
72
|
-
client.device_manager.devices.__getitem__.side_effect = lambda x: mocked_devices.get(x)
|
73
|
-
client.device_manager.devices.__contains__.side_effect = lambda x: x in mocked_devices
|
74
|
-
|
75
|
-
# Set each device as an attribute of the mock
|
76
|
-
for name, device in mocked_devices.items():
|
77
|
-
setattr(client.device_manager.devices, name, device)
|
78
|
-
|
79
|
-
return client
|
80
|
-
|
81
|
-
|
82
21
|
@pytest.fixture(scope="function")
|
83
22
|
def monitor(bec_dispatcher, qtbot, mocked_client):
|
84
23
|
# client = MagicMock()
|
@@ -266,9 +205,6 @@ def test_on_scan_segment(monitor, config_name, msg, metadata, expected_data):
|
|
266
205
|
config = load_test_config(config_name)
|
267
206
|
monitor.on_config_update(config)
|
268
207
|
|
269
|
-
# Get hints
|
270
|
-
monitor.dev.__getitem__.side_effect = mock_getitem
|
271
|
-
|
272
208
|
# Mock scan_storage.find_scan_by_ID
|
273
209
|
mock_scan_data = MagicMock()
|
274
210
|
mock_scan_data.data = {
|
@@ -0,0 +1,125 @@
|
|
1
|
+
import pytest
|
2
|
+
|
3
|
+
from bec_widgets.widgets import BECMotorMap
|
4
|
+
from bec_widgets.widgets.plots.motor_map import MotorMapConfig
|
5
|
+
from bec_widgets.widgets.plots.waveform import Signal, SignalData
|
6
|
+
|
7
|
+
from .client_mocks import mocked_client
|
8
|
+
|
9
|
+
|
10
|
+
@pytest.fixture(scope="function")
|
11
|
+
def bec_motor_map(qtbot, mocked_client):
|
12
|
+
widget = BECMotorMap(client=mocked_client, gui_id="BECMotorMap_test")
|
13
|
+
# qtbot.addWidget(widget)
|
14
|
+
# qtbot.waitExposed(widget)
|
15
|
+
yield widget
|
16
|
+
|
17
|
+
|
18
|
+
def test_motor_map_init(bec_motor_map):
|
19
|
+
default_config = MotorMapConfig(widget_class="BECMotorMap", gui_id="BECMotorMap_test")
|
20
|
+
|
21
|
+
assert bec_motor_map.config == default_config
|
22
|
+
|
23
|
+
|
24
|
+
def test_motor_map_change_motors(bec_motor_map):
|
25
|
+
bec_motor_map.change_motors("samx", "samy")
|
26
|
+
|
27
|
+
assert bec_motor_map.config.signals.x == SignalData(name="samx", entry="samx", limits=[-10, 10])
|
28
|
+
assert bec_motor_map.config.signals.y == SignalData(name="samy", entry="samy", limits=[-5, 5])
|
29
|
+
|
30
|
+
|
31
|
+
def test_motor_map_get_limits(bec_motor_map):
|
32
|
+
expected_limits = {
|
33
|
+
"samx": [-10, 10],
|
34
|
+
"samy": [-5, 5],
|
35
|
+
}
|
36
|
+
|
37
|
+
for motor_name, expected_limit in expected_limits.items():
|
38
|
+
actual_limit = bec_motor_map._get_motor_limit(motor_name)
|
39
|
+
assert actual_limit == expected_limit
|
40
|
+
|
41
|
+
|
42
|
+
def test_motor_map_get_init_position(bec_motor_map):
|
43
|
+
bec_motor_map.set_precision(2)
|
44
|
+
|
45
|
+
motor_map_dev = bec_motor_map.client.device_manager.devices
|
46
|
+
|
47
|
+
expected_positions = {
|
48
|
+
("samx", "samx"): motor_map_dev["samx"].read()["samx"]["value"],
|
49
|
+
("samy", "samy"): motor_map_dev["samy"].read()["samy"]["value"],
|
50
|
+
("aptrx", "aptrx"): motor_map_dev["aptrx"].read()["aptrx"]["value"],
|
51
|
+
("aptry", "aptry"): motor_map_dev["aptry"].read()["aptry"]["value"],
|
52
|
+
}
|
53
|
+
|
54
|
+
for (motor_name, entry), expected_position in expected_positions.items():
|
55
|
+
actual_position = bec_motor_map._get_motor_init_position(motor_name, entry, 2)
|
56
|
+
assert actual_position == expected_position
|
57
|
+
|
58
|
+
|
59
|
+
def test_motor_movement_updates_position_and_database(bec_motor_map):
|
60
|
+
motor_map_dev = bec_motor_map.client.device_manager.devices
|
61
|
+
|
62
|
+
init_positions = {
|
63
|
+
"samx": [motor_map_dev["samx"].read()["samx"]["value"]],
|
64
|
+
"samy": [motor_map_dev["samy"].read()["samy"]["value"]],
|
65
|
+
}
|
66
|
+
|
67
|
+
bec_motor_map.change_motors("samx", "samy")
|
68
|
+
|
69
|
+
assert bec_motor_map.database_buffer["x"] == init_positions["samx"]
|
70
|
+
assert bec_motor_map.database_buffer["y"] == init_positions["samy"]
|
71
|
+
|
72
|
+
# Simulate motor movement for 'samx' only
|
73
|
+
new_position_samx = 4.0
|
74
|
+
bec_motor_map.on_device_readback({"signals": {"samx": {"value": new_position_samx}}})
|
75
|
+
|
76
|
+
init_positions["samx"].append(new_position_samx)
|
77
|
+
init_positions["samy"].append(init_positions["samy"][-1])
|
78
|
+
# Verify database update for 'samx'
|
79
|
+
assert bec_motor_map.database_buffer["x"] == init_positions["samx"]
|
80
|
+
|
81
|
+
# Verify 'samy' retains its last known position
|
82
|
+
assert bec_motor_map.database_buffer["y"] == init_positions["samy"]
|
83
|
+
|
84
|
+
|
85
|
+
def test_scatter_plot_rendering(bec_motor_map):
|
86
|
+
motor_map_dev = bec_motor_map.client.device_manager.devices
|
87
|
+
|
88
|
+
init_positions = {
|
89
|
+
"samx": [motor_map_dev["samx"].read()["samx"]["value"]],
|
90
|
+
"samy": [motor_map_dev["samy"].read()["samy"]["value"]],
|
91
|
+
}
|
92
|
+
|
93
|
+
bec_motor_map.change_motors("samx", "samy")
|
94
|
+
|
95
|
+
# Simulate motor movement for 'samx' only
|
96
|
+
new_position_samx = 4.0
|
97
|
+
bec_motor_map.on_device_readback({"signals": {"samx": {"value": new_position_samx}}})
|
98
|
+
bec_motor_map._update_plot()
|
99
|
+
|
100
|
+
# Get the scatter plot item
|
101
|
+
scatter_plot_item = bec_motor_map.plot_components["scatter"]
|
102
|
+
|
103
|
+
# Check the scatter plot item properties
|
104
|
+
assert len(scatter_plot_item.data) > 0, "Scatter plot data is empty"
|
105
|
+
x_data = scatter_plot_item.data["x"]
|
106
|
+
y_data = scatter_plot_item.data["y"]
|
107
|
+
assert x_data[-1] == new_position_samx, "Scatter plot X data not updated correctly"
|
108
|
+
assert (
|
109
|
+
y_data[-1] == init_positions["samy"][-1]
|
110
|
+
), "Scatter plot Y data should retain last known position"
|
111
|
+
|
112
|
+
|
113
|
+
def test_plot_visualization_consistency(bec_motor_map):
|
114
|
+
bec_motor_map.change_motors("samx", "samy")
|
115
|
+
# Simulate updating the plot with new data
|
116
|
+
bec_motor_map.on_device_readback({"signals": {"samx": {"value": 5}}})
|
117
|
+
bec_motor_map.on_device_readback({"signals": {"samy": {"value": 9}}})
|
118
|
+
bec_motor_map._update_plot()
|
119
|
+
|
120
|
+
scatter_plot_item = bec_motor_map.plot_components["scatter"]
|
121
|
+
|
122
|
+
# Check if the scatter plot reflects the new data correctly
|
123
|
+
assert (
|
124
|
+
scatter_plot_item.data["x"][-1] == 5 and scatter_plot_item.data["y"][-1] == 9
|
125
|
+
), "Plot not updated correctly with new data"
|
tests/test_config_dialog.py
CHANGED
@@ -8,6 +8,8 @@ from qtpy.QtWidgets import QTableWidgetItem, QTabWidget
|
|
8
8
|
|
9
9
|
from bec_widgets.widgets.monitor.config_dialog import ConfigDialog
|
10
10
|
|
11
|
+
from .client_mocks import mocked_client
|
12
|
+
|
11
13
|
|
12
14
|
def load_test_config(config_name):
|
13
15
|
"""Helper function to load config from yaml file."""
|
@@ -17,69 +19,6 @@ def load_test_config(config_name):
|
|
17
19
|
return config
|
18
20
|
|
19
21
|
|
20
|
-
class FakeDevice:
|
21
|
-
"""Fake minimal positioner class for testing."""
|
22
|
-
|
23
|
-
def __init__(self, name, enabled=True):
|
24
|
-
self.name = name
|
25
|
-
self.enabled = enabled
|
26
|
-
self.signals = {self.name: {"value": 1.0}}
|
27
|
-
self.description = {self.name: {"source": self.name}}
|
28
|
-
|
29
|
-
def __contains__(self, item):
|
30
|
-
return item == self.name
|
31
|
-
|
32
|
-
@property
|
33
|
-
def _hints(self):
|
34
|
-
return [self.name]
|
35
|
-
|
36
|
-
def set_value(self, fake_value: float = 1.0) -> None:
|
37
|
-
"""
|
38
|
-
Setup fake value for device readout
|
39
|
-
Args:
|
40
|
-
fake_value(float): Desired fake value
|
41
|
-
"""
|
42
|
-
self.signals[self.name]["value"] = fake_value
|
43
|
-
|
44
|
-
def describe(self) -> dict:
|
45
|
-
"""
|
46
|
-
Get the description of the device
|
47
|
-
Returns:
|
48
|
-
dict: Description of the device
|
49
|
-
"""
|
50
|
-
return self.description
|
51
|
-
|
52
|
-
|
53
|
-
def get_mocked_device(device_name: str):
|
54
|
-
"""
|
55
|
-
Helper function to mock the devices
|
56
|
-
Args:
|
57
|
-
device_name(str): Name of the device to mock
|
58
|
-
"""
|
59
|
-
return FakeDevice(name=device_name, enabled=True)
|
60
|
-
|
61
|
-
|
62
|
-
@pytest.fixture(scope="function")
|
63
|
-
def mocked_client():
|
64
|
-
# Create a dictionary of mocked devices
|
65
|
-
device_names = ["samx", "gauss_bpm", "gauss_adc1", "gauss_adc2", "gauss_adc3", "bpm4i"]
|
66
|
-
mocked_devices = {name: get_mocked_device(name) for name in device_names}
|
67
|
-
|
68
|
-
# Create a MagicMock object
|
69
|
-
client = MagicMock()
|
70
|
-
|
71
|
-
# Mock the device_manager.devices attribute
|
72
|
-
client.device_manager.devices = MagicMock()
|
73
|
-
client.device_manager.devices.__getitem__.side_effect = lambda x: mocked_devices.get(x)
|
74
|
-
client.device_manager.devices.__contains__.side_effect = lambda x: x in mocked_devices
|
75
|
-
|
76
|
-
# Set each device as an attribute of the mock
|
77
|
-
for name, device in mocked_devices.items():
|
78
|
-
setattr(client.device_manager.devices, name, device)
|
79
|
-
|
80
|
-
return client
|
81
|
-
|
82
|
-
|
83
22
|
@pytest.fixture(scope="function")
|
84
23
|
def config_dialog(qtbot, mocked_client):
|
85
24
|
client = mocked_client
|