bec-widgets 0.51.0__py3-none-any.whl → 0.52.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. bec_widgets/cli/__init__.py +1 -1
  2. bec_widgets/cli/bec_widgets_icon.png +0 -0
  3. bec_widgets/cli/client.py +213 -5
  4. bec_widgets/cli/client_utils.py +16 -5
  5. bec_widgets/cli/generate_cli.py +6 -3
  6. bec_widgets/cli/rpc_wigdet_handler.py +26 -0
  7. bec_widgets/cli/server.py +34 -9
  8. bec_widgets/examples/jupyter_console/jupyter_console_window.py +54 -2
  9. bec_widgets/examples/jupyter_console/jupyter_console_window.ui +26 -2
  10. bec_widgets/examples/jupyter_console/terminal_icon.png +0 -0
  11. bec_widgets/utils/__init__.py +1 -0
  12. bec_widgets/utils/bec_connector.py +11 -3
  13. bec_widgets/utils/layout_manager.py +117 -0
  14. bec_widgets/widgets/__init__.py +1 -0
  15. bec_widgets/widgets/dock/__init__.py +2 -0
  16. bec_widgets/widgets/dock/dock.py +269 -0
  17. bec_widgets/widgets/dock/dock_area.py +220 -0
  18. bec_widgets/widgets/figure/figure.py +33 -16
  19. bec_widgets/widgets/plots/__init__.py +1 -1
  20. bec_widgets/widgets/plots/image.py +5 -9
  21. bec_widgets/widgets/plots/motor_map.py +3 -3
  22. bec_widgets/widgets/plots/plot_base.py +4 -3
  23. bec_widgets/widgets/plots/waveform.py +6 -10
  24. {bec_widgets-0.51.0.dist-info → bec_widgets-0.52.0.dist-info}/METADATA +1 -1
  25. {bec_widgets-0.51.0.dist-info → bec_widgets-0.52.0.dist-info}/RECORD +36 -28
  26. tests/end-2-end/conftest.py +19 -4
  27. tests/end-2-end/test_bec_dock_rpc_e2e.py +145 -0
  28. tests/end-2-end/test_bec_figure_rpc_e2e.py +17 -17
  29. tests/end-2-end/test_rpc_register_e2e.py +3 -3
  30. tests/unit_tests/test_bec_dock.py +114 -0
  31. tests/unit_tests/test_bec_figure.py +20 -22
  32. tests/unit_tests/test_generate_cli_client.py +1 -1
  33. tests/unit_tests/test_waveform1d.py +1 -1
  34. {bec_widgets-0.51.0.dist-info → bec_widgets-0.52.0.dist-info}/LICENSE +0 -0
  35. {bec_widgets-0.51.0.dist-info → bec_widgets-0.52.0.dist-info}/WHEEL +0 -0
  36. {bec_widgets-0.51.0.dist-info → bec_widgets-0.52.0.dist-info}/top_level.txt +0 -0
@@ -1,27 +1,25 @@
1
1
  # pylint: disable = no-name-in-module,missing-module-docstring
2
2
  from __future__ import annotations
3
3
 
4
- import itertools
5
- import os
4
+ import uuid
6
5
  from collections import defaultdict
7
- from typing import Literal, Optional, Type
6
+ from typing import Literal, Optional
8
7
 
9
8
  import numpy as np
10
9
  import pyqtgraph as pg
11
10
  import qdarktheme
12
11
  from pydantic import Field
13
- from pyqtgraph.Qt import uic
14
12
  from qtpy.QtCore import Signal as pyqtSignal
15
- from qtpy.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget
13
+ from qtpy.QtWidgets import QWidget
16
14
 
17
- from bec_widgets.utils import BECConnector, BECDispatcher, ConnectionConfig, WidgetContainerUtils
15
+ from bec_widgets.utils import BECConnector, ConnectionConfig, WidgetContainerUtils
18
16
  from bec_widgets.widgets.plots import (
19
17
  BECImageShow,
20
18
  BECMotorMap,
21
19
  BECPlotBase,
22
20
  BECWaveform,
21
+ SubplotConfig,
23
22
  Waveform1DConfig,
24
- WidgetConfig,
25
23
  )
26
24
  from bec_widgets.widgets.plots.image import ImageConfig
27
25
  from bec_widgets.widgets.plots.motor_map import MotorMapConfig
@@ -33,7 +31,7 @@ class FigureConfig(ConnectionConfig):
33
31
  theme: Literal["dark", "light"] = Field("dark", description="The theme of the figure widget.")
34
32
  num_cols: int = Field(1, description="The number of columns in the figure widget.")
35
33
  num_rows: int = Field(1, description="The number of rows in the figure widget.")
