bec-widgets 0.47.0__tar.gz → 0.49.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 (109) hide show
  1. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/PKG-INFO +1 -1
  2. bec_widgets-0.49.0/bec_widgets/cli/__init__.py +2 -0
  3. bec_widgets-0.49.0/bec_widgets/cli/auto_updates.py +118 -0
  4. bec_widgets-0.49.0/bec_widgets/cli/bec_widgets_icon.png +0 -0
  5. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/cli/client_utils.py +39 -60
  6. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/cli/server.py +10 -0
  7. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/utils/bec_connector.py +4 -0
  8. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets.egg-info/PKG-INFO +1 -1
  9. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets.egg-info/SOURCES.txt +2 -0
  10. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/setup.py +8 -2
  11. bec_widgets-0.47.0/bec_widgets/cli/__init__.py +0 -1
  12. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/LICENSE +0 -0
  13. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/README.md +0 -0
  14. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/__init__.py +0 -0
  15. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/cli/client.py +0 -0
  16. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/cli/generate_cli.py +0 -0
  17. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/__init__.py +0 -0
  18. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/eiger_plot/__init__.py +0 -0
  19. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/eiger_plot/eiger_plot.py +0 -0
  20. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/eiger_plot/eiger_plot.ui +0 -0
  21. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/jupyter_console/__init__.py +0 -0
  22. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/jupyter_console/jupyter_console_window.py +0 -0
  23. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/jupyter_console/jupyter_console_window.ui +0 -0
  24. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/mca_readout/__init__.py +0 -0
  25. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/mca_readout/mca_plot.py +0 -0
  26. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/mca_readout/mca_sim.py +0 -0
  27. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/motor_movement/__init__.py +0 -0
  28. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/motor_movement/config_example.yaml +0 -0
  29. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/motor_movement/csax_bec_config.yaml +0 -0
  30. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/motor_movement/csaxs_config.yaml +0 -0
  31. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/motor_movement/motor_control_compilations.py +0 -0
  32. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/motor_movement/motor_controller.ui +0 -0
  33. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/motor_movement/motor_example.py +0 -0
  34. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/stream_plot/__init__.py +0 -0
  35. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/stream_plot/line_plot.ui +0 -0
  36. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/examples/stream_plot/stream_plot.py +0 -0
  37. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/simulations/__init__.py +0 -0
  38. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/utils/__init__.py +0 -0
  39. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/utils/bec_dispatcher.py +0 -0
  40. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/utils/bec_table.py +0 -0
  41. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/utils/colors.py +0 -0
  42. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/utils/container_utils.py +0 -0
  43. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/utils/crosshair.py +0 -0
  44. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/utils/ctrl_c.py +0 -0
  45. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/utils/entry_validator.py +0 -0
  46. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/utils/rpc_decorator.py +0 -0
  47. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/utils/thread_checker.py +0 -0
  48. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/utils/validator_delegate.py +0 -0
  49. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/utils/widget_io.py +0 -0
  50. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/utils/yaml_dialog.py +0 -0
  51. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/validation/__init__.py +0 -0
  52. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/validation/monitor_config_validator.py +0 -0
  53. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/__init__.py +0 -0
  54. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/editor/__init__.py +0 -0
  55. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/editor/editor.py +0 -0
  56. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/figure/__init__.py +0 -0
  57. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/figure/figure.py +0 -0
  58. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/monitor/__init__.py +0 -0
  59. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/monitor/config_dialog.py +0 -0
  60. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/monitor/config_dialog.ui +0 -0
  61. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/monitor/monitor.py +0 -0
  62. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/monitor/tab_template.ui +0 -0
  63. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/motor_control/__init__.py +0 -0
  64. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/motor_control/motor_control.py +0 -0
  65. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/motor_control/motor_control_absolute.ui +0 -0
  66. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/motor_control/motor_control_relative.ui +0 -0
  67. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/motor_control/motor_control_selection.ui +0 -0
  68. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/motor_control/motor_control_table.ui +0 -0
  69. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/motor_map/__init__.py +0 -0
  70. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/motor_map/motor_map.py +0 -0
  71. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/plots/__init__.py +0 -0
  72. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/plots/image.py +0 -0
  73. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/plots/motor_map.py +0 -0
  74. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/plots/plot_base.py +0 -0
  75. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/plots/waveform.py +0 -0
  76. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/scan_control/__init__.py +0 -0
  77. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/scan_control/scan_control.py +0 -0
  78. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/toolbar/__init__.py +0 -0
  79. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets/widgets/toolbar/toolbar.py +0 -0
  80. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets.egg-info/dependency_links.txt +0 -0
  81. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets.egg-info/requires.txt +0 -0
  82. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/bec_widgets.egg-info/top_level.txt +0 -0
  83. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/setup.cfg +0 -0
  84. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/__init__.py +0 -0
  85. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/__init__.py +0 -0
  86. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/client_mocks.py +0 -0
  87. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/conftest.py +0 -0
  88. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_bec_connector.py +0 -0
  89. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_bec_dispatcher.py +0 -0
  90. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_bec_figure.py +0 -0
  91. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_bec_monitor.py +0 -0
  92. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_bec_motor_map.py +0 -0
  93. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_client_utils.py +0 -0
  94. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_config_dialog.py +0 -0
  95. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_crosshair.py +0 -0
  96. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_editor.py +0 -0
  97. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_eiger_plot.py +0 -0
  98. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_generate_cli_client.py +0 -0
  99. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_motor_control.py +0 -0
  100. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_motor_map.py +0 -0
  101. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_msgs/__init__.py +0 -0
  102. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_msgs/available_scans_message.py +0 -0
  103. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_plot_base.py +0 -0
  104. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_scan_control.py +0 -0
  105. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_stream_plot.py +0 -0
  106. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_validator_errors.py +0 -0
  107. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_waveform1d.py +0 -0
  108. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_widget_io.py +0 -0
  109. {bec_widgets-0.47.0 → bec_widgets-0.49.0}/tests/unit_tests/test_yaml_dialog.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bec_widgets
