bec-widgets 0.74.1__py3-none-any.whl → 0.76.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,29 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v0.76.0 (2024-06-28)
4
+
5
+ ### Feature
6
+
7
+ * feat(designer): added support for creating designer plugins automatically ([`c1dd0ee`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/c1dd0ee1906dba1f2e2ae9ce40a84d55c26a1cce))
8
+
9
+ ### Fix
10
+
11
+ * fix: fixed qwidget inheritance for ring progress bar ([`0610d2f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/0610d2f9f027f8659e7149f2dfbb316ff30e337d))
12
+
13
+ ### Unknown
14
+
15
+ * fix:parent set as first kwarg TextBox and WebsiteWidget ([`a45c407`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/a45c4075684b93bfdcee03e5a416b84f61d3bc6f))
16
+
17
+ ## v0.75.0 (2024-06-26)
18
+
19
+ ### Feature
20
+
21
+ * feat(widgets): added simple bec queue widget ([`3faee98`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/3faee98ec80041a27e4c1f1156178de6f9dcdc63))
22
+
23
+ ### Refactor
24
+
25
+ * refactor(dispatcher): cleanup ([`ca02132`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ca02132c8d18535b37e9192e00459d2aca6ba5cf))
26
+
3
27
  ## v0.74.1 (2024-06-26)
4
28
 
5
29
  ### Build
@@ -118,14 +142,6 @@
118
142
 
119
143
  * fix(WidgetIO): find handlers within base classes ([`ca85638`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ca856384f380dabf28d43f1cd48511af784c035b))
120
144
 
121
- * fix(scan_control): adapted widget to scan BEC gui config ([`8b822e0`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/8b822e0fa8e28f080b9a4bf81948a7280a4c07bf))
122
-
123
- * fix(scan_control): scan_control.py combatible with the newest BEC versions, test disabled ([`67d398c`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/67d398caf74e08ab25a70cc5d85a5f0c2de8212d))
124
-
125
- ### Refactor
126
-
127
- * refactor(device_line_edit): renamed default_device to default ([`4e2c9df`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/4e2c9df6a4979d935285fd7eba17fd7fd455a35c))
128
-
129
145
  ### Test
130
146
 
131
147
  * test(scan_control): tests added ([`56e74a0`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/56e74a0e7da72d18e89bc30d1896dbf9ef97cd6b))
@@ -139,15 +155,3 @@
139
155
  * fix(device_line_edit):SizePolicy fixed for 100 horizontal ([`21d20e0`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/21d20e0fc78e9a3853abe802733388cce119ce20))
140
156
 
141
157
  * tests WIP ([`c09644b`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/c09644b29ddb291c91dc58bcd6ebf02ff45cab36))
142
-
143
- ## v0.70.0 (2024-06-21)
144
-
145
- ### Feature
146
-
147
- * feat(bec-designer): automatic plugin discovery ([`4639eee`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/4639eee0b975ebd7a946e0e290449f5b88c372eb))
148
-
149
- * feat(device_line_edit): plugin added to bec-designer ([`b4b27ae`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/b4b27aea3d8c08fa3d5d5514c69dbde32721d1dc))
150
-
151
- ### Fix
152
-
153
- * fix(bec-desiger+plugins): imports fixed, PYSIDE6 check to not enable run plugins with pyqt6 ([`50b3422`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/50b3422528d46d74317e8c903b6286e868ab7fe0))
PKG-INFO CHANGED
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bec_widgets
3
- Version: 0.74.1
3
+ Version: 0.76.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
@@ -13,6 +13,7 @@ class Widgets(str, enum.Enum):
13
13
  Enum for the available widgets.
14
14
  """
15
15
 
16
+ BECQueue = "BECQueue"
16
17
  BECStatusBox = "BECStatusBox"
17
18
  BECDock = "BECDock"
18
19
  BECDockArea = "BECDockArea"
@@ -1446,6 +1447,24 @@ class BECPlotBase(RPCBase):
1446
1447
  """
1447
1448
 
1448
1449
 
1450
+ class BECQueue(RPCBase):
1451
+ @property
1452
+ @rpc_call
1453
+ def config_dict(self) -> "dict":
1454
+ """
1455
+ Get the configuration of the widget.
1456
+
1457
+ Returns:
1458
+ dict: The configuration of the widget.
1459
+ """
1460
+
1461
+ @rpc_call
1462
+ def get_all_rpc(self) -> "dict":
1463
+ """
1464
+ Get all registered RPC objects.
1465
+ """
1466
+
1467
+
1449
1468
  class BECStatusBox(RPCBase):
1450
1469
  @property
1451
1470
  @rpc_call
@@ -10,6 +10,7 @@ from typing import Literal
10
10
  import black
11
11
  import isort
12
12
 
13
+ from bec_widgets.utils.generate_designer_plugin import DesignerPluginGenerator
13
14
  from bec_widgets.utils.plugin_utils import get_rpc_classes
14
15
 
15
16
  if sys.version_info >= (3, 11):
@@ -161,6 +162,26 @@ def main():
161
162
  generator.generate_client(rpc_classes)
162
163
  generator.write(client_path)
163
164
 
165
+ for cls in rpc_classes["top_level_classes"]:
166
+ plugin = DesignerPluginGenerator(cls)
167
+ if not hasattr(plugin, "info"):
168
+ continue
169
+
170
+ # if the class directory already has a register, plugin and pyproject file, skip
171
+ if os.path.exists(
172
+ os.path.join(plugin.info.base_path, f"register_{plugin.info.plugin_name_snake}.py")
173
+ ):
174
+ continue
175
+ if os.path.exists(
176
+ os.path.join(plugin.info.base_path, f"{plugin.info.plugin_name_snake}_plugin.py")
177
+ ):
178
+ continue
179
+ if os.path.exists(
180
+ os.path.join(plugin.info.base_path, f"{plugin.info.plugin_name_snake}.pyproject")
181
+ ):
182
+ continue
183
+ plugin.run()
184
+
164
185
 
165
186
  if __name__ == "__main__": # pragma: no cover
166
187
  sys.argv = ["generate_cli.py", "--core"]
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import argparse
4
3
  import collections
5
4
  from collections.abc import Callable
6
5
  from typing import TYPE_CHECKING, Union
@@ -0,0 +1,147 @@
1
+ import inspect
2
+ import os
3
+ import re
4
+
5
+ from qtpy.QtCore import QObject
6
+
7
+ EXCLUDED_PLUGINS = ["BECConnector", "BECDockArea", "BECDock"]
8
+
9
+
10
+ class DesignerPluginInfo:
11
+ def __init__(self, plugin_class):
12
+ self.plugin_class = plugin_class
13
+ self.plugin_name_pascal = plugin_class.__name__
14
+ self.plugin_name_snake = self.pascal_to_snake(self.plugin_name_pascal)
15
+ self.widget_import = f"from {plugin_class.__module__} import {self.plugin_name_pascal}"
16
+ plugin_module = (
17
+ ".".join(plugin_class.__module__.split(".")[:-1]) + f".{self.plugin_name_snake}_plugin"
18
+ )
19
+ self.plugin_import = f"from {plugin_module} import {self.plugin_name_pascal}Plugin"
20
+
21
+ # first sentence / line of the docstring is used as tooltip
22
+ self.plugin_tooltip = (
23
+ plugin_class.__doc__.split("\n")[0].strip().replace('"', "'")
24
+ if plugin_class.__doc__
25
+ else self.plugin_name_pascal
26
+ )
27
+
28
+ self.base_path = os.path.dirname(inspect.getfile(plugin_class))
29
+
30
+ @staticmethod
31
+ def pascal_to_snake(name: str) -> str:
32
+ """
33
+ Convert PascalCase to snake_case.
34
+
35
+ Args:
36
+ name (str): The name to be converted.
37
+
38
+ Returns:
39
+ str: The converted name.
40
+ """
41
+ s1 = re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", name)
42
+ s2 = re.sub(r"([A-Z]+)([A-Z][a-z])", r"\1_\2", s1)
43
+ return s2.lower()
44
+
45
+
46
+ class DesignerPluginGenerator:
47
+ def __init__(self, widget: type):
48
+ self._excluded = False
49
+ self.widget = widget
50
+ if widget.__name__ in EXCLUDED_PLUGINS:
51
+
52
+ self._excluded = True
53
+ return
54
+
55
+ self.info = DesignerPluginInfo(widget)
56
+
57
+ self.templates = {}
58
+ self.template_path = os.path.join(
59
+ os.path.dirname(os.path.abspath(__file__)), "plugin_templates"
60
+ )
61
+
62
+ def run(self):
63
+ if self._excluded:
64
+ print(f"Plugin {self.widget.__name__} is excluded from generation.")
65
+ return
66
+ self._check_class_validity()
67
+ self._load_templates()
68
+ self._write_templates()
69
+
70
+ def _check_class_validity(self):
71
+
72
+ # Check if the widget is a QWidget subclass
73
+ if not issubclass(self.widget, QObject):
74
+ return
75
+
76
+ # Check if the widget class has parent as the first argument. This is a strict requirement of Qt!
77
+ signature = list(inspect.signature(self.widget.__init__).parameters.values())
78
+ if signature[1].name != "parent":
79
+ raise ValueError(
80
+ f"Widget class {self.widget.__name__} must have parent as the first argument."
81
+ )
82
+
83
+ base_cls = [val for val in self.widget.__bases__ if issubclass(val, QObject)]
84
+ if not base_cls:
85
+ raise ValueError(
86
+ f"Widget class {self.widget.__name__} must inherit from a QObject subclass."
87
+ )
88
+
89
+ # Check if the widget class calls the super constructor with parent argument
90
+ init_source = inspect.getsource(self.widget.__init__)
91
+ cls_init_found = (
92
+ bool(init_source.find(f"{base_cls[0].__name__}.__init__(self, parent=parent"))
93
+ or bool(init_source.find(f"{base_cls[0].__name__}.__init__(self, parent)"))
94
+ or bool(init_source.find(f"{base_cls[0].__name__}.__init__(self, parent,"))
95
+ )
96
+ super_init_found = (
97
+ bool(init_source.find(f"super({self.widget.__name__}, self).__init__(parent=parent"))
98
+ or bool(init_source.find(f"super({self.widget.__name__}, self).__init__(parent,"))
99
+ or bool(init_source.find(f"super({self.widget.__name__}, self).__init__(parent)"))
100
+ )
101
+ if issubclass(self.widget.__bases__[0], QObject) and super_init_found == -1:
102
+ super_init_found = (
103
+ bool(init_source.find("super().__init__(parent=parent"))
104
+ or bool(init_source.find("super().__init__(parent,"))
105
+ or bool(init_source.find("super().__init__(parent)"))
106
+ )
107
+
108
+ if not cls_init_found and not super_init_found:
109
+ raise ValueError(
110
+ f"Widget class {self.widget.__name__} must call the super constructor with parent."
111
+ )
112
+
113
+ def _write_templates(self):
114
+ self._write_register()
115
+ self._write_plugin()
116
+ self._write_pyproject()
117
+
118
+ def _write_register(self):
119
+ file_path = os.path.join(self.info.base_path, f"register_{self.info.plugin_name_snake}.py")
120
+ with open(file_path, "w", encoding="utf-8") as f:
121
+ f.write(self.templates["register"].format(**self.info.__dict__))
122
+
123
+ def _write_plugin(self):
124
+ file_path = os.path.join(self.info.base_path, f"{self.info.plugin_name_snake}_plugin.py")
125
+ with open(file_path, "w", encoding="utf-8") as f:
126
+ f.write(self.templates["plugin"].format(**self.info.__dict__))
127
+
128
+ def _write_pyproject(self):
129
+ file_path = os.path.join(self.info.base_path, f"{self.info.plugin_name_snake}.pyproject")
130
+ out = {"files": [f"{self.info.plugin_class.__module__.split('.')[-1]}.py"]}
131
+ with open(file_path, "w", encoding="utf-8") as f:
132
+ f.write(str(out))
133
+
134
+ def _load_templates(self):
135
+ for file in os.listdir(self.template_path):
136
+ if not file.endswith(".template"):
137
+ continue
138
+ with open(os.path.join(self.template_path, file), "r", encoding="utf-8") as f:
139
+ self.templates[file.split(".")[0]] = f.read()
140
+
141
+
142
+ if __name__ == "__main__":
143
+ # from bec_widgets.widgets.bec_queue.bec_queue import BECQueue
144
+ from bec_widgets.widgets.dock import BECDockArea
145
+
146
+ generator = DesignerPluginGenerator(BECDockArea)
147
+ generator.run()
@@ -0,0 +1,54 @@
1
+ # Copyright (C) 2022 The Qt Company Ltd.
2
+ # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
3
+
4
+ from qtpy.QtDesigner import QDesignerCustomWidgetInterface
5
+ from qtpy.QtGui import QIcon
6
+
7
+ {widget_import}
8
+
9
+ DOM_XML = """
10
+ <ui language='c++'>
11
+ <widget class='{plugin_name_pascal}' name='{plugin_name_snake}'>
12
+ </widget>
13
+ </ui>
14
+ """
15
+
16
+
17
+ class {plugin_name_pascal}Plugin(QDesignerCustomWidgetInterface): # pragma: no cover
18
+ def __init__(self):
19
+ super().__init__()
20
+ self._form_editor = None
21
+
22
+ def createWidget(self, parent):
23
+ t = {plugin_name_pascal}(parent)
24
+ return t
25
+
26
+ def domXml(self):
27
+ return DOM_XML
28
+
29
+ def group(self):
30
+ return ""
31
+
32
+ def icon(self):
33
+ return QIcon()
34
+
35
+ def includeFile(self):
36
+ return "{plugin_name_snake}"
37
+
38
+ def initialize(self, form_editor):
39
+ self._form_editor = form_editor
40
+
41
+ def isContainer(self):
42
+ return False
43
+
44
+ def isInitialized(self):
45
+ return self._form_editor is not None
46
+
47
+ def name(self):
48
+ return "{plugin_name_pascal}"
49
+
50
+ def toolTip(self):
51
+ return "{plugin_tooltip}"
52
+
53
+ def whatsThis(self):
54
+ return self.toolTip()
@@ -0,0 +1,15 @@
1
+ def main(): # pragma: no cover
2
+ from qtpy import PYSIDE6
3
+
4
+ if not PYSIDE6:
5
+ print("PYSIDE6 is not available in the environment. Cannot patch designer.")
6
+ return
7
+ from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
8
+
9
+ {plugin_import}
10
+
11
+ QPyDesignerCustomWidgetCollection.addCustomWidget({plugin_name_pascal}Plugin())
12
+
13
+
14
+ if __name__ == "__main__": # pragma: no cover
15
+ main()
File without changes
@@ -0,0 +1,111 @@
1
+ from bec_lib.endpoints import MessageEndpoints
2
+ from qtpy.QtCore import Qt, Slot
3
+ from qtpy.QtWidgets import QHeaderView, QTableWidget, QTableWidgetItem, QWidget
4
+
5
+ from bec_widgets.utils.bec_connector import BECConnector, ConnectionConfig
6
+
7
+
8
+ class BECQueue(BECConnector, QTableWidget):
9
+ """
10
+ Widget to display the BEC queue.
11
+ """
12
+
13
+ def __init__(
14
+ self,
15
+ parent: QWidget | None = None,
16
+ client=None,
17
+ config: ConnectionConfig = None,
18
+ gui_id: str = None,
19
+ ):
20
+ super().__init__(client, config, gui_id)
21
+ QTableWidget.__init__(self, parent=parent)
22
+ self.setColumnCount(3)
23
+ self.setHorizontalHeaderLabels(["Scan Number", "Type", "Status"])
24
+ header = self.horizontalHeader()
25
+ header.setSectionResizeMode(QHeaderView.Stretch)
26
+ self.bec_dispatcher.connect_slot(self.update_queue, MessageEndpoints.scan_queue_status())
27
+ self.reset_content()
28
+
29
+ @Slot(dict, dict)
30
+ def update_queue(self, content, _metadata):
31
+ """
32
+ Update the queue table with the latest queue information.
33
+
34
+ Args:
35
+ content (dict): The queue content.
36
+ _metadata (dict): The metadata.
37
+ """
38
+ # only show the primary queue for now
39
+ queue_info = content.get("queue", {}).get("primary", {}).get("info", [])
40
+ self.setRowCount(len(queue_info))
41
+ self.clearContents()
42
+
43
+ if not queue_info:
44
+ self.reset_content()
45
+ return
46
+
47
+ for index, item in enumerate(queue_info):
48
+ blocks = item.get("request_blocks", [])
49
+ scan_types = []
50
+ scan_numbers = []
51
+ status = item.get("status", "")
52
+ for request_block in blocks:
53
+ scan_type = request_block.get("content", {}).get("scan_type", "")
54
+ if scan_type:
55
+ scan_types.append(scan_type)
56
+ scan_number = request_block.get("scan_number", "")
57
+ if scan_number:
58
+ scan_numbers.append(str(scan_number))
59
+ if scan_types:
60
+ scan_types = ", ".join(scan_types)
61
+ if scan_numbers:
62
+ scan_numbers = ", ".join(scan_numbers)
63
+ self.set_row(index, scan_numbers, scan_types, status)
64
+
65
+ def format_item(self, content: str) -> QTableWidgetItem:
66
+ """
67
+ Format the content of the table item.
68
+
69
+ Args:
70
+ content (str): The content to be formatted.
71
+
72
+ Returns:
73
+ QTableWidgetItem: The formatted item.
74
+ """
75
+ item = QTableWidgetItem(content)
76
+ item.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
77
+ return item
78
+
79
+ def set_row(self, index: int, scan_number: str, scan_type: str, status: str):
80
+ """
81
+ Set the row of the table.
82
+
83
+ Args:
84
+ index (int): The index of the row.
85
+ scan_number (str): The scan number.
86
+ scan_type (str): The scan type.
87
+ status (str): The status.
88
+ """
89
+
90
+ self.setItem(index, 0, self.format_item(scan_number))
91
+ self.setItem(index, 1, self.format_item(scan_type))
92
+ self.setItem(index, 2, self.format_item(status))
93
+
94
+ def reset_content(self):
95
+ """
96
+ Reset the content of the table.
97
+ """
98
+
99
+ self.setRowCount(1)
100
+ self.set_row(0, "", "", "")
101
+
102
+
103
+ if __name__ == "__main__": # pragma: no cover
104
+ import sys
105
+
106
+ from qtpy.QtWidgets import QApplication
107
+
108
+ app = QApplication(sys.argv)
109
+ widget = BECQueue()
110
+ widget.show()
111
+ sys.exit(app.exec_())
@@ -0,0 +1 @@
1
+ {'files': ['bec_queue.py']}
@@ -0,0 +1,54 @@
1
+ # Copyright (C) 2022 The Qt Company Ltd.
2
+ # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
3
+
4
+ from qtpy.QtDesigner import QDesignerCustomWidgetInterface
5
+ from qtpy.QtGui import QIcon
6
+
7
+ from bec_widgets.widgets.bec_queue.bec_queue import BECQueue
8
+
9
+ DOM_XML = """
10
+ <ui language='c++'>
11
+ <widget class='BECQueue' name='bec_queue'>
12
+ </widget>
13
+ </ui>
14
+ """
15
+
16
+
17
+ class BECQueuePlugin(QDesignerCustomWidgetInterface): # pragma: no cover
18
+ def __init__(self):
19
+ super().__init__()
20
+ self._form_editor = None
21
+
22
+ def createWidget(self, parent):
23
+ t = BECQueue(parent)
24
+ return t
25
+
26
+ def domXml(self):
27
+ return DOM_XML
28
+
29
+ def group(self):
30
+ return ""
31
+
32
+ def icon(self):
33
+ return QIcon()
34
+
35
+ def includeFile(self):
36
+ return "bec_queue"
37
+
38
+ def initialize(self, form_editor):
39
+ self._form_editor = form_editor
40
+
41
+ def isContainer(self):
42
+ return False
43
+
44
+ def isInitialized(self):
45
+ return self._form_editor is not None
46
+
47
+ def name(self):
48
+ return "BECQueue"
49
+
50
+ def toolTip(self):
51
+ return "Widget to display the BEC queue."
52
+
53
+ def whatsThis(self):
54
+ return self.toolTip()
@@ -0,0 +1,15 @@
1
+ def main(): # pragma: no cover
2
+ from qtpy import PYSIDE6
3
+
4
+ if not PYSIDE6:
5
+ print("PYSIDE6 is not available in the environment. Cannot patch designer.")
6
+ return
7
+ from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
8
+
9
+ from bec_widgets.widgets.bec_queue.bec_queue_plugin import BECQueuePlugin
10
+
11
+ QPyDesignerCustomWidgetCollection.addCustomWidget(BECQueuePlugin())
12
+
13
+
14
+ if __name__ == "__main__": # pragma: no cover
15
+ main()
@@ -104,7 +104,7 @@ class RingProgressBar(BECConnector, QWidget):
104
104
  config = RingProgressBarConfig(**config, widget_class=self.__class__.__name__)
105
105
  self.config = config
106
106
  super().__init__(client=client, config=config, gui_id=gui_id)
107
- QWidget.__init__(self, parent=None)
107
+ QWidget.__init__(self, parent=parent)
108
108
 
109
109
  self.get_bec_shortcuts()
110
110
  self.entry_validator = EntryValidator(self.dev)
@@ -31,7 +31,7 @@ class TextBox(BECConnector, QTextEdit):
31
31
 
32
32
  USER_ACCESS = ["set_color", "set_text", "set_font_size"]
33
33
 
34
- def __init__(self, text: str = "", parent=None, client=None, config=None, gui_id=None):
34
+ def __init__(self, parent=None, text: str = "", client=None, config=None, gui_id=None):
35
35
  if config is None:
36
36
  config = TextBoxConfig(widget_class=self.__class__.__name__)
37
37
  else:
@@ -21,7 +21,7 @@ class WebsiteWidget(BECConnector, QWebEngineView):
21
21
 
22
22
  USER_ACCESS = ["set_url", "get_url", "reload", "back", "forward"]
23
23
 
24
- def __init__(self, url: str = None, parent=None, config=None, client=None, gui_id=None):
24
+ def __init__(self, parent=None, url: str = None, config=None, client=None, gui_id=None):
25
25
  super().__init__(client=client, config=config, gui_id=gui_id)
26
26
  QWebEngineView.__init__(self, parent=parent)
27
27
  self.set_url(url)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bec_widgets
3
- Version: 0.74.1
3
+ Version: 0.76.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=aGvafXlmnzAG4Eu08nM3q6ule47giC-cjueEsIHpiWk,7057
5
+ CHANGELOG.md,sha256=f7NEQ2MAF9BEMk8iD2jAixb0HA5WGAKthPBShjyIzz8,6859
6
6
  LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
7
- PKG-INFO,sha256=sxQGITcAB0UpR2bYuY2dUGxFuqeSHV8yiZw3FQHOg2U,1407
7
+ PKG-INFO,sha256=Zi2GSe-npT55crEiQspELhVGcx_gfEiW_E4Duz9AS-0,1407
8
8
  README.md,sha256=y4jB6wvArS7N8_iTbKWnSM_oRAqLA2GqgzUR-FMh5sU,2645
9
- pyproject.toml,sha256=ljABqddhgOWctRagAmk6CRg_pBS4bCGGfWXmRRkIktM,2344
9
+ pyproject.toml,sha256=p_NQqe-hmuikpj0AVASlTPa-z4L6zsho2G0fQXv9gNA,2344
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=ewhDGqzbP6iT-MPLMWs3fhZsj-RuO2Mm5bC2RvHEMMg,61210
20
+ bec_widgets/cli/client.py,sha256=754vTVMVLkdpGa5wsH2wGP0fJW59wRubt6HOB8AG7_w,61582
21
21
  bec_widgets/cli/client_utils.py,sha256=zq1gPW7t4n9Nsn4MLkdUeKwwl-9nUcf5UjuN8lZr9iY,12281
22
- bec_widgets/cli/generate_cli.py,sha256=InKBVYM7DRfAVLNJhRJbWWSSPBQBHI8Ek6v7NCsK0ME,4997
22
+ bec_widgets/cli/generate_cli.py,sha256=FUMSm84ztE6UIIHs8U0Irof1i5LRu6CXW1sl-RF_UKA,5877
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=2EJvkQDzrDTsZjRPs7g2v_iPTspGqxzY34tRAnvjxjY,7281
@@ -40,12 +40,13 @@ bec_widgets/examples/plugin_example_pyside/tictactoetaskmenu.py,sha256=LNwplI6de
40
40
  bec_widgets/utils/__init__.py,sha256=1930ji1Jj6dVuY81Wd2kYBhHYNV-2R0bN_L4o9zBj1U,533
41
41
  bec_widgets/utils/bec_connector.py,sha256=t59482Tu30eiQ2YNHJZFEE-wQFt4qf85OmBfPkl-3N4,7335
42
42
  bec_widgets/utils/bec_designer.py,sha256=Q5qhdB7Jiw768dzlJ9bNxLrCbDKw4qNmhbO-9zLTVpw,4318
43
- bec_widgets/utils/bec_dispatcher.py,sha256=yM9PG04O7ABhiA9Nzk38Rv9Qbjc5O93wi2xfSbOlOxc,6202
43
+ bec_widgets/utils/bec_dispatcher.py,sha256=QZjRKNrZ181yt_6nLJCfdNk5EyeaGImApNA1FWR4rqo,6186
44
44
  bec_widgets/utils/bec_table.py,sha256=nA2b8ukSeUfquFMAxGrUVOqdrzMoDYD6O_4EYbOG2zk,717
45
45
  bec_widgets/utils/colors.py,sha256=GYSDe0ZxsJSwxvuy-yG2BH17qlf_Sjq8dhDcyp9IhBI,8532
46
46
  bec_widgets/utils/container_utils.py,sha256=m3VUyAYmSWkEwApP9tBvKxPYVtc2kHw4toxIpMryJy4,1495
47
47
  bec_widgets/utils/crosshair.py,sha256=SubY4FQCI6vUKsmMYGKHR7uYdGQJ6vhoYLuC1XlKS9I,9626
48
48
  bec_widgets/utils/entry_validator.py,sha256=IqmtResXQtnmMvWVSl8IrnggqSzXLp4cSggn6WdSTpE,1298
49
+ bec_widgets/utils/generate_designer_plugin.py,sha256=6-bPGULexbO02IcUBNqclSdNrZsWsCo-eAdzNpAYsGk,5703
49
50
  bec_widgets/utils/layout_manager.py,sha256=H0nKsIMaPxRkof1MEXlSmW6w1dFxA6astaGzf4stI84,4727
50
51
  bec_widgets/utils/plugin_utils.py,sha256=tmZkUNvVlldPjHDfL_TbaV2jjAECgPjGsvLMmmyZcfc,3342
51
52
  bec_widgets/utils/rpc_decorator.py,sha256=pIvtqySQLnuS7l2Ti_UAe4WX7CRivZnsE5ZdKAihxh0,479
@@ -54,7 +55,14 @@ bec_widgets/utils/ui_loader.py,sha256=5NktcP1r1HQub7K82fW_jkj8rT2cqJQdMvDxwToLY4
54
55
  bec_widgets/utils/validator_delegate.py,sha256=Emj1WF6W8Ke1ruBWUfmHdVJpmOSPezuOt4zvQTay_44,442
55
56
  bec_widgets/utils/widget_io.py,sha256=U_02ESf9Ukz63B01AzYioNepSc6SX11nJhPPSDmL4IA,11318
56
57
  bec_widgets/utils/yaml_dialog.py,sha256=cMVif-39SB9WjwGH5FWBJcFs4tnfFJFs5cacydRyhy0,1853
58
+ bec_widgets/utils/plugin_templates/plugin.template,sha256=JHkUvYegesW-xEhZuY4FQVGqyEMBRLaPY4JNI8Ni_vE,1182
59
+ bec_widgets/utils/plugin_templates/register.template,sha256=XyL3OZPT_FTArLAM8tHd5qMqv2ZuAbJAZLsNNnHcagU,417
57
60
  bec_widgets/widgets/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
61
+ bec_widgets/widgets/bec_queue/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
+ bec_widgets/widgets/bec_queue/bec_queue.py,sha256=voIsj599a5t-u-H15tpSqjGBmy5ra6LsHpZnqEZFrI8,3551
63
+ bec_widgets/widgets/bec_queue/bec_queue.pyproject,sha256=VhoNmAv1DQUl9dg7dELyf5i4pZ5k65N3GnqOYiSwbQo,27
64
+ bec_widgets/widgets/bec_queue/bec_queue_plugin.py,sha256=hDJm8Zd_GIDw2R8VYn4ytwrHVCmJUjC9dGDMae2omU0,1175
65
+ bec_widgets/widgets/bec_queue/register_bec_queue.py,sha256=XnwtUSa1asK1b80knKWodcyX9qJy4DnKsQL_FoDfZy4,463
58
66
  bec_widgets/widgets/bec_status_box/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
67
  bec_widgets/widgets/bec_status_box/bec_status_box.py,sha256=twWugYlGVSl9ziSbjeB75BZwuruXFszRoOlN0d79Gnk,14523
60
68
  bec_widgets/widgets/bec_status_box/status_item.py,sha256=wPkDm0GCGNXXpy3rR_Ljaxy0ZHeiiYcrWFqEntZnz4E,5869
@@ -109,18 +117,18 @@ bec_widgets/widgets/motor_control/selection/selection.py,sha256=WNHndvv4JvxeAMnD
109
117
  bec_widgets/widgets/motor_control/selection/selection.ui,sha256=vXXpvNWuL6xyHhW7Lx1zmVFX-95Z5AXGlhKQD2HmM1A,1779
110
118
  bec_widgets/widgets/ring_progress_bar/__init__.py,sha256=_uoJKnDM2YAeUBfwc5WLbIHSJj7zm_FAurSKP3WRaCw,47
111
119
  bec_widgets/widgets/ring_progress_bar/ring.py,sha256=3XwvM5cymCxffOYEjaDTqfqpNLjEunHTyZCBxz0cvmc,11238
112
- bec_widgets/widgets/ring_progress_bar/ring_progress_bar.py,sha256=jc-2VtFBASzA15M8S2ZNAvu0Z7RFp130jHz7HpLyIRs,24068
120
+ bec_widgets/widgets/ring_progress_bar/ring_progress_bar.py,sha256=9TzlR4mGWnV1dPBwdkwL-GVNzG30r3oy0secm7k-gKM,24070
113
121
  bec_widgets/widgets/scan_control/__init__.py,sha256=IOfHl15vxb_uC6KN62-PeUzbBha_vQyqkkXbJ2HU674,38
114
122
  bec_widgets/widgets/scan_control/scan_control.py,sha256=u2fjSUiSRYTkIq9WhdfQuQV6Sv3iWWcSfCraVGro1RQ,7686
115
123
  bec_widgets/widgets/scan_control/scan_group_box.py,sha256=8XGpYcdKTEtiqOFbBxZ6xV07ZJ_tg9R-JDfsdTdqXSI,7400
116
124
  bec_widgets/widgets/text_box/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
117
- bec_widgets/widgets/text_box/text_box.py,sha256=kykQ_Zcxh8IGcPEP5-oGGQwoZEpY9vhxRIM8TY8kTYg,4240
125
+ bec_widgets/widgets/text_box/text_box.py,sha256=dg2gpOqdBZNKD08mygb40twweFBiG-xsXz0GlIhfXV0,4240
118
126
  bec_widgets/widgets/toolbar/__init__.py,sha256=d-TP4_cr_VbpwreMM4ePnfZ5YXsEPQ45ibEf75nuGoE,36
119
127
  bec_widgets/widgets/toolbar/toolbar.py,sha256=e0zCD_0q7K4NVhrzD8001Qvfxt-VhqHTgofchS9NgCM,5125
120
128
  bec_widgets/widgets/vscode/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
121
129
  bec_widgets/widgets/vscode/vscode.py,sha256=ZyJJCJapYrGhqgudEt8JQn723DDqLdwjsXxXa5q3EkU,2544
122
130
  bec_widgets/widgets/website/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
123
- bec_widgets/widgets/website/website.py,sha256=Scvpl4I52qpL7s69tnNBRQSG6GcRI9jzoR3RsSTXfPE,1722
131
+ bec_widgets/widgets/website/website.py,sha256=iMOooGlZPQ5Y_T_7g4rJZXj-tKpbIupA1O6_WN27JuI,1722
124
132
  docs/Makefile,sha256=i2WHuFlgfyAPEW4ssEP8NY4cOibDJrVjvzSEU8_Ggwc,634
125
133
  docs/conf.py,sha256=HxLxupNGu0Smhwn57g1kFdjZzFuaWVREgRJKhT1zi2k,2464
126
134
  docs/index.md,sha256=8ZCgaLIbJsYvt-jwi--QxsNwnK4-k3rejIeOOLclG40,1101
@@ -185,6 +193,7 @@ tests/unit_tests/test_bec_dock.py,sha256=BXKXpuyIYj-l6KSyhQtM_p3kRFCRECIoXLzvkcJ
185
193
  tests/unit_tests/test_bec_figure.py,sha256=aEd2R8K6fU2ON8QvPemGWpql_LaaYLipRlvnjBY2qFA,8009
186
194
  tests/unit_tests/test_bec_image.py,sha256=mjvcrHgOF_FCj6WbUyxvZH9HL63QGA5C0PNZ5dXYn50,2541
187
195
  tests/unit_tests/test_bec_motor_map.py,sha256=AfD_9-x6VV3TPnkQgNfFYRndPHDsGx-a_YknFeDr6hc,4588
196
+ tests/unit_tests/test_bec_queue.py,sha256=u-uc-iZeGAS8P90o6Cxy5oz_60zHpirGAu04OgQPDXw,4598
188
197
  tests/unit_tests/test_bec_status_box.py,sha256=xR8c-hXFI9gKpNGhnnC5l_nzazfvPkWkhcAfJ77hxqY,4731
189
198
  tests/unit_tests/test_client_utils.py,sha256=eViJ1Tz-HX9TkMvQH6W8cO-c3_1I8bUc4_Yen6LOc0E,830
190
199
  tests/unit_tests/test_color_validation.py,sha256=csdvVKAohENZIRY-JQ97Hv-TShb1erj4oKMX7QRwo78,1883
@@ -212,8 +221,8 @@ tests/unit_tests/test_configs/config_device_no_entry.yaml,sha256=hdvue9KLc_kfNzG
212
221
  tests/unit_tests/test_configs/config_scan.yaml,sha256=vo484BbWOjA_e-h6bTjSV9k7QaQHrlAvx-z8wtY-P4E,1915
213
222
  tests/unit_tests/test_msgs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
214
223
  tests/unit_tests/test_msgs/available_scans_message.py,sha256=m_z97hIrjHXXMa2Ex-UvsPmTxOYXfjxyJaGkIY6StTY,46532
215
- bec_widgets-0.74.1.dist-info/METADATA,sha256=sxQGITcAB0UpR2bYuY2dUGxFuqeSHV8yiZw3FQHOg2U,1407
216
- bec_widgets-0.74.1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
217
- bec_widgets-0.74.1.dist-info/entry_points.txt,sha256=3otEkCdDB9LZJuBLzG4pFLK5Di0CVybN_12IsZrQ-58,166
218
- bec_widgets-0.74.1.dist-info/licenses/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
219
- bec_widgets-0.74.1.dist-info/RECORD,,
224
+ bec_widgets-0.76.0.dist-info/METADATA,sha256=Zi2GSe-npT55crEiQspELhVGcx_gfEiW_E4Duz9AS-0,1407
225
+ bec_widgets-0.76.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
226
+ bec_widgets-0.76.0.dist-info/entry_points.txt,sha256=3otEkCdDB9LZJuBLzG4pFLK5Di0CVybN_12IsZrQ-58,166
227
+ bec_widgets-0.76.0.dist-info/licenses/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
228
+ bec_widgets-0.76.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.74.1"
7
+ version = "0.76.0"
8
8
  description = "BEC Widgets"
9
9
  requires-python = ">=3.10"
10
10
  classifiers = [
@@ -0,0 +1,111 @@
1
+ import pytest
2
+ from bec_lib import messages
3
+
4
+ from bec_widgets.widgets.bec_queue.bec_queue import BECQueue
5
+
6
+ from .client_mocks import mocked_client
7
+
8
+
9
+ @pytest.fixture
10
+ def bec_queue_msg_full():
11
+ content = {
12
+ "primary": {
13
+ "info": [
14
+ {
15
+ "active_request_block": None,
16
+ "is_scan": [True],
17
+ "queue_id": "600163fc-5e56-4901-af25-14e9ee76817c",
18
+ "request_blocks": [
19
+ {
20
+ "RID": "89a76021-28c0-4297-828e-74ae40b941e5",
21
+ "content": {
22
+ "parameter": {
23
+ "args": {"samx": [-0.1, 0.1]},
24
+ "kwargs": {
25
+ "exp_time": 0.5,
26
+ "relative": True,
27
+ "steps": 20,
28
+ "system_config": {
29
+ "file_directory": None,
30
+ "file_suffix": None,
31
+ },
32
+ },
33
+ },
34
+ "queue": "primary",
35
+ "scan_type": "line_scan",
36
+ },
37
+ "is_scan": True,
38
+ "metadata": {
39
+ "RID": "89a76021-28c0-4297-828e-74ae40b941e5",
40
+ "file_directory": None,
41
+ "file_suffix": None,
42
+ "user_metadata": {"sample_name": "testA"},
43
+ },
44
+ "msg": messages.ScanQueueMessage(
45
+ metadata={
46
+ "file_suffix": None,
47
+ "file_directory": None,
48
+ "user_metadata": {"sample_name": "testA"},
49
+ "RID": "89a76021-28c0-4297-828e-74ae40b941e5",
50
+ },
51
+ scan_type="line_scan",
52
+ parameter={
53
+ "args": {"samx": [-0.1, 0.1]},
54
+ "kwargs": {
55
+ "steps": 20,
56
+ "exp_time": 0.5,
57
+ "relative": True,
58
+ "system_config": {
59
+ "file_suffix": None,
60
+ "file_directory": None,
61
+ },
62
+ },
63
+ },
64
+ queue="primary",
65
+ ),
66
+ "readout_priority": {
67
+ "async": [],
68
+ "baseline": [],
69
+ "monitored": ["samx"],
70
+ "on_request": [],
71
+ },
72
+ "report_instructions": [{"scan_progress": 20}],
73
+ "scan_id": "2d704cc3-c172-404c-866d-608ce09fce40",
74
+ "scan_motors": ["samx"],
75
+ "scan_number": 1289,
76
+ }
77
+ ],
78
+ "scan_id": ["2d704cc3-c172-404c-866d-608ce09fce40"],
79
+ "scan_number": [1289],
80
+ "status": "COMPLETED",
81
+ }
82
+ ],
83
+ "status": "RUNNING",
84
+ }
85
+ }
86
+ msg = messages.ScanQueueStatusMessage(metadata={}, queue=content)
87
+ return msg
88
+
89
+
90
+ @pytest.fixture
91
+ def bec_queue(qtbot, mocked_client):
92
+ widget = BECQueue(client=mocked_client)
93
+ qtbot.addWidget(widget)
94
+ qtbot.waitExposed(widget)
95
+ yield widget
96
+
97
+
98
+ def test_bec_queue(bec_queue, bec_queue_msg_full):
99
+ bec_queue.update_queue(bec_queue_msg_full.content, {})
100
+ assert bec_queue.rowCount() == 1
101
+ assert bec_queue.item(0, 0).text() == "1289"
102
+ assert bec_queue.item(0, 1).text() == "line_scan"
103
+ assert bec_queue.item(0, 2).text() == "COMPLETED"
104
+
105
+
106
+ def test_bec_queue_empty(bec_queue):
107
+ bec_queue.update_queue({}, {})
108
+ assert bec_queue.rowCount() == 1
109
+ assert bec_queue.item(0, 0).text() == ""
110
+ assert bec_queue.item(0, 1).text() == ""
111
+ assert bec_queue.item(0, 2).text() == ""