bec-widgets 0.63.1__py3-none-any.whl → 0.63.2__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.
CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
 
4
4
 
5
+ ## v0.63.2 (2024-06-14)
6
+
7
+ ### Fix
8
+
9
+ * fix: do not import "server" in client, prevents from having trouble with QApplication creation order
10
+
11
+ Like with QtWebEngine ([`6f96498`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6f96498de66358b89f3a2035627eed2e02dde5a1))
12
+
13
+ ### Unknown
14
+
15
+ * Reapply "feat: implement non-polling, interruptible waiting of gui instruction response with timeout"
16
+
17
+ This reverts commit fe04dd80e59a0e74f7fdea603e0642707ecc7c2a. ([`836b6e6`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/836b6e64f694916d6b6f909dedf11a4a6d2c86a4))
18
+
19
+
5
20
  ## v0.63.1 (2024-06-13)
6
21
 
7
22
  ### Fix
@@ -159,14 +174,3 @@ This reverts commit abc6caa2d0b6141dfbe1f3d025f78ae14deddcb3 ([`fe04dd8`](https:
159
174
 
160
175
 
161
176
  ## v0.57.7 (2024-06-07)
162
-
163
- ### Documentation
164
-
165
- * docs: added schema of BECDockArea and BECFigure ([`828067f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/828067f486a905eb4678538df58e2bdd6c770de1))
166
-
167
- ### Fix
168
-
169
- * fix: add model_config to pydantic models to allow runtime checks after creation ([`ca5e8d2`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ca5e8d2fbbffbf221cc5472710fef81a33ee29d6))
170
-
171
-
172
- ## v0.57.6 (2024-06-06)
PKG-INFO CHANGED
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bec_widgets
3
- Version: 0.63.1
3
+ Version: 0.63.2
4
4
  Summary: BEC Widgets
5
5
  Project-URL: Bug Tracker, https://gitlab.psi.ch/bec/bec_widgets/issues
6
6
  Project-URL: Homepage, https://gitlab.psi.ch/bec/bec_widgets
@@ -14,7 +14,7 @@ from typing import TYPE_CHECKING
14
14
 
15
15
  from bec_lib.endpoints import MessageEndpoints
16
16
  from bec_lib.utils.import_utils import isinstance_based_on_class_name, lazy_import, lazy_import_from
17
- from qtpy.QtCore import QCoreApplication
17
+ from qtpy.QtCore import QEventLoop, QSocketNotifier, QTimer
18
18
 
19
19
  import bec_widgets.cli.client as client
20
20
  from bec_widgets.cli.auto_updates import AutoUpdates
@@ -24,6 +24,8 @@ if TYPE_CHECKING:
24
24
 
25
25
  from bec_widgets.cli.client import BECDockArea, BECFigure
26
26
 
27
+ from bec_lib.serialization import MsgpackSerialization
28
+
27
29
  messages = lazy_import("bec_lib.messages")
28
30
  # from bec_lib.connector import MessageObject
29
31
  MessageObject = lazy_import_from("bec_lib.connector", ("MessageObject",))
@@ -84,13 +86,8 @@ def _start_plot_process(gui_id, gui_class, config) -> None:
84
86
  Start the plot in a new process.
85
87
  """
86
88
  # pylint: disable=subprocess-run-check
87
- monitor_module = importlib.import_module("bec_widgets.cli.server")
88
- monitor_path = monitor_module.__file__
89
-
90
89
  command = [
91
- sys.executable,
92
- "-u",
93
- monitor_path,
90
+ "bec-gui-server",
94
91
  "--id",
95
92
  gui_id,
96
93
  "--config",
@@ -98,7 +95,11 @@ def _start_plot_process(gui_id, gui_class, config) -> None:
98
95
  "--gui_class",
99
96
  gui_class.__name__,
100
97
  ]
101
- process = subprocess.Popen(command, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
98
+ env_dict = os.environ.copy()
99
+ env_dict["PYTHONUNBUFFERED"] = "1"
100
+ process = subprocess.Popen(
101
+ command, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env_dict
102
+ )
102
103
  process_output_processing_thread = threading.Thread(target=_get_output, args=(process,))
103
104
  process_output_processing_thread.start()
104
105
  return process, process_output_processing_thread
@@ -200,6 +201,48 @@ class RPCResponseTimeoutError(Exception):
200
201
  )
201
202
 
202
203
 
204
+ class QtRedisMessageWaiter:
205
+ def __init__(self, redis_connector, message_to_wait):
206
+ self.ev_loop = QEventLoop()
207
+ self.response = None
208
+ self.connector = redis_connector
209
+ self.message_to_wait = message_to_wait
210
+ self.pubsub = redis_connector._redis_conn.pubsub()
211
+ self.pubsub.subscribe(self.message_to_wait.endpoint)
212
+ fd = self.pubsub.connection._sock.fileno()
213
+ self.notifier = QSocketNotifier(fd, QSocketNotifier.Read)
214
+ self.notifier.activated.connect(self._pubsub_readable)
215
+
216
+ def _msg_received(self, msg_obj):
217
+ self.response = msg_obj.value
218
+ self.ev_loop.quit()
219
+
220
+ def wait(self, timeout=1):
221
+ timer = QTimer()
222
+ timer.singleShot(timeout * 1000, self.ev_loop.quit)
223
+ self.ev_loop.exec_()
224
+ timer.stop()
225
+ self.notifier.setEnabled(False)
226
+ self.pubsub.close()
227
+ return self.response
228
+
229
+ def _pubsub_readable(self, fd):
230
+ while True:
231
+ msg = self.pubsub.get_message()
232
+ if msg:
233
+ if msg["type"] == "subscribe":
234
+ # get_message buffers, so we may already have the answer
235
+ # let's check...
236
+ continue
237
+ else:
238
+ break
239
+ else:
240
+ return
241
+ channel = msg["channel"].decode()
242
+ msg = MessageObject(topic=channel, value=MsgpackSerialization.loads(msg["data"]))
243
+ self.connector._execute_callback(self._msg_received, msg, {})
244
+
245
+
203
246
  class RPCBase:
204
247
  def __init__(self, gui_id: str = None, config: dict = None, parent=None) -> None:
205
248
  self._client = BECDispatcher().client
@@ -226,7 +269,7 @@ class RPCBase:
226
269
  parent = parent._parent
227
270
  return parent
228
271
 
229
- def _run_rpc(self, method, *args, wait_for_rpc_response=True, **kwargs):
272
+ def _run_rpc(self, method, *args, wait_for_rpc_response=True, timeout=3, **kwargs):
230
273
  """
231
274
  Run the RPC call.
232
275
 
@@ -248,16 +291,24 @@ class RPCBase:
248
291
 
249
292
  # pylint: disable=protected-access
250
293
  receiver = self._root._gui_id
294
+ if wait_for_rpc_response:
295
+ redis_msg = QtRedisMessageWaiter(
296
+ self._client.connector, MessageEndpoints.gui_instruction_response(request_id)
297
+ )
298
+
251
299
  self._client.connector.set_and_publish(MessageEndpoints.gui_instructions(receiver), rpc_msg)
252
300
 
253
- if not wait_for_rpc_response:
254
- return None
255
- response = self._wait_for_response(request_id)
256
- # get class name
257
- if not response.content["accepted"]:
258
- raise ValueError(response.content["message"]["error"])
259
- msg_result = response.content["message"].get("result")
260
- return self._create_widget_from_msg_result(msg_result)
301
+ if wait_for_rpc_response:
302
+ response = redis_msg.wait(timeout)
303
+
304
+ if response is None:
305
+ raise RPCResponseTimeoutError(request_id, timeout)
306
+
307
+ # get class name
308
+ if not response.accepted:
309
+ raise ValueError(response.message["error"])
310
+ msg_result = response.message.get("result")
311
+ return self._create_widget_from_msg_result(msg_result)
261
312
 
262
313
  def _create_widget_from_msg_result(self, msg_result):
263
314
  if msg_result is None:
@@ -280,30 +331,6 @@ class RPCBase:
280
331
  return cls(parent=self, **msg_result)
281
332
  return msg_result
282
333
 
283
- def _wait_for_response(self, request_id: str, timeout: int = 5):
284
- """
285
- Wait for the response from the server.
286
-
287
- Args:
288
- request_id(str): The request ID.
289
- timeout(int): The timeout in seconds.
290
-
291
- Returns:
292
- The response from the server.
293
- """
294
- start_time = time.time()
295
- response = None
296
-
297
- while response is None and self.gui_is_alive() and (time.time() - start_time) < timeout:
298
- response = self._client.connector.get(
299
- MessageEndpoints.gui_instruction_response(request_id)
300
- )
301
- QCoreApplication.processEvents() # keep UI responsive (and execute signals/slots)
302
- if response is None and (time.time() - start_time) >= timeout:
303
- raise RPCResponseTimeoutError(request_id, timeout)
304
-
305
- return response
306
-
307
334
  def gui_is_alive(self):
308
335
  """
309
336
  Check if the GUI is alive.
bec_widgets/cli/server.py CHANGED
@@ -114,7 +114,7 @@ class BECWidgetsCLIServer:
114
114
  self.client.shutdown()
115
115
 
116
116
 
117
- if __name__ == "__main__": # pragma: no cover
117
+ def main():
118
118
  import argparse
119
119
  import os
120
120
  import sys
@@ -166,3 +166,7 @@ if __name__ == "__main__": # pragma: no cover
166
166
 
167
167
  app.aboutToQuit.connect(server.shutdown)
168
168
  sys.exit(app.exec())
169
+
170
+
171
+ if __name__ == "__main__": # pragma: no cover
172
+ main()
@@ -136,17 +136,18 @@ if __name__ == "__main__": # pragma: no cover
136
136
 
137
137
  module_path = os.path.dirname(bec_widgets.__file__)
138
138
 
139
- bec_dispatcher = BECDispatcher()
140
- client = bec_dispatcher.client
141
- client.start()
142
-
143
139
  app = QApplication(sys.argv)
144
140
  app.setApplicationName("Jupyter Console")
145
141
  app.setApplicationDisplayName("Jupyter Console")
146
- # qdarktheme.setup_theme("auto")
142
+ qdarktheme.setup_theme("auto")
147
143
  icon = QIcon()
148
144
  icon.addFile(os.path.join(module_path, "assets", "terminal_icon.png"), size=QSize(48, 48))
149
145
  app.setWindowIcon(icon)
146
+
147
+ bec_dispatcher = BECDispatcher()
148
+ client = bec_dispatcher.client
149
+ client.start()
150
+
150
151
  win = JupyterConsoleWindow()
151
152
  win.show()
152
153
 
@@ -9,7 +9,7 @@ import redis
9
9
  from bec_lib.client import BECClient
10
10
  from bec_lib.redis_connector import MessageObject, RedisConnector
11
11
  from bec_lib.service_config import ServiceConfig
12
- from qtpy.QtCore import QObject
12
+ from qtpy.QtCore import QCoreApplication, QObject
13
13
  from qtpy.QtCore import Signal as pyqtSignal
14
14
 
15
15
  if TYPE_CHECKING:
@@ -71,6 +71,7 @@ class BECDispatcher:
71
71
 
72
72
  _instance = None
73
73
  _initialized = False
74
+ qapp = None
74
75
 
75
76
  def __new__(cls, client=None, config: str = None, *args, **kwargs):
76
77
  if cls._instance is None:
@@ -82,6 +83,9 @@ class BECDispatcher:
82
83
  if self._initialized:
83
84
  return
84
85
 
86
+ if not QCoreApplication.instance():
87
+ BECDispatcher.qapp = QCoreApplication([])
88
+
85
89
  self._slots = collections.defaultdict(set)
86
90
  self.client = client
87
91
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bec_widgets
3
- Version: 0.63.1
3
+ Version: 0.63.2
4
4
  Summary: BEC Widgets
5
5
  Project-URL: Bug Tracker, https://gitlab.psi.ch/bec/bec_widgets/issues
6
6
  Project-URL: Homepage, https://gitlab.psi.ch/bec/bec_widgets
@@ -2,11 +2,11 @@
2
2
  .gitlab-ci.yml,sha256=3PU2LONUl10zIOD4UCPQgA6vVBtniabww1MQkTMce7I,7995
3
3
  .pylintrc,sha256=OstrgmEyP0smNFBKoIN5_26-UmNZgMHnbjvAWX0UrLs,18535
4
4
  .readthedocs.yaml,sha256=aSOc277LqXcsTI6lgvm_JY80lMlr69GbPKgivua2cS0,603
5
- CHANGELOG.md,sha256=2guAV_VW9TfxaJIOGzjUg0l968nM8kwFLtXNUkop-jY,6936
5
+ CHANGELOG.md,sha256=giASCkqBIkuIXlmChXud4DRYYvt4CqEKj_gKmtEqsZU,7107
6
6
  LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
7
- PKG-INFO,sha256=MNvEiOQ0tVlzDg9MrZ4Jq1HjSIb0l2Lg14-2kN9IgqQ,1302
7
+ PKG-INFO,sha256=7MgGM-dR2iIoVEq11DTeyYgoeOXbWchJg8b3iQClLN0,1302
8
8
  README.md,sha256=y4jB6wvArS7N8_iTbKWnSM_oRAqLA2GqgzUR-FMh5sU,2645
9
- pyproject.toml,sha256=oJZwUnqVMwN3MDK_gvSWFIVyGvKEidp-NyAgJwB_LUQ,2115
9
+ pyproject.toml,sha256=da8TkNzJjBLBfnpIEXECsteZlMVT8pIMtmDwdVz75G8,2162
10
10
  .git_hooks/pre-commit,sha256=n3RofIZHJl8zfJJIUomcMyYGFi_rwq4CC19z0snz3FI,286
11
11
  .gitlab/issue_templates/bug_report_template.md,sha256=gAuyEwl7XlnebBrkiJ9AqffSNOywmr8vygUFWKTuQeI,386
12
12
  .gitlab/issue_templates/documentation_update_template.md,sha256=FHLdb3TS_D9aL4CYZCjyXSulbaW5mrN2CmwTaeLPbNw,860
@@ -18,21 +18,21 @@ bec_widgets/assets/terminal_icon.png,sha256=bJl7Tft4Fi2uxvuXI8o14uMHnI9eAWKSU2uf
18
18
  bec_widgets/cli/__init__.py,sha256=d0Q6Fn44e7wFfLabDOBxpcJ1DPKWlFunGYDUBmO-4hA,22
19
19
  bec_widgets/cli/auto_updates.py,sha256=DyBV3HnjMSH-cvVkYNcDiYKVf0Xut4Qy2qGQqkW47Bw,4833
20
20
  bec_widgets/cli/client.py,sha256=PkKPeR4KJjJP-DOPTq3yYJIuWlwXLHjTyZunCYSsU1I,55332
21
- bec_widgets/cli/client_utils.py,sha256=tGfe3OKCDxgPHWKbJsM8myHooDwKNa-e5bjqGrtwwLg,10464
21
+ bec_widgets/cli/client_utils.py,sha256=ttEE3iyMpK-yEbIAJsI8rXGVn27UT4GYzyrAEZIqFks,11400
22
22
  bec_widgets/cli/generate_cli.py,sha256=DIaGz7nhwef3ebIaP4LtiUC3q7MoM1swJ_e0SgAO2jo,6901
23
23
  bec_widgets/cli/rpc_register.py,sha256=QxXUZu5XNg00Yf5O3UHWOXg3-f_pzKjjoZYMOa-MOJc,2216
24
24
  bec_widgets/cli/rpc_wigdet_handler.py,sha256=1oE2TSbwQdfLEaZiscyDX2eExHsenp2BF5Lwy8PE6LA,1118
25
- bec_widgets/cli/server.py,sha256=rsj31Vsx6ayThNe4PQelQFahGjYXFZjfrNyB2fnm6Ro,5737
25
+ bec_widgets/cli/server.py,sha256=1iHDbYxNcsUz-HxFEJ2aM1z4sut-quaftyp4EFeGLkw,5762
26
26
  bec_widgets/examples/__init__.py,sha256=WWQ0cu7m8sA4Ehy-DWdTIqSISjaHsbxhsNmNrMnhDZU,202
27
27
  bec_widgets/examples/jupyter_console/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- bec_widgets/examples/jupyter_console/jupyter_console_window.py,sha256=lViKNC3TOh6_-SztcKaRnYkf-V_EQ9T1cuyORskVX6c,5339
28
+ bec_widgets/examples/jupyter_console/jupyter_console_window.py,sha256=AKIlwcOMBJ8UAIBEhPipc9lDwA25UmmBDEYAfC0L7kU,5338
29
29
  bec_widgets/examples/jupyter_console/jupyter_console_window.ui,sha256=2A2mNTUMZBYygz8K4qWzrcjnNqZBMVyeHm26iLZVRWI,1473
30
30
  bec_widgets/examples/motor_movement/__init__.py,sha256=LzPJkxLAxOsZCbXR-fRCPmeYobp7Yqds6tDxW4W1gSw,214
31
31
  bec_widgets/examples/motor_movement/motor_control_compilations.py,sha256=8rpA7a2xVZTDMrx7YQIj3IJew78J1gcVMkHvloS0U_Q,9055
32
32
  bec_widgets/examples/motor_movement/motor_controller.ui,sha256=83XX6NGILwntoUIghvzWnMuGf80O8khK3SduVKTAEFM,29105
33
33
  bec_widgets/utils/__init__.py,sha256=B7OZ2ArjyFaGNh4XYIbk49agnYCz704ltuFSalLCjSA,481
34
34
  bec_widgets/utils/bec_connector.py,sha256=RxHJNF7JjtY5pRbTMu2eQTiRXvoyJ53QuTYxHjZba38,5357
35
- bec_widgets/utils/bec_dispatcher.py,sha256=nLdcj2u4dy8-ZR03XioCzr7hBg9Wq4Kw58OU6sDorT4,5593
35
+ bec_widgets/utils/bec_dispatcher.py,sha256=3zzf7LXCWtxiroUuSdObGexuYfRoq0QY1i3hJ7GmbBE,5726
36
36
  bec_widgets/utils/bec_table.py,sha256=nA2b8ukSeUfquFMAxGrUVOqdrzMoDYD6O_4EYbOG2zk,717
37
37
  bec_widgets/utils/colors.py,sha256=GYSDe0ZxsJSwxvuy-yG2BH17qlf_Sjq8dhDcyp9IhBI,8532
38
38
  bec_widgets/utils/container_utils.py,sha256=m3VUyAYmSWkEwApP9tBvKxPYVtc2kHw4toxIpMryJy4,1495
@@ -167,8 +167,8 @@ tests/unit_tests/test_configs/config_device_no_entry.yaml,sha256=hdvue9KLc_kfNzG
167
167
  tests/unit_tests/test_configs/config_scan.yaml,sha256=vo484BbWOjA_e-h6bTjSV9k7QaQHrlAvx-z8wtY-P4E,1915
168
168
  tests/unit_tests/test_msgs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
169
169
  tests/unit_tests/test_msgs/available_scans_message.py,sha256=m_z97hIrjHXXMa2Ex-UvsPmTxOYXfjxyJaGkIY6StTY,46532
170
- bec_widgets-0.63.1.dist-info/METADATA,sha256=MNvEiOQ0tVlzDg9MrZ4Jq1HjSIb0l2Lg14-2kN9IgqQ,1302
171
- bec_widgets-0.63.1.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
172
- bec_widgets-0.63.1.dist-info/entry_points.txt,sha256=80s2YKCNziN2ROUYbpDRyEmiejMf_dshmiYCdN7qNsU,70
173
- bec_widgets-0.63.1.dist-info/licenses/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
174
- bec_widgets-0.63.1.dist-info/RECORD,,
170
+ bec_widgets-0.63.2.dist-info/METADATA,sha256=7MgGM-dR2iIoVEq11DTeyYgoeOXbWchJg8b3iQClLN0,1302
171
+ bec_widgets-0.63.2.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
172
+ bec_widgets-0.63.2.dist-info/entry_points.txt,sha256=OvoqiNzNF9bizFQNhbAmmdc_njHrnVewLE-Kl-u9sh0,115
173
+ bec_widgets-0.63.2.dist-info/licenses/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
174
+ bec_widgets-0.63.2.dist-info/RECORD,,
@@ -1,2 +1,3 @@
1
1
  [console_scripts]
2
+ bec-gui-server = bec_widgets.cli.server:main
2
3
  bw-generate-cli = bec_widgets.cli.generate_cli:main
pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "bec_widgets"
7
- version = "0.63.1"
7
+ version = "0.63.2"
8
8
  description = "BEC Widgets"
9
9
  requires-python = ">=3.10"
10
10
  classifiers = [
@@ -48,6 +48,7 @@ Homepage = "https://gitlab.psi.ch/bec/bec_widgets"
48
48
 
49
49
  [project.scripts]
50
50
  bw-generate-cli = "bec_widgets.cli.generate_cli:main"
51
+ bec-gui-server = "bec_widgets.cli.server:main"
51
52
 
52
53
  [tool.hatch.build.targets.wheel]
53
54
  include = ["*"]