bec-widgets 0.93.3__py3-none-any.whl → 0.93.4__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,13 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v0.93.4 (2024-08-07)
4
+
5
+ ### Fix
6
+
7
+ * fix: rename DeviceBox to PositionerBox, fix test for validation ([`37aa371`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/37aa371e7c4c62d70abf37abc125db0c088790fe))
8
+
9
+ * fix: add validation for bec_lib.device.Positioner; closes #268 ([`eb54e9f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/eb54e9f788e97af23db8fe0c78f8facb8688bb99))
10
+
3
11
  ## v0.93.3 (2024-08-07)
4
12
 
5
13
  ### Fix
@@ -128,10 +136,6 @@ This reverts commit fd6ae91993a23a7b8dbb2cf3c4b7c3eda6d2b0f6 ([`5aad401`](https:
128
136
 
129
137
  * feat(dock_area): plugin added ([`a16b87a`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/a16b87ac28d164230dd2e8020f50ff3a63cd407e))
130
138
 
131
- * feat(dock_area): Added toolbar to dock area to add widgets without CLI interactions ([`cce1367`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/cce1367a72fca7206d351894bd1831b7bbfa7ec6))
132
-
133
- * feat(toolbar): expandable menu actions ([`28f26e9`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/28f26e92a46063db1a194be552156a5d3b2c43e7))
134
-
135
139
  ### Fix
136
140
 
137
141
  * fix(status_item): icons changed to material design ([`1b9c55a`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/1b9c55a46a0dfd8678c8e95ff64dd6e8cfb9233e))
@@ -141,5 +145,3 @@ This reverts commit fd6ae91993a23a7b8dbb2cf3c4b7c3eda6d2b0f6 ([`5aad401`](https:
141
145
  ### Test
142
146
 
143
147
  * test(dock_area): tests extended ([`06fab0e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/06fab0eab926cef5677d4988fd1fce09da342dd8))
144
-
145
- ## v0.90.0 (2024-07-23)
PKG-INFO CHANGED
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bec_widgets
3
- Version: 0.93.3
3
+ Version: 0.93.4
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
@@ -21,9 +21,9 @@ class Widgets(str, enum.Enum):
21
21
  BECQueue = "BECQueue"
22
22
  BECStatusBox = "BECStatusBox"
23
23
  BECWaveformWidget = "BECWaveformWidget"
24
- DeviceBox = "DeviceBox"
25
24
  DeviceComboBox = "DeviceComboBox"
26
25
  DeviceLineEdit = "DeviceLineEdit"
26
+ PositionerBox = "PositionerBox"
27
27
  RingProgressBar = "RingProgressBar"
28
28
  ScanControl = "ScanControl"
29
29
  StopButton = "StopButton"
@@ -2287,7 +2287,7 @@ class BECWaveformWidget(RPCBase):
2287
2287
  """
2288
2288
 
2289
2289
 
2290
- class DeviceBox(RPCBase):
2290
+ class DeviceComboBox(RPCBase):
2291
2291
  @property
2292
2292
  @rpc_call
2293
2293
  def _config_dict(self) -> "dict":
@@ -2305,7 +2305,7 @@ class DeviceBox(RPCBase):
2305
2305
  """
2306
2306
 
2307
2307
 
2308
- class DeviceComboBox(RPCBase):
2308
+ class DeviceInputBase(RPCBase):
2309
2309
  @property
2310
2310
  @rpc_call
2311
2311
  def _config_dict(self) -> "dict":
@@ -2323,7 +2323,7 @@ class DeviceComboBox(RPCBase):
2323
2323
  """
2324
2324
 
2325
2325
 
2326
- class DeviceInputBase(RPCBase):
2326
+ class DeviceLineEdit(RPCBase):
2327
2327
  @property
2328
2328
  @rpc_call
2329
2329
  def _config_dict(self) -> "dict":
@@ -2341,21 +2341,14 @@ class DeviceInputBase(RPCBase):
2341
2341
  """
2342
2342
 
2343
2343
 
2344
- class DeviceLineEdit(RPCBase):
2345
- @property
2344
+ class PositionerBox(RPCBase):
2346
2345
  @rpc_call
2347
- def _config_dict(self) -> "dict":
2348
- """
2349
- Get the configuration of the widget.
2350
-
2351
- Returns:
2352
- dict: The configuration of the widget.
2346
+ def set_positioner(self, positioner: str):
2353
2347
  """
2348
+ Set the device
2354
2349
 
2355
- @rpc_call
2356
- def _get_all_rpc(self) -> "dict":
2357
- """
2358
- Get all registered RPC objects.
2350
+ Args:
2351
+ positioner (Positioner | str) : Positioner to set, accepts str or the device
2359
2352
  """
2360
2353
 
2361
2354
 
@@ -83,8 +83,8 @@ class BECDockArea(BECWidget, QWidget):
83
83
  "scan_control": IconAction(
84
84
  icon_path="scan_control.svg", tooltip="Add Scan Control"
85
85
  ),
86
- "device_box": IconAction(
87
- icon_path="device_box.svg", tooltip="Add Device Box"
86
+ "positioner_box": IconAction(
87
+ icon_path="positioner_box.svg", tooltip="Add Device Box"
88
88
  ),
89
89
  },
90
90
  ),
@@ -132,8 +132,8 @@ class BECDockArea(BECWidget, QWidget):
132
132
  self.toolbar.widgets["menu_devices"].widgets["scan_control"].triggered.connect(
133
133
  lambda: self.add_dock(widget="ScanControl", prefix="scan_control")
134
134
  )
135
- self.toolbar.widgets["menu_devices"].widgets["device_box"].triggered.connect(
136
- lambda: self.add_dock(widget="DeviceBox", prefix="device_box")
135
+ self.toolbar.widgets["menu_devices"].widgets["positioner_box"].triggered.connect(
136
+ lambda: self.add_dock(widget="PositionerBox", prefix="positioner_box")
137
137
  )
138
138
 
139
139
  # Menu Utils
@@ -1,7 +1,11 @@
1
+ """ Module for a PositionerBox widget to control a positioner device."""
2
+
1
3
  import os
2
4
  import uuid
3
5
 
6
+ from bec_lib.device import Positioner
4
7
  from bec_lib.endpoints import MessageEndpoints
8
+ from bec_lib.logger import bec_logger
5
9
  from bec_lib.messages import ScanQueueMessage
6
10
  from qtpy.QtCore import Property, Signal, Slot
7
11
  from qtpy.QtGui import QDoubleValidator
@@ -11,12 +15,23 @@ from bec_widgets.utils import UILoader
11
15
  from bec_widgets.utils.bec_widget import BECWidget
12
16
  from bec_widgets.utils.colors import apply_theme
13
17
 
18
+ logger = bec_logger.logger
19
+
20
+
21
+ class PositionerBox(BECWidget, QWidget):
22
+ """Simple Widget to control a positioner in box form"""
14
23
 
15
- class DeviceBox(BECWidget, QWidget):
24
+ USER_ACCESS = ["set_positioner"]
16
25
  device_changed = Signal(str, str)
17
26
 
18
- def __init__(self, parent=None, device=None, *args, **kwargs):
19
- super().__init__(*args, **kwargs)
27
+ def __init__(self, parent=None, device: Positioner = None, *args, **kwargs):
28
+ """Initialize the PositionerBox widget.
29
+
30
+ Args:
31
+ parent: The parent widget.
32
+ device (Positioner): The device to control.
33
+ """
34
+ super().__init__(**kwargs)
20
35
  QWidget.__init__(self, parent=parent)
21
36
  self.get_bec_shortcuts()
22
37
  self._device = ""
@@ -29,10 +44,11 @@ class DeviceBox(BECWidget, QWidget):
29
44
  self.init_device()
30
45
 
31
46
  def init_ui(self):
47
+ """Init the ui"""
32
48
  self.device_changed.connect(self.on_device_change)
33
49
 
34
50
  current_path = os.path.dirname(__file__)
35
- self.ui = UILoader(self).loader(os.path.join(current_path, "device_box.ui"))
51
+ self.ui = UILoader(self).loader(os.path.join(current_path, "positioner_box.ui"))
36
52
 
37
53
  self.layout = QVBoxLayout(self)
38
54
  self.layout.addWidget(self.ui)
@@ -57,28 +73,73 @@ class DeviceBox(BECWidget, QWidget):
57
73
  self.ui.spinner_widget.start()
58
74
 
59
75
  def init_device(self):
60
- if self.device in self.dev:
76
+ """Init the device view and readback"""
77
+ if self._check_device_is_valid(self.device):
61
78
  data = self.dev[self.device].read()
62
79
  self.on_device_readback({"signals": data}, {})
63
80
 
81
+ def _toogle_enable_buttons(self, enable: bool) -> None:
82
+ """Toogle enable/disable on available buttons
83
+
84
+ Args:
85
+ enable (bool): Enable buttons
86
+ """
87
+ self.ui.tweak_left.setEnabled(enable)
88
+ self.ui.tweak_right.setEnabled(enable)
89
+ self.ui.stop.setEnabled(enable)
90
+ self.ui.setpoint.setEnabled(enable)
91
+ self.ui.step_size.setEnabled(enable)
92
+
64
93
  @Property(str)
65
94
  def device(self):
95
+ """Property to set the device"""
66
96
  return self._device
67
97
 
68
98
  @device.setter
69
- def device(self, value):
99
+ def device(self, value: str):
100
+ """Setter, checks if device is a string"""
70
101
  if not value or not isinstance(value, str):
71
102
  return
72
103
  old_device = self._device
73
104
  self._device = value
74
105
  self.device_changed.emit(old_device, value)
75
106
 
107
+ def set_positioner(self, positioner: str):
108
+ """Set the device
109
+
110
+ Args:
111
+ positioner (Positioner | str) : Positioner to set, accepts str or the device
112
+ """
113
+ if isinstance(positioner, Positioner):
114
+ positioner = positioner.name
115
+ self.device = positioner
116
+
117
+ def _check_device_is_valid(self, device: str):
118
+ """Check if the device is a positioner
119
+
120
+ Args:
121
+ device (str): The device name
122
+ """
123
+ if device not in self.dev:
124
+ logger.info(f"Device {device} not found in the device list")
125
+ return False
126
+ if not isinstance(self.dev[device], Positioner):
127
+ logger.info(f"Device {device} is not a positioner")
128
+ return False
129
+ return True
130
+
76
131
  @Slot(str, str)
77
132
  def on_device_change(self, old_device: str, new_device: str):
78
- if new_device not in self.dev:
79
- print(f"Device {new_device} not found in the device list")
133
+ """Upon changing the device, a check will be performed if the device is a Positioner.
134
+
135
+ Args:
136
+ old_device (str): The old device name.
137
+ new_device (str): The new device name.
138
+ """
139
+ if not self._check_device_is_valid(new_device):
80
140
  return
81
- print(f"Device changed from {old_device} to {new_device}")
141
+ logger.info(f"Device changed from {old_device} to {new_device}")
142
+ self._toogle_enable_buttons(True)
82
143
  self.init_device()
83
144
  self.bec_dispatcher.disconnect_slot(
84
145
  self.on_device_readback, MessageEndpoints.device_readback(old_device)
@@ -98,6 +159,12 @@ class DeviceBox(BECWidget, QWidget):
98
159
 
99
160
  @Slot(dict, dict)
100
161
  def on_device_readback(self, msg_content: dict, metadata: dict):
162
+ """Callback for device readback.
163
+
164
+ Args:
165
+ msg_content (dict): The message content.
166
+ metadata (dict): The message metadata.
167
+ """
101
168
  signals = msg_content.get("signals", {})
102
169
  # pylint: disable=protected-access
103
170
  hinted_signals = self.dev[self.device]._hints
@@ -134,7 +201,12 @@ class DeviceBox(BECWidget, QWidget):
134
201
  pos = (readback_val - limits[0]) / (limits[1] - limits[0])
135
202
  self.ui.position_indicator.on_position_update(pos)
136
203
 
137
- def update_limits(self, limits):
204
+ def update_limits(self, limits: tuple):
205
+ """Update limits
206
+
207
+ Args:
208
+ limits (tuple): Limits of the positioner
209
+ """
138
210
  if limits == self._limits:
139
211
  return
140
212
  self._limits = limits
@@ -147,6 +219,7 @@ class DeviceBox(BECWidget, QWidget):
147
219
 
148
220
  @Slot()
149
221
  def on_stop(self):
222
+ """Stop call"""
150
223
  request_id = str(uuid.uuid4())
151
224
  params = {
152
225
  "device": self.device,
@@ -165,18 +238,22 @@ class DeviceBox(BECWidget, QWidget):
165
238
 
166
239
  @property
167
240
  def step_size(self):
241
+ """Step size for tweak"""
168
242
  return self.ui.step_size.value()
169
243
 
170
244
  @Slot()
171
245
  def on_tweak_right(self):
246
+ """Tweak motor right"""
172
247
  self.dev[self.device].move(self.step_size, relative=True)
173
248
 
174
249
  @Slot()
175
250
  def on_tweak_left(self):
251
+ """Tweak motor left"""
176
252
  self.dev[self.device].move(-self.step_size, relative=True)
177
253
 
178
254
  @Slot()
179
255
  def on_setpoint_change(self):
256
+ """Change the setpoint for the motor"""
180
257
  self.ui.setpoint.clearFocus()
181
258
  setpoint = self.ui.setpoint.text()
182
259
  self.dev[self.device].move(float(setpoint), relative=False)
@@ -191,7 +268,7 @@ if __name__ == "__main__": # pragma: no cover
191
268
 
192
269
  app = QApplication(sys.argv)
193
270
  apply_theme("light")
194
- widget = DeviceBox(device="samx")
271
+ widget = PositionerBox(device="bpm4i")
195
272
 
196
273
  widget.show()
197
274
  sys.exit(app.exec_())
@@ -0,0 +1 @@
1
+ {'files': ['positioner_box.py']}
@@ -29,17 +29,24 @@
29
29
  <item>
30
30
  <widget class="QGroupBox" name="device_box">
31
31
  <property name="title">
32
- <string>Device Name</string>
32
+ <string>No positioner selected</string>
33
33
  </property>
34
34
  <layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0,0">
35
35
  <property name="topMargin">
36
36
  <number>0</number>
37
37
  </property>
38
38
  <item row="3" column="1">
39
- <widget class="QDoubleSpinBox" name="step_size"/>
39
+ <widget class="QDoubleSpinBox" name="step_size">
40
+ <property name="enabled">
41
+ <bool>false</bool>
42
+ </property>
43
+ </widget>
40
44
  </item>
41
45
  <item row="3" column="2">
42
46
  <widget class="QToolButton" name="tweak_right">
47
+ <property name="enabled">
48
+ <bool>false</bool>
49
+ </property>
43
50
  <property name="minimumSize">
44
51
  <size>
45
52
  <width>50</width>
@@ -67,10 +74,17 @@
67
74
  </widget>
68
75
  </item>
69
76
  <item row="2" column="0" colspan="3">
70
- <widget class="QLineEdit" name="setpoint"/>
77
+ <widget class="QLineEdit" name="setpoint">
78
+ <property name="enabled">
79
+ <bool>false</bool>
80
+ </property>
81
+ </widget>
71
82
  </item>
72
83
  <item row="3" column="0">
73
84
  <widget class="QToolButton" name="tweak_left">
85
+ <property name="enabled">
86
+ <bool>false</bool>
87
+ </property>
74
88
  <property name="minimumSize">
75
89
  <size>
76
90
  <width>50</width>
@@ -99,6 +113,9 @@
99
113
  </item>
100
114
  <item row="4" column="0" colspan="3">
101
115
  <widget class="QPushButton" name="stop">
116
+ <property name="enabled">
117
+ <bool>false</bool>
118
+ </property>
102
119
  <property name="text">
103
120
  <string>Stop</string>
104
121
  </property>
@@ -1,44 +1,39 @@
1
1
  # Copyright (C) 2022 The Qt Company Ltd.
2
2
  # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
3
- import os
4
3
 
5
4
  from qtpy.QtDesigner import QDesignerCustomWidgetInterface
6
5
  from qtpy.QtGui import QIcon
7
6
 
8
- import bec_widgets
9
- from bec_widgets.widgets.device_box.device_box import DeviceBox
7
+ from bec_widgets.widgets.positioner_box.positioner_box import PositionerBox
10
8
 
11
9
  DOM_XML = """
12
10
  <ui language='c++'>
13
- <widget class='DeviceBox' name='device_box'>
11
+ <widget class='PositionerBox' name='positioner_box'>
14
12
  </widget>
15
13
  </ui>
16
14
  """
17
15
 
18
- MODULE_PATH = os.path.dirname(bec_widgets.__file__)
19
16
 
20
-
21
- class DeviceBoxPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
17
+ class PositionerBoxPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
22
18
  def __init__(self):
23
19
  super().__init__()
24
20
  self._form_editor = None
25
21
 
26
22
  def createWidget(self, parent):
27
- t = DeviceBox(parent)
23
+ t = PositionerBox(parent)
28
24
  return t
29
25
 
30
26
  def domXml(self):
31
27
  return DOM_XML
32
28
 
33
29
  def group(self):
34
- return "Device Control"
30
+ return ""
35
31
 
36
32
  def icon(self):
37
- icon_path = os.path.join(MODULE_PATH, "assets", "designer_icons", "device_box.png")
38
- return QIcon(icon_path)
33
+ return QIcon()
39
34
 
40
35
  def includeFile(self):
41
- return "device_box"
36
+ return "positioner_box"
42
37
 
43
38
  def initialize(self, form_editor):
44
39
  self._form_editor = form_editor
@@ -50,10 +45,10 @@ class DeviceBoxPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
50
45
  return self._form_editor is not None
51
46
 
52
47
  def name(self):
53
- return "DeviceBox"
48
+ return "PositionerBox"
54
49
 
55
50
  def toolTip(self):
56
- return "A widget for controlling a single positioner. "
51
+ return "Simple Widget to control a positioner in box form"
57
52
 
58
53
  def whatsThis(self):
59
54
  return self.toolTip()
@@ -6,9 +6,9 @@ def main(): # pragma: no cover
6
6
  return
7
7
  from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
8
8
 
9
- from bec_widgets.widgets.device_box.device_box_plugin import DeviceBoxPlugin
9
+ from bec_widgets.widgets.positioner_box.positioner_box_plugin import PositionerBoxPlugin
10
10
 
11
- QPyDesignerCustomWidgetCollection.addCustomWidget(DeviceBoxPlugin())
11
+ QPyDesignerCustomWidgetCollection.addCustomWidget(PositionerBoxPlugin())
12
12
 
13
13
 
14
14
  if __name__ == "__main__": # pragma: no cover
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bec_widgets
3
- Version: 0.93.3
3
+ Version: 0.93.4
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=BtKhZI3dhK09En1BfpglYi-ZJwG6ZdC-iJr7kXFVfCg,8346
3
3
  .pylintrc,sha256=eeY8YwSI74oFfq6IYIbCqnx3Vk8ZncKaatv96n_Y8Rs,18544
4
4
  .readthedocs.yaml,sha256=aSOc277LqXcsTI6lgvm_JY80lMlr69GbPKgivua2cS0,603
5
- CHANGELOG.md,sha256=U5vCm00ka49FYkJ9jdcAusiIKlWRfmpBHPSFiuDcsuE,6646
5
+ CHANGELOG.md,sha256=9EMQ1Af_QTOMF06XtrQGfth_oD5stOlkjsSdeKkgV14,6659
6
6
  LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
7
- PKG-INFO,sha256=_VblxDpuCc284m1SFf95vKgTaR-Jng60jurwZViD06c,1307
7
+ PKG-INFO,sha256=xpE3WACvw9YH_nuy0jPV4Z6i7pmskaF_vKGawCZmRj4,1307
8
8
  README.md,sha256=Od69x-RS85Hph0-WwWACwal4yUd67XkEn4APEfHhHFw,2649
9
- pyproject.toml,sha256=xNXznccvvpAdxIq46iwq_IJJcLfqag12-4IaiJaw0CY,2356
9
+ pyproject.toml,sha256=82c_u5P42OZ7b5q0YCuRpdwyNig4v_cDMaRISa5CNX4,2356
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
@@ -81,7 +81,7 @@ bec_widgets/assets/toolbar_icons/transform.svg,sha256=Fgug9wCi1FONy08nssEvnoDDDB
81
81
  bec_widgets/assets/toolbar_icons/waveform.svg,sha256=darXWaIww4HEu9skFUd8Vs1NSAgUo1d37xBNr6DX-bM,231
82
82
  bec_widgets/cli/__init__.py,sha256=d0Q6Fn44e7wFfLabDOBxpcJ1DPKWlFunGYDUBmO-4hA,22
83
83
  bec_widgets/cli/auto_updates.py,sha256=DyBV3HnjMSH-cvVkYNcDiYKVf0Xut4Qy2qGQqkW47Bw,4833
84
- bec_widgets/cli/client.py,sha256=GqhR36UCp3ZSjzDdBlUCK4ud0RL6PRcPjv0GVuKJ1XQ,76054
84
+ bec_widgets/cli/client.py,sha256=3zXER7rSN5DfFO_-rkSrkHdERnPD5bnrk3WjxJE9EiI,75957
85
85
  bec_widgets/cli/client_utils.py,sha256=cDhabblwaP88a0jlVpbn_RWWKVbsyjhmmGtMh9gesEw,12388
86
86
  bec_widgets/cli/generate_cli.py,sha256=Ea5px9KblUlcGg-1JbJBTIU7laGg2n8PM7Efw9WVVzM,5889
87
87
  bec_widgets/cli/rpc_register.py,sha256=QxXUZu5XNg00Yf5O3UHWOXg3-f_pzKjjoZYMOa-MOJc,2216
@@ -152,12 +152,6 @@ bec_widgets/widgets/colormap_selector/colormap_selector.pyproject,sha256=lHl9qml
152
152
  bec_widgets/widgets/colormap_selector/colormap_selector_plugin.py,sha256=NWTldO9XMyyOVL0No-Bmr-tvWrinmU7LkDxB5LkIQtA,1416
153
153
  bec_widgets/widgets/colormap_selector/register_colormap_selector.py,sha256=bfw7RWmTmMLTLxGT-izSwcGtxGLKvL3jdivJw2z8oN4,512
154
154
  bec_widgets/widgets/console/console.py,sha256=NG0cBuqqPX4hC-sHhk_UEkT-nHhhN9Y7karJITPLzyo,17864
155
- bec_widgets/widgets/device_box/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
156
- bec_widgets/widgets/device_box/device_box.py,sha256=2hWCbDaBvYnWK4-HDqeYetzb5KR4DBk7UPQJMLhT4w0,6929
157
- bec_widgets/widgets/device_box/device_box.pyproject,sha256=jtwvhaySJRdnuV99mEZT3htmWKVLphFeetEW4al7s-o,28
158
- bec_widgets/widgets/device_box/device_box.ui,sha256=z7j60J4ZKYjH9eyHl6FnZ_Z8lkdq1LQftxveSZQ6g_w,4865
159
- bec_widgets/widgets/device_box/device_box_plugin.py,sha256=ASTAEgBDKFERLT4IamuFHffe0pET6CgyjjPOD814q1A,1395
160
- bec_widgets/widgets/device_box/register_device_box.py,sha256=K7Hx4FIQDXasejaw6njwkFkkkwk63Smm6pHoOEdLWPw,467
161
155
  bec_widgets/widgets/device_combobox/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
162
156
  bec_widgets/widgets/device_combobox/device_combo_box.pyproject,sha256=wI2eXR5ky_IM9-BCHJnH_9CEqYcZwIuLcgitSEr8OJU,40
163
157
  bec_widgets/widgets/device_combobox/device_combo_box_plugin.py,sha256=py1VYOpy0gTpdQ9eCut1dxMSfF0ckAwO5qT8ZDNkSts,1439
@@ -170,7 +164,7 @@ bec_widgets/widgets/device_line_edit/device_line_edit_plugin.py,sha256=RPtGVPLad
170
164
  bec_widgets/widgets/device_line_edit/register_device_line_edit.py,sha256=8gEPnC8djYCw-idoZAENNB3bPOxM6pbzEp9A366EAGg,489
171
165
  bec_widgets/widgets/dock/__init__.py,sha256=B7foHt02gnhM7mFksa7GJVwT7n0j_JvYDCt6wc6XR5g,61
172
166
  bec_widgets/widgets/dock/dock.py,sha256=hQw5tpGrRbybjfF-aVEAeGdLTudtH4kFa70flu6_ZA8,10349
173
- bec_widgets/widgets/dock/dock_area.py,sha256=mHF8TPHnUl4x0ZWLQhgXF9Ca7uUBKD6ggMUIchjsisA,13559
167
+ bec_widgets/widgets/dock/dock_area.py,sha256=VfKyMxKo-r1Ugu2xjSsfGMYZUg3i3xxaokaZCFcCoxA,13579
174
168
  bec_widgets/widgets/dock/dock_area.pyproject,sha256=URW0UrDXCnkzk80rbQmUMgF6Uqay2TjHsq8Dq0g1j-c,37
175
169
  bec_widgets/widgets/dock/dock_area_plugin.py,sha256=oG2zDxUA1YLvSBoFVeFVkz4HIWLruAwOsCZ00H2Z70A,1345
176
170
  bec_widgets/widgets/dock/register_dock_area.py,sha256=Yqd1mq6CcHwlxHZxX5EHKONy4P44nMm8pso-4X0tvJI,464
@@ -209,6 +203,12 @@ bec_widgets/widgets/position_indicator/position_indicator.py,sha256=QVlWvs_RvEJe
209
203
  bec_widgets/widgets/position_indicator/position_indicator.pyproject,sha256=s0JEf5YkpMag19ddFSYeRZ8erBau7erO3bqw05YrTyg,36
210
204
  bec_widgets/widgets/position_indicator/position_indicator_plugin.py,sha256=xD8YyATYfpoHxGVcsecDKx9CLASAP6lKyypCEjRhNd0,1441
211
205
  bec_widgets/widgets/position_indicator/register_position_indicator.py,sha256=OZNiMgM_80TPSAXK_0hXAkne4vUh8DGvh_OdpOiMpwI,516
206
+ bec_widgets/widgets/positioner_box/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
207
+ bec_widgets/widgets/positioner_box/positioner_box.py,sha256=nD_Nlk6-Q6rUWlhoGZ_IpF7PJwdZqumTnoBSKFYM-XI,9437
208
+ bec_widgets/widgets/positioner_box/positioner_box.pyproject,sha256=7966pHdDseaHciaPNEKgdQgbUThSZf5wEDCeAEJh9po,32
209
+ bec_widgets/widgets/positioner_box/positioner_box.ui,sha256=Odvy2uFKt2guLmBQo8ZVX_32fkkHCAbBvGRlYr_dsu4,5318
210
+ bec_widgets/widgets/positioner_box/positioner_box_plugin.py,sha256=-zv5LuUEp2lNwQ8G-vaBoxJHOKGn7WZpTQn5LD_M5Lk,1237
211
+ bec_widgets/widgets/positioner_box/register_positioner_box.py,sha256=UPOUjXXq6-IgSj0kdV_nJe1rYPMF8aIZxF4eSmWgQAg,483
212
212
  bec_widgets/widgets/ring_progress_bar/__init__.py,sha256=_uoJKnDM2YAeUBfwc5WLbIHSJj7zm_FAurSKP3WRaCw,47
213
213
  bec_widgets/widgets/ring_progress_bar/register_ring_progress_bar.py,sha256=uJrMhkuQi2PdWa0BwFJqjVXSkO-TXoyai4EQYOOe9t4,493
214
214
  bec_widgets/widgets/ring_progress_bar/ring.py,sha256=2pdEzETaJpvx4Dzyosq2YhnvDOEUvFnj_f9GfFKpG5Q,11159
@@ -328,7 +328,7 @@ tests/unit_tests/client_mocks.py,sha256=4pS4KvvFGY9hjphds9i-GoIjVWVkax4XpDnVp6Mc
328
328
  tests/unit_tests/conftest.py,sha256=EE5RX_xR50ELJPgT2kny9rM1NCmCRO22sd_L9fvVSEk,1917
329
329
  tests/unit_tests/test_bec_connector.py,sha256=5uqBfjgMeOlGvqJlFbytxEpZ1El7_Y2q8fZHh4GvtD8,2478
330
330
  tests/unit_tests/test_bec_dispatcher.py,sha256=rYPiRizHaswhGZw55IBMneDFxmPiCCLAZQBqjEkpdyY,3992
331
- tests/unit_tests/test_bec_dock.py,sha256=oxOGzeHUmyxYI7eDOnvnhVeFNPRTlo8fjpHXMmPiS1s,5574
331
+ tests/unit_tests/test_bec_dock.py,sha256=iZcyF6tjNHstFx0rtbI8zhvFvgQiOpb_CuOF-L6Dipc,5610
332
332
  tests/unit_tests/test_bec_figure.py,sha256=oTlwHgDSrE4QRN3i9ZRM3QT2Xt8jfOyUTNxIZqZ4WKQ,9780
333
333
  tests/unit_tests/test_bec_image.py,sha256=Bc9eaLDk_9MfVFC6BZ-dymf-bQZg_CHL810nssXsj_k,2814
334
334
  tests/unit_tests/test_bec_image_widget.py,sha256=eU7uhKTQSf1Q5uV6EjsuUpf_oiMLNrZ1m10DjeQae0Y,7459
@@ -339,7 +339,6 @@ tests/unit_tests/test_client_utils.py,sha256=CBdWIVJ_UiyFzTJnX3XJm4PGw2uXhFvRCP_
339
339
  tests/unit_tests/test_color_map_selector.py,sha256=dTsizpT7TUpX2AEWIc0v09KPOryhWepFXFI9duQ3NF8,1497
340
340
  tests/unit_tests/test_color_validation.py,sha256=xbFbtFDia36XLgaNrX2IwvAX3IDC_Odpj5BGoJSgiIE,2389
341
341
  tests/unit_tests/test_crosshair.py,sha256=3OMAJ2ZaISYXMOtkXf1rPdy94vCr8njeLi6uHblBL9Q,5045
342
- tests/unit_tests/test_device_box.py,sha256=q9IVFpt1NF3TBF0Jhk-I-LRiuvvHG3FGUalw4jEYwVo,3431
343
342
  tests/unit_tests/test_device_input_base.py,sha256=LY-3adMb2xM9pBiP6V2bAJF_65csCe2Xfaq5ArVEE1E,2859
344
343
  tests/unit_tests/test_device_input_widgets.py,sha256=Y3mc_EaeQAPxpj6DijvxLLyMPSxnaNN86KhIL4ASO3E,5821
345
344
  tests/unit_tests/test_error_utils.py,sha256=LQOxz29WCGOe0qwFkaPDixjUmdnF3qeAGxD4A3t9IKg,2108
@@ -348,6 +347,7 @@ tests/unit_tests/test_generate_plugin.py,sha256=9603ucZChM-pYpHadzsR94U1Zec1KZT3
348
347
  tests/unit_tests/test_motor_map_widget.py,sha256=j3Vv_jNTsJTg6UgtwoxFp-Qwi_1blT9HK-USALPgxSI,7469
349
348
  tests/unit_tests/test_plot_base.py,sha256=evejmkYBBAu9f5XoA4dpYGPRGR5lIc3JqN4UQdGRY3Q,4134
350
349
  tests/unit_tests/test_plugin_utils.py,sha256=ayksWdrFY7kOiA0wVEjKFmFCF3UhH3lG8tzPVOpwysk,528
350
+ tests/unit_tests/test_positioner_box.py,sha256=Uc8d3rfgo74b-S53xglQr1HIXNBIKJIE5y5lkSSVZeg,3919
351
351
  tests/unit_tests/test_ring_progress_bar.py,sha256=Q-hbRPj44Oa3RLJayQGNUKTnsDllk6j4sJwyJdDudT4,12233
352
352
  tests/unit_tests/test_rpc_register.py,sha256=hECjZEimd440mwRrO0rg7L3PKN7__3DgjmESN6wx3bo,1179
353
353
  tests/unit_tests/test_rpc_server.py,sha256=MvstcvqUsnGAzUxw8Et1xXXikk_VIxFPwDZD0v1QGkg,1500
@@ -370,8 +370,8 @@ tests/unit_tests/test_configs/config_device_no_entry.yaml,sha256=hdvue9KLc_kfNzG
370
370
  tests/unit_tests/test_configs/config_scan.yaml,sha256=vo484BbWOjA_e-h6bTjSV9k7QaQHrlAvx-z8wtY-P4E,1915
371
371
  tests/unit_tests/test_msgs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
372
372
  tests/unit_tests/test_msgs/available_scans_message.py,sha256=m_z97hIrjHXXMa2Ex-UvsPmTxOYXfjxyJaGkIY6StTY,46532
373
- bec_widgets-0.93.3.dist-info/METADATA,sha256=_VblxDpuCc284m1SFf95vKgTaR-Jng60jurwZViD06c,1307
374
- bec_widgets-0.93.3.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
375
- bec_widgets-0.93.3.dist-info/entry_points.txt,sha256=3otEkCdDB9LZJuBLzG4pFLK5Di0CVybN_12IsZrQ-58,166
376
- bec_widgets-0.93.3.dist-info/licenses/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
377
- bec_widgets-0.93.3.dist-info/RECORD,,
373
+ bec_widgets-0.93.4.dist-info/METADATA,sha256=xpE3WACvw9YH_nuy0jPV4Z6i7pmskaF_vKGawCZmRj4,1307
374
+ bec_widgets-0.93.4.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
375
+ bec_widgets-0.93.4.dist-info/entry_points.txt,sha256=3otEkCdDB9LZJuBLzG4pFLK5Di0CVybN_12IsZrQ-58,166
376
+ bec_widgets-0.93.4.dist-info/licenses/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
377
+ bec_widgets-0.93.4.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.93.3"
7
+ version = "0.93.4"
8
8
  description = "BEC Widgets"
9
9
  requires-python = ">=3.10"
10
10
  classifiers = [
@@ -127,10 +127,12 @@ def test_toolbar_add_plot_motor_map(bec_dock_area):
127
127
  assert bec_dock_area.panels["motor_map_1"].widgets[0].config.widget_class == "BECMotorMapWidget"
128
128
 
129
129
 
130
- def test_toolbar_add_device_device_box(bec_dock_area):
131
- bec_dock_area.toolbar.widgets["menu_devices"].widgets["device_box"].trigger()
132
- assert "device_box_1" in bec_dock_area.panels
133
- assert bec_dock_area.panels["device_box_1"].widgets[0].config.widget_class == "DeviceBox"
130
+ def test_toolbar_add_device_positioner_box(bec_dock_area):
131
+ bec_dock_area.toolbar.widgets["menu_devices"].widgets["positioner_box"].trigger()
132
+ assert "positioner_box_1" in bec_dock_area.panels
133
+ assert (
134
+ bec_dock_area.panels["positioner_box_1"].widgets[0].config.widget_class == "PositionerBox"
135
+ )
134
136
 
135
137
 
136
138
  def test_toolbar_add_utils_queue(bec_dock_area):
@@ -0,0 +1,104 @@
1
+ from unittest import mock
2
+
3
+ import pytest
4
+ from bec_lib.device import Positioner
5
+ from bec_lib.endpoints import MessageEndpoints
6
+ from bec_lib.messages import ScanQueueMessage
7
+ from qtpy.QtGui import QValidator
8
+
9
+ from bec_widgets.widgets.positioner_box.positioner_box import PositionerBox
10
+
11
+ from .client_mocks import mocked_client
12
+
13
+
14
+ @pytest.fixture
15
+ def positioner_box(qtbot, mocked_client):
16
+ with mock.patch("bec_widgets.widgets.positioner_box.positioner_box.uuid.uuid4") as mock_uuid:
17
+ mock_uuid.return_value = "fake_uuid"
18
+ with mock.patch(
19
+ "bec_widgets.widgets.positioner_box.positioner_box.PositionerBox._check_device_is_valid",
20
+ return_value=True,
21
+ ):
22
+ db = PositionerBox(device="samx", client=mocked_client)
23
+ qtbot.addWidget(db)
24
+ yield db
25
+
26
+
27
+ def test_positioner_box(positioner_box):
28
+ assert positioner_box.device == "samx"
29
+ data = positioner_box.dev["samx"].read()
30
+ # Avoid check for Positioner class from BEC in _init_device
31
+
32
+ setpoint_text = positioner_box.ui.setpoint.text()
33
+ # check that the setpoint is taken correctly after init
34
+ assert float(setpoint_text) == data["samx_setpoint"]["value"]
35
+
36
+ # check that the precision is taken correctly after isnit
37
+ precision = positioner_box.dev["samx"].precision
38
+ assert setpoint_text == f"{data['samx_setpoint']['value']:.{precision}f}"
39
+
40
+ # check that the step size is set according to the device precision
41
+ assert positioner_box.ui.step_size.value() == 10**-precision * 10
42
+
43
+
44
+ def test_positioner_box_update_limits(positioner_box):
45
+ positioner_box._limits = None
46
+ positioner_box.update_limits([0, 10])
47
+ assert positioner_box._limits == [0, 10]
48
+ assert positioner_box.setpoint_validator.bottom() == 0
49
+ assert positioner_box.setpoint_validator.top() == 10
50
+ assert positioner_box.setpoint_validator.validate("100", 0) == (
51
+ QValidator.State.Intermediate,
52
+ "100",
53
+ 0,
54
+ )
55
+
56
+ positioner_box.update_limits(None)
57
+ assert positioner_box._limits is None
58
+ assert positioner_box.setpoint_validator.validate("100", 0) == (
59
+ QValidator.State.Acceptable,
60
+ "100",
61
+ 0,
62
+ )
63
+
64
+
65
+ def test_positioner_box_on_stop(positioner_box):
66
+ with mock.patch.object(positioner_box.client.connector, "send") as mock_send:
67
+ positioner_box.on_stop()
68
+ params = {"device": "samx", "rpc_id": "fake_uuid", "func": "stop", "args": [], "kwargs": {}}
69
+ msg = ScanQueueMessage(
70
+ scan_type="device_rpc",
71
+ parameter=params,
72
+ queue="emergency",
73
+ metadata={"RID": "fake_uuid", "response": False},
74
+ )
75
+ mock_send.assert_called_once_with(MessageEndpoints.scan_queue_request(), msg)
76
+
77
+
78
+ def test_positioner_box_setpoint_change(positioner_box):
79
+ with mock.patch.object(positioner_box.dev["samx"], "move") as mock_move:
80
+ positioner_box.ui.setpoint.setText("100")
81
+ positioner_box.on_setpoint_change()
82
+ mock_move.assert_called_once_with(100, relative=False)
83
+
84
+
85
+ def test_positioner_box_on_tweak_right(positioner_box):
86
+ with mock.patch.object(positioner_box.dev["samx"], "move") as mock_move:
87
+ positioner_box.ui.step_size.setValue(0.1)
88
+ positioner_box.on_tweak_right()
89
+ mock_move.assert_called_once_with(0.1, relative=True)
90
+
91
+
92
+ def test_positioner_box_on_tweak_left(positioner_box):
93
+ with mock.patch.object(positioner_box.dev["samx"], "move") as mock_move:
94
+ positioner_box.ui.step_size.setValue(0.1)
95
+ positioner_box.on_tweak_left()
96
+ mock_move.assert_called_once_with(-0.1, relative=True)
97
+
98
+
99
+ def test_positioner_box_setpoint_out_of_range(positioner_box):
100
+ positioner_box.update_limits([0, 10])
101
+ positioner_box.ui.setpoint.setText("100")
102
+ positioner_box.on_setpoint_change()
103
+ assert positioner_box.ui.setpoint.text() == "100"
104
+ assert positioner_box.ui.setpoint.hasAcceptableInput() == False
@@ -1 +0,0 @@
1
- {'files': ['device_box.py']}
@@ -1,98 +0,0 @@
1
- from unittest import mock
2
-
3
- import pytest
4
- from bec_lib.endpoints import MessageEndpoints
5
- from bec_lib.messages import ScanQueueMessage
6
- from qtpy.QtGui import QValidator
7
-
8
- from bec_widgets.widgets.device_box.device_box import DeviceBox
9
-
10
- from .client_mocks import mocked_client
11
-
12
-
13
- @pytest.fixture
14
- def device_box(qtbot, mocked_client):
15
- with mock.patch("bec_widgets.widgets.device_box.device_box.uuid.uuid4") as mock_uuid:
16
- mock_uuid.return_value = "fake_uuid"
17
- db = DeviceBox(device="samx", client=mocked_client)
18
- qtbot.addWidget(db)
19
- yield db
20
-
21
-
22
- def test_device_box(device_box):
23
- assert device_box.device == "samx"
24
- data = device_box.dev["samx"].read()
25
-
26
- setpoint_text = device_box.ui.setpoint.text()
27
- # check that the setpoint is taken correctly after init
28
- assert float(setpoint_text) == data["samx_setpoint"]["value"]
29
-
30
- # check that the precision is taken correctly after init
31
- precision = device_box.dev["samx"].precision
32
- assert setpoint_text == f"{data['samx_setpoint']['value']:.{precision}f}"
33
-
34
- # check that the step size is set according to the device precision
35
- assert device_box.ui.step_size.value() == 10**-precision * 10
36
-
37
-
38
- def test_device_box_update_limits(device_box):
39
- device_box._limits = None
40
- device_box.update_limits([0, 10])
41
- assert device_box._limits == [0, 10]
42
- assert device_box.setpoint_validator.bottom() == 0
43
- assert device_box.setpoint_validator.top() == 10
44
- assert device_box.setpoint_validator.validate("100", 0) == (
45
- QValidator.State.Intermediate,
46
- "100",
47
- 0,
48
- )
49
-
50
- device_box.update_limits(None)
51
- assert device_box._limits is None
52
- assert device_box.setpoint_validator.validate("100", 0) == (
53
- QValidator.State.Acceptable,
54
- "100",
55
- 0,
56
- )
57
-
58
-
59
- def test_device_box_on_stop(device_box):
60
- with mock.patch.object(device_box.client.connector, "send") as mock_send:
61
- device_box.on_stop()
62
- params = {"device": "samx", "rpc_id": "fake_uuid", "func": "stop", "args": [], "kwargs": {}}
63
- msg = ScanQueueMessage(
64
- scan_type="device_rpc",
65
- parameter=params,
66
- queue="emergency",
67
- metadata={"RID": "fake_uuid", "response": False},
68
- )
69
- mock_send.assert_called_once_with(MessageEndpoints.scan_queue_request(), msg)
70
-
71
-
72
- def test_device_box_setpoint_change(device_box):
73
- with mock.patch.object(device_box.dev["samx"], "move") as mock_move:
74
- device_box.ui.setpoint.setText("100")
75
- device_box.on_setpoint_change()
76
- mock_move.assert_called_once_with(100, relative=False)
77
-
78
-
79
- def test_device_box_on_tweak_right(device_box):
80
- with mock.patch.object(device_box.dev["samx"], "move") as mock_move:
81
- device_box.ui.step_size.setValue(0.1)
82
- device_box.on_tweak_right()
83
- mock_move.assert_called_once_with(0.1, relative=True)
84
-
85
-
86
- def test_device_box_on_tweak_left(device_box):
87
- with mock.patch.object(device_box.dev["samx"], "move") as mock_move:
88
- device_box.ui.step_size.setValue(0.1)
89
- device_box.on_tweak_left()
90
- mock_move.assert_called_once_with(-0.1, relative=True)
91
-
92
-
93
- def test_device_box_setpoint_out_of_range(device_box):
94
- device_box.update_limits([0, 10])
95
- device_box.ui.setpoint.setText("100")
96
- device_box.on_setpoint_change()
97
- assert device_box.ui.setpoint.text() == "100"
98
- assert device_box.ui.setpoint.hasAcceptableInput() == False