36
- widgets: dict[str, WidgetConfig] = Field(
34
+ widgets: dict[str, SubplotConfig] = Field(
37
35
  {}, description="The list of widgets to be added to the figure widget."
38
36
  )
39
37
 
@@ -43,7 +41,7 @@ class WidgetHandler:
43
41
 
44
42
  def __init__(self):
45
43
  self.widget_factory = {
46
- "PlotBase": (BECPlotBase, WidgetConfig),
44
+ "PlotBase": (BECPlotBase, SubplotConfig),
47
45
  "Waveform1D": (BECWaveform, Waveform1DConfig),
48
46
  "ImShow": (BECImageShow, ImageConfig),
49
47
  "MotorMap": (BECMotorMap, MotorMapConfig),
@@ -166,14 +164,29 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
166
164
 
167
165
  @widget_list.setter
168
166
  def widget_list(self, value: list[BECPlotBase]):
167
+ """
168
+ Access all widget in BECFigure as a list
169
+ Returns:
170
+ list[BECPlotBase]: List of all widgets in the figure.
171
+ """
169
172
  self._axes = value
170
173
 
171
174
  @property
172
175
  def widgets(self) -> dict:
176
+ """
177
+ All widgets within the figure with gui ids as keys.
178
+ Returns:
179
+ dict: All widgets within the figure.
180
+ """
173
181
  return self._widgets
174
182
 
175
183
  @widgets.setter
176
184
  def widgets(self, value: dict):
185
+ """
186
+ All widgets within the figure with gui ids as keys.
187
+ Returns:
188
+ dict: All widgets within the figure.
189
+ """
177
190
  self._widgets = value
178
191
 
179
192
  def add_plot(
@@ -204,7 +217,7 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
204
217
  config(dict): Additional configuration for the widget.
205
218
  **axis_kwargs(dict): Additional axis properties to set on the widget after creation.
206
219
  """
207
- widget_id = WidgetContainerUtils.generate_unique_widget_id(self._widgets)
220
+ widget_id = str(uuid.uuid4())
208
221
  waveform = self.add_widget(
209
222
  widget_type="Waveform1D",
210
223
  widget_id=widget_id,
@@ -430,7 +443,7 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
430
443
  BECImageShow: The image widget.
431
444
  """
432
445
 
433
- widget_id = WidgetContainerUtils.generate_unique_widget_id(self._widgets)
446
+ widget_id = str(uuid.uuid4())
434
447
  if config is None:
435
448
  config = ImageConfig(
436
449
  widget_class="BECImageShow",
@@ -513,7 +526,7 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
513
526
  Returns:
514
527
  BECMotorMap: The motor map widget.
515
528
  """
516
- widget_id = WidgetContainerUtils.generate_unique_widget_id(self._widgets)
529
+ widget_id = str(uuid.uuid4())
517
530
  if config is None:
518
531
  config = MotorMapConfig(
519
532
  widget_class="BECMotorMap",
@@ -554,7 +567,7 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
554
567
  **axis_kwargs(dict): Additional axis properties to set on the widget after creation.
555
568
  """
556
569
  if not widget_id:
557
- widget_id = WidgetContainerUtils.generate_unique_widget_id(self._widgets)
570
+ widget_id = str(uuid.uuid4())
558
571
  if widget_id in self._widgets:
559
572
  raise ValueError(f"Widget with ID '{widget_id}' already exists.")
560
573
 
@@ -767,12 +780,16 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
767
780
 
768
781
  def clear_all(self):
769
782
  """Clear all widgets from the figure and reset to default state"""
770
- for widget in self._widgets.values():
771
- widget.cleanup()
772
- self.clear()
783
+ for widget in list(self._widgets.values()):
784
+ widget.remove()
785
+ # self.clear()
773
786
  self._widgets = defaultdict(dict)
774
787
  self.grid = []
775
788
  theme = self.config.theme
776
789
  self.config = FigureConfig(
777
790
  widget_class=self.__class__.__name__, gui_id=self.gui_id, theme=theme
778
791
  )
792
+
793
+ def cleanup(self):
794
+ self.clear_all()
795
+ super().cleanup()
@@ -1,4 +1,4 @@
1
1
  from .image import BECImageItem, BECImageShow, ImageItemConfig
2
2
  from .motor_map import BECMotorMap, MotorMapConfig
3
- from .plot_base import AxisConfig, BECPlotBase, WidgetConfig
3
+ from .plot_base import AxisConfig, BECPlotBase, SubplotConfig
4
4
  from .waveform import BECCurve, BECWaveform, Waveform1DConfig
@@ -14,7 +14,7 @@ from qtpy.QtWidgets import QWidget
14
14
 
15
15
  from bec_widgets.utils import BECConnector, ConnectionConfig, EntryValidator
16
16
 
17
- from .plot_base import BECPlotBase, WidgetConfig
17
+ from .plot_base import BECPlotBase, SubplotConfig
18
18
 
19
19
 
20
20
  class ProcessingConfig(BaseModel):
@@ -50,7 +50,7 @@ class ImageItemConfig(ConnectionConfig):
50
50
  )
51
51
 
52
52
 
53
- class ImageConfig(WidgetConfig):
53
+ class ImageConfig(SubplotConfig):
54
54
  images: dict[str, ImageItemConfig] = Field(
55
55
  {},
56
56
  description="The configuration of the images. The key is the name of the image (source).",
@@ -288,10 +288,6 @@ class BECImageItem(BECConnector, pg.ImageItem):
288
288
  else:
289
289
  raise ValueError("style should be 'simple' or 'full'")
290
290
 
291
- def cleanup(self):
292
- """Clean up widget."""
293
- self.rpc_register.remove_rpc(self)
294
-
295
291
 
296
292
  class BECImageShow(BECPlotBase):
297
293
  USER_ACCESS = [
@@ -382,11 +378,11 @@ class BECImageShow(BECPlotBase):
382
378
  if result is not None:
383
379
  return result
384
380
 
385
- def apply_config(self, config: dict | WidgetConfig):
381
+ def apply_config(self, config: dict | SubplotConfig):
386
382
  """
387
383
  Apply the configuration to the 1D waveform widget.
388
384
  Args:
389
- config(dict|WidgetConfig): Configuration settings.
385
+ config(dict|SubplotConfig): Configuration settings.
390
386
  replot_last_scan(bool, optional): If True, replot the last scan. Defaults to False.
391
387
  """
392
388
  if isinstance(config, dict):
@@ -806,7 +802,7 @@ class BECImageShow(BECPlotBase):
806
802
  for image in self.images:
807
803
  image.cleanup()
808
804
 
809
- self.rpc_register.remove_rpc(self)
805
+ super().cleanup()
810
806
 
811
807
 
812
808
  class ImageProcessor:
@@ -13,11 +13,11 @@ from qtpy.QtCore import Slot as pyqtSlot
13
13
  from qtpy.QtWidgets import QWidget
14
14
 
15
15
  from bec_widgets.utils import EntryValidator
16
- from bec_widgets.widgets.plots.plot_base import BECPlotBase, WidgetConfig
16
+ from bec_widgets.widgets.plots.plot_base import BECPlotBase, SubplotConfig
17
17
  from bec_widgets.widgets.plots.waveform import Signal, SignalData
18
18
 
19
19
 
20
- class MotorMapConfig(WidgetConfig):
20
+ class MotorMapConfig(SubplotConfig):
21
21
  signals: Optional[Signal] = Field(None, description="Signals of the motor map")
22
22
  color_map: Optional[str] = Field(
23
23
  "Greys", description="Color scheme of the motor position gradient."
@@ -425,4 +425,4 @@ class BECMotorMap(BECPlotBase):
425
425
  def cleanup(self):
426
426
  """Cleanup the widget."""
427
427
  self._disconnect_current_motors()
428
- self.rpc_register.remove_rpc(self)
428
+ super().cleanup()
@@ -22,7 +22,7 @@ class AxisConfig(BaseModel):
22
22
  y_grid: bool = Field(False, description="Show grid on the y-axis.")
23
23
 
24
24
 
25
- class WidgetConfig(ConnectionConfig):
25
+ class SubplotConfig(ConnectionConfig):
26
26
  parent_id: Optional[str] = Field(None, description="The parent figure of the plot.")
27
27
 
28
28
  # Coordinates in the figure
@@ -56,12 +56,12 @@ class BECPlotBase(BECConnector, pg.GraphicsLayout):
56
56
  self,
57
57
  parent: Optional[QWidget] = None, # TODO decide if needed for this class
58
58
  parent_figure=None,
59
- config: Optional[WidgetConfig] = None,
59
+ config: Optional[SubplotConfig] = None,
60
60
  client=None,
61
61
  gui_id: Optional[str] = None,
62
62
  ):
63
63
  if config is None:
64
- config = WidgetConfig(widget_class=self.__class__.__name__)
64
+ config = SubplotConfig(widget_class=self.__class__.__name__)
65
65
  super().__init__(client=client, config=config, gui_id=gui_id)
66
66
  pg.GraphicsLayout.__init__(self, parent)
67
67
 
@@ -248,3 +248,4 @@ class BECPlotBase(BECConnector, pg.GraphicsLayout):
248
248
 
249
249
  def cleanup(self):
250
250
  """Cleanup the plot widget."""
251
+ super().cleanup()
@@ -15,7 +15,7 @@ from qtpy.QtCore import Slot as pyqtSlot
15
15
  from qtpy.QtWidgets import QWidget
16
16
 
17
17
  from bec_widgets.utils import BECConnector, Colors, ConnectionConfig, EntryValidator
18
- from bec_widgets.widgets.plots.plot_base import BECPlotBase, WidgetConfig
18
+ from bec_widgets.widgets.plots.plot_base import BECPlotBase, SubplotConfig
19
19
 
20
20
 
21
21
  class SignalData(BaseModel):
@@ -53,7 +53,7 @@ class CurveConfig(ConnectionConfig):
53
53
  colormap: Optional[str] = Field("plasma", description="The colormap of the curves z gradient.")
54
54
 
55
55
 
56
- class Waveform1DConfig(WidgetConfig):
56
+ class Waveform1DConfig(SubplotConfig):
57
57
  color_palette: Literal["plasma", "viridis", "inferno", "magma"] = Field(
58
58
  "plasma", description="The color palette of the figure widget."
59
59
  ) # TODO can be extended to all colormaps from current pyqtgraph session
@@ -229,14 +229,10 @@ class BECCurve(BECConnector, pg.PlotDataItem):
229
229
  x_data, y_data = self.getData()
230
230
  return x_data, y_data
231
231
 
232
- def cleanup(self):
233
- """Cleanup the curve."""
234
- self.rpc_register.remove_rpc(self)
235
-
236
232
  def remove(self):
237
233
  """Remove the curve from the plot."""
238
- self.cleanup()
239
234
  self.parent_item.removeItem(self)
235
+ self.cleanup()
240
236
 
241
237
 
242
238
  class BECWaveform(BECPlotBase):
@@ -300,11 +296,11 @@ class BECWaveform(BECPlotBase):
300
296
  self.add_legend()
301
297
  self.apply_config(self.config)
302
298
 
303
- def apply_config(self, config: dict | WidgetConfig, replot_last_scan: bool = False):
299
+ def apply_config(self, config: dict | SubplotConfig, replot_last_scan: bool = False):
304
300
  """
305
301
  Apply the configuration to the 1D waveform widget.
306
302
  Args:
307
- config(dict|WidgetConfig): Configuration settings.
303
+ config(dict|SubplotConfig): Configuration settings.
308
304
  replot_last_scan(bool, optional): If True, replot the last scan. Defaults to False.
309
305
  """
310
306
  if isinstance(config, dict):
@@ -799,4 +795,4 @@ class BECWaveform(BECPlotBase):
799
795
  self.bec_dispatcher.disconnect_slot(self.on_scan_segment, MessageEndpoints.scan_segment())
800
796
  for curve in self.curves:
801
797
  curve.cleanup()
802
- self.rpc_register.remove_rpc(self)
798
+ super().cleanup()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bec-widgets
3
- Version: 0.51.0
3
+ Version: 0.52.0
4
4
  Summary: BEC Widgets
5
5
  Home-page: https://gitlab.psi.ch/bec/bec-widgets
6
6
  Project-URL: Bug Tracker, https://gitlab.psi.ch/bec/bec-widgets/issues
@@ -1,19 +1,21 @@
1
1
  bec_widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- bec_widgets/cli/__init__.py,sha256=ULoNTVnv2UeSSjhFq3uCQJ-0JTJf9oU76l27aRiizL4,78
2
+ bec_widgets/cli/__init__.py,sha256=EHPu69lxYndxm6tJqwHHlktuq0hvOCaid1Nxh0jaexo,91
3
3
  bec_widgets/cli/auto_updates.py,sha256=ptZeBKr13o9THc8oKLn93K_16i6G3pxzw8hZ4MUgjW4,3845
4
- bec_widgets/cli/bec_widgets_icon.png,sha256=pRCGpoOtwyZl97fBV_CHcGppliErzd0qQkCXLxjbp-s,5760
5
- bec_widgets/cli/client.py,sha256=AvkaEDKB8cZFm2WS5JWIusMXtcqErEeP2Ayk9l7iAp8,39163
6
- bec_widgets/cli/client_utils.py,sha256=IzyVAcko47vC47_oT0fAi9M-8OrZ2qmUfMlOAvQGuhU,10205
7
- bec_widgets/cli/generate_cli.py,sha256=JLqUlUgfz_f_4KHPRUAN-Xli-K7uNOc8-F-LkAC7Scw,4004
4
+ bec_widgets/cli/bec_widgets_icon.png,sha256=K8dgGwIjalDh9PRHUsSQBqgdX7a00nM3igZdc20pkYM,1747017
5
+ bec_widgets/cli/client.py,sha256=yvGQ5c-i-YhNr_8G3ls0n_PGURDeCWoPSMIdCeSoRUY,45200
6
+ bec_widgets/cli/client_utils.py,sha256=jiboQwyZ78_F3s_2Ujl2XNVd_svUklRt7nZdOLpflMc,10401
7
+ bec_widgets/cli/generate_cli.py,sha256=3YJU4dYgvW27KURUwc7oyt4IvgqEEdjMVXvrwPSbSQQ,4100
8
8
  bec_widgets/cli/rpc_register.py,sha256=OZOWX0IKGXqDsnrUYi0Irl_zpPS4Q_JPCV9JQfN6YYw,2212
9
- bec_widgets/cli/server.py,sha256=UpbegcLn2nd9gPF2swNfPQGHVwG14ZjQBpZKCAjQT4E,4942
9
+ bec_widgets/cli/rpc_wigdet_handler.py,sha256=RcIUsmrMJGCKIo8iI9-wi0tOiwIlTouuEWAMx-Vu7Y8,797
10
+ bec_widgets/cli/server.py,sha256=wIDOd56ZPfnM42pOJD8NCI3Dw38Aurb9TwwTrricfvU,5773
10
11
  bec_widgets/examples/__init__.py,sha256=WWQ0cu7m8sA4Ehy-DWdTIqSISjaHsbxhsNmNrMnhDZU,202
11
12
  bec_widgets/examples/eiger_plot/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
13
  bec_widgets/examples/eiger_plot/eiger_plot.py,sha256=Uxl2Usf8jEzaX7AT8zVqa1x8ZIEgI1HmazSlb-tRFWE,10359
13
14
  bec_widgets/examples/eiger_plot/eiger_plot.ui,sha256=grHfnO3OG_lelJhdRsnA0badCvRdDunPrIMIyNQ5N-w,5809
14
15
  bec_widgets/examples/jupyter_console/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- bec_widgets/examples/jupyter_console/jupyter_console_window.py,sha256=aEwwOHNW4CJab41hbEB3hvWEEAPNtGjFQEwMo8GkEmM,3581
16
- bec_widgets/examples/jupyter_console/jupyter_console_window.ui,sha256=GodXBvBvs5QAUsHbo3pcxR4o51Tvce4DTqpTluk3hOs,742
16
+ bec_widgets/examples/jupyter_console/jupyter_console_window.py,sha256=s8ysnlktLv3932ody8pRA1mghH1QQcxLjQK1HTZ59b8,5642
17
+ bec_widgets/examples/jupyter_console/jupyter_console_window.ui,sha256=2A2mNTUMZBYygz8K4qWzrcjnNqZBMVyeHm26iLZVRWI,1473
18
+ bec_widgets/examples/jupyter_console/terminal_icon.png,sha256=bJl7Tft4Fi2uxvuXI8o14uMHnI9eAWKSU2uftXCH9ws,3889
17
19
  bec_widgets/examples/mca_readout/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
20
  bec_widgets/examples/mca_readout/mca_plot.py,sha256=do7mSK_nzHtojRiMi8JoN_Rckg9yfjYYWz2S_Nl3xbE,5079
19
21
  bec_widgets/examples/mca_readout/mca_sim.py,sha256=yiX_3sOgDZIbAYA4D2BGmOgLMBWbQMOej0hSP4cQd0o,754
@@ -28,8 +30,8 @@ bec_widgets/examples/stream_plot/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRk
28
30
  bec_widgets/examples/stream_plot/line_plot.ui,sha256=rgNfhOXu1AcWF0P6wnOlmJKDjS-VIoduVrREvmzJQR8,4626
29
31
  bec_widgets/examples/stream_plot/stream_plot.py,sha256=vHii1p9JxSyGQ_VcCjnk9SHJ41Q6Oi1GGd6swVVHLRM,12177
30
32
  bec_widgets/simulations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
- bec_widgets/utils/__init__.py,sha256=xytx86Yosjkta0PU4rHfoeO7FCPcimS15xjMPQUgIXc,403
32
- bec_widgets/utils/bec_connector.py,sha256=U_quQy7p1ISEpTnvwKsnDw5rdCc3jEoATfPVez2K7eI,4867
33
+ bec_widgets/utils/__init__.py,sha256=PAHNbPFnPD-XGxKBZ7ctx9WBrvm9MArkCYDNfoOxVJA,449
34
+ bec_widgets/utils/bec_connector.py,sha256=sfYscTdj3MfWL5KuUqecnPl1Lhws2DXgA_FGsQz4DuY,5178
33
35
  bec_widgets/utils/bec_dispatcher.py,sha256=xJrsHJ-flLFGA-XCa6wCsMzMpRu1fAy9IcUuLh6igSo,5569
34
36
  bec_widgets/utils/bec_table.py,sha256=Xy5qM343K8EvEpB4g_129b63yo1wdEvEY3wqxB_p_Iw,716
35
37
  bec_widgets/utils/colors.py,sha256=JsLxzkxbw-I8GIuvnIKyiM83n0edhyMG2Fa4Ffm62ww,2392
@@ -37,6 +39,7 @@ bec_widgets/utils/container_utils.py,sha256=rL-ryupQ4-7Y8mKNup5aklXleOfXSd97uwXT
37
39
  bec_widgets/utils/crosshair.py,sha256=5gG4G6jjtp6Bd1Y5EySHP2EkmtR4mYdxLCgVtx9fokE,9406
38
40
  bec_widgets/utils/ctrl_c.py,sha256=NMJlPDZcuqMUGykyhuZY5Ibed4yRI1K_uh16z2MmlXQ,1198
39
41
  bec_widgets/utils/entry_validator.py,sha256=88OpJqaldMjiaEk7F9rRcwPuCOTLCzXmAlSEL-_7iXU,1296
42
+ bec_widgets/utils/layout_manager.py,sha256=hSHH3DTnaM7DyjUF9ko5FVrBdeFhY6KbhteLBnujFt0,4723
40
43
  bec_widgets/utils/plugin_utils.py,sha256=wi5x7VVFee0PqAcP-EqPWjYfSe-LLhaK93y6qmnbLIw,1487
41
44
  bec_widgets/utils/rpc_decorator.py,sha256=pIvtqySQLnuS7l2Ti_UAe4WX7CRivZnsE5ZdKAihxh0,479
42
45
  bec_widgets/utils/thread_checker.py,sha256=rDNuA3X6KQyA7JPb67mccTg0z8YkInynLAENQDQpbuE,1607
@@ -45,9 +48,12 @@ bec_widgets/utils/widget_io.py,sha256=JKl508VnqQSxcaHqKaoBQ1TWSOm3pXhxQGx7iF_pRA
45
48
  bec_widgets/utils/yaml_dialog.py,sha256=soZI8BOjlqYGfYDga70MEvkxJTsktq4y7B3uog2cSik,1851
46
49
  bec_widgets/validation/__init__.py,sha256=ismd1bU5FhFb0zFPwNKuq7oT48G4Y2GfaMZOdNKUtGk,132
47
50
  bec_widgets/validation/monitor_config_validator.py,sha256=M9p8K_nvxicnqJB4X7j90R377WHYVH4wMCtSXsRI51M,8150
48
- bec_widgets/widgets/__init__.py,sha256=HBzIWJYX4dp2iDZl_qIuyy-X5IWRMhGwQ-4UisP8wqE,353
51
+ bec_widgets/widgets/__init__.py,sha256=NOgRDV9-uwrH1OK2JdfG5c0WcW77TSRz3PeNlGw22Lc,392
52
+ bec_widgets/widgets/dock/__init__.py,sha256=B7foHt02gnhM7mFksa7GJVwT7n0j_JvYDCt6wc6XR5g,61
53
+ bec_widgets/widgets/dock/dock.py,sha256=vnOQnOWWnd-3X07kniSW_I5l0uEHZOaWhfuqZkDGIqE,8467
54
+ bec_widgets/widgets/dock/dock_area.py,sha256=qwwjfpGCwGk7w2F5JTD3IbJQc_06vGnhBAkCT8zr-4g,7202
49
55
  bec_widgets/widgets/figure/__init__.py,sha256=3hGx_KOV7QHCYAV06aNuUgKq4QIYCjUTad-DrwkUaBM,44
50
- bec_widgets/widgets/figure/figure.py,sha256=IOj5rz3dXHOThtdLRPHx0lpoIQCLg-QbPGO1ECM-CKo,28484
56
+ bec_widgets/widgets/figure/figure.py,sha256=IJXSpza5uNIsSN2TuzSE1n9ASbB7JIBYK31MnI6OHo0,28744
51
57
  bec_widgets/widgets/monitor/__init__.py,sha256=afXuZcBOxNAuYdCkIQXX5J60R5A3Q_86lNEW2vpFtPI,32
52
58
  bec_widgets/widgets/monitor/config_dialog.py,sha256=Z1a4WRIVlfEGdwC-QG25kba2EHCZWi5J843tBVZlWiI,20275
53
59
  bec_widgets/widgets/monitor/config_dialog.ui,sha256=ISMcF7CLTAMXhfZh2Yv5yezzAjMtb9fxY1pmX4B_jCg,5932
@@ -61,33 +67,35 @@ bec_widgets/widgets/motor_control/motor_control_selection.ui,sha256=vXXpvNWuL6xy
61
67
  bec_widgets/widgets/motor_control/motor_control_table.ui,sha256=t6aRKiSmutMfp0AyupavbCs0cal-FANEnlKQiPzC9PQ,2792
62
68
  bec_widgets/widgets/motor_map/__init__.py,sha256=K3c-3A_LbxK0UJ0_bV3opL-wGLTwBLendsJXsg8GAqE,32
63
69
  bec_widgets/widgets/motor_map/motor_map.py,sha256=vJlLWa0BXv5KMZ7UVT0q3I1I5CXgsDiXoM_ptsAsG3c,21860
64
- bec_widgets/widgets/plots/__init__.py,sha256=kGQTORTr-2M9vmVCK-T7AFre4bY5LVVzGxcIzT81-ZU,237
65
- bec_widgets/widgets/plots/image.py,sha256=uanFs3YoAefLgfQnAW5oiQtssRLfhKmWHMlOMpb9HqQ,32504
66
- bec_widgets/widgets/plots/motor_map.py,sha256=wbD95aIA4K3BLDZHZmHLblvKea7jPA7u4yw_tFaA4OE,15298
67
- bec_widgets/widgets/plots/plot_base.py,sha256=ZieahcTwz0tynszdYe4r0rrOlWcRmXblplIYuuTX1ic,8474
68
- bec_widgets/widgets/plots/waveform.py,sha256=CzPPq_9ZgBr4pZkLNSDqPbP8AJXXkan221-Fe8rw31c,28693
70
+ bec_widgets/widgets/plots/__init__.py,sha256=yaCWQEXiEVj3Oh9qvD3UDzY2HE2PiDKKyKINEcVeL2k,238
71
+ bec_widgets/widgets/plots/image.py,sha256=8E1aEh6x2KhOoH9S87lEDlAmqi-JDuZS4aW1PenVhaE,32393
72
+ bec_widgets/widgets/plots/motor_map.py,sha256=gnESz9ig6MMxYasuACvtd1sXDIvB2zxiYtVbtlxwwXQ,15283
73
+ bec_widgets/widgets/plots/plot_base.py,sha256=O-eitUfWGaCFF-Qtz2nOsMCjfNMF5ZYr7T-0suOU9v0,8503
74
+ bec_widgets/widgets/plots/waveform.py,sha256=n-rNB8RWMviqY7M22lxhk-p7chpuZMIkJ81F5O7Q1jk,28580
69
75
  bec_widgets/widgets/scan_control/__init__.py,sha256=IOfHl15vxb_uC6KN62-PeUzbBha_vQyqkkXbJ2HU674,38
70
76
  bec_widgets/widgets/scan_control/scan_control.py,sha256=tbO9tbVynRvs4VCxTZ4ZFBDTVAojIr-zkl70vuHbWgw,17116
71
77
  bec_widgets/widgets/toolbar/__init__.py,sha256=d-TP4_cr_VbpwreMM4ePnfZ5YXsEPQ45ibEf75nuGoE,36
72
78
  bec_widgets/widgets/toolbar/toolbar.py,sha256=sxz7rbc8XNPS6n2WMObF4-2PqdYfPxVtsOZEGV6mqa0,5124
73
79
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
80
  tests/end-2-end/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
- tests/end-2-end/conftest.py,sha256=jksYsc3Vm15LDyke-fmc80qCKBUnYuEjYi_QikeSOkE,756
76
- tests/end-2-end/test_bec_figure_rpc_e2e.py,sha256=-eMCKkj6sh_OkuVRhVTGMw5KJOyNhzDR783jdi5hNM4,5350
77
- tests/end-2-end/test_rpc_register_e2e.py,sha256=zqatLWjM_tYxiB3GgupYHHGTorGUFa0jvDFaqJpkZyA,1560
81
+ tests/end-2-end/conftest.py,sha256=b5Yebbj8C1-IcXq23XGbOnXF0kOZD_Po46Z-p4cBwfs,1346
82
+ tests/end-2-end/test_bec_dock_rpc_e2e.py,sha256=vfskJxQ6xQFfG6X6Ec8GOj2SoWIk8slMd43fERroaaw,4548
83
+ tests/end-2-end/test_bec_figure_rpc_e2e.py,sha256=aEpyhRYrDC3dNScsHxJfQPfuehU6Q9wGhCGkYmooAMk,5461
84
+ tests/end-2-end/test_rpc_register_e2e.py,sha256=Jrv46F-fyJa0tls1KPTeIxXQ4oUNgWkhAMwzvMQBRR8,1581
78
85
  tests/unit_tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
86
  tests/unit_tests/client_mocks.py,sha256=LNUgI9Ccv5Ol7_pmybIhoVqZZem1RPIsTDk7ZTARNls,4128
80
87
  tests/unit_tests/conftest.py,sha256=KrnktXPWmZhnKNue-xGWOLD1XGEvdz9Vf7V2eO3XQ3A,596
81
88
  tests/unit_tests/test_bec_connector.py,sha256=f2XXGGw3NoZLIUrDuZuEWwF_ttOYmmquCgUrV5XkIOY,1951
82
89
  tests/unit_tests/test_bec_dispatcher.py,sha256=WW-wlzSgZA_h2Qx5EMvXfMlb2i7RYbWj2Cz3S2EzsZQ,4178
83
- tests/unit_tests/test_bec_figure.py,sha256=T4k-E1D3sjTTDTFZGdTFDQv0EYNQ_R-QbWOM7pQwFw4,7926
90
+ tests/unit_tests/test_bec_dock.py,sha256=ZnHUoVQCGbikd0mM64XBL_k0Kxp0d3UqCHpcyY59emg,3596
91
+ tests/unit_tests/test_bec_figure.py,sha256=AOPJBGJIdAz80YqSiU1PosEHo-DjlmV8869HBcSHdS0,7860
84
92
  tests/unit_tests/test_bec_monitor.py,sha256=mN7gBY7oXY6j65zzihpy8r-FvwVoCQlie3F6SoVq0mo,7042
85
93
  tests/unit_tests/test_bec_motor_map.py,sha256=IXSfitUGxOPqmngwVNPK5nwi2QDcXWjBkGNb0dBZDxQ,4611
86
94
  tests/unit_tests/test_client_utils.py,sha256=fIApd5WgnJuyIzV-hdSABn6T-aOel2Wr2xuUX4Z651A,774
87
95
  tests/unit_tests/test_config_dialog.py,sha256=5uNGcpvrx8qDdMwFCTXr8HMzFZF4rFi-ZHoDpMxGMf8,6955
88
96
  tests/unit_tests/test_crosshair.py,sha256=d7fX-ymboZPALNqqiAj86PZ96llmGZ_3jf0yjVP0S94,5039
89
97
  tests/unit_tests/test_eiger_plot.py,sha256=bWnKBQid0YcLMQeBLy6ojb4ZpwTG-rFVT0kMg9Y08p8,4427
90
- tests/unit_tests/test_generate_cli_client.py,sha256=BdpTZMNUFOBJa2e-rme9AJUoXfueYyLiUCOpGi3SNvc,2400
98
+ tests/unit_tests/test_generate_cli_client.py,sha256=J7CFoO67txGu_u1Mwk32EejRX204FRuvmVg_yhAr1WM,2397
91
99
  tests/unit_tests/test_motor_control.py,sha256=jdTG35z3jOL9XCAIDNIGfdv60vcwGLHa3KJjKqJkoZw,20322
92
100
  tests/unit_tests/test_motor_map.py,sha256=UEjmtIYI2mxq9BUeopqoqNNy7UiPJEts9h45ufsFcrA,5979
93
101
  tests/unit_tests/test_plot_base.py,sha256=bOdlgAxh9oKk5PwiQ_MSFmzr44uJ61Tlg242RCIhl5c,2610
@@ -95,13 +103,13 @@ tests/unit_tests/test_rpc_register.py,sha256=hECjZEimd440mwRrO0rg7L3PKN7__3DgjmE
95
103
  tests/unit_tests/test_scan_control.py,sha256=7dtGpE0g4FqUhhQeCkyJl-9o7NH3DFZJgEaqDmBYbBc,7551
96
104
  tests/unit_tests/test_stream_plot.py,sha256=LNCYIj9CafremGaz-DwDktCRJRrjgfOdVewCUwwZE5s,5843
97
105
  tests/unit_tests/test_validator_errors.py,sha256=NFxyv0TIOXeZKZRRUBfVQ7bpunwY4KkG95yTUdQmvns,3532
98
- tests/unit_tests/test_waveform1d.py,sha256=-YfBi_m91sR_v4oj8rshARk4G6AOxqQB_gbVqJ3iXvY,15003
106
+ tests/unit_tests/test_waveform1d.py,sha256=cBtESTQgsVQdv-Wl75eHK9D8YY-b60Z5wqtPCo9ohu0,15002
99
107
  tests/unit_tests/test_widget_io.py,sha256=FeL3ZYSBQnRt6jxj8VGYw1cmcicRQyHKleahw7XIyR0,3475
100
108
  tests/unit_tests/test_yaml_dialog.py,sha256=HNrqferkdg02-9ieOhhI2mr2Qvt7GrYgXmQ061YCTbg,5794
101
109
  tests/unit_tests/test_msgs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
102
110
  tests/unit_tests/test_msgs/available_scans_message.py,sha256=m_z97hIrjHXXMa2Ex-UvsPmTxOYXfjxyJaGkIY6StTY,46532
103
- bec_widgets-0.51.0.dist-info/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
104
- bec_widgets-0.51.0.dist-info/METADATA,sha256=PwzbcGJ0Sy4MSwKmxEb2lh4XZVPxC_fHNjHyHVcPFHg,3724
105
- bec_widgets-0.51.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
106
- bec_widgets-0.51.0.dist-info/top_level.txt,sha256=EXCwhJYmXmd1DjYYL3hrGsddX-97IwYSiIHrf27FFVk,18
107
- bec_widgets-0.51.0.dist-info/RECORD,,
111
+ bec_widgets-0.52.0.dist-info/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
112
+ bec_widgets-0.52.0.dist-info/METADATA,sha256=lSrW1foR3MPKDrHbNrH-5B8Qp1oRgvkFnwrtgsFW8C4,3724
113
+ bec_widgets-0.52.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
114
+ bec_widgets-0.52.0.dist-info/top_level.txt,sha256=EXCwhJYmXmd1DjYYL3hrGsddX-97IwYSiIHrf27FFVk,18
115
+ bec_widgets-0.52.0.dist-info/RECORD,,
@@ -3,6 +3,7 @@ import pytest
3
3
  from bec_widgets.cli.rpc_register import RPCRegister
4
4
  from bec_widgets.cli.server import BECWidgetsCLIServer
5
5
  from bec_widgets.utils import BECDispatcher
6
+ from bec_widgets.widgets import BECDockArea, BECFigure
6
7
 
7
8
 
8
9
  @pytest.fixture(autouse=True)
@@ -12,11 +13,25 @@ def rpc_register():
12
13
 
13
14
 
14
15
  @pytest.fixture
15
- def rpc_server(qtbot, bec_client_lib, threads_check):
16
+ def rpc_server_figure(qtbot, bec_client_lib, threads_check):
16
17
  dispatcher = BECDispatcher(client=bec_client_lib) # Has to init singleton with fixture client
17
- server = BECWidgetsCLIServer(gui_id="figure")
18
- qtbot.addWidget(server.fig)
19
- qtbot.waitExposed(server.fig)
18
+ server = BECWidgetsCLIServer(gui_id="figure", gui_class=BECFigure)
19
+ qtbot.addWidget(server.gui)
20
+ qtbot.waitExposed(server.gui)
21
+ qtbot.wait(1000) # 1s long to wait until gui is ready
22
+ yield server
23
+ dispatcher.disconnect_all()
24
+ server.client.shutdown()
25
+ server.shutdown()
26
+ dispatcher.reset_singleton()
27
+
28
+
29
+ @pytest.fixture
30
+ def rpc_server_dock(qtbot, bec_client_lib, threads_check):
31
+ dispatcher = BECDispatcher(client=bec_client_lib) # Has to init singleton with fixture client
32
+ server = BECWidgetsCLIServer(gui_id="figure", gui_class=BECDockArea)
33
+ qtbot.addWidget(server.gui)
34
+ qtbot.waitExposed(server.gui)
20
35
  qtbot.wait(1000) # 1s long to wait until gui is ready
21
36
  yield server
22
37
  dispatcher.disconnect_all()
@@ -0,0 +1,145 @@
1
+ import numpy as np
2
+ import pytest
3
+ from bec_lib import MessageEndpoints
4
+
5
+ from bec_widgets.cli.client import BECDockArea, BECFigure, BECImageShow, BECMotorMap, BECWaveform
6
+
7
+
8
+ def test_rpc_add_dock_with_figure_e2e(rpc_server_dock, qtbot):
9
+ dock = BECDockArea(rpc_server_dock.gui_id)
10
+ dock_server = rpc_server_dock.gui
11
+
12
+ # BEC client shortcuts
13
+ client = rpc_server_dock.client
14
+ dev = client.device_manager.devices
15
+ scans = client.scans
16
+ queue = client.queue
17
+
18
+ # Create 3 docks
19
+ d0 = dock.add_dock("dock_0")
20
+ d1 = dock.add_dock("dock_1")
21
+ d2 = dock.add_dock("dock_2")
22
+
23
+ assert len(dock_server.docks) == 3
24
+
25
+ # Add 3 figures with some widgets
26
+ fig0 = d0.add_widget_bec("BECFigure")
27
+ fig1 = d1.add_widget_bec("BECFigure")
28
+ fig2 = d2.add_widget_bec("BECFigure")
29
+
30
+ assert len(dock_server.docks) == 3
31
+ assert len(dock_server.docks["dock_0"].widgets) == 1
32
+ assert len(dock_server.docks["dock_1"].widgets) == 1
33
+ assert len(dock_server.docks["dock_2"].widgets) == 1
34
+
35
+ assert fig1.__class__.__name__ == "BECFigure"
36
+ assert fig1.__class__ == BECFigure
37
+ assert fig2.__class__.__name__ == "BECFigure"
38
+ assert fig2.__class__ == BECFigure
39
+
40
+ mm = fig0.motor_map("samx", "samy")
41
+ plt = fig1.plot("samx", "bpm4i")
42
+ im = fig2.image("eiger")
43
+
44
+ assert mm.__class__.__name__ == "BECMotorMap"
45
+ assert mm.__class__ == BECMotorMap
46
+ assert plt.__class__.__name__ == "BECWaveform"
47
+ assert plt.__class__ == BECWaveform
48
+ assert im.__class__.__name__ == "BECImageShow"
49
+ assert im.__class__ == BECImageShow
50
+
51
+ assert mm.config_dict["signals"] == {
52
+ "source": "device_readback",
53
+ "x": {
54
+ "name": "samx",
55
+ "entry": "samx",
56
+ "unit": None,
57
+ "modifier": None,
58
+ "limits": [-50.0, 50.0],
59
+ },
60
+ "y": {
61
+ "name": "samy",
62
+ "entry": "samy",
63
+ "unit": None,
64
+ "modifier": None,
65
+ "limits": [-50.0, 50.0],
66
+ },
67
+ "z": None,
68
+ }
69
+ assert plt.config_dict["curves"]["bpm4i-bpm4i"]["signals"] == {
70
+ "source": "scan_segment",
71
+ "x": {"name": "samx", "entry": "samx", "unit": None, "modifier": None, "limits": None},
72
+ "y": {"name": "bpm4i", "entry": "bpm4i", "unit": None, "modifier": None, "limits": None},
73
+ "z": None,
74
+ }
75
+ assert im.config_dict["images"]["eiger"]["monitor"] == "eiger"
76
+
77
+ # check initial position of motor map
78
+ initial_pos_x = dev.samx.read()["samx"]["value"]
79
+ initial_pos_y = dev.samy.read()["samy"]["value"]
80
+
81
+ # Try to make a scan
82
+ status = scans.line_scan(dev.samx, -5, 5, steps=10, exp_time=0.05, relative=False)
83
+
84
+ # wait for scan to finish
85
+ while not status.status == "COMPLETED":
86
+ qtbot.wait(200)
87
+
88
+ # plot
89
+ plt_last_scan_data = queue.scan_storage.storage[-1].data
90
+ plt_data = plt.get_all_data()
91
+ assert plt_data["bpm4i-bpm4i"]["x"] == plt_last_scan_data["samx"]["samx"].val
92
+ assert plt_data["bpm4i-bpm4i"]["y"] == plt_last_scan_data["bpm4i"]["bpm4i"].val
93
+
94
+ # image
95
+ last_image_device = client.connector.get_last(MessageEndpoints.device_monitor("eiger"))[
96
+ "data"
97
+ ].data
98
+ qtbot.wait(500)
99
+ last_image_plot = im.images[0].get_data()
100
+ np.testing.assert_equal(last_image_device, last_image_plot)
101
+
102
+ # motor map
103
+ final_pos_x = dev.samx.read()["samx"]["value"]
104
+ final_pos_y = dev.samy.read()["samy"]["value"]
105
+
106
+ # check final coordinates of motor map
107
+ motor_map_data = mm.get_data()
108
+
109
+ np.testing.assert_equal(
110
+ [motor_map_data["x"][0], motor_map_data["y"][0]], [initial_pos_x, initial_pos_y]
111
+ )
112
+ np.testing.assert_equal(
113
+ [motor_map_data["x"][-1], motor_map_data["y"][-1]], [final_pos_x, final_pos_y]
114
+ )
115
+
116
+
117
+ def test_dock_manipulations_e2e(rpc_server_dock, qtbot):
118
+ dock = BECDockArea(rpc_server_dock.gui_id)
119
+ dock_server = rpc_server_dock.gui
120
+
121
+ d0 = dock.add_dock("dock_0")
122
+ d1 = dock.add_dock("dock_1")
123
+ d2 = dock.add_dock("dock_2")
124
+ assert len(dock_server.docks) == 3
125
+
126
+ d0.detach()
127
+ dock.detach_dock("dock_2")
128
+ assert len(dock_server.docks) == 3
129
+ assert len(dock_server.tempAreas) == 2
130
+
131
+ d0.attach()
132
+ assert len(dock_server.docks) == 3
133
+ assert len(dock_server.tempAreas) == 1
134
+
135
+ d2.remove()
136
+ qtbot.wait(200)
137
+
138
+ assert len(dock_server.docks) == 2
139
+ docks_list = list(dict(dock_server.docks).keys())
140
+ assert ["dock_0", "dock_1"] == docks_list
141
+
142
+ dock.clear_all()
143
+
144
+ assert len(dock_server.docks) == 0
145
+ assert len(dock_server.tempAreas) == 0