3
- Version: 0.47.0
3
+ Version: 0.49.0
4
4
  Summary: BEC Widgets
5
5
  Home-page: https://gitlab.psi.ch/bec/bec-widgets
6
6
  Project-URL: Bug Tracker, https://gitlab.psi.ch/bec/bec-widgets/issues
@@ -0,0 +1,2 @@
1
+ from .auto_updates import AutoUpdates, ScanInfo
2
+ from .client import BECFigure
@@ -0,0 +1,118 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from pydantic import BaseModel
6
+
7
+ if TYPE_CHECKING:
8
+ from .client import BECFigure
9
+
10
+
11
+ class ScanInfo(BaseModel):
12
+ scan_id: str
13
+ scan_number: int
14
+ scan_name: str
15
+ scan_report_devices: list
16
+ monitored_devices: list
17
+ status: str
18
+
19
+
20
+ class AutoUpdates:
21
+ def __init__(self, figure: BECFigure, enabled: bool = True):
22
+ self.enabled = enabled
23
+ self.figure = figure
24
+
25
+ @staticmethod
26
+ def get_scan_info(msg) -> ScanInfo:
27
+ """
28
+ Update the script with the given data.
29
+ """
30
+ info = msg.info
31
+ status = msg.status
32
+ scan_id = msg.scan_id
33
+ scan_number = info.get("scan_number", 0)
34
+ scan_name = info.get("scan_name", "Unknown")
35
+ scan_report_devices = info.get("scan_report_devices", [])
36
+ monitored_devices = info.get("readout_priority", {}).get("monitored", [])
37
+ monitored_devices = [dev for dev in monitored_devices if dev not in scan_report_devices]
38
+ return ScanInfo(
39
+ scan_id=scan_id,
40
+ scan_number=scan_number,
41
+ scan_name=scan_name,
42
+ scan_report_devices=scan_report_devices,
43
+ monitored_devices=monitored_devices,
44
+ status=status,
45
+ )
46
+
47
+ def run(self, msg):
48
+ """
49
+ Run the update function if enabled.
50
+ """
51
+ if not self.enabled:
52
+ return
53
+ if msg.status != "open":
54
+ return
55
+ info = self.get_scan_info(msg)
56
+ self.handler(info)
57
+
58
+ @staticmethod
59
+ def get_selected_device(monitored_devices, selected_device):
60
+ """
61
+ Get the selected device for the plot. If no device is selected, the first
62
+ device in the monitored devices list is selected.
63
+ """
64
+ if selected_device:
65
+ return selected_device
66
+ if len(monitored_devices) > 0:
67
+ sel_device = monitored_devices[0]
68
+ return sel_device
69
+ return None
70
+
71
+ def handler(self, info: ScanInfo) -> None:
72
+ """
73
+ Default update function.
74
+ """
75
+ if info.scan_name == "line_scan" and info.scan_report_devices:
76
+ self.simple_line_scan(info)
77
+ return
78
+ if info.scan_name == "grid_scan" and info.scan_report_devices:
79
+ self.simple_grid_scan(info)
80
+ return
81
+ if info.scan_report_devices:
82
+ self.best_effort(info)
83
+ return
84
+
85
+ def simple_line_scan(self, info: ScanInfo) -> None:
86
+ """
87
+ Simple line scan.
88
+ """
89
+ dev_x = info.scan_report_devices[0]
90
+ dev_y = self.get_selected_device(info.monitored_devices, self.figure.selected_device)
91
+ if not dev_y:
92
+ return
93
+ self.figure.clear_all()
94
+ plt = self.figure.plot(dev_x, dev_y)
95
+ plt.set(title=f"Scan {info.scan_number}", x_label=dev_x, y_label=dev_y)
96
+
97
+ def simple_grid_scan(self, info: ScanInfo) -> None:
98
+ """
99
+ Simple grid scan.
100
+ """
101
+ dev_x = info.scan_report_devices[0]
102
+ dev_y = info.scan_report_devices[1]
103
+ dev_z = self.get_selected_device(info.monitored_devices, self.figure.selected_device)
104
+ self.figure.clear_all()
105
+ plt = self.figure.plot(dev_x, dev_y, dev_z, label=f"Scan {info.scan_number}")
106
+ plt.set(title=f"Scan {info.scan_number}", x_label=dev_x, y_label=dev_y)
107
+
108
+ def best_effort(self, info: ScanInfo) -> None:
109
+ """
110
+ Best effort scan.
111
+ """
112
+ dev_x = info.scan_report_devices[0]
113
+ dev_y = self.get_selected_device(info.monitored_devices, self.figure.selected_device)
114
+ if not dev_y:
115
+ return
116
+ self.figure.clear_all()
117
+ plt = self.figure.plot(dev_x, dev_y, label=f"Scan {info.scan_number}")
118
+ plt.set(title=f"Scan {info.scan_number}", x_label=dev_x, y_label=dev_y)
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import importlib
4
+ import importlib.metadata as imd
4
5
  import os
