bec-ipython-client 3.141.0__tar.gz → 3.142.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.
Files changed (44) hide show
  1. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/PKG-INFO +1 -1
  2. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/callbacks/device_progress.py +35 -2
  3. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/callbacks/ipython_live_updates.py +1 -1
  4. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/pyproject.toml +2 -1
  5. bec_ipython_client-3.142.0/tests/client_tests/test_device_progress.py +125 -0
  6. bec_ipython_client-3.141.0/tests/client_tests/test_device_progress.py +0 -62
  7. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/.gitignore +0 -0
  8. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/__init__.py +0 -0
  9. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/beamline_mixin.py +0 -0
  10. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/bec_magics.py +0 -0
  11. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/bec_startup.py +0 -0
  12. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/callbacks/__init__.py +0 -0
  13. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/callbacks/live_table.py +0 -0
  14. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/callbacks/move_device.py +0 -0
  15. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/callbacks/utils.py +0 -0
  16. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/high_level_interfaces/__init__.py +0 -0
  17. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/high_level_interfaces/bec_hli.py +0 -0
  18. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/high_level_interfaces/spec_hli.py +0 -0
  19. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/main.py +0 -0
  20. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/plugins/SLS/__init__.py +0 -0
  21. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/plugins/SLS/sls_info.py +0 -0
  22. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/plugins/XTreme/__init__.py +0 -0
  23. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/plugins/XTreme/x-treme.py +0 -0
  24. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/plugins/__init__.py +0 -0
  25. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/plugins/flomni/flomni_config.yaml +0 -0
  26. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/prettytable.py +0 -0
  27. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/progressbar.py +0 -0
  28. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/bec_ipython_client/signals.py +0 -0
  29. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/demo.py +0 -0
  30. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/tests/client_tests/conftest.py +0 -0
  31. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/tests/client_tests/test_beamline_mixins.py +0 -0
  32. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/tests/client_tests/test_bec_client.py +0 -0
  33. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/tests/client_tests/test_ipython_live_updates.py +0 -0
  34. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/tests/client_tests/test_live_table.py +0 -0
  35. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/tests/client_tests/test_move_callback.py +0 -0
  36. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/tests/client_tests/test_pretty_table.py +0 -0
  37. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/tests/client_tests/test_signals.py +0 -0
  38. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/tests/conftest.py +0 -0
  39. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/tests/end-2-end/_ensure_requirements_container.py +0 -0
  40. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/tests/end-2-end/test_actors_e2e.py +0 -0
  41. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/tests/end-2-end/test_procedures_e2e.py +0 -0
  42. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/tests/end-2-end/test_scans_e2e.py +0 -0
  43. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/tests/end-2-end/test_scans_lib_e2e.py +0 -0
  44. {bec_ipython_client-3.141.0 → bec_ipython_client-3.142.0}/tests/end-2-end/test_scans_v4_lib_e2e.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bec_ipython_client
3
- Version: 3.141.0
3
+ Version: 3.142.0
4
4
  Summary: BEC IPython client
5
5
  Project-URL: Bug Tracker, https://github.com/bec-project/bec/issues
6
6
  Project-URL: Homepage, https://github.com/bec-project/bec
@@ -1,6 +1,7 @@
1
1
  import time
2
2
 
3
3
  from bec_ipython_client.progressbar import ScanProgressBar
4
+ from bec_lib.bec_errors import ScanInterruption, ScanRestart
4
5
  from bec_lib.endpoints import MessageEndpoints
5
6
  from bec_lib.logger import bec_logger
6
7
 
@@ -14,6 +15,34 @@ class LiveUpdatesDeviceProgress(LiveUpdatesTable):
14
15
 
15
16
  REPORT_TYPE = "device_progress"
16
17
 
