bec-ipython-client 3.84.0__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.
- PKG-INFO +1 -1
- bec_ipython_client/callbacks/ipython_live_updates.py +41 -16
- bec_ipython_client/callbacks/live_table.py +27 -5
- bec_ipython_client/callbacks/utils.py +1 -19
- bec_ipython_client/main.py +7 -7
- bec_ipython_client/signals.py +9 -3
- {bec_ipython_client-3.84.0.dist-info → bec_ipython_client-3.89.3.dist-info}/METADATA +1 -1
- {bec_ipython_client-3.84.0.dist-info → bec_ipython_client-3.89.3.dist-info}/RECORD +15 -15
- pyproject.toml +1 -1
- tests/client_tests/test_ipython_live_updates.py +259 -68
- tests/end-2-end/_ensure_requirements_container.py +2 -2
- tests/end-2-end/test_procedures_e2e.py +14 -13
- tests/end-2-end/test_scans_e2e.py +58 -9
- {bec_ipython_client-3.84.0.dist-info → bec_ipython_client-3.89.3.dist-info}/WHEEL +0 -0
- {bec_ipython_client-3.84.0.dist-info → bec_ipython_client-3.89.3.dist-info}/entry_points.txt +0 -0
PKG-INFO
CHANGED
|
@@ -31,7 +31,7 @@ class IPythonLiveUpdates:
|
|
|
31
31
|
self._interrupted_request = None
|
|
32
32
|
self._active_callback = None
|
|
33
33
|
self._processed_instructions = 0
|
|
34
|
-
self._active_request = None
|
|
34
|
+
self._active_request: messages.ScanQueueMessage | None = None
|
|
35
35
|
self._user_callback = None
|
|
36
36
|
self._request_block_index = collections.defaultdict(lambda: 0)
|
|
37
37
|
self._request_block_id = None
|
|
@@ -47,7 +47,9 @@ class IPythonLiveUpdates:
|
|
|
47
47
|
Args:
|
|
48
48
|
report_instructions (list): The list of report instructions.
|
|
49
49
|
"""
|
|
50
|
-
|
|
50
|
+
if not self._active_request:
|
|
51
|
+
return
|
|
52
|
+
scan_type = self._active_request.scan_type
|
|
51
53
|
if scan_type in ["open_scan_def", "close_scan_def"]:
|
|
52
54
|
self._process_instruction({"scan_progress": {"points": 0, "show_table": True}})
|
|
53
55
|
return
|
|
@@ -74,6 +76,9 @@ class IPythonLiveUpdates:
|
|
|
74
76
|
scan_report_type = list(instr.keys())[0]
|
|
75
77
|
scan_def_id = self.client.scans._scan_def_id
|
|
76
78
|
interactive_scan = self.client.scans._interactive_scan
|
|
79
|
+
if self._active_request is None:
|
|
80
|
+
# Already checked in caller method. It is just for type checking purposes.
|
|
81
|
+
return
|
|
77
82
|
if scan_def_id is None or interactive_scan:
|
|
78
83
|
if scan_report_type == "readback":
|
|
79
84
|
LiveUpdatesReadbackProgressbar(
|
|
@@ -126,17 +131,22 @@ class IPythonLiveUpdates:
|
|
|
126
131
|
)
|
|
127
132
|
self._active_callback.run()
|
|
128
133
|
|
|
129
|
-
def _available_req_blocks(
|
|
134
|
+
def _available_req_blocks(
|
|
135
|
+
self, queue: QueueItem, request: messages.ScanQueueMessage
|
|
136
|
+
) -> list[messages.RequestBlock]:
|
|
130
137
|
"""Get the available request blocks.
|
|
131
138
|
|
|
132
139
|
Args:
|
|
133
140
|
queue (QueueItem): The queue item.
|
|
134
141
|
request (messages.ScanQueueMessage): The request message.
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
list[messages.RequestBlock]: The list of available request blocks.
|
|
135
145
|
"""
|
|
136
146
|
available_blocks = [
|
|
137
147
|
req_block
|
|
138
148
|
for req_block in queue.request_blocks
|
|
139
|
-
if req_block
|
|
149
|
+
if req_block.RID == request.metadata["RID"]
|
|
140
150
|
]
|
|
141
151
|
return available_blocks
|
|
142
152
|
|
|
@@ -167,7 +177,7 @@ class IPythonLiveUpdates:
|
|
|
167
177
|
|
|
168
178
|
available_blocks = self._available_req_blocks(queue, request)
|
|
169
179
|
req_block = available_blocks[self._request_block_index[req_id]]
|
|
170
|
-
report_instructions = req_block.
|
|
180
|
+
report_instructions = req_block.report_instructions or []
|
|
171
181
|
self._process_report_instructions(report_instructions)
|
|
172
182
|
|
|
173
183
|
self._reset()
|
|
@@ -191,12 +201,19 @@ class IPythonLiveUpdates:
|
|
|
191
201
|
self.client.queue.request_scan_halt()
|
|
192
202
|
|
|
193
203
|
def _element_in_queue(self) -> bool:
|
|
194
|
-
|
|
195
|
-
"info", []
|
|
196
|
-
)
|
|
197
|
-
if not queue:
|
|
204
|
+
if self.client.queue is None:
|
|
198
205
|
return False
|
|
199
|
-
|
|
206
|
+
if (csq := self.client.queue.queue_storage.current_scan_queue) is None:
|
|
207
|
+
return False
|
|
208
|
+
scan_queue_status = csq.get(self.client.queue.get_default_scan_queue())
|
|
209
|
+
if scan_queue_status is None:
|
|
210
|
+
return False
|
|
211
|
+
queue_info = scan_queue_status.info
|
|
212
|
+
if not queue_info:
|
|
213
|
+
return False
|
|
214
|
+
if self._current_queue is None:
|
|
215
|
+
return False
|
|
216
|
+
return self._current_queue.queue_id == queue_info[0].queue_id
|
|
200
217
|
|
|
201
218
|
def _process_queue(
|
|
202
219
|
self, queue: QueueItem, request: messages.ScanQueueMessage, req_id: str
|
|
@@ -216,11 +233,15 @@ class IPythonLiveUpdates:
|
|
|
216
233
|
if not queue.request_blocks or not queue.status or queue.queue_position is None:
|
|
217
234
|
return False
|
|
218
235
|
if queue.status == "PENDING" and queue.queue_position > 0:
|
|
219
|
-
|
|
220
|
-
|
|
236
|
+
target_queue = self.client.queue.queue_storage.current_scan_queue.get(
|
|
237
|
+
self.client.queue.get_default_scan_queue()
|
|
221
238
|
)
|
|
239
|
+
|
|
240
|
+
if target_queue is None:
|
|
241
|
+
return False
|
|
242
|
+
status = target_queue.status
|
|
222
243
|
print(
|
|
223
|
-
"Scan is enqueued and is waiting for execution. Current position in queue:"
|
|
244
|
+
f"Scan is enqueued and is waiting for execution. Current position in queue {self.client.queue.get_default_scan_queue()}:"
|
|
224
245
|
f" {queue.queue_position + 1}. Queue status: {status}.",
|
|
225
246
|
end="\r",
|
|
226
247
|
flush=True,
|
|
@@ -229,13 +250,13 @@ class IPythonLiveUpdates:
|
|
|
229
250
|
if not available_blocks:
|
|
230
251
|
return False
|
|
231
252
|
req_block = available_blocks[self._request_block_index[req_id]]
|
|
232
|
-
if req_block
|
|
253
|
+
if req_block.msg.scan_type in [
|
|
233
254
|
"open_scan_def",
|
|
234
255
|
"mv",
|
|
235
256
|
]: # TODO: make this more general for all scan types that don't have report instructions
|
|
236
257
|
return True
|
|
237
258
|
|
|
238
|
-
report_instructions = req_block[
|
|
259
|
+
report_instructions = req_block.report_instructions or []
|
|
239
260
|
if not report_instructions:
|
|
240
261
|
return False
|
|
241
262
|
self._process_report_instructions(report_instructions)
|
|
@@ -263,7 +284,11 @@ class IPythonLiveUpdates:
|
|
|
263
284
|
self._current_queue = None
|
|
264
285
|
self._user_callback = None
|
|
265
286
|
self._processed_instructions = 0
|
|
266
|
-
scan_closed =
|
|
287
|
+
scan_closed = (
|
|
288
|
+
forced
|
|
289
|
+
or self._active_request is None
|
|
290
|
+
or (self._active_request.scan_type == "close_scan_def")
|
|
291
|
+
)
|
|
267
292
|
self._active_request = None
|
|
268
293
|
|
|
269
294
|
if self.client.scans._scan_def_id and not scan_closed:
|
|
@@ -56,7 +56,6 @@ class LiveUpdatesTable(LiveUpdatesBase):
|
|
|
56
56
|
super().__init__(
|
|
57
57
|
bec, report_instruction=report_instruction, request=request, callbacks=callbacks
|
|
58
58
|
)
|
|
59
|
-
self.scan_queue_request = None
|
|
60
59
|
self.scan_item = None
|
|
61
60
|
self.dev_values = None
|
|
62
61
|
self.point_data = None
|
|
@@ -73,6 +72,8 @@ class LiveUpdatesTable(LiveUpdatesBase):
|
|
|
73
72
|
def wait_for_scan_to_start(self):
|
|
74
73
|
"""wait until the scan starts"""
|
|
75
74
|
while True:
|
|
75
|
+
if not self.scan_item or not self.scan_item.queue:
|
|
76
|
+
raise RuntimeError("No scan item or scan queue available.")
|
|
76
77
|
queue_pos = self.scan_item.queue.queue_position
|
|
77
78
|
self.check_alarms()
|
|
78
79
|
if self.scan_item.status == "closed":
|
|
@@ -160,7 +161,20 @@ class LiveUpdatesTable(LiveUpdatesBase):
|
|
|
160
161
|
return header
|
|
161
162
|
|
|
162
163
|
def update_scan_item(self, timeout: float = 15):
|
|
163
|
-
"""
|
|
164
|
+
"""
|
|
165
|
+
Get the current scan item and update self.scan_item
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
timeout (float): timeout in seconds
|
|
169
|
+
|
|
170
|
+
Raises:
|
|
171
|
+
RuntimeError: if no scan queue request is available
|
|
172
|
+
TimeoutError: if no scan item is found before reaching the timeout
|
|
173
|
+
|
|
174
|
+
"""
|
|
175
|
+
if not self.scan_queue_request:
|
|
176
|
+
raise RuntimeError("No scan queue request available.")
|
|
177
|
+
|
|
164
178
|
start = time.time()
|
|
165
179
|
while self.scan_queue_request.scan is None:
|
|
166
180
|
self.check_alarms()
|
|
@@ -178,14 +192,19 @@ class LiveUpdatesTable(LiveUpdatesBase):
|
|
|
178
192
|
|
|
179
193
|
def _wait_for_report_instructions(self):
|
|
180
194
|
"""wait until the report instructions are available"""
|
|
195
|
+
if not self.scan_queue_request or not self.scan_item or not self.scan_item.queue:
|
|
196
|
+
logger.warning(
|
|
197
|
+
f"Cannot wait for report instructions. scan_queue_request: {self.scan_queue_request}, scan_item: {self.scan_item}, scan_item.queue: {getattr(self.scan_item, 'queue', None)}"
|
|
198
|
+
)
|
|
199
|
+
return
|
|
181
200
|
req_ID = self.scan_queue_request.requestID
|
|
182
201
|
while True:
|
|
183
202
|
request_block = [
|
|
184
|
-
req for req in self.scan_item.queue.request_blocks if req
|
|
203
|
+
req for req in self.scan_item.queue.request_blocks if req.RID == req_ID
|
|
185
204
|
][0]
|
|
186
|
-
if not request_block
|
|
205
|
+
if not request_block.is_scan:
|
|
187
206
|
break
|
|
188
|
-
if request_block
|
|
207
|
+
if request_block.report_instructions:
|
|
189
208
|
break
|
|
190
209
|
self.check_alarms()
|
|
191
210
|
|
|
@@ -195,6 +214,9 @@ class LiveUpdatesTable(LiveUpdatesBase):
|
|
|
195
214
|
Args:
|
|
196
215
|
target_num_points (int): number of points to be collected
|
|
197
216
|
"""
|
|
217
|
+
if not self.scan_item:
|
|
218
|
+
logger.warning("No scan item available for live updates.")
|
|
219
|
+
return
|
|
198
220
|
with ScanProgressBar(
|
|
199
221
|
scan_number=self.scan_item.scan_number, clear_on_exit=self._print_table_data
|
|
200
222
|
) as progressbar:
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import abc
|
|
4
|
-
import threading
|
|
5
4
|
import time
|
|
6
5
|
import traceback
|
|
7
6
|
from collections.abc import Callable
|
|
@@ -21,23 +20,6 @@ class ScanRequestError(Exception):
|
|
|
21
20
|
"""Error raised when a scan request is rejected"""
|
|
22
21
|
|
|
23
22
|
|
|
24
|
-
def set_event_delayed(event: threading.Event, delay: int) -> None:
|
|
25
|
-
"""Set event with a delay
|
|
26
|
-
|
|
27
|
-
Args:
|
|
28
|
-
event (threading.Event): event that should be set
|
|
29
|
-
delay (int): delay time in seconds
|
|
30
|
-
|
|
31
|
-
"""
|
|
32
|
-
|
|
33
|
-
def call_set():
|
|
34
|
-
time.sleep(delay)
|
|
35
|
-
event.set()
|
|
36
|
-
|
|
37
|
-
thread = threading.Thread(target=call_set, daemon=True)
|
|
38
|
-
thread.start()
|
|
39
|
-
|
|
40
|
-
|
|
41
23
|
def check_alarms(bec):
|
|
42
24
|
"""check for alarms and raise them if needed"""
|
|
43
25
|
bec.alarm_handler.raise_alarms()
|
|
@@ -62,7 +44,7 @@ class LiveUpdatesBase(abc.ABC):
|
|
|
62
44
|
self.bec = bec
|
|
63
45
|
self.request = request
|
|
64
46
|
self.RID = request.metadata["RID"]
|
|
65
|
-
self.scan_queue_request = None
|
|
47
|
+
self.scan_queue_request: RequestItem | None = None
|
|
66
48
|
self.report_instruction = report_instruction
|
|
67
49
|
if callbacks is None:
|
|
68
50
|
self.callbacks = []
|
bec_ipython_client/main.py
CHANGED
|
@@ -29,6 +29,7 @@ from bec_lib.bec_service import parse_cmdline_args
|
|
|
29
29
|
from bec_lib.callback_handler import EventType
|
|
30
30
|
from bec_lib.client import BECClient
|
|
31
31
|
from bec_lib.logger import bec_logger
|
|
32
|
+
from bec_lib.procedures.hli import ProcedureHli
|
|
32
33
|
from bec_lib.redis_connector import RedisConnector
|
|
33
34
|
from bec_lib.service_config import ServiceConfig
|
|
34
35
|
from bec_lib.utils.pydantic_pretty_print import pretty_print_pydantic_validation_error
|
|
@@ -58,6 +59,7 @@ class BECIPythonClient:
|
|
|
58
59
|
# the CLIBECClient but directly through the BECIPythonClient. While this is not
|
|
59
60
|
# needed for normal usage, it is required, e.g. for mocks.
|
|
60
61
|
_local_only_types: Tuple = ()
|
|
62
|
+
_client: CLIBECClient | BECClient
|
|
61
63
|
|
|
62
64
|
def __init__(
|
|
63
65
|
self,
|
|
@@ -75,6 +77,7 @@ class BECIPythonClient:
|
|
|
75
77
|
name="BECIPythonClient",
|
|
76
78
|
prompt_for_acl=True,
|
|
77
79
|
)
|
|
80
|
+
|
|
78
81
|
self._ip = IPython.get_ipython()
|
|
79
82
|
self.started = False
|
|
80
83
|
self._sighandler = None
|
|
@@ -150,6 +153,7 @@ class BECIPythonClient:
|
|
|
150
153
|
object,
|
|
151
154
|
lambda o, p, cycle: o.__str__ is object.__str__ and p.text(repr(o)) or p.text(str(o)),
|
|
152
155
|
)
|
|
156
|
+
self._set_idle()
|
|
153
157
|
|
|
154
158
|
def _update_namespace_callback(self, action: Literal["add", "remove"], ns_objects: dict):
|
|
155
159
|
"""Callback to update the global namespace of ipython.
|
|
@@ -187,13 +191,14 @@ class BECIPythonClient:
|
|
|
187
191
|
magics = BECMagics(self._ip, self)
|
|
188
192
|
self._ip.register_magics(magics)
|
|
189
193
|
|
|
190
|
-
def shutdown(self):
|
|
194
|
+
def shutdown(self, per_thread_timeout_s: float | None = None):
|
|
191
195
|
"""shutdown the client and all its components"""
|
|
192
196
|
try:
|
|
193
197
|
self.gui.close()
|
|
194
198
|
except AttributeError:
|
|
195
199
|
pass
|
|
196
|
-
self._client.shutdown()
|
|
200
|
+
self._client.shutdown(per_thread_timeout_s)
|
|
201
|
+
logger.success("done")
|
|
197
202
|
|
|
198
203
|
def _create_exception_handler(self):
|
|
199
204
|
return functools.partial(_ip_exception_handler, parent=self)
|
|
@@ -338,7 +343,6 @@ def main():
|
|
|
338
343
|
parser = argparse.ArgumentParser(
|
|
339
344
|
prog="BEC IPython client", description="BEC command line interface"
|
|
340
345
|
)
|
|
341
|
-
parser.add_argument("--version", action="store_true", default=False)
|
|
342
346
|
parser.add_argument("--nogui", action="store_true", default=False)
|
|
343
347
|
parser.add_argument(
|
|
344
348
|
"--gui-id",
|
|
@@ -358,10 +362,6 @@ def main():
|
|
|
358
362
|
# remove already parsed args from command line args
|
|
359
363
|
sys.argv = sys.argv[:1] + left_args
|
|
360
364
|
|
|
361
|
-
if args.version:
|
|
362
|
-
print(f"BEC IPython client: {version('bec_ipython_client')}")
|
|
363
|
-
sys.exit(0)
|
|
364
|
-
|
|
365
365
|
if available_plugins and config.is_default():
|
|
366
366
|
# check if config is defined in a plugin;
|
|
367
367
|
# in this case the plugin config takes precedence over
|
bec_ipython_client/signals.py
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import signal
|
|
2
4
|
import threading
|
|
3
5
|
import time
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
4
7
|
|
|
5
8
|
from bec_lib.bec_errors import ScanInterruption
|
|
6
9
|
|
|
10
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
11
|
+
from bec_lib.client import BECClient
|
|
12
|
+
|
|
7
13
|
PAUSE_MSG = """
|
|
8
14
|
The Scan Queue is entering a paused state. These are your options for changing
|
|
9
15
|
the state of the queue:
|
|
@@ -73,7 +79,7 @@ class SignalHandler:
|
|
|
73
79
|
|
|
74
80
|
|
|
75
81
|
class SigintHandler(SignalHandler):
|
|
76
|
-
def __init__(self, bec):
|
|
82
|
+
def __init__(self, bec: BECClient):
|
|
77
83
|
super().__init__(signal.SIGINT)
|
|
78
84
|
self.bec = bec
|
|
79
85
|
self.last_sigint_time = None # time most recent SIGINT was processed
|
|
@@ -84,11 +90,11 @@ class SigintHandler(SignalHandler):
|
|
|
84
90
|
if not current_scan:
|
|
85
91
|
raise KeyboardInterrupt
|
|
86
92
|
|
|
87
|
-
status = current_scan.
|
|
93
|
+
status = current_scan.status.lower()
|
|
88
94
|
if status not in ["running", "deferred_pause"]:
|
|
89
95
|
raise KeyboardInterrupt
|
|
90
96
|
|
|
91
|
-
if any(current_scan.
|
|
97
|
+
if any(current_scan.is_scan) and (
|
|
92
98
|
self.last_sigint_time is None or time.time() - self.last_sigint_time > 10
|
|
93
99
|
):
|
|
94
100
|
# reset the counter to 1
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
.gitignore,sha256=XxC6jyyftTo2CLtm4K8axuNPYwA9Wgaz2R93WhX8bTQ,3364
|
|
2
|
-
PKG-INFO,sha256=
|
|
2
|
+
PKG-INFO,sha256=trZwsE2OpNig8TZ6MjQ6HN5lX5tRxLrygSFHiz4FATs,1052
|
|
3
3
|
demo.py,sha256=AquJB-0Tu2bIEFpcJ0Q3RUBt1xldqS6GgU5CjOAg_ww,7083
|
|
4
|
-
pyproject.toml,sha256=
|
|
4
|
+
pyproject.toml,sha256=Gv8V_TLxvNXUR9W-ROwlP7dGq9cbC8BfRC9anNsoddQ,1229
|
|
5
5
|
bec_ipython_client/__init__.py,sha256=ihd_V8I7Qo0MWKMo7bcvPf-ZyUQqkcNf8IAWLJKiFJE,79
|
|
6
6
|
bec_ipython_client/beamline_mixin.py,sha256=scMWIFbHJajyECzbwEVKyQUGjpqA9C_KiU2M6FuRH_Q,1067
|
|
7
7
|
bec_ipython_client/bec_magics.py,sha256=Rz2aXkUCeAV_VxdXqLUNHh8T44kSH9ha83OiEtdptzI,2792
|
|
8
8
|
bec_ipython_client/bec_startup.py,sha256=GGlHyxnSCQfYF5n-pYq2ic0pSyW5zvnT2PAlI5kY77w,1930
|
|
9
|
-
bec_ipython_client/main.py,sha256=
|
|
9
|
+
bec_ipython_client/main.py,sha256=h7417qQj0rwj5gjbKg6pn8Y_yYJf4b8Fs5EP29sXXOg,13564
|
|
10
10
|
bec_ipython_client/prettytable.py,sha256=TnhGPGuU0XEvnIYJ1UfTEwadcowFW4rqJW8z_Sm0EDw,2534
|
|
11
11
|
bec_ipython_client/progressbar.py,sha256=aDKYjzXmGSwa82ewm59V8WSuqVQz9GiZPx5G65fEwpk,11090
|
|
12
|
-
bec_ipython_client/signals.py,sha256=
|
|
12
|
+
bec_ipython_client/signals.py,sha256=P7FrIB66dGdPESUngBnIVPGrAhcd2Tek8ufq9ALBoYU,4340
|
|
13
13
|
bec_ipython_client/callbacks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
14
|
bec_ipython_client/callbacks/device_progress.py,sha256=NzWIO1oowxpN14hPXBne6RfZxOW82EhwDM3jHLnn3xI,2603
|
|
15
|
-
bec_ipython_client/callbacks/ipython_live_updates.py,sha256=
|
|
16
|
-
bec_ipython_client/callbacks/live_table.py,sha256=
|
|
15
|
+
bec_ipython_client/callbacks/ipython_live_updates.py,sha256=zaXR6UX7fA01-N0B0C2t67lOqjBgq8nal8eZpgf_nDc,11416
|
|
16
|
+
bec_ipython_client/callbacks/live_table.py,sha256=ewdter1z1arV1EvEsReOihluyTmAHMrHtOu_S29vixo,14432
|
|
17
17
|
bec_ipython_client/callbacks/move_device.py,sha256=TkbtKFBr1nuJ8THTSm70Y8D7_va2YQ57oBGGt0BavW4,8153
|
|
18
|
-
bec_ipython_client/callbacks/utils.py,sha256=
|
|
18
|
+
bec_ipython_client/callbacks/utils.py,sha256=e8USLnufNTpI2Bkp-sjRsSFvIXxB2CirF6WRPVsOets,5338
|
|
19
19
|
bec_ipython_client/high_level_interfaces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
20
|
bec_ipython_client/high_level_interfaces/bec_hli.py,sha256=G1eF-lbLEDuN2mr_AYSxhhGb4LT6P72g0a4sU9M9zgk,1221
|
|
21
21
|
bec_ipython_client/high_level_interfaces/spec_hli.py,sha256=z7WtjiC4LtMfKJn12SbguHPCLqbAsZNfUDyiUW0LOiU,5818
|
|
@@ -30,15 +30,15 @@ tests/client_tests/conftest.py,sha256=dUvYqvl6wogxN-kRCUuo_Uzna3P2uSYD7qGHyMGBlP
|
|
|
30
30
|
tests/client_tests/test_beamline_mixins.py,sha256=8Ws0bmzl2gSW0VuOVu80_JbYNb5Y-htchmrrptwjwDo,4611
|
|
31
31
|
tests/client_tests/test_bec_client.py,sha256=gks7IYoDDXpbkC_EGWQfKtH08Yig71PRZtleXFhkU8A,8903
|
|
32
32
|
tests/client_tests/test_device_progress.py,sha256=GEw2g8MQZnv5mxABEZlxBmaMpxVS33wogaYohFolDEs,2353
|
|
33
|
-
tests/client_tests/test_ipython_live_updates.py,sha256=
|
|
33
|
+
tests/client_tests/test_ipython_live_updates.py,sha256=s4HLqF2hVQaaJhRKv0dxj0DiZK5M9Z_WwMAbGk19EFg,11918
|
|
34
34
|
tests/client_tests/test_live_table.py,sha256=0EKgWOgDqpjN8fJEeAzoKNCwFneDEsUY2NfWQkxB6xc,18155
|
|
35
35
|
tests/client_tests/test_move_callback.py,sha256=bUCcWoz_tc-yRAtwmEUMrKE_qKwatop_wReSugGGEIQ,8670
|
|
36
36
|
tests/client_tests/test_pretty_table.py,sha256=uQ-KPb3RXoCFE_t1IrpkT6kZAoqW7pFXxbFc445sX0Y,469
|
|
37
|
-
tests/end-2-end/_ensure_requirements_container.py,sha256=
|
|
38
|
-
tests/end-2-end/test_procedures_e2e.py,sha256=
|
|
39
|
-
tests/end-2-end/test_scans_e2e.py,sha256=
|
|
37
|
+
tests/end-2-end/_ensure_requirements_container.py,sha256=dv_ACfo9nHyiiEL3AMccaEg38VxGqB0W7u_iPyCVeiE,701
|
|
38
|
+
tests/end-2-end/test_procedures_e2e.py,sha256=ai8pUrHaL-5sYuaKYucuYEwyvhelS1dsW9KGoBb1Riw,4872
|
|
39
|
+
tests/end-2-end/test_scans_e2e.py,sha256=JhyWjDyUlBZAM_gL6QtfKXfI_fXdUnykYCIWCSorRiA,32527
|
|
40
40
|
tests/end-2-end/test_scans_lib_e2e.py,sha256=dqs0ojkyQWStIQbqABq9mQrjqQyE43gr37VPhxvQ8b8,19427
|
|
41
|
-
bec_ipython_client-3.
|
|
42
|
-
bec_ipython_client-3.
|
|
43
|
-
bec_ipython_client-3.
|
|
44
|
-
bec_ipython_client-3.
|
|
41
|
+
bec_ipython_client-3.89.3.dist-info/METADATA,sha256=trZwsE2OpNig8TZ6MjQ6HN5lX5tRxLrygSFHiz4FATs,1052
|
|
42
|
+
bec_ipython_client-3.89.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
43
|
+
bec_ipython_client-3.89.3.dist-info/entry_points.txt,sha256=oQUXYY0jjD9ZvKPHwaGn2wkUIWpDZM8L4ixDA3RlBWE,53
|
|
44
|
+
bec_ipython_client-3.89.3.dist-info/RECORD,,
|
pyproject.toml
CHANGED
|
@@ -7,34 +7,94 @@ from bec_lib import messages
|
|
|
7
7
|
from bec_lib.queue_items import QueueItem
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
@pytest.
|
|
11
|
-
def
|
|
10
|
+
@pytest.fixture
|
|
11
|
+
def queue_elements(bec_client_mock):
|
|
12
12
|
client = bec_client_mock
|
|
13
|
-
live_updates = IPythonLiveUpdates(client)
|
|
14
13
|
request_msg = messages.ScanQueueMessage(
|
|
15
14
|
scan_type="grid_scan",
|
|
16
15
|
parameter={"args": {"samx": (-5, 5, 3)}, "kwargs": {}},
|
|
17
16
|
queue="primary",
|
|
18
17
|
metadata={"RID": "something"},
|
|
19
18
|
)
|
|
19
|
+
request_block = messages.RequestBlock(
|
|
20
|
+
msg=request_msg,
|
|
21
|
+
RID="req_id",
|
|
22
|
+
scan_motors=["samx"],
|
|
23
|
+
report_instructions=[],
|
|
24
|
+
readout_priority={"monitored": ["samx"]},
|
|
25
|
+
is_scan=True,
|
|
26
|
+
scan_number=1,
|
|
27
|
+
scan_id="scan_id",
|
|
28
|
+
)
|
|
20
29
|
queue = QueueItem(
|
|
21
30
|
scan_manager=client.queue,
|
|
22
31
|
queue_id="queue_id",
|
|
23
|
-
request_blocks=[
|
|
32
|
+
request_blocks=[request_block],
|
|
24
33
|
status="PENDING",
|
|
25
34
|
active_request_block={},
|
|
26
35
|
scan_id=["scan_id"],
|
|
27
36
|
)
|
|
28
|
-
|
|
37
|
+
return queue, request_block, request_msg
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@pytest.fixture
|
|
41
|
+
def sample_request_msg():
|
|
42
|
+
return messages.ScanQueueMessage(
|
|
43
|
+
scan_type="grid_scan",
|
|
44
|
+
parameter={"args": {"samx": (-5, 5, 3)}, "kwargs": {}},
|
|
45
|
+
queue="primary",
|
|
46
|
+
metadata={"RID": "something"},
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@pytest.fixture
|
|
51
|
+
def sample_request_block(sample_request_msg):
|
|
52
|
+
return messages.RequestBlock(
|
|
53
|
+
msg=sample_request_msg,
|
|
54
|
+
RID="req_id",
|
|
55
|
+
scan_motors=["samx"],
|
|
56
|
+
report_instructions=[],
|
|
57
|
+
readout_priority={"monitored": ["samx"]},
|
|
58
|
+
is_scan=True,
|
|
59
|
+
scan_number=1,
|
|
60
|
+
scan_id="scan_id",
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@pytest.fixture
|
|
65
|
+
def sample_queue_info_entry(sample_request_block):
|
|
66
|
+
return messages.QueueInfoEntry(
|
|
67
|
+
queue_id="test_queue_id",
|
|
68
|
+
scan_id=["scan_id"],
|
|
69
|
+
is_scan=[True],
|
|
70
|
+
request_blocks=[sample_request_block],
|
|
71
|
+
scan_number=[1],
|
|
72
|
+
status="RUNNING",
|
|
73
|
+
active_request_block=None,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@pytest.fixture
|
|
78
|
+
def sample_scan_queue_status(sample_queue_info_entry):
|
|
79
|
+
return messages.ScanQueueStatus(info=[sample_queue_info_entry], status="RUNNING")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@pytest.mark.timeout(20)
|
|
83
|
+
def test_live_updates_process_queue_pending(bec_client_mock, queue_elements):
|
|
84
|
+
client = bec_client_mock
|
|
85
|
+
live_updates = IPythonLiveUpdates(client)
|
|
86
|
+
queue, request_block, request_msg = queue_elements
|
|
87
|
+
|
|
88
|
+
client.queue.queue_storage.current_scan_queue = {
|
|
89
|
+
"primary": messages.ScanQueueStatus(info=[], status="RUNNING")
|
|
90
|
+
}
|
|
29
91
|
with mock.patch.object(queue, "_update_with_buffer"):
|
|
30
92
|
with mock.patch(
|
|
31
93
|
"bec_lib.queue_items.QueueItem.queue_position", new_callable=mock.PropertyMock
|
|
32
94
|
) as queue_pos:
|
|
33
95
|
queue_pos.return_value = 2
|
|
34
96
|
with mock.patch.object(
|
|
35
|
-
live_updates,
|
|
36
|
-
"_available_req_blocks",
|
|
37
|
-
return_value=[{"report_instructions": [], "content": {"scan_type": "grid_scan"}}],
|
|
97
|
+
live_updates, "_available_req_blocks", return_value=[request_block]
|
|
38
98
|
):
|
|
39
99
|
with mock.patch.object(live_updates, "_process_report_instructions") as process:
|
|
40
100
|
with mock.patch("builtins.print") as prt:
|
|
@@ -45,39 +105,30 @@ def test_live_updates_process_queue_pending(bec_client_mock):
|
|
|
45
105
|
|
|
46
106
|
|
|
47
107
|
@pytest.mark.timeout(20)
|
|
48
|
-
def test_live_updates_process_queue_running(bec_client_mock):
|
|
108
|
+
def test_live_updates_process_queue_running(bec_client_mock, queue_elements):
|
|
49
109
|
client = bec_client_mock
|
|
50
110
|
live_updates = IPythonLiveUpdates(client)
|
|
51
|
-
request_msg =
|
|
52
|
-
scan_type="grid_scan",
|
|
53
|
-
parameter={"args": {"samx": (-5, 5, 3)}, "kwargs": {}},
|
|
54
|
-
queue="primary",
|
|
55
|
-
metadata={"RID": "something"},
|
|
56
|
-
)
|
|
111
|
+
_, request_block, request_msg = queue_elements
|
|
57
112
|
queue = QueueItem(
|
|
58
113
|
scan_manager=client.queue,
|
|
59
114
|
queue_id="queue_id",
|
|
60
|
-
request_blocks=[
|
|
115
|
+
request_blocks=[request_block],
|
|
61
116
|
status="RUNNING",
|
|
62
117
|
active_request_block={},
|
|
63
118
|
scan_id=["scan_id"],
|
|
64
119
|
)
|
|
65
120
|
live_updates._active_request = request_msg
|
|
66
|
-
|
|
121
|
+
request_block.report_instructions = [{"wait_table": 10}]
|
|
122
|
+
client.queue.queue_storage.current_scan_queue = {
|
|
123
|
+
"primary": messages.ScanQueueStatus(info=[], status="RUNNING")
|
|
124
|
+
}
|
|
67
125
|
with mock.patch.object(queue, "_update_with_buffer"):
|
|
68
126
|
with mock.patch(
|
|
69
127
|
"bec_lib.queue_items.QueueItem.queue_position", new_callable=mock.PropertyMock
|
|
70
128
|
) as queue_pos:
|
|
71
129
|
queue_pos.return_value = 2
|
|
72
130
|
with mock.patch.object(
|
|
73
|
-
live_updates,
|
|
74
|
-
"_available_req_blocks",
|
|
75
|
-
return_value=[
|
|
76
|
-
{
|
|
77
|
-
"report_instructions": [{"wait_table": 10}],
|
|
78
|
-
"content": {"scan_type": "grid_scan"},
|
|
79
|
-
}
|
|
80
|
-
],
|
|
131
|
+
live_updates, "_available_req_blocks", return_value=[request_block]
|
|
81
132
|
):
|
|
82
133
|
with mock.patch.object(live_updates, "_process_instruction") as process:
|
|
83
134
|
with mock.patch("builtins.print") as prt:
|
|
@@ -88,37 +139,19 @@ def test_live_updates_process_queue_running(bec_client_mock):
|
|
|
88
139
|
|
|
89
140
|
|
|
90
141
|
@pytest.mark.timeout(20)
|
|
91
|
-
def test_live_updates_process_queue_without_status(bec_client_mock):
|
|
142
|
+
def test_live_updates_process_queue_without_status(bec_client_mock, queue_elements):
|
|
92
143
|
client = bec_client_mock
|
|
93
144
|
live_updates = IPythonLiveUpdates(client)
|
|
94
|
-
request_msg =
|
|
95
|
-
scan_type="grid_scan",
|
|
96
|
-
parameter={"args": {"samx": (-5, 5, 3)}, "kwargs": {}},
|
|
97
|
-
queue="primary",
|
|
98
|
-
metadata={"RID": "something"},
|
|
99
|
-
)
|
|
100
|
-
queue = QueueItem(
|
|
101
|
-
scan_manager=client.queue,
|
|
102
|
-
queue_id="queue_id",
|
|
103
|
-
request_blocks=[request_msg],
|
|
104
|
-
status=None,
|
|
105
|
-
active_request_block={},
|
|
106
|
-
scan_id=["scan_id"],
|
|
107
|
-
)
|
|
145
|
+
queue, _, request_msg = queue_elements
|
|
108
146
|
with mock.patch.object(queue, "_update_with_buffer"):
|
|
109
147
|
assert live_updates._process_queue(queue, request_msg, "req_id") is False
|
|
110
148
|
|
|
111
149
|
|
|
112
150
|
@pytest.mark.timeout(20)
|
|
113
|
-
def test_live_updates_process_queue_without_queue_number(bec_client_mock):
|
|
151
|
+
def test_live_updates_process_queue_without_queue_number(bec_client_mock, queue_elements):
|
|
114
152
|
client = bec_client_mock
|
|
115
153
|
live_updates = IPythonLiveUpdates(client)
|
|
116
|
-
request_msg =
|
|
117
|
-
scan_type="grid_scan",
|
|
118
|
-
parameter={"args": {"samx": (-5, 5, 3)}, "kwargs": {}},
|
|
119
|
-
queue="primary",
|
|
120
|
-
metadata={"RID": "something"},
|
|
121
|
-
)
|
|
154
|
+
queue, _, request_msg = queue_elements
|
|
122
155
|
|
|
123
156
|
with mock.patch(
|
|
124
157
|
"bec_lib.queue_items.QueueItem.queue_position", new_callable=mock.PropertyMock
|
|
@@ -136,24 +169,182 @@ def test_live_updates_process_queue_without_queue_number(bec_client_mock):
|
|
|
136
169
|
assert live_updates._process_queue(queue, request_msg, "req_id") is False
|
|
137
170
|
|
|
138
171
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
#
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
#
|
|
150
|
-
|
|
151
|
-
#
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
172
|
+
@pytest.mark.timeout(20)
|
|
173
|
+
def test_available_req_blocks(bec_client_mock, queue_elements):
|
|
174
|
+
client = bec_client_mock
|
|
175
|
+
live_updates = IPythonLiveUpdates(client)
|
|
176
|
+
queue, request_block, request_msg = queue_elements
|
|
177
|
+
|
|
178
|
+
# Test with matching RID
|
|
179
|
+
available_blocks = live_updates._available_req_blocks(queue, request_msg)
|
|
180
|
+
assert (
|
|
181
|
+
len(available_blocks) == 0
|
|
182
|
+
) # request_block.RID is "req_id", request_msg.metadata["RID"] is "something"
|
|
183
|
+
|
|
184
|
+
# Test with correct RID
|
|
185
|
+
request_block.RID = "something"
|
|
186
|
+
available_blocks = live_updates._available_req_blocks(queue, request_msg)
|
|
187
|
+
assert len(available_blocks) == 1
|
|
188
|
+
assert available_blocks[0] == request_block
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@pytest.mark.timeout(20)
|
|
192
|
+
def test_available_req_blocks_multiple_blocks(bec_client_mock):
|
|
193
|
+
client = bec_client_mock
|
|
194
|
+
live_updates = IPythonLiveUpdates(client)
|
|
195
|
+
|
|
196
|
+
request_msg = messages.ScanQueueMessage(
|
|
197
|
+
scan_type="grid_scan",
|
|
198
|
+
parameter={"args": {"samx": (-5, 5, 3)}, "kwargs": {}},
|
|
199
|
+
queue="primary",
|
|
200
|
+
metadata={"RID": "test_rid"},
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
request_block1 = messages.RequestBlock(
|
|
204
|
+
msg=request_msg,
|
|
205
|
+
RID="test_rid",
|
|
206
|
+
scan_motors=["samx"],
|
|
207
|
+
report_instructions=[],
|
|
208
|
+
readout_priority={"monitored": ["samx"]},
|
|
209
|
+
is_scan=True,
|
|
210
|
+
scan_number=1,
|
|
211
|
+
scan_id="scan_id_1",
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
request_block2 = messages.RequestBlock(
|
|
215
|
+
msg=request_msg,
|
|
216
|
+
RID="test_rid",
|
|
217
|
+
scan_motors=["samy"],
|
|
218
|
+
report_instructions=[],
|
|
219
|
+
readout_priority={"monitored": ["samy"]},
|
|
220
|
+
is_scan=True,
|
|
221
|
+
scan_number=2,
|
|
222
|
+
scan_id="scan_id_2",
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
request_block3 = messages.RequestBlock(
|
|
226
|
+
msg=request_msg,
|
|
227
|
+
RID="different_rid",
|
|
228
|
+
scan_motors=["samz"],
|
|
229
|
+
report_instructions=[],
|
|
230
|
+
readout_priority={"monitored": ["samz"]},
|
|
231
|
+
is_scan=True,
|
|
232
|
+
scan_number=3,
|
|
233
|
+
scan_id="scan_id_3",
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
queue = QueueItem(
|
|
237
|
+
scan_manager=client.queue,
|
|
238
|
+
queue_id="queue_id",
|
|
239
|
+
request_blocks=[request_block1, request_block2, request_block3],
|
|
240
|
+
status="RUNNING",
|
|
241
|
+
active_request_block={},
|
|
242
|
+
scan_id=["scan_id_1", "scan_id_2", "scan_id_3"],
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
available_blocks = live_updates._available_req_blocks(queue, request_msg)
|
|
246
|
+
assert len(available_blocks) == 2
|
|
247
|
+
assert request_block1 in available_blocks
|
|
248
|
+
assert request_block2 in available_blocks
|
|
249
|
+
assert request_block3 not in available_blocks
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
@pytest.mark.timeout(20)
|
|
253
|
+
def test_element_in_queue_no_queue(bec_client_mock):
|
|
254
|
+
client = bec_client_mock
|
|
255
|
+
live_updates = IPythonLiveUpdates(client)
|
|
256
|
+
|
|
257
|
+
# Test when client.queue is None
|
|
258
|
+
client.queue = None
|
|
259
|
+
assert live_updates._element_in_queue() is False
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
@pytest.mark.timeout(20)
|
|
263
|
+
def test_element_in_queue_no_current_scan_queue(bec_client_mock):
|
|
264
|
+
client = bec_client_mock
|
|
265
|
+
live_updates = IPythonLiveUpdates(client)
|
|
266
|
+
|
|
267
|
+
# Test when current_scan_queue is None
|
|
268
|
+
client.queue.queue_storage.current_scan_queue = None
|
|
269
|
+
assert live_updates._element_in_queue() is False
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
@pytest.mark.timeout(20)
|
|
273
|
+
def test_element_in_queue_no_primary_queue(bec_client_mock):
|
|
274
|
+
client = bec_client_mock
|
|
275
|
+
live_updates = IPythonLiveUpdates(client)
|
|
276
|
+
|
|
277
|
+
# Test when primary queue doesn't exist
|
|
278
|
+
scan_queue_status = messages.ScanQueueStatus(info=[], status="RUNNING")
|
|
279
|
+
client.queue.queue_storage.current_scan_queue = {"secondary": scan_queue_status}
|
|
280
|
+
assert live_updates._element_in_queue() is False
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
@pytest.mark.timeout(20)
|
|
284
|
+
def test_element_in_queue_no_queue_info(bec_client_mock):
|
|
285
|
+
client = bec_client_mock
|
|
286
|
+
live_updates = IPythonLiveUpdates(client)
|
|
287
|
+
|
|
288
|
+
# Test when queue_info is empty
|
|
289
|
+
scan_queue_status = messages.ScanQueueStatus(info=[], status="RUNNING")
|
|
290
|
+
client.queue.queue_storage.current_scan_queue = {"primary": scan_queue_status}
|
|
291
|
+
assert live_updates._element_in_queue() is False
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
@pytest.mark.timeout(20)
|
|
295
|
+
def test_element_in_queue_no_current_queue(bec_client_mock, sample_scan_queue_status):
|
|
296
|
+
client = bec_client_mock
|
|
297
|
+
live_updates = IPythonLiveUpdates(client)
|
|
298
|
+
|
|
299
|
+
# Test when _current_queue is None
|
|
300
|
+
live_updates._current_queue = None
|
|
301
|
+
client.queue.queue_storage.current_scan_queue = {"primary": sample_scan_queue_status}
|
|
302
|
+
assert live_updates._element_in_queue() is False
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
@pytest.mark.timeout(20)
|
|
306
|
+
def test_element_in_queue_queue_id_not_in_info(bec_client_mock, sample_request_block):
|
|
307
|
+
client = bec_client_mock
|
|
308
|
+
live_updates = IPythonLiveUpdates(client)
|
|
309
|
+
|
|
310
|
+
# Test when queue_id is not in info
|
|
311
|
+
current_queue = mock.MagicMock()
|
|
312
|
+
current_queue.queue_id = "my_queue_id"
|
|
313
|
+
live_updates._current_queue = current_queue
|
|
314
|
+
|
|
315
|
+
queue_info_entry = messages.QueueInfoEntry(
|
|
316
|
+
queue_id="different_queue_id",
|
|
317
|
+
scan_id=["scan_id"],
|
|
318
|
+
is_scan=[True],
|
|
319
|
+
request_blocks=[sample_request_block],
|
|
320
|
+
scan_number=[1],
|
|
321
|
+
status="RUNNING",
|
|
322
|
+
active_request_block=None,
|
|
323
|
+
)
|
|
324
|
+
scan_queue_status = messages.ScanQueueStatus(info=[queue_info_entry], status="RUNNING")
|
|
325
|
+
client.queue.queue_storage.current_scan_queue = {"primary": scan_queue_status}
|
|
326
|
+
assert live_updates._element_in_queue() is False
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
@pytest.mark.timeout(20)
|
|
330
|
+
def test_element_in_queue_queue_id_in_info(bec_client_mock, sample_request_block):
|
|
331
|
+
client = bec_client_mock
|
|
332
|
+
live_updates = IPythonLiveUpdates(client)
|
|
333
|
+
|
|
334
|
+
# Test when queue_id is in info (should return True)
|
|
335
|
+
current_queue = mock.MagicMock()
|
|
336
|
+
current_queue.queue_id = "my_queue_id"
|
|
337
|
+
live_updates._current_queue = current_queue
|
|
338
|
+
|
|
339
|
+
queue_info_entry = messages.QueueInfoEntry(
|
|
340
|
+
queue_id="my_queue_id",
|
|
341
|
+
scan_id=["scan_id"],
|
|
342
|
+
is_scan=[True],
|
|
343
|
+
request_blocks=[sample_request_block],
|
|
344
|
+
scan_number=[1],
|
|
345
|
+
status="RUNNING",
|
|
346
|
+
active_request_block=None,
|
|
347
|
+
)
|
|
348
|
+
scan_queue_status = messages.ScanQueueStatus(info=[queue_info_entry], status="RUNNING")
|
|
349
|
+
client.queue.queue_storage.current_scan_queue = {"primary": scan_queue_status}
|
|
350
|
+
assert live_updates._element_in_queue() is True
|
|
@@ -1,7 +1,7 @@
|
|
|
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}"
|
|
@@ -12,10 +12,10 @@ from bec_ipython_client.main import BECIPythonClient
|
|
|
12
12
|
from bec_lib import messages
|
|
13
13
|
from bec_lib.endpoints import MessageEndpoints
|
|
14
14
|
from bec_lib.logger import bec_logger
|
|
15
|
-
from bec_server.
|
|
16
|
-
from bec_server.
|
|
17
|
-
from bec_server.
|
|
18
|
-
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
|
|
19
19
|
|
|
20
20
|
if TYPE_CHECKING:
|
|
21
21
|
from pytest_bec_e2e.plugin import LogTestTool
|
|
@@ -43,9 +43,9 @@ def client_logtool_and_manager(
|
|
|
43
43
|
bec_ipython_client_fixture_with_logtool: tuple[BECIPythonClient, "LogTestTool"],
|
|
44
44
|
) -> Generator[tuple[BECIPythonClient, "LogTestTool", ProcedureManager], None, None]:
|
|
45
45
|
client, logtool = bec_ipython_client_fixture_with_logtool
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
manager = ProcedureManager(
|
|
47
|
+
f"{client.connector.host}:{client.connector.port}", ContainerProcedureWorker
|
|
48
|
+
)
|
|
49
49
|
yield client, logtool, manager
|
|
50
50
|
manager.shutdown()
|
|
51
51
|
|
|
@@ -67,7 +67,8 @@ def test_building_worker_image():
|
|
|
67
67
|
|
|
68
68
|
|
|
69
69
|
@pytest.mark.timeout(100)
|
|
70
|
-
@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())
|
|
71
72
|
def test_procedure_runner_spawns_worker(
|
|
72
73
|
client_logtool_and_manager: tuple[BECIPythonClient, "LogTestTool", ProcedureManager],
|
|
73
74
|
):
|
|
@@ -75,7 +76,7 @@ def test_procedure_runner_spawns_worker(
|
|
|
75
76
|
assert manager._active_workers == {}
|
|
76
77
|
endpoint = MessageEndpoints.procedure_request()
|
|
77
78
|
msg = messages.ProcedureRequestMessage(
|
|
78
|
-
identifier="sleep", args_kwargs=((), {"time_s":
|
|
79
|
+
identifier="sleep", args_kwargs=((), {"time_s": 0.1}), queue="test"
|
|
79
80
|
)
|
|
80
81
|
|
|
81
82
|
logs = []
|
|
@@ -88,14 +89,14 @@ def test_procedure_runner_spawns_worker(
|
|
|
88
89
|
client.connector.xadd(topic=endpoint, msg_dict=msg.model_dump())
|
|
89
90
|
|
|
90
91
|
_wait_while(lambda: manager._active_workers == {}, 5)
|
|
91
|
-
_wait_while(lambda: manager._active_workers != {},
|
|
92
|
+
_wait_while(lambda: manager._active_workers != {}, 90)
|
|
92
93
|
|
|
93
94
|
assert logs != []
|
|
94
95
|
|
|
95
96
|
|
|
96
97
|
@pytest.mark.timeout(100)
|
|
97
|
-
@patch("bec_server.
|
|
98
|
-
@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())
|
|
99
100
|
def test_happy_path_container_procedure_runner(
|
|
100
101
|
client_logtool_and_manager: tuple[BECIPythonClient, "LogTestTool", ProcedureManager],
|
|
101
102
|
):
|
|
@@ -111,7 +112,7 @@ def test_happy_path_container_procedure_runner(
|
|
|
111
112
|
conn.xadd(topic=endpoint, msg_dict=msg.model_dump())
|
|
112
113
|
|
|
113
114
|
_wait_while(lambda: manager._active_workers == {}, 5)
|
|
114
|
-
_wait_while(lambda: manager._active_workers != {},
|
|
115
|
+
_wait_while(lambda: manager._active_workers != {}, 90)
|
|
115
116
|
|
|
116
117
|
logtool.fetch()
|
|
117
118
|
assert logtool.is_present_in_any_message("procedure accepted: True, message:")
|
|
@@ -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:
|
|
@@ -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
|
|
File without changes
|
{bec_ipython_client-3.84.0.dist-info → bec_ipython_client-3.89.3.dist-info}/entry_points.txt
RENAMED
|
File without changes
|