bec-widgets 0.68.0__py3-none-any.whl → 0.69.0__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
@@ -1,5 +1,15 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v0.69.0 (2024-06-21)
4
+
5
+ ### Feature
6
+
7
+ * feat(widgets): added vscode widget ([`48ae950`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/48ae950d57b454307ce409e2511f7b7adf3cfc6b))
8
+
9
+ ### Fix
10
+
11
+ * fix(generate_cli): fixed rpc generate for classes without user access; closes #226 ([`925c893`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/925c893f3ff4337fc8b4d237c8ffc19a597b0996))
12
+
3
13
  ## v0.68.0 (2024-06-21)
4
14
 
5
15
  ### Feature
@@ -166,15 +176,3 @@ on SIGTERM ([`9263f8e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/9263f8ef5
166
176
  ### Test
167
177
 
168
178
  * test: add test for text box ([`b49462a`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/b49462abeb186e56bac79d2ef0b0add1ef28a1a5))
169
-
170
- ### Unknown
171
-
172
- * Revert "feat: implement non-polling, interruptible waiting of gui instruction response with timeout"
173
-
174
- This reverts commit abc6caa2d0b6141dfbe1f3d025f78ae14deddcb3 ([`fe04dd8`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/fe04dd80e59a0e74f7fdea603e0642707ecc7c2a))
175
-
176
- ## v0.62.0 (2024-06-12)
177
-
178
- ### Unknown
179
-
180
- * doc: add documentation about creating custom GUI applications embedding BEC Widgets ([`17a0068`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/17a00687579f5efab1990cd83862ec0e78198633))
PKG-INFO CHANGED
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bec_widgets
3
- Version: 0.68.0
3
+ Version: 0.69.0
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
bec_widgets/cli/client.py CHANGED
@@ -19,6 +19,7 @@ class Widgets(str, enum.Enum):
19
19
  BECFigure = "BECFigure"
20
20
  SpiralProgressBar = "SpiralProgressBar"
21
21
  TextBox = "TextBox"
22
+ VSCodeEditor = "VSCodeEditor"
22
23
  WebsiteWidget = "WebsiteWidget"
23
24
 
24
25
 
@@ -2049,6 +2050,9 @@ class TextBox(RPCBase):
2049
2050
  """
2050
2051
 
2051
2052
 
2053
+ class VSCodeEditor(RPCBase): ...
2054
+
2055
+
2052
2056
  class WebsiteWidget(RPCBase):
2053
2057
  @rpc_call
2054
2058
  def set_url(self, url: str) -> None:
@@ -83,6 +83,9 @@ class {class_name}(RPCBase, BECGuiClientMixin):"""
83
83
  else:
84
84
  self.content += f"""
85
85
  class {class_name}(RPCBase):"""
86
+ if not cls.USER_ACCESS:
87
+ self.content += """...
88
+ """
86
89
  for method in cls.USER_ACCESS:
87
90
  obj = getattr(cls, method)
88
91
  if isinstance(obj, property):
File without changes
@@ -0,0 +1,86 @@
1
+ import os
2
+ import select
3
+ import shlex
4
+ import signal
5
+ import subprocess
6
+ import sys
7
+
8
+ from bec_widgets.widgets.website.website import WebsiteWidget
9
+
10
+
11
+ class VSCodeEditor(WebsiteWidget):
12
+ """
13
+ A widget to display the VSCode editor.
14
+ """
15
+
16
+ token = "bec"
17
+ host = "127.0.0.1"
18
+ port = 7000
19
+
20
+ USER_ACCESS = []
21
+
22
+ def __init__(self, parent=None, config=None, client=None, gui_id=None):
23
+
24
+ self.process = None
25
+ self._url = f"http://{self.host}:{self.port}?tkn={self.token}"
26
+ super().__init__(parent=parent, config=config, client=client, gui_id=gui_id)
27
+ self.start_server()
28
+
29
+ def start_server(self):
30
+ """
31
+ Start the server.
32
+
33
+ This method starts the server for the VSCode editor in a subprocess.
34
+ """
35
+
36
+ cmd = shlex.split(
37
+ f"code serve-web --port {self.port} --connection-token={self.token} --accept-server-license-terms"
38
+ )
39
+ self.process = subprocess.Popen(
40
+ cmd, text=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, preexec_fn=os.setsid
41
+ )
42
+
43
+ os.set_blocking(self.process.stdout.fileno(), False)
44
+ while self.process.poll() is None:
45
+ readylist, _, _ = select.select([self.process.stdout], [], [], 1)
46
+ if self.process.stdout in readylist:
47
+ output = self.process.stdout.read(1024)
48
+ if output and f"available at {self._url}" in output:
49
+ break
50
+ self.set_url(self._url)
51
+
52
+ def closeEvent(self, event):
53
+ """
54
+ Hook for the close event to terminate the server.
55
+ """
56
+ self.cleanup_vscode()
57
+ super().closeEvent(event)
58
+
59
+ def cleanup_vscode(self):
60
+ """
61
+ Cleanup the VSCode editor.
62
+ """
63
+ if not self.process:
64
+ return
65
+ os.killpg(os.getpgid(self.process.pid), signal.SIGTERM)
66
+ self.process.wait()
67
+
68
+ def cleanup(self):
69
+ """
70
+ Cleanup the widget. This method is called from the dock area when the widget is removed.
71
+ """
72
+ self.cleanup_vscode()
73
+ return super().cleanup()
74
+
75
+
76
+ if __name__ == "__main__": # pragma: no cover
77
+ import sys
78
+
79
+ from qtpy.QtWidgets import QApplication
80
+
81
+ app = QApplication(sys.argv)
82
+ widget = VSCodeEditor()
83
+ widget.show()
84
+ app.exec_()
85
+ widget.bec_dispatcher.disconnect_all()
86
+ widget.client.shutdown()
@@ -1,10 +1,19 @@
1
- from qtpy.QtCore import QUrl
1
+ from qtpy.QtCore import QUrl, qInstallMessageHandler
2
2
  from qtpy.QtWebEngineWidgets import QWebEngineView
3
3
  from qtpy.QtWidgets import QApplication
4
4
 
5
5
  from bec_widgets.utils import BECConnector
6
6
 
7
7
 
8
+ def suppress_qt_messages(type_, context, msg):
9
+ if context.category in ["js", "default"]:
10
+ return
11
+ print(msg)
12
+
13
+
14
+ qInstallMessageHandler(suppress_qt_messages)
15
+
16
+
8
17
  class WebsiteWidget(BECConnector, QWebEngineView):
9
18
  """
10
19
  A simple widget to display a website
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bec_widgets
3
- Version: 0.68.0
3
+ Version: 0.69.0
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=RnYDz4zKXjlqltTryprlB1s5vLXxI2-seW-Vb70NNF0,8162
3
3
  .pylintrc,sha256=OstrgmEyP0smNFBKoIN5_26-UmNZgMHnbjvAWX0UrLs,18535
4
4
  .readthedocs.yaml,sha256=aSOc277LqXcsTI6lgvm_JY80lMlr69GbPKgivua2cS0,603
5
- CHANGELOG.md,sha256=EhWy5RDQRny8SHputsNnGM7Hy1HOZoSmZ6cJB2Gw8Cw,7198
5
+ CHANGELOG.md,sha256=48HpbXwe-Y_t9YJAntu3fJ8MU4DN6bSWSJWj-1bJAEY,7057
6
6
  LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
7
- PKG-INFO,sha256=I5LEt7gWZyuBZpnkwiIXlKyxz5sQOmtI-RAIDZjzD9s,1302
7
+ PKG-INFO,sha256=GEZve_LqjICZHq1bEuZ7S1woFWxfQSVUsGmIVgudNYE,1302
8
8
  README.md,sha256=y4jB6wvArS7N8_iTbKWnSM_oRAqLA2GqgzUR-FMh5sU,2645
9
- pyproject.toml,sha256=wCSTnyvyFrQnQiDgC5Pn18_zeLOguN86bLfJVSIboz8,2162
9
+ pyproject.toml,sha256=Td8223p7vyZ4AVOTaqH50fwtAgfFtSIRq-QYp625MOA,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
@@ -17,9 +17,9 @@ bec_widgets/assets/bec_widgets_icon.png,sha256=K8dgGwIjalDh9PRHUsSQBqgdX7a00nM3i
17
17
  bec_widgets/assets/terminal_icon.png,sha256=bJl7Tft4Fi2uxvuXI8o14uMHnI9eAWKSU2uftXCH9ws,3889
18
18
  bec_widgets/cli/__init__.py,sha256=d0Q6Fn44e7wFfLabDOBxpcJ1DPKWlFunGYDUBmO-4hA,22
19
19
  bec_widgets/cli/auto_updates.py,sha256=DyBV3HnjMSH-cvVkYNcDiYKVf0Xut4Qy2qGQqkW47Bw,4833
20
- bec_widgets/cli/client.py,sha256=Zd4oMSE5-HY3IBUIVcparGGV2Ew86gaWAFTd4OjFVmg,58005
20
+ bec_widgets/cli/client.py,sha256=DNsCueEdVwW0MWjBIIg-vhTu_p64qr0QurT7mHM79is,58074
21
21
  bec_widgets/cli/client_utils.py,sha256=_Hb2nl1rKEf7k4By9VZDYl5YyGFczxMuYIFMVrOAZD0,12182
22
- bec_widgets/cli/generate_cli.py,sha256=Bi8HxHhge1I87vbdYHZUZiZwvbB-OSkLYS5Xfmwiz9M,4922
22
+ bec_widgets/cli/generate_cli.py,sha256=InKBVYM7DRfAVLNJhRJbWWSSPBQBHI8Ek6v7NCsK0ME,4997
23
23
  bec_widgets/cli/rpc_register.py,sha256=QxXUZu5XNg00Yf5O3UHWOXg3-f_pzKjjoZYMOa-MOJc,2216
24
24
  bec_widgets/cli/rpc_wigdet_handler.py,sha256=1qQOGrM8rozaWLkoxAW8DTVLv_L_DZdZgUMDPy5MOek,1486
25
25
  bec_widgets/cli/server.py,sha256=3bFBPmtXKXFMjeja18d0hF3CO66Jo0-LEDtcF7lYb7k,7166
@@ -100,8 +100,10 @@ bec_widgets/widgets/text_box/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
100
100
  bec_widgets/widgets/text_box/text_box.py,sha256=kykQ_Zcxh8IGcPEP5-oGGQwoZEpY9vhxRIM8TY8kTYg,4240
101
101
  bec_widgets/widgets/toolbar/__init__.py,sha256=d-TP4_cr_VbpwreMM4ePnfZ5YXsEPQ45ibEf75nuGoE,36
102
102
  bec_widgets/widgets/toolbar/toolbar.py,sha256=e0zCD_0q7K4NVhrzD8001Qvfxt-VhqHTgofchS9NgCM,5125
103
+ bec_widgets/widgets/vscode/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
104
+ bec_widgets/widgets/vscode/vscode.py,sha256=k4Y54zp9jGfeUKsFc482TnUJQd3pj-jdIb3i_dLiWUA,2376
103
105
  bec_widgets/widgets/website/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
104
- bec_widgets/widgets/website/website.py,sha256=C679bpGUoSqfLtu4_BcEQEmesNj_L9HaTu0buJzb4c0,1526
106
+ bec_widgets/widgets/website/website.py,sha256=Scvpl4I52qpL7s69tnNBRQSG6GcRI9jzoR3RsSTXfPE,1722
105
107
  docs/Makefile,sha256=i2WHuFlgfyAPEW4ssEP8NY4cOibDJrVjvzSEU8_Ggwc,634
106
108
  docs/conf.py,sha256=HxLxupNGu0Smhwn57g1kFdjZzFuaWVREgRJKhT1zi2k,2464
107
109
  docs/index.md,sha256=8ZCgaLIbJsYvt-jwi--QxsNwnK4-k3rejIeOOLclG40,1101
@@ -177,6 +179,7 @@ tests/unit_tests/test_scan_control.py,sha256=Xf8bGt8lRJobRwBoqUdVXxsHno8ejvC77Fq
177
179
  tests/unit_tests/test_spiral_progress_bar.py,sha256=n5aLSZ2B6K5a1vQuKTERnCSmIz9hYGFyk7jP3TU0AwQ,12438
178
180
  tests/unit_tests/test_stop_button.py,sha256=2OH9dhs_-S5QovPPgU-5hJoViE1YKZa0gxisb4vOY28,712
179
181
  tests/unit_tests/test_text_box_widget.py,sha256=cT0uEHt_6d-FwST0A_wE9sFW9E3F_nJbKhuBAeU4yHg,1862
182
+ tests/unit_tests/test_vscode_widget.py,sha256=sCVNAuWVMiPFinh9mDqz_ulBay_H3qwHyEwkHsbWh4c,2173
180
183
  tests/unit_tests/test_waveform1d.py,sha256=I3_pF0ieltcTWtweOBjICaOxJ8NCQ0-NWxpKg8Pas3E,15893
181
184
  tests/unit_tests/test_website_widget.py,sha256=fBADIJJBAHU4Ro7u95kdemFVNv196UOcuO9oLHuHt8A,761
182
185
  tests/unit_tests/test_widget_io.py,sha256=FeL3ZYSBQnRt6jxj8VGYw1cmcicRQyHKleahw7XIyR0,3475
@@ -186,8 +189,8 @@ tests/unit_tests/test_configs/config_device_no_entry.yaml,sha256=hdvue9KLc_kfNzG
186
189
  tests/unit_tests/test_configs/config_scan.yaml,sha256=vo484BbWOjA_e-h6bTjSV9k7QaQHrlAvx-z8wtY-P4E,1915
187
190
  tests/unit_tests/test_msgs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
188
191
  tests/unit_tests/test_msgs/available_scans_message.py,sha256=m_z97hIrjHXXMa2Ex-UvsPmTxOYXfjxyJaGkIY6StTY,46532
189
- bec_widgets-0.68.0.dist-info/METADATA,sha256=I5LEt7gWZyuBZpnkwiIXlKyxz5sQOmtI-RAIDZjzD9s,1302
190
- bec_widgets-0.68.0.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
191
- bec_widgets-0.68.0.dist-info/entry_points.txt,sha256=OvoqiNzNF9bizFQNhbAmmdc_njHrnVewLE-Kl-u9sh0,115
192
- bec_widgets-0.68.0.dist-info/licenses/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
193
- bec_widgets-0.68.0.dist-info/RECORD,,
192
+ bec_widgets-0.69.0.dist-info/METADATA,sha256=GEZve_LqjICZHq1bEuZ7S1woFWxfQSVUsGmIVgudNYE,1302
193
+ bec_widgets-0.69.0.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
194
+ bec_widgets-0.69.0.dist-info/entry_points.txt,sha256=OvoqiNzNF9bizFQNhbAmmdc_njHrnVewLE-Kl-u9sh0,115
195
+ bec_widgets-0.69.0.dist-info/licenses/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
196
+ bec_widgets-0.69.0.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.68.0"
7
+ version = "0.69.0"
8
8
  description = "BEC Widgets"
9
9
  requires-python = ">=3.10"
10
10
  classifiers = [
@@ -0,0 +1,61 @@
1
+ import os
2
+ import shlex
3
+ import subprocess
4
+ from unittest import mock
5
+
6
+ import pytest
7
+
8
+ from bec_widgets.widgets.vscode.vscode import VSCodeEditor
9
+
10
+ from .client_mocks import mocked_client
11
+
12
+
13
+ @pytest.fixture
14
+ def vscode_widget(qtbot, mocked_client):
15
+ with mock.patch("bec_widgets.widgets.vscode.vscode.subprocess.Popen") as mock_popen:
16
+ widget = VSCodeEditor(client=mocked_client)
17
+ yield widget
18
+
19
+
20
+ def test_vscode_widget(qtbot, vscode_widget):
21
+ assert vscode_widget.process is not None
22
+ assert vscode_widget._url == "http://127.0.0.1:7000?tkn=bec"
23
+
24
+
25
+ def test_start_server(qtbot, mocked_client):
26
+
27
+ with mock.patch("bec_widgets.widgets.vscode.vscode.subprocess.Popen") as mock_popen:
28
+ mock_process = mock.Mock()
29
+ mock_process.stdout.fileno.return_value = 1
30
+ mock_process.poll.return_value = None
31
+ mock_process.stdout.read.return_value = (
32
+ f"available at http://{VSCodeEditor.host}:{VSCodeEditor.port}?tkn={VSCodeEditor.token}"
33
+ )
34
+ mock_popen.return_value = mock_process
35
+
36
+ widget = VSCodeEditor(client=mocked_client)
37
+
38
+ mock_popen.assert_called_once_with(
39
+ shlex.split(
40
+ f"code serve-web --port {widget.port} --connection-token={widget.token} --accept-server-license-terms"
41
+ ),
42
+ text=True,
43
+ stdout=subprocess.PIPE,
44
+ stderr=subprocess.DEVNULL,
45
+ preexec_fn=os.setsid,
46
+ )
47
+
48
+
49
+ def test_close_event(qtbot, vscode_widget):
50
+ with mock.patch("bec_widgets.widgets.vscode.vscode.os.killpg") as mock_killpg:
51
+ with mock.patch("bec_widgets.widgets.vscode.vscode.os.getpgid") as mock_getpgid:
52
+ with mock.patch(
53
+ "bec_widgets.widgets.website.website.WebsiteWidget.closeEvent"
54
+ ) as mock_close_event:
55
+ mock_getpgid.return_value = 123
56
+ vscode_widget.process = mock.Mock()
57
+ vscode_widget.process.pid = 123
58
+ vscode_widget.closeEvent(None)
59
+ mock_killpg.assert_called_once_with(123, 15)
60
+ vscode_widget.process.wait.assert_called_once()
61
+ mock_close_event.assert_called_once()