18
+ def _check_scan_state(self) -> bool:
19
+ """Check whether the scan has reached a terminal or exceptional state.
20
+
21
+ Returns:
22
+ bool: True if the scan should stop without error.
23
+ """
24
+ if not self.scan_item:
25
+ return False
26
+
27
+ restarted_msg = getattr(self.scan_item, "restarted_msg", None)
28
+ if restarted_msg:
29
+ raise ScanRestart(new_scan_msg=restarted_msg)
30
+
31
+ if getattr(self.scan_item, "status", None) == "user_completed":
32
+ print("Scan was set to 'completed' by user.")
33
+ return True
34
+
35
+ status_message = getattr(self.scan_item, "status_message", None)
36
+ if status_message and getattr(status_message, "reason", None) == "user":
37
+ scan_number = getattr(self.scan_item, "scan_number", None)
38
+ if scan_number is None:
39
+ msg = "Scan was aborted by user."
40
+ else:
41
+ msg = f"Scan {scan_number} was aborted by user."
42
+ raise ScanInterruption(msg)
43
+
44
+ return False
45
+
17
46
  def core(self):
18
47
  """core function to run the live updates for the table"""
19
48
  self._wait_for_report_instructions()
@@ -23,7 +52,7 @@ class LiveUpdatesDeviceProgress(LiveUpdatesTable):
23
52
  """Run the update loop for the progress bar.
24
53
 
25
54
  Args:
26
- device_names (list[str]): The name of the device to monitor.
55
+ device_names (list[str]): The names of the devices to monitor.
27
56
  """
