bec-ipython-client 3.125.2__tar.gz → 3.127.0__tar.gz
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_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/PKG-INFO +1 -1
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/main.py +19 -2
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/pyproject.toml +3 -1
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/client_tests/test_bec_client.py +54 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/.gitignore +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/__init__.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/beamline_mixin.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/bec_magics.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/bec_startup.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/callbacks/__init__.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/callbacks/device_progress.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/callbacks/ipython_live_updates.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/callbacks/live_table.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/callbacks/move_device.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/callbacks/utils.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/high_level_interfaces/__init__.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/high_level_interfaces/bec_hli.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/high_level_interfaces/spec_hli.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/plugins/SLS/__init__.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/plugins/SLS/sls_info.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/plugins/XTreme/__init__.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/plugins/XTreme/x-treme.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/plugins/__init__.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/plugins/flomni/flomni_config.yaml +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/prettytable.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/progressbar.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/signals.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/demo.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/client_tests/conftest.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/client_tests/test_beamline_mixins.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/client_tests/test_device_progress.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/client_tests/test_ipython_live_updates.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/client_tests/test_live_table.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/client_tests/test_move_callback.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/client_tests/test_pretty_table.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/conftest.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/end-2-end/_ensure_requirements_container.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/end-2-end/test_procedures_e2e.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/end-2-end/test_scans_e2e.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/end-2-end/test_scans_lib_e2e.py +0 -0
- {bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/end-2-end/test_scans_v4_lib_e2e.py +0 -0
|
@@ -5,6 +5,7 @@ import collections
|
|
|
5
5
|
import functools
|
|
6
6
|
import os
|
|
7
7
|
import sys
|
|
8
|
+
import traceback
|
|
8
9
|
from typing import Iterable, Literal, Tuple
|
|
9
10
|
|
|
10
11
|
import IPython
|
|
@@ -147,7 +148,7 @@ class BECIPythonClient:
|
|
|
147
148
|
self._ip.prompts = BECClientPrompt(ip=self._ip, client=self._client, username="unknown")
|
|
148
149
|
self._refresh_ipython_username()
|
|
149
150
|
self._load_magics()
|
|
150
|
-
self._ip.events.register("
|
|
151
|
+
self._ip.events.register("pre_run_cell", log_console)
|
|
151
152
|
self._ip.set_custom_exc((Exception,), self._create_exception_handler())
|
|
152
153
|
# represent objects using __str__, if overwritten, otherwise use __repr__
|
|
153
154
|
self._ip.display_formatter.formatters["text/plain"].for_type(
|
|
@@ -252,25 +253,31 @@ def _ip_exception_handler(
|
|
|
252
253
|
):
|
|
253
254
|
if issubclass(etype, AlarmBase):
|
|
254
255
|
parent._alarm_history.append((etype, evalue, tb, tb_offset))
|
|
256
|
+
log_console_error(etype, evalue, tb)
|
|
255
257
|
print("\x1b[31m BEC alarm:\x1b[0m")
|
|
256
258
|
evalue.pretty_print()
|
|
257
259
|
print("For more details, use 'bec.show_last_alarm()'")
|
|
258
260
|
return
|
|
259
261
|
if issubclass(etype, ValidationError):
|
|
262
|
+
log_console_error(etype, evalue, tb)
|
|
260
263
|
pretty_print_pydantic_validation_error(evalue)
|
|
261
264
|
return
|
|
262
265
|
if issubclass(etype, (ScanInterruption, DeviceConfigError)):
|
|
266
|
+
log_console_error(etype, evalue, tb, f"{evalue.__class__.__name__}: {evalue}")
|
|
263
267
|
print(f"\x1b[31m {evalue.__class__.__name__}:\x1b[0m {evalue}")
|
|
264
268
|
return
|
|
265
269
|
if issubclass(etype, redis.exceptions.NoPermissionError):
|
|
266
270
|
# pylint: disable=protected-access
|
|
267
271
|
msg = f"The current user ({bec._client.username}) does not have the required permissions.\n {evalue}"
|
|
272
|
+
log_console_error(etype, evalue, tb, f"Unauthorized: {msg}")
|
|
268
273
|
logger.info(f"Unauthorized: {msg}")
|
|
269
274
|
print(f"\x1b[31m Unauthorized:\x1b[0m {msg}")
|
|
270
275
|
return
|
|
271
276
|
if issubclass(etype, ExceptionWithErrorInfo):
|
|
277
|
+
log_console_error(etype, evalue, tb)
|
|
272
278
|
evalue.pretty_print()
|
|
273
279
|
return
|
|
280
|
+
log_console_error(etype, evalue, tb)
|
|
274
281
|
self.showtraceback((etype, evalue, tb), tb_offset=None) # standard IPython's printout
|
|
275
282
|
|
|
276
283
|
|
|
@@ -322,7 +329,17 @@ class BECClientPrompt(Prompts):
|
|
|
322
329
|
|
|
323
330
|
def log_console(execution_info):
|
|
324
331
|
"""log the console input"""
|
|
325
|
-
logger.log("CONSOLE_LOG", f"{execution_info.
|
|
332
|
+
logger.log("CONSOLE_LOG", f"{execution_info.raw_cell}")
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def log_console_error(etype, evalue, tb=None, message: str | None = None):
|
|
336
|
+
"""Log console errors to the shared log stream."""
|
|
337
|
+
if message is None:
|
|
338
|
+
if tb is not None:
|
|
339
|
+
message = "".join(traceback.format_exception(etype, evalue, tb)).rstrip()
|
|
340
|
+
else:
|
|
341
|
+
message = f"{etype.__name__}: {evalue}"
|
|
342
|
+
logger.log("CONSOLE_LOG_ERROR", message)
|
|
326
343
|
|
|
327
344
|
|
|
328
345
|
# pylint: disable=wrong-import-position
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "bec_ipython_client"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.127.0"
|
|
8
8
|
description = "BEC IPython client"
|
|
9
9
|
requires-python = ">=3.11"
|
|
10
10
|
classifiers = [
|
|
@@ -62,6 +62,8 @@ Homepage = "https://github.com/bec-project/bec"
|
|
|
62
62
|
|
|
63
63
|
|
|
64
64
|
|
|
65
|
+
|
|
66
|
+
|
|
65
67
|
|
|
66
68
|
|
|
67
69
|
|
{bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/client_tests/test_bec_client.py
RENAMED
|
@@ -4,10 +4,12 @@ from unittest import mock
|
|
|
4
4
|
|
|
5
5
|
import IPython
|
|
6
6
|
import pytest
|
|
7
|
+
import redis.exceptions
|
|
7
8
|
|
|
8
9
|
from bec_ipython_client import BECIPythonClient, main
|
|
9
10
|
from bec_lib import messages
|
|
10
11
|
from bec_lib.alarm_handler import AlarmBase, AlarmHandler, Alarms
|
|
12
|
+
from bec_lib.bec_errors import DeviceConfigError
|
|
11
13
|
from bec_lib.redis_connector import RedisConnector
|
|
12
14
|
from bec_lib.service_config import ServiceConfig
|
|
13
15
|
|
|
@@ -238,3 +240,55 @@ def test_bec_ipython_client_show_last_no_alarm(ipython_client, capsys):
|
|
|
238
240
|
client.show_last_alarm()
|
|
239
241
|
captured = capsys.readouterr()
|
|
240
242
|
assert "No alarm has been raised in this session." in captured.out
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def test_ipython_exception_handler_logs_console_error_for_device_config_error():
|
|
246
|
+
shell = mock.MagicMock()
|
|
247
|
+
with mock.patch.object(main.logger, "log") as mock_log:
|
|
248
|
+
main._ip_exception_handler(
|
|
249
|
+
shell, DeviceConfigError, DeviceConfigError("bad config"), None, parent=mock.MagicMock()
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
mock_log.assert_called_once_with("CONSOLE_LOG_ERROR", "DeviceConfigError: bad config")
|
|
253
|
+
shell.showtraceback.assert_not_called()
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def test_ipython_exception_handler_logs_console_error_for_unhandled_exception():
|
|
257
|
+
shell = mock.MagicMock()
|
|
258
|
+
try:
|
|
259
|
+
raise RuntimeError("boom")
|
|
260
|
+
except RuntimeError as exc:
|
|
261
|
+
with mock.patch.object(main.logger, "log") as mock_log:
|
|
262
|
+
main._ip_exception_handler(
|
|
263
|
+
shell, RuntimeError, exc, exc.__traceback__, parent=mock.MagicMock()
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
mock_log.assert_called_once()
|
|
267
|
+
assert mock_log.call_args.args[0] == "CONSOLE_LOG_ERROR"
|
|
268
|
+
assert "RuntimeError: boom" in mock_log.call_args.args[1]
|
|
269
|
+
shell.showtraceback.assert_called_once()
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def test_ipython_exception_handler_logs_console_error_for_permission_error():
|
|
273
|
+
shell = mock.MagicMock()
|
|
274
|
+
parent = mock.MagicMock()
|
|
275
|
+
with (
|
|
276
|
+
mock.patch.object(main.logger, "log") as mock_log,
|
|
277
|
+
mock.patch.object(main.logger, "info") as mock_info,
|
|
278
|
+
mock.patch.object(
|
|
279
|
+
main, "bec", mock.MagicMock(_client=mock.MagicMock(username="alice")), create=True
|
|
280
|
+
),
|
|
281
|
+
):
|
|
282
|
+
main._ip_exception_handler(
|
|
283
|
+
shell,
|
|
284
|
+
redis.exceptions.NoPermissionError,
|
|
285
|
+
redis.exceptions.NoPermissionError("denied"),
|
|
286
|
+
None,
|
|
287
|
+
parent=parent,
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
mock_log.assert_called_once()
|
|
291
|
+
assert mock_log.call_args.args[0] == "CONSOLE_LOG_ERROR"
|
|
292
|
+
assert "Unauthorized:" in mock_log.call_args.args[1]
|
|
293
|
+
mock_info.assert_called_once()
|
|
294
|
+
shell.showtraceback.assert_not_called()
|
|
File without changes
|
|
File without changes
|
{bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/beamline_mixin.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/callbacks/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/callbacks/live_table.py
RENAMED
|
File without changes
|
|
File without changes
|
{bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/callbacks/utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/plugins/SLS/__init__.py
RENAMED
|
File without changes
|
{bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/plugins/SLS/sls_info.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/bec_ipython_client/plugins/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/client_tests/test_beamline_mixins.py
RENAMED
|
File without changes
|
{bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/client_tests/test_device_progress.py
RENAMED
|
File without changes
|
|
File without changes
|
{bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/client_tests/test_live_table.py
RENAMED
|
File without changes
|
{bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/client_tests/test_move_callback.py
RENAMED
|
File without changes
|
{bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/client_tests/test_pretty_table.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/end-2-end/test_procedures_e2e.py
RENAMED
|
File without changes
|
|
File without changes
|
{bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/end-2-end/test_scans_lib_e2e.py
RENAMED
|
File without changes
|
{bec_ipython_client-3.125.2 → bec_ipython_client-3.127.0}/tests/end-2-end/test_scans_v4_lib_e2e.py
RENAMED
|
File without changes
|