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 +15 -11
- PKG-INFO +1 -1
- bec_widgets/cli/client_utils.py +68 -41
- bec_widgets/cli/server.py +5 -1
- bec_widgets/examples/jupyter_console/jupyter_console_window.py +6 -5
- bec_widgets/utils/bec_dispatcher.py +5 -1
- {bec_widgets-0.63.1.dist-info → bec_widgets-0.63.2.dist-info}/METADATA +1 -1
- {bec_widgets-0.63.1.dist-info → bec_widgets-0.63.2.dist-info}/RECORD +12 -12
- {bec_widgets-0.63.1.dist-info → bec_widgets-0.63.2.dist-info}/entry_points.txt +1 -0
- pyproject.toml +2 -1
- {bec_widgets-0.63.1.dist-info → bec_widgets-0.63.2.dist-info}/WHEEL +0 -0
- {bec_widgets-0.63.1.dist-info → bec_widgets-0.63.2.dist-info}/licenses/LICENSE +0 -0
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
bec_widgets/cli/client_utils.py
CHANGED
@@ -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
|
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
|
-
|
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
|
-
|
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
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
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
|
-
|
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
|
-
|
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
|
|
@@ -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=
|
5
|
+
CHANGELOG.md,sha256=giASCkqBIkuIXlmChXud4DRYYvt4CqEKj_gKmtEqsZU,7107
|
6
6
|
LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
|
7
|
-
PKG-INFO,sha256=
|
7
|
+
PKG-INFO,sha256=7MgGM-dR2iIoVEq11DTeyYgoeOXbWchJg8b3iQClLN0,1302
|
8
8
|
README.md,sha256=y4jB6wvArS7N8_iTbKWnSM_oRAqLA2GqgzUR-FMh5sU,2645
|
9
|
-
pyproject.toml,sha256=
|
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=
|
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=
|
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=
|
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=
|
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.
|
171
|
-
bec_widgets-0.63.
|
172
|
-
bec_widgets-0.63.
|
173
|
-
bec_widgets-0.63.
|
174
|
-
bec_widgets-0.63.
|
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,,
|
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.
|
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 = ["*"]
|
File without changes
|
File without changes
|