5
6
  import select
6
7
  import subprocess
@@ -17,6 +18,7 @@ from bec_lib.device import DeviceBase
17
18
  from qtpy.QtCore import QCoreApplication
18
19
 
19
20
  import bec_widgets.cli.client as client
21
+ from bec_widgets.cli.auto_updates import AutoUpdates
20
22
  from bec_widgets.utils.bec_dispatcher import BECDispatcher
21
23
 
22
24
  if TYPE_CHECKING:
@@ -54,68 +56,22 @@ def rpc_call(func):
54
56
  return wrapper
55
57
 
56
58
 
57
- def get_selected_device(monitored_devices, selected_device):
58
- """
59
- Get the selected device for the plot. If no device is selected, the first
60
- device in the monitored devices list is selected.
61
- """
62
- if selected_device:
63
- return selected_device
64
- if len(monitored_devices) > 0:
65
- sel_device = monitored_devices[0]
66
- return sel_device
67
- return None
68
-
69
-
70
- def update_script(figure: BECFigure, msg):
71
- """
72
- Update the script with the given data.
73
- """
74
- info = msg.info
75
- status = msg.status
76
- scan_id = msg.scan_id
77
- scan_number = info.get("scan_number", 0)
78
- scan_name = info.get("scan_name", "Unknown")
79
- scan_report_devices = info.get("scan_report_devices", [])
80
- monitored_devices = info.get("readout_priority", {}).get("monitored", [])
81
- monitored_devices = [dev for dev in monitored_devices if dev not in scan_report_devices]
82
-
83
- if scan_name == "line_scan" and scan_report_devices:
84
- dev_x = scan_report_devices[0]
85
- dev_y = get_selected_device(monitored_devices, figure.selected_device)
86
- print(f"Selected device: {dev_y}")
87
- if not dev_y:
88
- return
89
- figure.clear_all()
90
- plt = figure.plot(dev_x, dev_y)
91
- plt.set(title=f"Scan {scan_number}", x_label=dev_x, y_label=dev_y)
92
- elif scan_name == "grid_scan" and scan_report_devices:
93
- print(f"Scan {scan_number} is running")
94
- dev_x = scan_report_devices[0]
95
- dev_y = scan_report_devices[1]
96
- dev_z = get_selected_device(monitored_devices, figure.selected_device)
97
- figure.clear_all()
98
- plt = figure.plot(dev_x, dev_y, dev_z, label=f"Scan {scan_number}")
99
- plt.set(title=f"Scan {scan_number}", x_label=dev_x, y_label=dev_y)
100
- elif scan_report_devices:
101
- dev_x = scan_report_devices[0]
102
- dev_y = get_selected_device(monitored_devices, figure.selected_device)
103
- if not dev_y:
104
- return
105
- figure.clear_all()
106
- plt = figure.plot(dev_x, dev_y, label=f"Scan {scan_number}")
107
- plt.set(title=f"Scan {scan_number}", x_label=dev_x, y_label=dev_y)
108
-
109
-
110
59
  class BECFigureClientMixin:
111
60
  def __init__(self, **kwargs) -> None:
112
61
  super().__init__(**kwargs)
113
62
  self._process = None
114
- self.update_script = update_script
63
+ self.update_script = self._get_update_script()
115
64
  self._target_endpoint = MessageEndpoints.scan_status()
116
65
  self._selected_device = None
117
66
  self.stderr_output = []
118
67
 
68
+ def _get_update_script(self) -> AutoUpdates:
69
+ eps = imd.entry_points(group="bec.widgets.auto_updates")
70
+ for ep in eps:
71
+ if ep.name == "plugin_widgets_update":
72
+ return ep.load()(figure=self)
73
+ return None
74
+
119
75
  @property
120
76
  def selected_device(self):
121
77
  """
@@ -147,8 +103,7 @@ class BECFigureClientMixin:
147
103
  if isinstance(msg, messages.ScanStatusMessage):
148
104
  if not self.gui_is_alive():
149
105
  return
150
- if msg.status == "open":
151
- self.update_script(self, msg)
106
+ self.update_script.run(msg)
152
107
 
153
108
  def show(self) -> None:
154
109
  """
@@ -166,7 +121,10 @@ class BECFigureClientMixin:
166
121
  """
167
122
  if self._process is None:
168
123
  return
169
- self._run_rpc("close", (), wait_for_rpc_response=False)
124
+ if self.gui_is_alive():
125
+ self._run_rpc("close", (), wait_for_rpc_response=True)
126
+ else:
127
+ self._run_rpc("close", (), wait_for_rpc_response=False)
170
128
  self._process.terminate()
171
129
  self._process_output_processing_thread.join()
172
130
  self._process = None
@@ -212,6 +170,15 @@ class BECFigureClientMixin:
212
170
  self.stderr_output.append(self._process.stderr.read(1024))
213
171
 
214
172
 
173
+ class RPCResponseTimeoutError(Exception):
174
+ """Exception raised when an RPC response is not received within the expected time."""
175
+
176
+ def __init__(self, request_id, timeout):
177
+ super().__init__(
178
+ f"RPC response not received within {timeout} seconds for request ID {request_id}"
179
+ )
180
+
181
+
215
182
  class RPCBase:
216
183
  def __init__(self, gui_id: str = None, config: dict = None, parent=None) -> None:
217
184
  self._client = BECDispatcher().client
@@ -257,7 +224,7 @@ class RPCBase:
257
224
  parameter={"args": args, "kwargs": kwargs, "gui_id": self._gui_id},
258
225
  metadata={"request_id": request_id},
259
226
  )
260
- # print(f"RPCBase: {rpc_msg}")
227
+
261
228
  # pylint: disable=protected-access
262
229
  receiver = self._root._gui_id
263
230
  self._client.connector.set_and_publish(MessageEndpoints.gui_instructions(receiver), rpc_msg)
@@ -292,16 +259,28 @@ class RPCBase:
292
259
  return cls(parent=self, **msg_result)
293
260
  return msg_result
294
261
 
295
- def _wait_for_response(self, request_id):
262
+ def _wait_for_response(self, request_id: str, timeout: int = 5):
296
263
  """
