bec-widgets 1.0.1__py3-none-any.whl → 1.1.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.
Files changed (36) hide show
  1. CHANGELOG.md +26 -24
  2. PKG-INFO +1 -1
  3. bec_widgets/applications/alignment/alignment_1d/alignment_1d.ui +60 -84
  4. bec_widgets/cli/client.py +56 -0
  5. bec_widgets/tests/__init__.py +0 -0
  6. bec_widgets/tests/utils.py +226 -0
  7. bec_widgets/utils/filter_io.py +156 -0
  8. bec_widgets/utils/widget_io.py +12 -9
  9. bec_widgets/widgets/base_classes/device_input_base.py +331 -62
  10. bec_widgets/widgets/base_classes/device_signal_input_base.py +280 -0
  11. bec_widgets/widgets/dap_combo_box/dap_combo_box_plugin.py +1 -1
  12. bec_widgets/widgets/device_combobox/device_combo_box_plugin.py +1 -1
  13. bec_widgets/widgets/device_combobox/device_combobox.py +118 -41
  14. bec_widgets/widgets/device_line_edit/device_line_edit.py +122 -59
  15. bec_widgets/widgets/device_line_edit/device_line_edit_plugin.py +1 -1
  16. bec_widgets/widgets/image/image_widget.py +7 -1
  17. bec_widgets/widgets/motor_map/motor_map_widget.py +4 -2
  18. bec_widgets/widgets/positioner_box/positioner_box.py +4 -1
  19. bec_widgets/widgets/scan_control/scan_control.py +2 -3
  20. bec_widgets/widgets/scan_control/scan_group_box.py +3 -1
  21. bec_widgets/widgets/signal_combobox/__init__.py +0 -0
  22. bec_widgets/widgets/signal_combobox/register_signal_combobox.py +15 -0
  23. bec_widgets/widgets/signal_combobox/signal_combobox.py +115 -0
  24. bec_widgets/widgets/signal_combobox/signal_combobox.pyproject +1 -0
  25. bec_widgets/widgets/signal_combobox/signal_combobox_plugin.py +54 -0
  26. bec_widgets/widgets/signal_line_edit/__init__.py +0 -0
  27. bec_widgets/widgets/signal_line_edit/register_signal_line_edit.py +15 -0
  28. bec_widgets/widgets/signal_line_edit/signal_line_edit.py +140 -0
  29. bec_widgets/widgets/signal_line_edit/signal_line_edit.pyproject +1 -0
  30. bec_widgets/widgets/signal_line_edit/signal_line_edit_plugin.py +54 -0
  31. {bec_widgets-1.0.1.dist-info → bec_widgets-1.1.0.dist-info}/METADATA +1 -1
  32. {bec_widgets-1.0.1.dist-info → bec_widgets-1.1.0.dist-info}/RECORD +36 -22
  33. pyproject.toml +1 -1
  34. {bec_widgets-1.0.1.dist-info → bec_widgets-1.1.0.dist-info}/WHEEL +0 -0
  35. {bec_widgets-1.0.1.dist-info → bec_widgets-1.1.0.dist-info}/entry_points.txt +0 -0
  36. {bec_widgets-1.0.1.dist-info → bec_widgets-1.1.0.dist-info}/licenses/LICENSE +0 -0
CHANGELOG.md CHANGED
@@ -1,6 +1,32 @@
1
1
  # CHANGELOG
2
2
 
3
3
 