28
57
  with ScanProgressBar(
29
58
  scan_number=self.scan_item.scan_number, clear_on_exit=False
@@ -39,11 +68,13 @@ class LiveUpdatesDeviceProgress(LiveUpdatesTable):
39
68
 
40
69
  Args:
41
70
  progressbar (ScanProgressBar): The progressbar to update.
42
- device_names (str): The name of the device to monitor.
71
+ device_names (list[str]): The names of the devices to monitor.
43
72
  Returns:
44
73
  bool: True if the scan is finished.
45
74
  """
46
75
  self.check_alarms()
76
+ if self._check_scan_state():
77
+ return True
47
78
  status = self.bec.connector.get(MessageEndpoints.device_progress(device_names[0]))
48
79
  if not status:
49
80
  logger.trace("waiting for new data point")
@@ -68,6 +99,8 @@ class LiveUpdatesDeviceProgress(LiveUpdatesTable):
68
99
  # process sync callbacks
69
100
  self.bec.callbacks.poll()
70
101
  self.scan_item.poll_callbacks()
102
+ if self._check_scan_state():
103
+ return True
71
104
 
72
105
  done = status.content.get("done")
73
106
  if point_id == max_value or done:
@@ -363,7 +363,7 @@ class IPythonLiveUpdates:
363
363
  return
364
364
 
365
365
  status = target_queue_status.status
366
- if status == "LOCKED":
366
+ if status == "LOCKED" and any(queue.scan_ids):
367
367
  lock_info = [
368
368
  f"{lock.identifier}: {lock.reason}\n" for lock in target_queue_status.locks
369
369
  ]
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "bec_ipython_client"
7
- version = "3.141.0"
7
+ version = "3.142.0"
8
8
  description = "BEC IPython client"
9
9
  requires-python = ">=3.11"
10
10
  classifiers = [
@@ -100,6 +100,7 @@ Homepage = "https://github.com/bec-project/bec"
100
100
 
101
101
 
102
102
 
103
+
103
104
 
104
105
 
105
106
  [tool.hatch.build.targets.wheel]
@@ -0,0 +1,125 @@
1
+ from unittest import mock
2
+
3
+ import pytest
4
+
5
+ from bec_ipython_client.callbacks.device_progress import LiveUpdatesDeviceProgress
6
+ from bec_lib import messages
7
+ from bec_lib.bec_errors import ScanInterruption, ScanRestart
8
+
9
+
10
+ def test_update_progressbar_continues_without_device_data():
11
+ bec = mock.MagicMock()
12
+ request = mock.MagicMock()
13
+ live_update = LiveUpdatesDeviceProgress(bec=bec, report_instruction={}, request=request)
14
+ progressbar = mock.MagicMock()
15
+
16
+ bec.connector.get.return_value = None
17
+ res = live_update._update_progressbar(progressbar, ["async_dev1"])
18
+ assert res is False
19
+
20
+
21
+ def test_update_progressbar_continues_when_scan_id_doesnt_match():
22
+ bec = mock.MagicMock()
23
+ request = mock.MagicMock()
24
+ live_update = LiveUpdatesDeviceProgress(bec=bec, report_instruction={}, request=request)
25
+ progressbar = mock.MagicMock()
26
+ live_update.scan_item = mock.MagicMock()
27
+ live_update.scan_item.scan_id = "scan_id2"
28
+ live_update.scan_item.restarted_msg = None
29
+ live_update.scan_item.status = "open"
30
+ live_update.scan_item.status_message = None
31
+
32
+ bec.connector.get.return_value = messages.ProgressMessage(
33
+ value=1, max_value=10, done=False, metadata={"scan_id": "scan_id"}
34
+ )
35
+ res = live_update._update_progressbar(progressbar, ["async_dev1"])
36
+ assert res is False
37
+
38
+
39
+ def test_update_progressbar_updates_max_value():
40
+ bec = mock.MagicMock()
41
+ request = mock.MagicMock()
42
+ live_update = LiveUpdatesDeviceProgress(bec=bec, report_instruction={}, request=request)
43
+ progressbar = mock.MagicMock()
44
+ live_update.scan_item = mock.MagicMock()
45
+ live_update.scan_item.scan_id = "scan_id"
46
+ live_update.scan_item.restarted_msg = None
47
+ live_update.scan_item.status = "open"
48
+ live_update.scan_item.status_message = None
49
+
50
+ bec.connector.get.return_value = messages.ProgressMessage(
51
+ value=10, max_value=20, done=False, metadata={"scan_id": "scan_id"}
52
+ )
53
+ res = live_update._update_progressbar(progressbar, ["async_dev1"])
54
+ assert res is False
55
+ assert progressbar.max_points == 20
56
+ progressbar.update.assert_called_once_with(10)
57
+
58
+
59
+ def test_update_progressbar_returns_true_when_max_value_is_reached():
60
+ bec = mock.MagicMock()
61
+ request = mock.MagicMock()
62
+ live_update = LiveUpdatesDeviceProgress(bec=bec, report_instruction={}, request=request)
63
+ progressbar = mock.MagicMock()
64
+ live_update.scan_item = mock.MagicMock()
65
+ live_update.scan_item.scan_id = "scan_id"
66
+ live_update.scan_item.restarted_msg = None
67
+ live_update.scan_item.status = "open"
68
+ live_update.scan_item.status_message = None
69
+
70
+ bec.connector.get.return_value = messages.ProgressMessage(
71
+ value=10, max_value=10, done=True, metadata={"scan_id": "scan_id"}
72
+ )
73
+ res = live_update._update_progressbar(progressbar, ["async_dev1"])
74
+ assert res is True
75
+
76
+
77
+ def test_update_progressbar_raises_scan_restart_when_scan_restarted():
78
+ bec = mock.MagicMock()
79
+ request = mock.MagicMock()
80
+ live_update = LiveUpdatesDeviceProgress(bec=bec, report_instruction={}, request=request)
81
+ progressbar = mock.MagicMock()
82
+ restart_msg = messages.ScanQueueMessage(scan_type="grid_scan", parameter={"args": {}})
83
+ live_update.scan_item = mock.MagicMock(
84
+ scan_id="scan_id", restarted_msg=restart_msg, status="open", status_message=None
85
+ )
86
+
87
+ with mock.patch("bec_ipython_client.callbacks.device_progress.print") as mock_print:
88
+ with pytest.raises(ScanRestart) as exc_info:
89
+ live_update._update_progressbar(progressbar, ["async_dev1"])
90
+
91
+ assert exc_info.value.new_scan_msg == restart_msg
92
+ mock_print.assert_not_called()
93
+
94
+
95
+ def test_update_progressbar_returns_true_when_scan_completed_by_user():
96
+ bec = mock.MagicMock()
97
+ request = mock.MagicMock()
98
+ live_update = LiveUpdatesDeviceProgress(bec=bec, report_instruction={}, request=request)
99
+ progressbar = mock.MagicMock()
100
+ live_update.scan_item = mock.MagicMock(
101
+ scan_id="scan_id", restarted_msg=None, status="user_completed", status_message=None
102
+ )
103
+
104
+ with mock.patch("bec_ipython_client.callbacks.device_progress.print") as mock_print:
105
+ res = live_update._update_progressbar(progressbar, ["async_dev1"])
106
+
107
+ assert res is True
108
+ mock_print.assert_called_once_with("Scan was set to 'completed' by user.")
109
+
110
+
111
+ def test_update_progressbar_raises_scan_interruption_when_aborted_by_user():
112
+ bec = mock.MagicMock()
113
+ request = mock.MagicMock()
114
+ live_update = LiveUpdatesDeviceProgress(bec=bec, report_instruction={}, request=request)
115
+ progressbar = mock.MagicMock()
116
+ live_update.scan_item = mock.MagicMock(
117
+ scan_id="scan_id",
118
+ scan_number=5,
119
+ restarted_msg=None,
120
+ status="open",
121
+ status_message=mock.MagicMock(reason="user"),
122
+ )
123
+
124
+ with pytest.raises(ScanInterruption, match="Scan 5 was aborted by user."):
125
+ live_update._update_progressbar(progressbar, ["async_dev1"])
@@ -1,62 +0,0 @@
1
- from unittest import mock
2
-
3
- from bec_ipython_client.callbacks.device_progress import LiveUpdatesDeviceProgress
4
- from bec_lib import messages
5
-
6
-
7
- def test_update_progressbar_continues_without_device_data():
8
- bec = mock.MagicMock()
9
- request = mock.MagicMock()
10
- live_update = LiveUpdatesDeviceProgress(bec=bec, report_instruction={}, request=request)
11
- progressbar = mock.MagicMock()
12
-
13
- bec.connector.get.return_value = None
14
- res = live_update._update_progressbar(progressbar, "async_dev1")
15
- assert res is False
16
-
17
-
18
- def test_update_progressbar_continues_when_scan_id_doesnt_match():
19
- bec = mock.MagicMock()
20
- request = mock.MagicMock()
21
- live_update = LiveUpdatesDeviceProgress(bec=bec, report_instruction={}, request=request)
22
- progressbar = mock.MagicMock()
23
- live_update.scan_item = mock.MagicMock()
24
- live_update.scan_item.scan_id = "scan_id2"
25
-
26
- bec.connector.get.return_value = messages.ProgressMessage(
27
- value=1, max_value=10, done=False, metadata={"scan_id": "scan_id"}
28
- )
29
- res = live_update._update_progressbar(progressbar, "async_dev1")
30
- assert res is False
31
-
32
-
33
- def test_update_progressbar_updates_max_value():
34
- bec = mock.MagicMock()
35
- request = mock.MagicMock()
36
- live_update = LiveUpdatesDeviceProgress(bec=bec, report_instruction={}, request=request)
37
- progressbar = mock.MagicMock()
38
- live_update.scan_item = mock.MagicMock()
39
- live_update.scan_item.scan_id = "scan_id"
40
-
41
- bec.connector.get.return_value = messages.ProgressMessage(
42
- value=10, max_value=20, done=False, metadata={"scan_id": "scan_id"}
43
- )
44
- res = live_update._update_progressbar(progressbar, "async_dev1")
45
- assert res is False
46
- assert progressbar.max_points == 20
47
- progressbar.update.assert_called_once_with(10)
48
-
49
-
50
- def test_update_progressbar_returns_true_when_max_value_is_reached():
51
- bec = mock.MagicMock()
52
- request = mock.MagicMock()
53
- live_update = LiveUpdatesDeviceProgress(bec=bec, report_instruction={}, request=request)
54
- progressbar = mock.MagicMock()
55
- live_update.scan_item = mock.MagicMock()
56
- live_update.scan_item.scan_id = "scan_id"
57
-
58
- bec.connector.get.return_value = messages.ProgressMessage(
59
- value=10, max_value=10, done=True, metadata={"scan_id": "scan_id"}
60
- )
61
- res = live_update._update_progressbar(progressbar, "async_dev1")
62
- assert res is True