297
264
  Wait for the response from the server.
265
+ Args:
266
+ request_id(str): The request ID.
267
+ timeout(int): The timeout in seconds.
268
+
269
+ Returns:
270
+ The response from the server.
298
271
  """
272
+ start_time = time.time()
299
273
  response = None
300
- while response is None and self.gui_is_alive():
274
+
275
+ while response is None and self.gui_is_alive() and (time.time() - start_time) < timeout:
301
276
  response = self._client.connector.get(
302
277
  MessageEndpoints.gui_instruction_response(request_id)
303
278
  )
304
279
  QCoreApplication.processEvents() # keep UI responsive (and execute signals/slots)
280
+ time.sleep(0.1)
281
+ if response is None and (time.time() - start_time) >= timeout:
282
+ raise RPCResponseTimeoutError(request_id, timeout)
283
+
305
284
  return response
306
285
 
307
286
  def gui_is_alive(self):
@@ -1,4 +1,6 @@
1
1
  import inspect
2
+ import threading
3
+ import time
2
4
 
3
5
  from bec_lib import MessageEndpoints, messages
4
6
  from qtpy.QtCore import QTimer
@@ -109,17 +111,25 @@ class BECWidgetsCLIServer:
109
111
  def shutdown(self):
110
112
  self._shutdown_event = True
111
113
  self._heartbeat_timer.stop()
114
+ self.client.shutdown()
112
115
 
113
116
 
114
117
  if __name__ == "__main__": # pragma: no cover
115
118
  import argparse
116
119
  import sys
117
120
 
121
+ from qtpy.QtCore import QSize
122
+ from qtpy.QtGui import QIcon
118
123
  from qtpy.QtWidgets import QApplication, QMainWindow
119
124
 
120
125
  app = QApplication(sys.argv)
121
126
  app.setApplicationName("BEC Figure")
127
+ icon = QIcon()
128
+ icon.addFile("bec_widgets_icon.png", size=QSize(48, 48))
129
+ app.setWindowIcon(icon)
130
+
122
131
  win = QMainWindow()
132
+ win.setWindowTitle("BEC Widgets")
123
133
 
124
134
  parser = argparse.ArgumentParser(description="BEC Widgets CLI Server")
125
135
  parser.add_argument("--id", type=str, help="The id of the server")
@@ -127,3 +127,7 @@ class BECConnector:
127
127
  return self.config.model_dump()
128
128
  else:
129
129
  return self.config
130
+
131
+ def closeEvent(self, event):
132
+ self.client.shutdown()
133
+ super().closeEvent(event)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bec-widgets
3
- Version: 0.47.0
3
+ Version: 0.49.0
4
4
  Summary: BEC Widgets
5
5
  Home-page: https://gitlab.psi.ch/bec/bec-widgets
6
6
  Project-URL: Bug Tracker, https://gitlab.psi.ch/bec/bec-widgets/issues
@@ -4,6 +4,8 @@ setup.cfg
4
4
  setup.py
5
5
  ./bec_widgets/__init__.py
6
6
  ./bec_widgets/cli/__init__.py
7
+ ./bec_widgets/cli/auto_updates.py
8
+ ./bec_widgets/cli/bec_widgets_icon.png
7
9
  ./bec_widgets/cli/client.py
8
10
  ./bec_widgets/cli/client_utils.py
9
11
  ./bec_widgets/cli/generate_cli.py
@@ -1,7 +1,7 @@
1
1
  # pylint: disable= missing-module-docstring
2
2
  from setuptools import find_packages, setup
3
3
 
4
- __version__ = "0.47.0"
4
+ __version__ = "0.49.0"
5
5
 
6
6
  # Default to PyQt6 if no other Qt binding is installed
7
7
  QT_DEPENDENCY = "PyQt6>=6.0"
@@ -48,5 +48,11 @@ if __name__ == "__main__":
48
48
  version=__version__,
49
49
  packages=find_packages(),
50
50
  include_package_data=True,
51
- package_data={"": ["*.ui", "*.yaml"]},
51
+ package_data={
52
+ "": [
53
+ "*.ui",
54
+ "*.yaml",
55
+ "*.png",
56
+ ]
57
+ },
52
58
  )
@@ -1 +0,0 @@
1
- from .client import BECFigure
File without changes
File without changes
File without changes