4
+ ## v1.1.0 (2024-10-25)
5
+
6
+ ### Features
7
+
8
+ * feat: add filter i/o utility class ([`0350833`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/0350833f36e0a7cadce4173f9b1d1fbfdf985375))
9
+
10
+ ### Refactoring
11
+
12
+ * refactor: do not flush selection upon receiving config update; allow widgetIO to receive kwargs to be able to use get_value to receive string instead of int for QComboBox ([`91959e8`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/91959e82de8586934af3ebb5aaa0923930effc51))
13
+
14
+ * refactor: allow to set selection in DeviceInput; automatic update of selection on device config update; cleanup ([`5eb15b7`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/5eb15b785f12e30eb8ccbc56d4ad9e759a4cf5eb))
15
+
16
+ * refactor: cleanup, added device_signal for signal inputs ([`6fb2055`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6fb20552ff57978f4aeb79fd7f062f8d6b5581e7))
17
+
18
+ ### Testing
19
+
20
+ * test(scan_control): tests added for grid_scan to ensure scan_args signal validity ([`acb7902`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/acb79020d4be546efc001ff47b6f5cdba2ee9375))
21
+
22
+
23
+ ## v1.0.2 (2024-10-22)
24
+
25
+ ### Bug Fixes
26
+
27
+ * fix(scan_control): scan args signal fixed to emit list instead of hardcoded structure ([`4f5448c`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/4f5448cf51a204e077af162c7f0aed1f1a60e57a))
28
+
29
+
4
30
  ## v1.0.1 (2024-10-22)
5
31
 
6
32
  ### Bug Fixes
