bec-ipython-client 3.64.5__py3-none-any.whl → 3.89.3__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.
Potentially problematic release.
This version of bec-ipython-client might be problematic. Click here for more details.
- .gitignore +3 -0
- PKG-INFO +2 -2
- bec_ipython_client/callbacks/device_progress.py +11 -6
- bec_ipython_client/callbacks/ipython_live_updates.py +49 -19
- bec_ipython_client/callbacks/live_table.py +36 -9
- bec_ipython_client/callbacks/move_device.py +121 -59
- bec_ipython_client/callbacks/utils.py +5 -23
- bec_ipython_client/main.py +83 -14
- bec_ipython_client/signals.py +9 -3
- {bec_ipython_client-3.64.5.dist-info → bec_ipython_client-3.89.3.dist-info}/METADATA +2 -2
- bec_ipython_client-3.89.3.dist-info/RECORD +44 -0
- {bec_ipython_client-3.64.5.dist-info → bec_ipython_client-3.89.3.dist-info}/WHEEL +1 -1
- demo.py +2 -1
- pyproject.toml +2 -2
- tests/client_tests/conftest.py +19 -0
- tests/client_tests/test_bec_client.py +32 -1
- tests/client_tests/test_ipython_live_updates.py +259 -68
- tests/client_tests/test_live_table.py +33 -12
- tests/client_tests/test_move_callback.py +112 -70
- tests/end-2-end/_ensure_requirements_container.py +5 -5
- tests/end-2-end/test_procedures_e2e.py +36 -26
- tests/end-2-end/test_scans_e2e.py +62 -13
- tests/end-2-end/test_scans_lib_e2e.py +23 -19
- bec_ipython_client-3.64.5.dist-info/RECORD +0 -43
- {bec_ipython_client-3.64.5.dist-info → bec_ipython_client-3.89.3.dist-info}/entry_points.txt +0 -0
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import collections
|
|
2
|
+
import time
|
|
2
3
|
from unittest import mock
|
|
3
4
|
|
|
4
5
|
import pytest
|
|
5
6
|
|
|
6
7
|
from bec_ipython_client.callbacks.move_device import (
|
|
7
8
|
LiveUpdatesReadbackProgressbar,
|
|
8
|
-
|
|
9
|
+
ReadbackDataHandler,
|
|
9
10
|
)
|
|
10
11
|
from bec_lib import messages
|
|
11
12
|
from bec_lib.endpoints import MessageEndpoints
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
@pytest.fixture
|
|
15
|
-
def
|
|
16
|
-
with mock.patch.object(bec_client_mock.device_manager, "connector"):
|
|
17
|
-
yield
|
|
16
|
+
def readback_data_handler(bec_client_mock, connected_connector):
|
|
17
|
+
with mock.patch.object(bec_client_mock.device_manager, "connector", connected_connector):
|
|
18
|
+
yield ReadbackDataHandler(
|
|
19
|
+
bec_client_mock.device_manager, ["samx", "samy"], request_id="something"
|
|
20
|
+
)
|
|
18
21
|
|
|
19
22
|
|
|
20
23
|
def test_move_callback(bec_client_mock):
|
|
@@ -33,30 +36,25 @@ def test_move_callback(bec_client_mock):
|
|
|
33
36
|
return readback[0]
|
|
34
37
|
|
|
35
38
|
req_done = collections.deque()
|
|
36
|
-
|
|
37
|
-
device="samx", success=True, metadata={"RID": "something"}
|
|
38
|
-
)
|
|
39
|
-
req_done.extend([[None], [None], [None], [msg_acc]])
|
|
39
|
+
req_done.extend([{"samx": (False, False)}, {"samx": (False, False)}, {"samx": (True, True)}])
|
|
40
40
|
|
|
41
41
|
def mock_req_msg(*args):
|
|
42
42
|
if len(req_done) > 1:
|
|
43
43
|
return req_done.popleft()
|
|
44
44
|
return req_done[0]
|
|
45
45
|
|
|
46
|
-
with mock.patch("bec_ipython_client.callbacks.move_device.check_alarms")
|
|
47
|
-
with mock.patch.object(
|
|
48
|
-
with mock.patch.object(
|
|
46
|
+
with mock.patch("bec_ipython_client.callbacks.move_device.check_alarms"):
|
|
47
|
+
with mock.patch.object(LiveUpdatesReadbackProgressbar, "wait_for_request_acceptance"):
|
|
48
|
+
with mock.patch.object(
|
|
49
|
+
LiveUpdatesReadbackProgressbar, "_print_client_msgs_asap"
|
|
50
|
+
) as mock_client_msgs:
|
|
49
51
|
with mock.patch.object(
|
|
50
|
-
LiveUpdatesReadbackProgressbar, "
|
|
51
|
-
) as
|
|
52
|
-
with mock.patch.object(
|
|
53
|
-
|
|
54
|
-
) as mock_client_msgs_all:
|
|
55
|
-
with mock.patch.object(
|
|
56
|
-
ReadbackDataMixin, "get_device_values", mock_readback
|
|
57
|
-
):
|
|
52
|
+
LiveUpdatesReadbackProgressbar, "_print_client_msgs_all"
|
|
53
|
+
) as mock_client_msgs_all:
|
|
54
|
+
with mock.patch.object(ReadbackDataHandler, "get_device_values", mock_readback):
|
|
55
|
+
with mock.patch.object(ReadbackDataHandler, "device_states", mock_req_msg):
|
|
58
56
|
with mock.patch.object(
|
|
59
|
-
|
|
57
|
+
ReadbackDataHandler, "done", side_effect=[False, False, True]
|
|
60
58
|
):
|
|
61
59
|
LiveUpdatesReadbackProgressbar(bec=client, request=request).run()
|
|
62
60
|
assert mock_client_msgs.called is True
|
|
@@ -82,28 +80,21 @@ def test_move_callback_with_report_instruction(bec_client_mock):
|
|
|
82
80
|
return readback[0]
|
|
83
81
|
|
|
84
82
|
req_done = collections.deque()
|
|
85
|
-
|
|
86
|
-
device="samx", success=True, metadata={"RID": "something"}
|
|
87
|
-
)
|
|
88
|
-
req_done.extend([[None], [None], [None], [msg_acc]])
|
|
83
|
+
req_done.extend([{"samx": (False, False)}, {"samx": (False, False)}, {"samx": (True, True)}])
|
|
89
84
|
|
|
90
85
|
def mock_req_msg(*args):
|
|
91
86
|
if len(req_done) > 1:
|
|
92
87
|
return req_done.popleft()
|
|
93
88
|
return req_done[0]
|
|
94
89
|
|
|
95
|
-
with mock.patch("bec_ipython_client.callbacks.move_device.check_alarms")
|
|
96
|
-
with mock.patch.object(
|
|
97
|
-
with mock.patch.object(LiveUpdatesReadbackProgressbar, "
|
|
98
|
-
with mock.patch.object(LiveUpdatesReadbackProgressbar, "
|
|
99
|
-
with mock.patch.object(
|
|
100
|
-
|
|
101
|
-
):
|
|
102
|
-
with mock.patch.object(
|
|
103
|
-
ReadbackDataMixin, "get_device_values", mock_readback
|
|
104
|
-
):
|
|
90
|
+
with mock.patch("bec_ipython_client.callbacks.move_device.check_alarms"):
|
|
91
|
+
with mock.patch.object(LiveUpdatesReadbackProgressbar, "wait_for_request_acceptance"):
|
|
92
|
+
with mock.patch.object(LiveUpdatesReadbackProgressbar, "_print_client_msgs_asap"):
|
|
93
|
+
with mock.patch.object(LiveUpdatesReadbackProgressbar, "_print_client_msgs_all"):
|
|
94
|
+
with mock.patch.object(ReadbackDataHandler, "get_device_values", mock_readback):
|
|
95
|
+
with mock.patch.object(ReadbackDataHandler, "device_states", mock_req_msg):
|
|
105
96
|
with mock.patch.object(
|
|
106
|
-
|
|
97
|
+
ReadbackDataHandler, "done", side_effect=[False, False, False, True]
|
|
107
98
|
):
|
|
108
99
|
LiveUpdatesReadbackProgressbar(
|
|
109
100
|
bec=client,
|
|
@@ -112,70 +103,121 @@ def test_move_callback_with_report_instruction(bec_client_mock):
|
|
|
112
103
|
).run()
|
|
113
104
|
|
|
114
105
|
|
|
115
|
-
def
|
|
116
|
-
|
|
117
|
-
messages.DeviceMessage(
|
|
106
|
+
def test_readback_data_handler(readback_data_handler):
|
|
107
|
+
readback_data_handler.data = {
|
|
108
|
+
"samx": messages.DeviceMessage(
|
|
118
109
|
signals={"samx": {"value": 10}, "samx_setpoint": {"value": 20}},
|
|
119
110
|
metadata={"device": "samx"},
|
|
120
111
|
),
|
|
121
|
-
messages.DeviceMessage(
|
|
112
|
+
"samy": messages.DeviceMessage(
|
|
122
113
|
signals={"samy": {"value": 10}, "samy_setpoint": {"value": 20}},
|
|
123
114
|
metadata={"device": "samy"},
|
|
124
115
|
),
|
|
125
|
-
|
|
126
|
-
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
res = readback_data_handler.get_device_values()
|
|
127
119
|
assert res == [10, 10]
|
|
128
120
|
|
|
129
121
|
|
|
130
|
-
def
|
|
131
|
-
|
|
122
|
+
def test_readback_data_handler_multiple_hints(readback_data_handler):
|
|
123
|
+
readback_data_handler.device_manager.devices.samx._info["hints"]["fields"] = [
|
|
132
124
|
"samx_setpoint",
|
|
133
125
|
"samx",
|
|
134
126
|
]
|
|
135
|
-
|
|
136
|
-
messages.DeviceMessage(
|
|
127
|
+
readback_data_handler.data = {
|
|
128
|
+
"samx": messages.DeviceMessage(
|
|
137
129
|
signals={"samx": {"value": 10}, "samx_setpoint": {"value": 20}},
|
|
138
130
|
metadata={"device": "samx"},
|
|
139
131
|
),
|
|
140
|
-
messages.DeviceMessage(
|
|
132
|
+
"samy": messages.DeviceMessage(
|
|
141
133
|
signals={"samy": {"value": 10}, "samy_setpoint": {"value": 20}},
|
|
142
134
|
metadata={"device": "samy"},
|
|
143
135
|
),
|
|
144
|
-
|
|
145
|
-
res =
|
|
136
|
+
}
|
|
137
|
+
res = readback_data_handler.get_device_values()
|
|
146
138
|
assert res == [20, 10]
|
|
147
139
|
|
|
148
140
|
|
|
149
|
-
def
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
messages.DeviceMessage(
|
|
141
|
+
def test_readback_data_handler_multiple_no_hints(readback_data_handler):
|
|
142
|
+
readback_data_handler.device_manager.devices.samx._info["hints"]["fields"] = []
|
|
143
|
+
readback_data_handler.data = {
|
|
144
|
+
"samx": messages.DeviceMessage(
|
|
153
145
|
signals={"samx": {"value": 10}, "samx_setpoint": {"value": 20}},
|
|
154
146
|
metadata={"device": "samx"},
|
|
155
147
|
),
|
|
156
|
-
messages.DeviceMessage(
|
|
148
|
+
"samy": messages.DeviceMessage(
|
|
157
149
|
signals={"samy": {"value": 10}, "samy_setpoint": {"value": 20}},
|
|
158
150
|
metadata={"device": "samy"},
|
|
159
151
|
),
|
|
160
|
-
|
|
161
|
-
res =
|
|
152
|
+
}
|
|
153
|
+
res = readback_data_handler.get_device_values()
|
|
162
154
|
assert res == [10, 10]
|
|
163
155
|
|
|
164
156
|
|
|
165
|
-
def
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
)
|
|
173
|
-
|
|
157
|
+
def test_readback_data_handler_init(readback_data_handler):
|
|
158
|
+
"""
|
|
159
|
+
Test that the ReadbackDataHandler is initialized correctly.
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
# Initial state
|
|
163
|
+
assert readback_data_handler._devices_done_state == {
|
|
164
|
+
"samx": (False, False),
|
|
165
|
+
"samy": (False, False),
|
|
166
|
+
}
|
|
167
|
+
assert readback_data_handler._devices_received == {"samx": False, "samy": False}
|
|
168
|
+
assert readback_data_handler.data == {}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def test_readback_data_handler_readback_callbacks(readback_data_handler):
|
|
172
|
+
"""
|
|
173
|
+
Test that the readback callback properly updates the readback data.
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
# Submit readback for samx
|
|
177
|
+
msg = messages.DeviceMessage(
|
|
178
|
+
signals={"samx": {"value": 15}}, metadata={"device": "samx", "RID": "something"}
|
|
174
179
|
)
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
180
|
+
readback_data_handler.connector.set_and_publish(MessageEndpoints.device_readback("samx"), msg)
|
|
181
|
+
|
|
182
|
+
msg_old = messages.DeviceMessage(
|
|
183
|
+
signals={"samy": {"value": 10}}, metadata={"device": "samx", "RID": "something_else"}
|
|
184
|
+
)
|
|
185
|
+
readback_data_handler.connector.set_and_publish(
|
|
186
|
+
MessageEndpoints.device_readback("samy"), msg_old
|
|
187
|
+
)
|
|
188
|
+
while (
|
|
189
|
+
not readback_data_handler._devices_received["samx"]
|
|
190
|
+
or "samx" not in readback_data_handler.data
|
|
191
|
+
):
|
|
192
|
+
time.sleep(0.01)
|
|
193
|
+
assert readback_data_handler.data["samx"].signals["samx"]["value"] == 15
|
|
194
|
+
dev_data = readback_data_handler.get_device_values()
|
|
195
|
+
assert dev_data[0] == 15
|
|
196
|
+
assert dev_data[1] == 10 # samy remains unchanged
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def test_readback_data_handler_request_done_callbacks(readback_data_handler):
|
|
200
|
+
"""
|
|
201
|
+
Test that the request done callback properly updates the device done state.
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
# Submit request done for samx
|
|
205
|
+
msg = messages.DeviceReqStatusMessage(device="samx", success=True, request_id="something")
|
|
206
|
+
readback_data_handler.connector.xadd(
|
|
207
|
+
MessageEndpoints.device_req_status("something"), {"data": msg}
|
|
208
|
+
)
|
|
209
|
+
while not readback_data_handler._devices_done_state["samx"][0]:
|
|
210
|
+
time.sleep(0.01)
|
|
211
|
+
assert readback_data_handler._devices_done_state["samx"] == (True, True)
|
|
212
|
+
|
|
213
|
+
assert readback_data_handler.done() is False
|
|
214
|
+
|
|
215
|
+
# Submit request done for samy
|
|
216
|
+
msg = messages.DeviceReqStatusMessage(device="samy", success=False, request_id="something")
|
|
217
|
+
readback_data_handler.connector.xadd(
|
|
218
|
+
MessageEndpoints.device_req_status("something"), {"data": msg}
|
|
181
219
|
)
|
|
220
|
+
while not readback_data_handler._devices_done_state["samy"][0]:
|
|
221
|
+
time.sleep(0.01)
|
|
222
|
+
assert readback_data_handler._devices_done_state["samy"] == (True, False)
|
|
223
|
+
assert readback_data_handler.done() is True
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
from time import sleep
|
|
2
2
|
|
|
3
|
-
from bec_server.
|
|
4
|
-
from bec_server.
|
|
3
|
+
from bec_server.procedures.constants import PROCEDURE, ProcedureWorkerError
|
|
4
|
+
from bec_server.procedures.container_utils import PodmanCliUtils
|
|
5
5
|
|
|
6
6
|
image_name = (
|
|
7
7
|
f"ghcr.io/bec-project/{PROCEDURE.CONTAINER.REQUIREMENTS_IMAGE_NAME}:v{PROCEDURE.BEC_VERSION}"
|
|
8
8
|
)
|
|
9
9
|
podman = PodmanCliUtils()
|
|
10
10
|
|
|
11
|
-
for i in range(1,
|
|
11
|
+
for i in range(1, 6):
|
|
12
12
|
try:
|
|
13
13
|
output = podman._run_and_capture_error("podman", "pull", image_name)
|
|
14
14
|
print("successfully pulled requirements image for current version")
|
|
15
15
|
exit(0)
|
|
16
16
|
except ProcedureWorkerError as e:
|
|
17
17
|
print(e)
|
|
18
|
-
print("retrying in
|
|
19
|
-
sleep(
|
|
18
|
+
print("retrying in 5 minutes...")
|
|
19
|
+
sleep(5 * 60)
|
|
20
20
|
print(f"No more retries. Check if {image_name} actually exists!")
|
|
21
21
|
exit(1)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import time
|
|
4
|
+
from dataclasses import dataclass
|
|
4
5
|
from importlib.metadata import version
|
|
5
6
|
from typing import TYPE_CHECKING, Callable, Generator
|
|
6
7
|
from unittest.mock import MagicMock, patch
|
|
@@ -11,10 +12,10 @@ from bec_ipython_client.main import BECIPythonClient
|
|
|
11
12
|
from bec_lib import messages
|
|
12
13
|
from bec_lib.endpoints import MessageEndpoints
|
|
13
14
|
from bec_lib.logger import bec_logger
|
|
14
|
-
from bec_server.
|
|
15
|
-
from bec_server.
|
|
16
|
-
from bec_server.
|
|
17
|
-
from bec_server.
|
|
15
|
+
from bec_server.procedures.constants import _CONTAINER, _WORKER
|
|
16
|
+
from bec_server.procedures.container_utils import get_backend
|
|
17
|
+
from bec_server.procedures.container_worker import ContainerProcedureWorker
|
|
18
|
+
from bec_server.procedures.manager import ProcedureManager
|
|
18
19
|
|
|
19
20
|
if TYPE_CHECKING:
|
|
20
21
|
from pytest_bec_e2e.plugin import LogTestTool
|
|
@@ -28,14 +29,23 @@ logger = bec_logger.logger
|
|
|
28
29
|
pytestmark = pytest.mark.random_order(disabled=True)
|
|
29
30
|
|
|
30
31
|
|
|
32
|
+
@dataclass(frozen=True)
|
|
33
|
+
class PATCHED_CONSTANTS:
|
|
34
|
+
WORKER = _WORKER()
|
|
35
|
+
CONTAINER = _CONTAINER()
|
|
36
|
+
MANAGER_SHUTDOWN_TIMEOUT_S = 2
|
|
37
|
+
BEC_VERSION = version("bec_lib")
|
|
38
|
+
REDIS_HOST = "localhost"
|
|
39
|
+
|
|
40
|
+
|
|
31
41
|
@pytest.fixture
|
|
32
42
|
def client_logtool_and_manager(
|
|
33
43
|
bec_ipython_client_fixture_with_logtool: tuple[BECIPythonClient, "LogTestTool"],
|
|
34
44
|
) -> Generator[tuple[BECIPythonClient, "LogTestTool", ProcedureManager], None, None]:
|
|
35
45
|
client, logtool = bec_ipython_client_fixture_with_logtool
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
46
|
+
manager = ProcedureManager(
|
|
47
|
+
f"{client.connector.host}:{client.connector.port}", ContainerProcedureWorker
|
|
48
|
+
)
|
|
39
49
|
yield client, logtool, manager
|
|
40
50
|
manager.shutdown()
|
|
41
51
|
|
|
@@ -52,20 +62,21 @@ def _wait_while(cond: Callable[[], bool], timeout_s):
|
|
|
52
62
|
def test_building_worker_image():
|
|
53
63
|
podman_utils = get_backend()
|
|
54
64
|
build = podman_utils.build_worker_image()
|
|
55
|
-
assert len(build._command_output.splitlines()[-1]) == 64
|
|
65
|
+
assert len(build._command_output.splitlines()[-1]) == 64 # type: ignore
|
|
56
66
|
assert podman_utils.image_exists(f"bec_procedure_worker:v{version('bec_lib')}")
|
|
57
67
|
|
|
58
68
|
|
|
59
69
|
@pytest.mark.timeout(100)
|
|
60
|
-
@patch("bec_server.
|
|
70
|
+
@patch("bec_server.procedures.manager.procedure_registry.is_registered", lambda _: True)
|
|
71
|
+
@patch("bec_server.procedures.container_worker.PROCEDURE", PATCHED_CONSTANTS())
|
|
61
72
|
def test_procedure_runner_spawns_worker(
|
|
62
73
|
client_logtool_and_manager: tuple[BECIPythonClient, "LogTestTool", ProcedureManager],
|
|
63
74
|
):
|
|
64
75
|
client, _, manager = client_logtool_and_manager
|
|
65
|
-
assert manager.
|
|
76
|
+
assert manager._active_workers == {}
|
|
66
77
|
endpoint = MessageEndpoints.procedure_request()
|
|
67
78
|
msg = messages.ProcedureRequestMessage(
|
|
68
|
-
identifier="sleep", args_kwargs=((), {"time_s":
|
|
79
|
+
identifier="sleep", args_kwargs=((), {"time_s": 0.1}), queue="test"
|
|
69
80
|
)
|
|
70
81
|
|
|
71
82
|
logs = []
|
|
@@ -77,21 +88,22 @@ def test_procedure_runner_spawns_worker(
|
|
|
77
88
|
manager.add_callback("test", cb)
|
|
78
89
|
client.connector.xadd(topic=endpoint, msg_dict=msg.model_dump())
|
|
79
90
|
|
|
80
|
-
_wait_while(lambda: manager.
|
|
81
|
-
_wait_while(lambda: manager.
|
|
91
|
+
_wait_while(lambda: manager._active_workers == {}, 5)
|
|
92
|
+
_wait_while(lambda: manager._active_workers != {}, 90)
|
|
82
93
|
|
|
83
94
|
assert logs != []
|
|
84
95
|
|
|
85
96
|
|
|
86
97
|
@pytest.mark.timeout(100)
|
|
87
|
-
@patch("bec_server.
|
|
98
|
+
@patch("bec_server.procedures.manager.procedure_registry.is_registered", lambda _: True)
|
|
99
|
+
@patch("bec_server.procedures.container_worker.PROCEDURE", PATCHED_CONSTANTS())
|
|
88
100
|
def test_happy_path_container_procedure_runner(
|
|
89
101
|
client_logtool_and_manager: tuple[BECIPythonClient, "LogTestTool", ProcedureManager],
|
|
90
102
|
):
|
|
91
103
|
test_args = (1, 2, 3)
|
|
92
104
|
test_kwargs = {"a": "b", "c": "d"}
|
|
93
105
|
client, logtool, manager = client_logtool_and_manager
|
|
94
|
-
assert manager.
|
|
106
|
+
assert manager._active_workers == {}
|
|
95
107
|
conn = client.connector
|
|
96
108
|
endpoint = MessageEndpoints.procedure_request()
|
|
97
109
|
msg = messages.ProcedureRequestMessage(
|
|
@@ -99,12 +111,15 @@ def test_happy_path_container_procedure_runner(
|
|
|
99
111
|
)
|
|
100
112
|
conn.xadd(topic=endpoint, msg_dict=msg.model_dump())
|
|
101
113
|
|
|
102
|
-
_wait_while(lambda: manager.
|
|
103
|
-
_wait_while(lambda: manager.
|
|
114
|
+
_wait_while(lambda: manager._active_workers == {}, 5)
|
|
115
|
+
_wait_while(lambda: manager._active_workers != {}, 90)
|
|
104
116
|
|
|
105
117
|
logtool.fetch()
|
|
106
118
|
assert logtool.is_present_in_any_message("procedure accepted: True, message:")
|
|
107
|
-
assert logtool.is_present_in_any_message(
|
|
119
|
+
assert logtool.is_present_in_any_message(
|
|
120
|
+
"ContainerWorker started container for queue primary"
|
|
121
|
+
), f"Log content relating to procedures: {manager._logs}"
|
|
122
|
+
|
|
108
123
|
res, msg = logtool.are_present_in_order(
|
|
109
124
|
[
|
|
110
125
|
"Container worker 'primary' status update: IDLE",
|
|
@@ -114,12 +129,7 @@ def test_happy_path_container_procedure_runner(
|
|
|
114
129
|
]
|
|
115
130
|
)
|
|
116
131
|
assert res, f"failed on {msg}"
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
f"Builtin procedure log_message_args_kwargs called with args: {test_args} and kwargs: {test_kwargs}",
|
|
121
|
-
"Container worker 'primary' status update: IDLE",
|
|
122
|
-
"Container worker 'primary' status update: FINISHED",
|
|
123
|
-
]
|
|
132
|
+
|
|
133
|
+
assert logtool.is_present_in_any_message(
|
|
134
|
+
f"Builtin procedure log_message_args_kwargs called with args: {test_args} and kwargs: {test_kwargs}"
|
|
124
135
|
)
|
|
125
|
-
assert res, f"failed on {msg}"
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import _thread
|
|
2
4
|
import io
|
|
3
5
|
import os
|
|
4
6
|
import threading
|
|
5
7
|
import time
|
|
6
8
|
from contextlib import redirect_stdout
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
7
10
|
from unittest.mock import PropertyMock
|
|
8
11
|
|
|
9
12
|
import h5py
|
|
@@ -19,6 +22,9 @@ from bec_lib.logger import bec_logger
|
|
|
19
22
|
|
|
20
23
|
logger = bec_logger.logger
|
|
21
24
|
|
|
25
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
26
|
+
from bec_ipython_client.main import BECIPythonClient
|
|
27
|
+
|
|
22
28
|
# pylint: disable=protected-access
|
|
23
29
|
|
|
24
30
|
|
|
@@ -201,13 +207,13 @@ def test_mv_scan_mv(bec_ipython_client_fixture):
|
|
|
201
207
|
|
|
202
208
|
|
|
203
209
|
@pytest.mark.timeout(100)
|
|
204
|
-
def test_scan_abort(bec_ipython_client_fixture):
|
|
210
|
+
def test_scan_abort(bec_ipython_client_fixture: BECIPythonClient):
|
|
205
211
|
def send_abort(bec):
|
|
206
212
|
while True:
|
|
207
213
|
current_scan_info = bec.queue.scan_storage.current_scan_info
|
|
208
214
|
if not current_scan_info:
|
|
209
215
|
continue
|
|
210
|
-
status = current_scan_info.
|
|
216
|
+
status = current_scan_info.status.lower()
|
|
211
217
|
if status not in ["running", "deferred_pause"]:
|
|
212
218
|
continue
|
|
213
219
|
if bec.queue.scan_storage.current_scan is None:
|
|
@@ -217,7 +223,7 @@ def test_scan_abort(bec_ipython_client_fixture):
|
|
|
217
223
|
break
|
|
218
224
|
while True:
|
|
219
225
|
queue = bec.queue.queue_storage.current_scan_queue
|
|
220
|
-
if queue["primary"]
|
|
226
|
+
if queue["primary"].info[0].status == "DEFERRED_PAUSE":
|
|
221
227
|
break
|
|
222
228
|
time.sleep(0.5)
|
|
223
229
|
_thread.interrupt_main()
|
|
@@ -241,7 +247,7 @@ def test_scan_abort(bec_ipython_client_fixture):
|
|
|
241
247
|
time.sleep(0.5)
|
|
242
248
|
|
|
243
249
|
current_queue = bec.queue.queue_storage.current_scan_queue["primary"]
|
|
244
|
-
while current_queue
|
|
250
|
+
while current_queue.info or current_queue.status != "RUNNING":
|
|
245
251
|
time.sleep(0.5)
|
|
246
252
|
current_queue = bec.queue.queue_storage.current_scan_queue["primary"]
|
|
247
253
|
|
|
@@ -307,7 +313,7 @@ def test_queued_scan(bec_ipython_client_fixture):
|
|
|
307
313
|
while len(scan2.scan.live_data) != 50:
|
|
308
314
|
time.sleep(0.5)
|
|
309
315
|
current_queue = bec.queue.queue_storage.current_scan_queue["primary"]
|
|
310
|
-
while current_queue
|
|
316
|
+
while current_queue.info or current_queue.status != "RUNNING":
|
|
311
317
|
time.sleep(0.5)
|
|
312
318
|
current_queue = bec.queue.queue_storage.current_scan_queue["primary"]
|
|
313
319
|
scan_number_end = bec.queue.next_scan_number
|
|
@@ -356,7 +362,7 @@ def test_scan_restart(bec_ipython_client_fixture):
|
|
|
356
362
|
scan2.wait()
|
|
357
363
|
|
|
358
364
|
current_queue = bec.queue.queue_storage.current_scan_queue["primary"]
|
|
359
|
-
while current_queue
|
|
365
|
+
while current_queue.info or current_queue.status != "RUNNING":
|
|
360
366
|
time.sleep(0.5)
|
|
361
367
|
current_queue = bec.queue.queue_storage.current_scan_queue["primary"]
|
|
362
368
|
scan_number_end = bec.queue.next_scan_number
|
|
@@ -364,7 +370,7 @@ def test_scan_restart(bec_ipython_client_fixture):
|
|
|
364
370
|
|
|
365
371
|
|
|
366
372
|
@pytest.mark.timeout(100)
|
|
367
|
-
def test_scan_observer_repeat_queued(bec_ipython_client_fixture):
|
|
373
|
+
def test_scan_observer_repeat_queued(bec_ipython_client_fixture: BECIPythonClient):
|
|
368
374
|
bec = bec_ipython_client_fixture
|
|
369
375
|
bec.metadata.update({"unit_test": "test_scan_observer_repeat_queued"})
|
|
370
376
|
scans = bec.scans
|
|
@@ -396,7 +402,7 @@ def test_scan_observer_repeat_queued(bec_ipython_client_fixture):
|
|
|
396
402
|
scan2.wait()
|
|
397
403
|
|
|
398
404
|
current_queue = bec.queue.queue_storage.current_scan_queue["primary"]
|
|
399
|
-
while current_queue
|
|
405
|
+
while current_queue.info or current_queue.status != "RUNNING":
|
|
400
406
|
time.sleep(0.5)
|
|
401
407
|
current_queue = bec.queue.queue_storage.current_scan_queue["primary"]
|
|
402
408
|
scan_number_end = bec.queue.next_scan_number
|
|
@@ -433,7 +439,7 @@ def test_scan_observer_repeat(bec_ipython_client_fixture):
|
|
|
433
439
|
scan1.wait()
|
|
434
440
|
|
|
435
441
|
current_queue = bec.queue.queue_storage.current_scan_queue["primary"]
|
|
436
|
-
while current_queue
|
|
442
|
+
while current_queue.info or current_queue.status != "RUNNING":
|
|
437
443
|
time.sleep(0.5)
|
|
438
444
|
current_queue = bec.queue.queue_storage.current_scan_queue["primary"]
|
|
439
445
|
while True:
|
|
@@ -737,12 +743,12 @@ def test_update_config(bec_ipython_client_fixture):
|
|
|
737
743
|
bec = bec_ipython_client_fixture
|
|
738
744
|
bec.metadata.update({"unit_test": "test_update_config"})
|
|
739
745
|
demo_config_path = os.path.join(os.path.dirname(configs.__file__), "demo_config.yaml")
|
|
740
|
-
config = bec.
|
|
746
|
+
config = bec.device_manager.config_helper._load_config_from_file(demo_config_path)
|
|
741
747
|
config.pop("samx")
|
|
742
|
-
bec.
|
|
748
|
+
bec.device_manager.config_helper.send_config_request(action="set", config=config)
|
|
743
749
|
assert "samx" not in bec.device_manager.devices
|
|
744
|
-
config = bec.
|
|
745
|
-
bec.
|
|
750
|
+
config = bec.device_manager.config_helper._load_config_from_file(demo_config_path)
|
|
751
|
+
bec.device_manager.config_helper.send_config_request(action="set", config=config)
|
|
746
752
|
|
|
747
753
|
|
|
748
754
|
@pytest.mark.timeout(100)
|
|
@@ -819,3 +825,46 @@ def test_client_info_message(bec_ipython_client_fixture):
|
|
|
819
825
|
s1 = scans.line_scan(dev.samx, 0, 1, steps=10, exp_time=0.5, relative=False)
|
|
820
826
|
output = buffer.getvalue()
|
|
821
827
|
assert "test_client_info_message" in output
|
|
828
|
+
|
|
829
|
+
|
|
830
|
+
@pytest.mark.timeout(100)
|
|
831
|
+
def test_device_progress_grid_scan(bec_ipython_client_fixture, capsys):
|
|
832
|
+
bec = bec_ipython_client_fixture
|
|
833
|
+
scans = bec.scans
|
|
834
|
+
bec.metadata.update({"unit_test": "test_device_progress_grid_scan"})
|
|
835
|
+
dev = bec.device_manager.devices
|
|
836
|
+
scans.device_progress_grid_scan(
|
|
837
|
+
dev.samx, -5, 5, 10, dev.samy, -5, 5, 10, relative=True, exp_time=0.01
|
|
838
|
+
)
|
|
839
|
+
captured = capsys.readouterr()
|
|
840
|
+
assert "bpm4i" not in captured.out
|
|
841
|
+
assert "samx" not in captured.out
|
|
842
|
+
assert "Scan" in captured.out
|
|
843
|
+
assert "100 %" in captured.out
|
|
844
|
+
|
|
845
|
+
|
|
846
|
+
@pytest.mark.timeout(100)
|
|
847
|
+
def test_grid_scan_secondary_queue(capsys, bec_ipython_client_fixture):
|
|
848
|
+
bec = bec_ipython_client_fixture
|
|
849
|
+
scans = bec.scans
|
|
850
|
+
bec.metadata.update({"unit_test": "test_grid_scan_secondary_queue"})
|
|
851
|
+
dev = bec.device_manager.devices
|
|
852
|
+
status = scans.grid_scan(
|
|
853
|
+
dev.samx,
|
|
854
|
+
-5,
|
|
855
|
+
5,
|
|
856
|
+
10,
|
|
857
|
+
dev.samy,
|
|
858
|
+
-5,
|
|
859
|
+
5,
|
|
860
|
+
10,
|
|
861
|
+
exp_time=0.01,
|
|
862
|
+
relative=False,
|
|
863
|
+
scan_queue="secondary",
|
|
864
|
+
)
|
|
865
|
+
assert len(status.scan.live_data) == 100
|
|
866
|
+
assert status.scan.num_points == 100
|
|
867
|
+
captured = capsys.readouterr()
|
|
868
|
+
assert "finished. Scan ID" in captured.out
|
|
869
|
+
|
|
870
|
+
assert "secondary" in bec.queue.queue_storage.current_scan_queue
|