@@ -144,30 +170,6 @@ is emitted multiple times. ([`f084e25`](https://gitlab.psi.ch/bec/bec_widgets/-/
144
170
 
145
171
  ## v0.113.0 (2024-10-02)
146
172
 
147
- ### Bug Fixes
148
-
149
- * fix: add is_log checks and functionality to plot_indicator_items ([`0f9953e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/0f9953e8fdcf3f9b5a09f994c69edb6b34756df9))
150
-
151
- ### Features
152
-
153
- * feat: add first draft for alignment_1d GUI ([`63c24f9`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/63c24f97a355edaa928b6e222909252b276bcada))
154
-
155
- * feat: add move to position button to lmfit dialog ([`281cb27`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/281cb27d8b5433e27a7ba0ca0a19e4b45b9c544f))
156
-
157
- ### Refactoring
158
-
159
- * refactor: various minor improvements for the alignment gui ([`f554f3c`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/f554f3c1672c4fe32968a5991dc98802556a6f3b))
160
-
161
- * refactor: allow hiding of arg/kwarg boxes ([`efe90eb`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/efe90eb163e2123a5b4d0bb59f66025a569336ad))
162
-
163
- * refactor: add proxy to waveform to limit the dap_request frequency ([`5c74037`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/5c740371d86d9b1b341bc3c4d8bdf62027aa089b))
164
-
165
- * refactor: update dap_model also if x and y axis are selected ([`28ee385`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/28ee3856be2c47a63182b16454ece37a0ec04811))
166
-
167
173
  ### Testing
168
174
 
169
175
  * test: add tests for scan_status_callback ([`dc0c825`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/dc0c825fd594c093a24543ff803d6c6564010e92))
170
-
171
- ### Unknown
172
-
173
- * feat : Add bec_signal_proxy to handle signals with option to unblock them manually. ([`1dcfeb6`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/1dcfeb6cfce3c69f0c5401731d4d3f9a1981b22e))
PKG-INFO CHANGED
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bec_widgets
3
- Version: 1.0.1
3
+ Version: 1.1.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
@@ -215,42 +215,18 @@
215
215
  <layout class="QVBoxLayout" name="verticalLayout_3">
216
216
  <item>
217
217
  <widget class="ScanControl" name="scan_control">
218
- <property name="sizePolicy">
219
- <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
220
- <horstretch>1</horstretch>
221
- <verstretch>0</verstretch>
222
- </sizepolicy>
223
- </property>
224
- <property name="minimumSize">
225
- <size>
226
- <width>0</width>
227
- <height>0</height>
228
- </size>
229
- </property>
230
218
  <property name="current_scan" stdset="0">
231
219
  <string>line_scan</string>
232
220
  </property>
233
221
  <property name="hide_arg_box" stdset="0">
234
222
  <bool>false</bool>
235
223
  </property>
236
- <property name="hide_kwarg_boxes" stdset="0">
237
- <bool>false</bool>
238
- </property>
239
- <property name="hide_scan_control_buttons" stdset="0">
240
- <bool>false</bool>
241
- </property>
242
224
  <property name="hide_scan_selection_combobox" stdset="0">
243
225
  <bool>true</bool>
244
226
  </property>
245
227
  <property name="hide_add_remove_buttons" stdset="0">
246
228
  <bool>true</bool>
247
229
  </property>
248
- <property name="hide_args_group" stdset="0">
249
- <bool>false</bool>
250
- </property>
251
- <property name="hide_kwargs_group" stdset="0">
252
- <bool>false</bool>
253
- </property>
254
230
  </widget>
255
231
  </item>
256
232
  <item>
@@ -440,54 +416,54 @@
440
416
  </widget>
441
417
  <customwidgets>
442
418
  <customwidget>
443
- <class>ToggleSwitch</class>
419
+ <class>DapComboBox</class>
444
420
  <extends>QWidget</extends>
445
- <header>toggle_switch</header>
421
+ <header>dap_combo_box</header>
446
422
  </customwidget>
447
423
  <customwidget>
448
- <class>BECWaveformWidget</class>
424
+ <class>StopButton</class>
449
425
  <extends>QWidget</extends>
450
- <header>bec_waveform_widget</header>
426
+ <header>stop_button</header>
451
427
  </customwidget>
452
428
  <customwidget>
453
- <class>BECStatusBox</class>
429
+ <class>WebsiteWidget</class>
454
430
  <extends>QWidget</extends>
455
- <header>bec_status_box</header>
431
+ <header>website_widget</header>
456
432
  </customwidget>
457
433
  <customwidget>
458
- <class>WebsiteWidget</class>
434
+ <class>BECQueue</class>
459
435
  <extends>QWidget</extends>
460
- <header>website_widget</header>
436
+ <header>bec_queue</header>
461
437
  </customwidget>
462
438
  <customwidget>
463
- <class>StopButton</class>
439
+ <class>ScanControl</class>
464
440
  <extends>QWidget</extends>
465
- <header>stop_button</header>
441
+ <header>scan_control</header>
466
442
  </customwidget>
467
443
  <customwidget>
468
- <class>LMFitDialog</class>
444
+ <class>ToggleSwitch</class>
469
445
  <extends>QWidget</extends>
470
- <header>lm_fit_dialog</header>
446
+ <header>toggle_switch</header>
471
447
  </customwidget>
472
448
  <customwidget>
473
- <class>PositionerGroup</class>
449
+ <class>BECProgressBar</class>
474
450
  <extends>QWidget</extends>
475
- <header>positioner_group</header>
451
+ <header>bec_progress_bar</header>
476
452
  </customwidget>
477
453
  <customwidget>
478
- <class>ScanControl</class>
454
+ <class>DarkModeButton</class>
479
455
  <extends>QWidget</extends>
480
- <header>scan_control</header>
456
+ <header>dark_mode_button</header>
481
457
  </customwidget>
482
458
  <customwidget>
483
- <class>BECQueue</class>
459
+ <class>PositionerGroup</class>
484
460
  <extends>QWidget</extends>
485
- <header>bec_queue</header>
461
+ <header>positioner_group</header>
486
462
  </customwidget>
487
463
  <customwidget>
488
- <class>BECProgressBar</class>
464
+ <class>BECWaveformWidget</class>
489
465
  <extends>QWidget</extends>
490
- <header>bec_progress_bar</header>
466
+ <header>bec_waveform_widget</header>
491
467
  </customwidget>
492
468
  <customwidget>
493
469
  <class>DeviceComboBox</class>
@@ -495,14 +471,14 @@
495
471
  <header>device_combobox</header>
496
472
  </customwidget>
497
473
  <customwidget>
498
- <class>DarkModeButton</class>
474
+ <class>LMFitDialog</class>
499
475
  <extends>QWidget</extends>
500
- <header>dark_mode_button</header>
476
+ <header>lm_fit_dialog</header>
501
477
  </customwidget>
502
478
  <customwidget>
503
- <class>DapComboBox</class>
479
+ <class>BECStatusBox</class>
504
480
  <extends>QWidget</extends>
505
- <header>dap_combo_box</header>
481
+ <header>bec_status_box</header>
506
482
  </customwidget>
507
483
  </customwidgets>
508
484
  <resources/>
@@ -514,12 +490,12 @@
514
490
  <slot>toogle_roi_select(bool)</slot>
515
491
  <hints>
516
492
  <hint type="sourcelabel">
517
- <x>529</x>
518
- <y>728</y>
493
+ <x>1042</x>
494
+ <y>212</y>
519
495
  </hint>
520
496
  <hint type="destinationlabel">
521
- <x>1099</x>
522
- <y>96</y>
497
+ <x>1416</x>
498
+ <y>322</y>
523
499
  </hint>
524
500
  </hints>
525
501
  </connection>
@@ -546,12 +522,12 @@
546
522
  <slot>plot(QString)</slot>
547
523
  <hints>
548
524
  <hint type="sourcelabel">
549
- <x>297</x>
550
- <y>170</y>
525
+ <x>577</x>
526
+ <y>215</y>
551
527
  </hint>
552
528
  <hint type="destinationlabel">
553
- <x>1099</x>
554
- <y>201</y>
529
+ <x>1416</x>
530
+ <y>427</y>
555
531
  </hint>
556
532
  </hints>
557
533
  </connection>
@@ -562,12 +538,12 @@
562
538
  <slot>select_y_axis(QString)</slot>
563
539
  <hints>
564
540
  <hint type="sourcelabel">
565
- <x>297</x>
566
- <y>170</y>
541
+ <x>577</x>
542
+ <y>215</y>
567
543
  </hint>
568
544
  <hint type="destinationlabel">
569
- <x>467</x>
570
- <y>170</y>
545
+ <x>909</x>
546
+ <y>215</y>
571
547
  </hint>
572
548
  </hints>
573
549
  </connection>
@@ -578,60 +554,60 @@
578
554
  <slot>add_dap(QString,QString,QString)</slot>
579
555
  <hints>
580
556
  <hint type="sourcelabel">
581
- <x>467</x>
582
- <y>170</y>
557
+ <x>909</x>
558
+ <y>215</y>
583
559
  </hint>
584
560
  <hint type="destinationlabel">
585
- <x>1099</x>
586
- <y>221</y>
561
+ <x>1416</x>
562
+ <y>447</y>
587
563
  </hint>
588
564
  </hints>
589
565
  </connection>
590
566
  <connection>
591
567
  <sender>scan_control</sender>
592
- <signal>scan_axis(QString,double,double)</signal>
593
- <receiver>bec_waveform_widget</receiver>
594
- <slot>set_x(QString)</slot>
568
+ <signal>device_selected(QString)</signal>
569
+ <receiver>positioner_group</receiver>
570
+ <slot>set_positioners(QString)</slot>
595
571
  <hints>
596
572
  <hint type="sourcelabel">
597
- <x>244</x>
598
- <y>348</y>
573
+ <x>230</x>
574
+ <y>306</y>
599
575
  </hint>
600
576
  <hint type="destinationlabel">
601
- <x>1140</x>
602
- <y>491</y>
577
+ <x>187</x>
578
+ <y>926</y>
603
579
  </hint>
604
580
  </hints>
605
581
  </connection>
606
582
  <connection>
607
583
  <sender>scan_control</sender>
608
- <signal>scan_axis(QString,double,double)</signal>
609
- <receiver>dap_combo_box</receiver>
610
- <slot>select_x_axis(QString)</slot>
584
+ <signal>device_selected(QString)</signal>
585
+ <receiver>bec_waveform_widget</receiver>
586
+ <slot>set_x(QString)</slot>
611
587
  <hints>
612
588
  <hint type="sourcelabel">
613
- <x>244</x>
614
- <y>322</y>
589
+ <x>187</x>
590
+ <y>356</y>
615
591
  </hint>
616
592
  <hint type="destinationlabel">
617
- <x>909</x>
618
- <y>189</y>
593
+ <x>972</x>
594
+ <y>509</y>
619
595
  </hint>
620
596
  </hints>
621
597
  </connection>
622
598
  <connection>
623
599
  <sender>scan_control</sender>
624
600
  <signal>device_selected(QString)</signal>
625
- <receiver>positioner_group</receiver>
626
- <slot>set_positioners(QString)</slot>
601
+ <receiver>dap_combo_box</receiver>
602
+ <slot>select_x_axis(QString)</slot>
627
603
  <hints>
628
604
  <hint type="sourcelabel">
629
- <x>227</x>
630
- <y>337</y>
605
+ <x>187</x>
606
+ <y>356</y>
631
607
  </hint>
632
608
  <hint type="destinationlabel">
633
- <x>227</x>
634
- <y>676</y>
609
+ <x>794</x>
610
+ <y>202</y>
635
611
  </hint>
636
612
  </hints>
637
613
  </connection>
bec_widgets/cli/client.py CHANGED
@@ -38,6 +38,8 @@ class Widgets(str, enum.Enum):
38
38
  ResumeButton = "ResumeButton"
39
39
  RingProgressBar = "RingProgressBar"
40
40
  ScanControl = "ScanControl"
41
+ SignalComboBox = "SignalComboBox"
42
+ SignalLineEdit = "SignalLineEdit"
41
43
  StopButton = "StopButton"
42
44
  TextBox = "TextBox"
43
45
  VSCodeEditor = "VSCodeEditor"
@@ -2591,6 +2593,24 @@ class DeviceLineEdit(RPCBase):
2591
2593
  """
2592
2594
 
2593
2595
 
2596
+ class DeviceSignalInputBase(RPCBase):
2597
+ @property
2598
+ @rpc_call
2599
+ def _config_dict(self) -> "dict":
2600
+ """
2601
+ Get the configuration of the widget.
2602
+
2603
+ Returns:
2604
+ dict: The configuration of the widget.
2605
+ """
2606
+
2607
+ @rpc_call
2608
+ def _get_all_rpc(self) -> "dict":
2609
+ """
2610
+ Get all registered RPC objects.
2611
+ """
2612
+
2613
+
2594
2614
  class LMFitDialog(RPCBase):
2595
2615
  @property
2596
2616
  @rpc_call
@@ -3003,6 +3023,42 @@ class ScanControl(RPCBase):
3003
3023
  """
3004
3024
 
3005
3025
 
3026
+ class SignalComboBox(RPCBase):
3027
+ @property
3028
+ @rpc_call
3029
+ def _config_dict(self) -> "dict":
3030
+ """
3031
+ Get the configuration of the widget.
3032
+
3033
+ Returns:
3034
+ dict: The configuration of the widget.
3035
+ """
3036
+
3037
+ @rpc_call
3038
+ def _get_all_rpc(self) -> "dict":
3039
+ """
3040
+ Get all registered RPC objects.
3041
+ """
3042
+
3043
+
3044
+ class SignalLineEdit(RPCBase):
3045
+ @property
3046
+ @rpc_call
3047
+ def _config_dict(self) -> "dict":
3048
+ """
3049
+ Get the configuration of the widget.
3050
+
3051
+ Returns:
3052
+ dict: The configuration of the widget.
3053
+ """
3054
+
3055
+ @rpc_call
3056
+ def _get_all_rpc(self) -> "dict":
3057
+ """
3058
+ Get all registered RPC objects.
3059
+ """
3060
+
3061
+
3006
3062
  class StopButton(RPCBase):
3007
3063
  @property
3008
3064
  @rpc_call
File without changes
@@ -0,0 +1,226 @@
1
+ from unittest.mock import MagicMock
2
+
3
+ from bec_lib.device import Device as BECDevice
4
+ from bec_lib.device import Positioner as BECPositioner
5
+ from bec_lib.device import ReadoutPriority
6
+ from bec_lib.devicemanager import DeviceContainer
7
+
8
+
9
+ class FakeDevice(BECDevice):
10
+ """Fake minimal positioner class for testing."""
11
+
12
+ def __init__(self, name, enabled=True, readout_priority=ReadoutPriority.MONITORED):
13
+ super().__init__(name=name)
14
+ self._enabled = enabled
15
+ self.signals = {self.name: {"value": 1.0}}
16
+ self.description = {self.name: {"source": self.name, "dtype": "number", "shape": []}}
17
+ self._readout_priority = readout_priority
18
+ self._config = {
19
+ "readoutPriority": "baseline",
20
+ "deviceClass": "ophyd.Device",
21
+ "deviceConfig": {},
22
+ "deviceTags": ["user device"],
23
+ "enabled": enabled,
24
+ "readOnly": False,
25
+ "name": self.name,
26
+ }
27
+
28
+ @property
29
+ def readout_priority(self):
30
+ return self._readout_priority
31
+
32
+ @readout_priority.setter
33
+ def readout_priority(self, value):
34
+ self._readout_priority = value
35
+
36
+ @property
37
+ def limits(self) -> tuple[float, float]:
38
+ return self._limits
39
+
40
+ @limits.setter
41
+ def limits(self, value: tuple[float, float]):
42
+ self._limits = value
43
+
44
+ def __contains__(self, item):
45
+ return item == self.name
46
+
47
+ @property
48
+ def _hints(self):
49
+ return [self.name]
50
+
51
+ def set_value(self, fake_value: float = 1.0) -> None:
52
+ """
53
+ Setup fake value for device readout
54
+ Args:
55
+ fake_value(float): Desired fake value
56
+ """
57
+ self.signals[self.name]["value"] = fake_value
58
+
59
+ def describe(self) -> dict:
60
+ """
61
+ Get the description of the device
62
+ Returns:
63
+ dict: Description of the device
64
+ """
65
+ return self.description
66
+
67
+
68
+ class FakePositioner(BECPositioner):
69
+
70
+ def __init__(
71
+ self,
72
+ name,
73
+ enabled=True,
74
+ limits=None,
75
+ read_value=1.0,
76
+ readout_priority=ReadoutPriority.MONITORED,
77
+ ):
78
+ super().__init__(name=name)
79
+ # self.limits = limits if limits is not None else [0.0, 0.0]
80
+ self.read_value = read_value
81
+ self.setpoint_value = read_value
82
+ self.motor_is_moving_value = 0
83
+ self._enabled = enabled
84
+ self._limits = limits
85
+ self._readout_priority = readout_priority
86
+ self.signals = {self.name: {"value": 1.0}}
87
+ self.description = {self.name: {"source": self.name, "dtype": "number", "shape": []}}
88
+ self._config = {
89
+ "readoutPriority": "baseline",
90
+ "deviceClass": "ophyd_devices.SimPositioner",
91
+ "deviceConfig": {"delay": 1, "tolerance": 0.01, "update_frequency": 400},
92
+ "deviceTags": ["user motors"],
93
+ "enabled": enabled,
94
+ "readOnly": False,
95
+ "name": self.name,
96
+ }
97
+ self._info = {
98
+ "signals": {
99
+ "readback": {"kind_str": "5"}, # hinted
100
+ "setpoint": {"kind_str": "1"}, # normal
101
+ "velocity": {"kind_str": "2"}, # config
102
+ }
103
+ }
104
+ self.signals = {
105
+ self.name: {"value": self.read_value},
106
+ f"{self.name}_setpoint": {"value": self.setpoint_value},
107
+ f"{self.name}_motor_is_moving": {"value": self.motor_is_moving_value},
108
+ }
109
+
110
+ @property
111
+ def readout_priority(self):
112
+ return self._readout_priority
113
+
114
+ @readout_priority.setter
115
+ def readout_priority(self, value):
116
+ self._readout_priority = value
117
+
118
+ @property
119
+ def enabled(self) -> bool:
120
+ return self._enabled
121
+
122
+ @enabled.setter
123
+ def enabled(self, value: bool):
124
+ self._enabled = value
125
+
126
+ @property
127
+ def limits(self) -> tuple[float, float]:
128
+ return self._limits
129
+
130
+ @limits.setter
131
+ def limits(self, value: tuple[float, float]):
132
+ self._limits = value
133
+
134
+ def __contains__(self, item):
135
+ return item == self.name
136
+
137
+ @property
138
+ def _hints(self):
139
+ return [self.name]
140
+
141
+ def set_value(self, fake_value: float = 1.0) -> None:
142
+ """
143
+ Setup fake value for device readout
144
+ Args:
145
+ fake_value(float): Desired fake value
146
+ """
147
+ self.read_value = fake_value
148
+
149
+ def describe(self) -> dict:
150
+ """
151
+ Get the description of the device
152
+ Returns:
153
+ dict: Description of the device
154
+ """
155
+ return self.description
156
+
157
+ @property
158
+ def precision(self):
159
+ return 3
160
+
161
+ def set_read_value(self, value):
162
+ self.read_value = value
163
+
164
+ def read(self):
165
+ return self.signals
166
+
167
+ def set_limits(self, limits):
168
+ self.limits = limits
169
+
170
+ def move(self, value, relative=False):
171
+ """Simulates moving the device to a new position."""
172
+ if relative:
173
+ self.read_value += value
174
+ else:
175
+ self.read_value = value
176
+ # Respect the limits
177
+ self.read_value = max(min(self.read_value, self.limits[1]), self.limits[0])
178
+
179
+ @property
180
+ def readback(self):
181
+ return MagicMock(get=MagicMock(return_value=self.read_value))
182
+
183
+
184
+ class Positioner(FakePositioner):
185
+ """just placeholder for testing embedded isinstance check in DeviceCombobox"""
186
+
187
+ def __init__(self, name="test", limits=None, read_value=1.0):
188
+ super().__init__(name, limits, read_value)
189
+
190
+
191
+ class Device(FakeDevice):
192
+ """just placeholder for testing embedded isinstance check in DeviceCombobox"""
193
+
194
+ def __init__(self, name, enabled=True):
195
+ super().__init__(name, enabled)
196
+
197
+
198
+ class DMMock:
199
+ def __init__(self):
200
+ self.devices = DeviceContainer()
201
+ self.enabled_devices = [device for device in self.devices if device.enabled]
202
+
203
+ def add_devives(self, devices: list):
204
+ for device in devices:
205
+ self.devices[device.name] = device
206
+
207
+
208
+ DEVICES = [
209
+ FakePositioner("samx", limits=[-10, 10], read_value=2.0),
210
+ FakePositioner("samy", limits=[-5, 5], read_value=3.0),
211
+ FakePositioner("samz", limits=[-8, 8], read_value=4.0),
212
+ FakePositioner("aptrx", limits=None, read_value=4.0),
213
+ FakePositioner("aptry", limits=None, read_value=5.0),
214
+ FakeDevice("gauss_bpm"),
215
+ FakeDevice("gauss_adc1"),
216
+ FakeDevice("gauss_adc2"),
217
+ FakeDevice("gauss_adc3"),
218
+ FakeDevice("bpm4i"),
219
+ FakeDevice("bpm3a"),
220
+ FakeDevice("bpm3i"),
221
+ FakeDevice("eiger", readout_priority=ReadoutPriority.ASYNC),
222
+ FakeDevice("waveform1d"),
223
+ FakeDevice("async_device", readout_priority=ReadoutPriority.ASYNC),
224
+ Positioner("test", limits=[-10, 10], read_value=2.0),
225
+ Device("test_device"),
226
+ ]