pymodaq 5.0.0__py3-none-any.whl → 5.0.2__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.

Potentially problematic release.


This version of pymodaq might be problematic. Click here for more details.

Files changed (63) hide show
  1. pymodaq/__init__.py +55 -89
  2. pymodaq/control_modules/daq_move.py +129 -55
  3. pymodaq/control_modules/daq_move_ui.py +42 -11
  4. pymodaq/control_modules/daq_viewer.py +32 -13
  5. pymodaq/control_modules/move_utility_classes.py +346 -79
  6. pymodaq/control_modules/utils.py +26 -9
  7. pymodaq/control_modules/viewer_utility_classes.py +51 -14
  8. pymodaq/daq_utils/daq_utils.py +6 -0
  9. pymodaq/dashboard.py +532 -263
  10. pymodaq/examples/qt_less_standalone_module.py +128 -0
  11. pymodaq/extensions/bayesian/bayesian_optimisation.py +30 -21
  12. pymodaq/extensions/bayesian/utils.py +6 -3
  13. pymodaq/extensions/daq_logger/__init__.py +1 -0
  14. pymodaq/extensions/daq_logger/daq_logger.py +4 -5
  15. pymodaq/extensions/daq_scan.py +28 -8
  16. pymodaq/extensions/daq_scan_ui.py +7 -9
  17. pymodaq/extensions/pid/__init__.py +0 -1
  18. pymodaq/extensions/pid/actuator_controller.py +13 -0
  19. pymodaq/extensions/pid/daq_move_PID.py +25 -46
  20. pymodaq/extensions/pid/pid_controller.py +49 -41
  21. pymodaq/extensions/pid/utils.py +7 -31
  22. pymodaq/extensions/utils.py +41 -7
  23. pymodaq/post_treatment/load_and_plot.py +43 -10
  24. pymodaq/resources/setup_plugin.py +1 -0
  25. pymodaq/updater.py +107 -0
  26. pymodaq/utils/chrono_timer.py +6 -7
  27. pymodaq/utils/daq_utils.py +6 -3
  28. pymodaq/utils/data.py +21 -17
  29. pymodaq/utils/enums.py +6 -0
  30. pymodaq/utils/gui_utils/loader_utils.py +29 -2
  31. pymodaq/utils/gui_utils/utils.py +9 -12
  32. pymodaq/utils/gui_utils/widgets/lcd.py +8 -0
  33. pymodaq/utils/h5modules/module_saving.py +5 -2
  34. pymodaq/utils/leco/daq_move_LECODirector.py +22 -16
  35. pymodaq/utils/leco/daq_xDviewer_LECODirector.py +15 -9
  36. pymodaq/utils/leco/leco_director.py +4 -3
  37. pymodaq/utils/leco/pymodaq_listener.py +9 -13
  38. pymodaq/utils/leco/utils.py +40 -7
  39. pymodaq/utils/managers/modules_manager.py +22 -12
  40. pymodaq/utils/managers/overshoot_manager.py +45 -1
  41. pymodaq/utils/managers/preset_manager.py +22 -46
  42. pymodaq/utils/managers/preset_manager_utils.py +17 -13
  43. pymodaq/utils/managers/remote_manager.py +1 -1
  44. pymodaq/utils/messenger.py +6 -0
  45. pymodaq/utils/parameter/__init__.py +5 -1
  46. pymodaq/utils/tcp_ip/mysocket.py +4 -110
  47. pymodaq/utils/tcp_ip/serializer.py +4 -769
  48. pymodaq/utils/tcp_ip/tcp_server_client.py +5 -5
  49. pymodaq-5.0.2.dist-info/METADATA +242 -0
  50. {pymodaq-5.0.0.dist-info → pymodaq-5.0.2.dist-info}/RECORD +54 -55
  51. {pymodaq-5.0.0.dist-info → pymodaq-5.0.2.dist-info}/WHEEL +1 -1
  52. {pymodaq-5.0.0.dist-info → pymodaq-5.0.2.dist-info}/entry_points.txt +1 -0
  53. pymodaq/examples/custom_app.py +0 -255
  54. pymodaq/examples/custom_viewer.py +0 -112
  55. pymodaq/examples/parameter_ex.py +0 -158
  56. pymodaq/examples/preset_MockCamera.xml +0 -1
  57. pymodaq/post_treatment/daq_measurement/daq_measurement_GUI.py +0 -142
  58. pymodaq/post_treatment/daq_measurement/daq_measurement_GUI.ui +0 -232
  59. pymodaq/post_treatment/daq_measurement/daq_measurement_main.py +0 -391
  60. pymodaq/post_treatment/daq_measurement/process_from_QtDesigner_DAQ_Measurement_GUI.bat +0 -2
  61. pymodaq-5.0.0.dist-info/METADATA +0 -166
  62. /pymodaq/{post_treatment/daq_measurement → daq_utils}/__init__.py +0 -0
  63. {pymodaq-5.0.0.dist-info → pymodaq-5.0.2.dist-info}/licenses/LICENSE +0 -0
pymodaq/utils/data.py CHANGED
@@ -1,15 +1,24 @@
1
1
  import numpy as np
2
2
  import numbers
3
3
  import warnings
4
+ import copy
4
5
 
5
6
  from typing import List
6
7
 
7
8
  from pymodaq_utils.warnings import deprecation_msg, user_warning
8
9
 
9
10
  from pymodaq_data.data import (DataRaw, DataWithAxes, DataToExport, DataCalculated, DataDim,
10
- DataSource, DataBase, Axis, NavAxis)
11
+ DataSource, DataBase, Axis, NavAxis, DataDistribution, Q_, Unit,
12
+ ) # imported here for backcompatibility. Will allow also the object serialization
13
+ # registration
11
14
 
12
15
 
16
+ from pymodaq_utils.serialize.factory import SerializableFactory, SerializableBase
17
+
18
+ ser_factory = SerializableFactory()
19
+
20
+
21
+ @ser_factory.register_decorator()
13
22
  class DataActuator(DataRaw):
14
23
  """Specialized DataWithAxes set with source as 'raw'.
15
24
  To be used for raw data generated by actuator plugins"""
@@ -24,27 +33,21 @@ class DataActuator(DataRaw):
24
33
 
25
34
  def __repr__(self):
26
35
  if self.dim.name == 'Data0D':
27
- return f'<{self.__class__.__name__} ({self.data[0][0]})>'
36
+ return f'<{self.__class__.__name__} ({self.data[0][0]} {self.units})>'
28
37
  else:
29
- return f'<{self.__class__.__name__} ({self.shape})>'
38
+ return f'<{self.__class__.__name__} ({self.shape} {self.units})>'
30
39
 
31
- def value(self) -> float:
32
- """Returns the underlying float value (of the first elt in the data list) if this data
33
- holds only a float otherwise returns a mean of the underlying data"""
34
- if self.length == 1 and self.size == 1:
35
- return float(self.data[0][0])
36
- else:
37
- return float(np.mean(self.data))
40
+ def __add__(self, other: object):
41
+ if isinstance(other, numbers.Number) and self.length == 1 and self.size == 1:
42
+ new_data = copy.deepcopy(self)
43
+ new_data = new_data + DataActuator(data=other)
44
+ return new_data
38
45
 
39
- def values(self) -> List[float]:
40
- """Returns the underlying float value (for each data array in the data list) if this data
41
- holds only a float otherwise returns a mean of the underlying data"""
42
- if self.length == 1 and self.size == 1:
43
- return [float(data_array[0]) for data_array in self.data]
44
46
  else:
45
- return [float(np.mean(data_array)) for data_array in self.data]
47
+ return super().__add__(other)
46
48
 
47
49
 
50
+ @ser_factory.register_decorator()
48
51
  class DataFromPlugins(DataRaw):
49
52
  """Specialized DataWithAxes set with source as 'raw'. To be used for raw data generated by Detector plugins
50
53
 
@@ -88,12 +91,14 @@ class DataFromPlugins(DataRaw):
88
91
  super().__init__(*args, **kwargs)
89
92
 
90
93
 
94
+ @ser_factory.register_decorator()
91
95
  class DataScan(DataToExport):
92
96
  """Specialized DataToExport.To be used for data to be saved """
93
97
  def __init__(self, name: str, data: List[DataWithAxes] = [], **kwargs):
94
98
  super().__init__(name, data, **kwargs)
95
99
 
96
100
 
101
+ @ser_factory.register_decorator()
97
102
  class DataToActuators(DataToExport):
98
103
  """ Particular case of a DataToExport adding one named parameter to indicate what kind of change
99
104
  should be applied to the actuators, absolute or relative
@@ -120,4 +125,3 @@ class DataToActuators(DataToExport):
120
125
 
121
126
  def __repr__(self):
122
127
  return f'{super().__repr__()}: {self.mode}'
123
-
pymodaq/utils/enums.py ADDED
@@ -0,0 +1,6 @@
1
+ from pymodaq_utils.enums import *
2
+
3
+ from pymodaq_utils.warnings import deprecation_msg
4
+
5
+ deprecation_msg('Importing enums stuff from pymodaq is deprecated in pymodaq>5.0.0,'
6
+ 'please use the pymodaq_utils.enums module')
@@ -5,19 +5,42 @@ from qtpy import QtWidgets
5
5
  from pymodaq.dashboard import DashBoard
6
6
  from pymodaq.utils.gui_utils import DockArea
7
7
  from pymodaq.utils.config import get_set_preset_path
8
+ from pymodaq.extensions.utils import CustomExt
8
9
 
9
10
 
10
- def load_dashboard_with_preset(preset_name: str, extension_name: str):
11
+ def load_dashboard_with_preset(preset_name: str, extension_name: str) -> \
12
+ (DashBoard, CustomExt, QtWidgets.QMainWindow):
13
+ """ Load the Dashboard using a given preset then load an extension
14
+
15
+ Parameters
16
+ ----------
17
+ preset_name: str
18
+ The filename (without extension) defining the preset to be loaded in the Dashboard
19
+ extension_name: str
20
+ The name of the extension. Either the builtins ones:
21
+ * 'DAQScan'
22
+ * 'DAQLogger'
23
+ * 'DAQ_PID'
24
+ * 'Bayesian'
25
+
26
+ or the ones defined within a plugin
27
+
28
+ Returns
29
+ -------
30
+
31
+ """
11
32
  win = QtWidgets.QMainWindow()
12
33
  area = DockArea()
13
34
  win.setCentralWidget(area)
14
35
  win.resize(1000, 500)
15
- win.setWindowTitle('PyMoDAQ Dashboard')
36
+ win.setWindowTitle('extension_name')
16
37
  win.show()
17
38
 
18
39
  # win.setVisible(False)
19
40
  dashboard = DashBoard(area)
20
41
 
42
+ preset_name = Path(preset_name).stem
43
+
21
44
  file = Path(get_set_preset_path()).joinpath(f"{preset_name}.xml")
22
45
 
23
46
  if file is not None and file.exists():
@@ -26,6 +49,10 @@ def load_dashboard_with_preset(preset_name: str, extension_name: str):
26
49
  extension = dashboard.load_scan_module()
27
50
  elif extension_name == 'DAQLogger':
28
51
  extension = dashboard.load_log_module()
52
+ elif extension_name == 'DAQ_PID':
53
+ extension = dashboard.load_pid_module()
54
+ elif extension_name == 'Bayesian':
55
+ extension = dashboard.load_bayesian()
29
56
  else:
30
57
  extension = dashboard.load_extension_from_name(extension_name)
31
58
  else:
@@ -1,21 +1,18 @@
1
- import sys
2
-
3
- from qtpy.QtCore import QObject, Signal, QEvent, QBuffer, QIODevice, Qt
4
- from qtpy import QtWidgets, QtCore, QtGui
5
-
6
- from pathlib import Path
7
1
  from pymodaq_utils.config import Config
8
2
  from pymodaq_utils.logger import set_logger, get_module_name
9
3
 
4
+ from pymodaq_gui.utils.splash import get_splash_sc
5
+
6
+
10
7
  config = Config()
11
8
  logger = set_logger(get_module_name(__file__))
12
9
 
10
+ from pymodaq_utils.warnings import deprecation_msg
11
+
12
+ deprecation_msg('Importing get_splash_sc stuff from pymodaq is deprecated '
13
+ 'in pymodaq>5.0.0,'
14
+ 'please use the same method from the '
15
+ 'pymodaq_gui.utils.splash module')
13
16
 
14
- def get_splash_sc():
15
- here = Path(__file__)
16
- splash_sc = QtWidgets.QSplashScreen(
17
- QtGui.QPixmap(str(here.parent.parent.parent.joinpath('splash.png'))),
18
- Qt.WindowStaysOnTopHint)
19
- return splash_sc
20
17
 
21
18
 
@@ -0,0 +1,8 @@
1
+ from pymodaq_gui.utils.widgets.lcd import LCD
2
+
3
+ from pymodaq_utils.warnings import deprecation_msg
4
+
5
+ deprecation_msg('Importing LCD from pymodaq is deprecated '
6
+ 'in pymodaq>5.0.0,'
7
+ 'please use the same method from the '
8
+ 'pymodaq_gui.utils.widgets.lcd module')
@@ -11,7 +11,7 @@ import xml.etree.ElementTree as ET
11
11
 
12
12
 
13
13
  import numpy as np
14
-
14
+ from pymodaq_utils.logger import set_logger, get_module_name
15
15
  from pymodaq_utils.abstract import ABCMeta, abstract_attribute, abstractmethod
16
16
  from pymodaq_utils.utils import capitalize
17
17
  from pymodaq_data.data import Axis, DataDim, DataWithAxes, DataToExport, DataDistribution
@@ -28,6 +28,9 @@ if TYPE_CHECKING:
28
28
  from pymodaq.extensions.daq_logger.h5logging import H5Logger
29
29
 
30
30
 
31
+ logger = set_logger(get_module_name(__file__))
32
+
33
+
31
34
  class ModuleSaver(metaclass=ABCMeta):
32
35
  """Abstract base class to save info and data from main modules (DAQScan, DAQViewer, DAQMove, ...)"""
33
36
  group_type: GroupType = abstract_attribute()
@@ -374,7 +377,7 @@ class ScanSaver(ModuleSaver):
374
377
  try:
375
378
  detector.insert_data(indexes, where=self._module_group, distribution=distribution)
376
379
  except Exception as e:
377
- pass
380
+ logger.exception(f'Cannot insert data: {str(e)}')
378
381
 
379
382
 
380
383
  class LoggerSaver(ScanSaver):
@@ -17,8 +17,7 @@ from pymodaq_gui.parameter import Parameter
17
17
 
18
18
  from pymodaq.utils.leco.leco_director import LECODirector, leco_parameters
19
19
  from pymodaq.utils.leco.director_utils import ActuatorDirector
20
- from pymodaq.utils.tcp_ip.serializer import DeSerializer
21
-
20
+ from pymodaq_utils.serialize.serializer_legacy import DeSerializer
22
21
 
23
22
  class DAQ_Move_LECODirector(LECODirector, DAQ_Move_base):
24
23
  """A control module, which in the dashboard, allows to control a remote Move module.
@@ -38,8 +37,6 @@ class DAQ_Move_LECODirector(LECODirector, DAQ_Move_base):
38
37
  settings: Parameter
39
38
  controller: ActuatorDirector
40
39
 
41
- is_multiaxes = False
42
- axes_names = []
43
40
  params_client = [] # parameters of a client grabber
44
41
  data_actuator_type = DataActuatorType['float'] # DataActuatorType['DataActuator']
45
42
 
@@ -47,19 +44,21 @@ class DAQ_Move_LECODirector(LECODirector, DAQ_Move_base):
47
44
  'get_actuator_value', 'stop_motion', 'position_is',
48
45
  'move_done']
49
46
  socket_types = ["ACTUATOR"]
50
- params = [
51
- ] + comon_parameters_fun(is_multiaxes=is_multiaxes, axes_names=axes_names) + leco_parameters
47
+ params = comon_parameters_fun() + leco_parameters
52
48
 
53
49
  def __init__(self, parent=None, params_state=None, **kwargs) -> None:
54
50
  super().__init__(parent=parent,
55
51
  params_state=params_state, **kwargs)
56
52
  self.register_rpc_methods((
57
53
  self.set_info,
54
+ ))
55
+ for method in (
58
56
  self.set_position,
59
57
  self.set_move_done,
60
58
  self.set_x_axis,
61
59
  self.set_y_axis,
62
- ))
60
+ ):
61
+ self.listener.register_binary_rpc_method(method, accept_binary_input=True)
63
62
 
64
63
  # copied, I think it is good:
65
64
  self.settings.child('bounds').hide()
@@ -143,22 +142,29 @@ class DAQ_Move_LECODirector(LECODirector, DAQ_Move_base):
143
142
  self.controller.stop_motion()
144
143
 
145
144
  # Methods accessible via remote calls
146
- def _set_position_value(self, position: Union[str, float]) -> DataActuator:
147
- if isinstance(position, str):
148
- deserializer = DeSerializer.from_b64_string(position)
149
- pos = deserializer.dwa_deserialization()
145
+ def _set_position_value(
146
+ self, position: Union[str, float, None], additional_payload=None
147
+ ) -> DataActuator:
148
+ if position:
149
+ if isinstance(position, str):
150
+ deserializer = DeSerializer.from_b64_string(position)
151
+ pos = deserializer.dwa_deserialization()
152
+ else:
153
+ pos = DataActuator(data=position)
154
+ elif additional_payload is not None:
155
+ pos = DeSerializer(additional_payload[0]).dwa_deserialization()
150
156
  else:
151
- pos = DataActuator(data=position)
157
+ raise ValueError("No position given")
152
158
  pos = self.get_position_with_scaling(pos) # type: ignore
153
159
  self._current_value = pos
154
160
  return pos
155
161
 
156
- def set_position(self, position: Union[str, float]) -> None:
157
- pos = self._set_position_value(position=position)
162
+ def set_position(self, position: Union[str, float, None], additional_payload=None) -> None:
163
+ pos = self._set_position_value(position=position, additional_payload=additional_payload)
158
164
  self.emit_status(ThreadCommand('get_actuator_value', [pos]))
159
165
 
160
- def set_move_done(self, position: Union[str, float]) -> None:
161
- pos = self._set_position_value(position=position)
166
+ def set_move_done(self, position: Union[str, float, None], additional_payload=None) -> None:
167
+ pos = self._set_position_value(position=position, additional_payload=additional_payload)
162
168
  self.emit_status(ThreadCommand('move_done', [pos]))
163
169
 
164
170
  def set_x_axis(self, data, label: str = "", units: str = "") -> None:
@@ -1,13 +1,14 @@
1
-
2
- from typing import Union
1
+ from __future__ import annotations
2
+ from typing import Optional, Union
3
3
 
4
4
  from easydict import EasyDict as edict
5
5
 
6
6
  from pymodaq.control_modules.viewer_utility_classes import DAQ_Viewer_base, comon_parameters, main
7
7
 
8
8
  from pymodaq_utils.utils import ThreadCommand, getLineInfo
9
+
9
10
  from pymodaq_gui.parameter import Parameter
10
- from pymodaq.utils.tcp_ip.serializer import DeSerializer
11
+ from pymodaq_utils.serialize.serializer_legacy import DeSerializer
11
12
 
12
13
  from pymodaq.utils.leco.leco_director import LECODirector, leco_parameters
13
14
  from pymodaq.utils.leco.director_utils import DetectorDirector
@@ -29,16 +30,18 @@ class DAQ_xDViewer_LECODirector(LECODirector, DAQ_Viewer_base):
29
30
  "Status", "Done", "Server Closed",
30
31
  "Info", "Infos", "Info_xml", 'x_axis', 'y_axis']
31
32
  socket_types = ["GRABBER"]
32
- params = [
33
- ] + comon_parameters + leco_parameters
33
+ params = comon_parameters + leco_parameters
34
34
 
35
35
  def __init__(self, parent=None, params_state=None, grabber_type: str = "0D", **kwargs) -> None:
36
36
  super().__init__(parent=parent, params_state=params_state, **kwargs)
37
37
  self.register_rpc_methods((
38
38
  self.set_x_axis,
39
39
  self.set_y_axis,
40
- self.set_data,
41
40
  ))
41
+ for method in (
42
+ self.set_data,
43
+ ):
44
+ self.listener.register_binary_rpc_method(method, accept_binary_input=True)
42
45
 
43
46
  self.client_type = "GRABBER"
44
47
  self.x_axis = None
@@ -150,7 +153,8 @@ class DAQ_xDViewer_LECODirector(LECODirector, DAQ_Viewer_base):
150
153
  self.y_axis = dict(data=data, label=label, units=units)
151
154
  self.emit_y_axis()
152
155
 
153
- def set_data(self, data: Union[list, str]) -> None:
156
+ def set_data(self, data: Union[list, str, None],
157
+ additional_payload: Optional[list[bytes]]=None) -> None:
154
158
  """
155
159
  Set the grabbed data signal.
156
160
 
@@ -160,10 +164,12 @@ class DAQ_xDViewer_LECODirector(LECODirector, DAQ_Viewer_base):
160
164
  """
161
165
  if isinstance(data, str):
162
166
  deserializer = DeSerializer.from_b64_string(data)
163
- dte = deserializer.dte_deserialization()
164
- self.dte_signal.emit(dte)
167
+ elif additional_payload is not None:
168
+ deserializer = DeSerializer(additional_payload[0])
165
169
  else:
166
170
  raise NotImplementedError("Not implemented to set a list of values.")
171
+ dte = deserializer.dte_deserialization()
172
+ self.dte_signal.emit(dte)
167
173
 
168
174
 
169
175
  if __name__ == '__main__':
@@ -1,8 +1,9 @@
1
-
2
1
  import random
3
-
4
2
  from typing import Callable, Sequence, List
5
3
 
4
+ from pymodaq_utils.enums import StrEnum
5
+ from typing import Callable, Sequence, List, Optional, Union
6
+
6
7
  import pymodaq_gui.parameter.utils as putils
7
8
  # object used to send info back to the main thread:
8
9
  from pymodaq_utils.utils import ThreadCommand
@@ -14,7 +15,7 @@ from pymodaq.utils.leco.pymodaq_listener import PymodaqListener
14
15
 
15
16
  leco_parameters = [
16
17
  {'title': 'Actor name:', 'name': 'actor_name', 'type': 'str', 'value': "actor_name",
17
- 'text': 'Name of the actor plugin to communicate with.'},
18
+ 'tip': 'Name of the actor plugin to communicate with.'},
18
19
  ]
19
20
 
20
21
 
@@ -1,11 +1,6 @@
1
1
 
2
- try:
3
- from enum import StrEnum # type: ignore
4
- except ImportError:
5
- from enum import Enum
2
+ from pymodaq_utils.enums import StrEnum
6
3
 
7
- class StrEnum(str, Enum):
8
- pass
9
4
  import logging
10
5
  from threading import Event
11
6
  from typing import Optional, Union, List, Type
@@ -16,8 +11,9 @@ from qtpy.QtCore import QObject, Signal # type: ignore
16
11
 
17
12
  from pymodaq_utils.utils import ThreadCommand
18
13
  from pymodaq_gui.parameter import ioxml
19
- from pymodaq.utils.tcp_ip.serializer import DataWithAxes, SERIALIZABLE, DeSerializer
20
- from pymodaq.utils.leco.utils import serialize_object
14
+ from pymodaq_data.data import DataWithAxes
15
+ from pymodaq_utils.serialize.serializer_legacy import SERIALIZABLE, DeSerializer
16
+ from pymodaq.utils.leco.utils import binary_serialization_to_kwargs
21
17
 
22
18
 
23
19
  class LECOClientCommands(StrEnum):
@@ -220,7 +216,7 @@ class ActorListener(PymodaqListener):
220
216
  self.communicator.ask_rpc(
221
217
  receiver=self.remote_name,
222
218
  method="set_data",
223
- data=serialize_object(value),
219
+ **binary_serialization_to_kwargs(value),
224
220
  )
225
221
 
226
222
  elif command.command == 'send_info':
@@ -236,14 +232,14 @@ class ActorListener(PymodaqListener):
236
232
  value = command.attribute[0] # type: ignore
237
233
  self.communicator.ask_rpc(receiver=self.remote_name,
238
234
  method="set_position",
239
- position=serialize_object(value),
235
+ **binary_serialization_to_kwargs(value, data_key="position"),
240
236
  )
241
237
 
242
238
  elif command.command == LECOMoveCommands.MOVE_DONE:
243
239
  value = command.attribute[0] # type: ignore
244
240
  self.communicator.ask_rpc(receiver=self.remote_name,
245
241
  method="set_move_done",
246
- position=serialize_object(value),
242
+ **binary_serialization_to_kwargs(value, data_key="position"),
247
243
  )
248
244
 
249
245
  elif command.command == 'x_axis':
@@ -251,7 +247,7 @@ class ActorListener(PymodaqListener):
251
247
  if isinstance(value, SERIALIZABLE):
252
248
  self.communicator.ask_rpc(receiver=self.remote_name,
253
249
  method="set_x_axis",
254
- data=serialize_object(value),
250
+ **binary_serialization_to_kwargs(value),
255
251
  )
256
252
  elif isinstance(value, dict):
257
253
  self.communicator.ask_rpc(receiver=self.remote_name, method="set_x_axis", **value)
@@ -263,7 +259,7 @@ class ActorListener(PymodaqListener):
263
259
  if isinstance(value, SERIALIZABLE):
264
260
  self.communicator.ask_rpc(receiver=self.remote_name,
265
261
  method="set_y_axis",
266
- data=serialize_object(value),
262
+ **binary_serialization_to_kwargs(value),
267
263
  )
268
264
  elif isinstance(value, dict):
269
265
  self.communicator.ask_rpc(receiver=self.remote_name, method="set_y_axis", **value)
@@ -1,26 +1,59 @@
1
+ from __future__ import annotations
1
2
  import subprocess
2
3
  import sys
3
- from typing import Any, Union, get_args
4
+ from typing import Any, Optional, Union, get_args, TypeVar
4
5
 
6
+ from pymodaq.utils import data
5
7
  # import also the DeSerializer for easier imports in dependents
6
- from pymodaq.utils.tcp_ip.serializer import SERIALIZABLE, Serializer, DeSerializer # type: ignore # noqa
8
+ from pymodaq_utils.serialize.serializer_legacy import Serializer, DeSerializer, SerializableFactory
9
+
10
+ # type: ignore # noqa
7
11
  from pymodaq_utils.logger import set_logger
8
12
 
9
13
 
10
14
  logger = set_logger('leco_utils')
11
-
15
+ ser_factory = SerializableFactory()
12
16
  JSON_TYPES = Union[str, int, float]
13
17
 
14
18
 
19
+
15
20
  def serialize_object(pymodaq_object: Union[SERIALIZABLE, Any]) -> Union[str, Any]:
16
21
  """Serialize a pymodaq object, if it is not JSON compatible."""
17
22
  if isinstance(pymodaq_object, get_args(JSON_TYPES)):
18
23
  return pymodaq_object
19
- elif isinstance(pymodaq_object, get_args(SERIALIZABLE)):
20
- return Serializer(pymodaq_object).to_b64_string()
21
24
  else:
22
- raise ValueError(f"{pymodaq_object} of type '{type(pymodaq_object).__name__}' is neither "
23
- "JSON serializable, nor via PyMoDAQ.")
25
+ return Serializer(pymodaq_object).to_b64_string() # will raise a proper error if the object
26
+ #is not serializable
27
+
28
+
29
+ ## this form below is to be compatible with python <= 3.10
30
+ ## for py>= 3.11 this could be written SERIALIZABLE = Union[ser_factory.get_serializables()]
31
+ SERIALIZABLE = Union[ser_factory.get_serializables()[0]]
32
+ for klass in ser_factory.get_serializables()[1:]:
33
+ SERIALIZABLE = Union[SERIALIZABLE, klass]
34
+
35
+
36
+ def binary_serialization(
37
+ pymodaq_object: Union[SERIALIZABLE, Any],
38
+ ) -> tuple[Optional[Any], Optional[list[bytes]]]:
39
+ """Serialize (binary) a pymodaq object, if it is not JSON compatible."""
40
+ if isinstance(pymodaq_object, get_args(JSON_TYPES)):
41
+ return pymodaq_object, None
42
+ elif isinstance(pymodaq_object, get_args(Union[*ser_factory.get_serializables()])):
43
+ return None, [Serializer(pymodaq_object).to_bytes()]
44
+ else:
45
+ raise ValueError(
46
+ f"{pymodaq_object} of type '{type(pymodaq_object).__name__}' is neither "
47
+ "JSON serializable, nor via PyMoDAQ."
48
+ )
49
+
50
+
51
+ def binary_serialization_to_kwargs(
52
+ pymodaq_object: Union[SERIALIZABLE, Any], data_key: str = "data"
53
+ ) -> dict[str, Any]:
54
+ """Create a dictionary of data parameters and of additional payload to send."""
55
+ d, b = binary_serialization(pymodaq_object=pymodaq_object)
56
+ return {data_key: d, "additional_payload": b}
24
57
 
25
58
 
26
59
  def run_coordinator():
@@ -39,6 +39,7 @@ class ModulesManager(QObject, ParameterManager):
39
39
  selected_actuators: list of DAQ_Move
40
40
  sublist of actuators
41
41
  """
42
+ settings_name = 'ModulesManagerSettings'
42
43
  detectors_changed = Signal(list)
43
44
  actuators_changed = Signal(list)
44
45
  det_done_signal = Signal(DataToExport) # dte here contains DataWithAxes
@@ -117,7 +118,7 @@ class ModulesManager(QObject, ParameterManager):
117
118
  modules = [modules]
118
119
  return [mod.title for mod in modules]
119
120
 
120
- def get_mods_from_names(self, names, mod='det'):
121
+ def get_mods_from_names(self, names, mod='det') -> List[Union['DAQ_Move', 'DAQ_Viewer']]:
121
122
  """Getter of a list of given modules from their name (title)
122
123
 
123
124
  Parameters
@@ -172,9 +173,14 @@ class ModulesManager(QObject, ParameterManager):
172
173
 
173
174
  @property
174
175
  def detectors_all(self):
175
- """Get the list of all detectors"""
176
+ """Get/Set the list of all detectors"""
176
177
  return self._detectors
177
178
 
179
+ @detectors_all.setter
180
+ def detectors_all(self, detectors: List['DAQ_Viewer']):
181
+ self._detectors = detectors
182
+
183
+
178
184
  @property
179
185
  def actuators(self) -> List['DAQ_Move']:
180
186
  """Get the list of selected actuators"""
@@ -185,6 +191,10 @@ class ModulesManager(QObject, ParameterManager):
185
191
  """Get the list of all actuators"""
186
192
  return self._actuators
187
193
 
194
+ @actuators_all.setter
195
+ def actuators_all(self, actuators: List['DAQ_Move']):
196
+ self._actuators = actuators
197
+
188
198
  @property
189
199
  def modules(self):
190
200
  """Get the list of all detectors and actuators"""
@@ -244,11 +254,11 @@ class ModulesManager(QObject, ParameterManager):
244
254
  elif param.name() == 'actuators':
245
255
  self.actuators_changed.emit(param.value()['selected'])
246
256
 
247
- def get_det_data_list(self):
257
+ def get_det_data_list(self) -> DataToExport:
248
258
  """Do a snap of selected detectors, to get the list of all the data and processed data"""
249
259
 
250
260
  self.connect_detectors()
251
- datas: DataToExport = self.grab_datas()
261
+ datas: DataToExport = self.grab_data()
252
262
 
253
263
  data_list0D = datas.get_full_names('data0D')
254
264
  data_list1D = datas.get_full_names('data1D')
@@ -265,6 +275,7 @@ class ModulesManager(QObject, ParameterManager):
265
275
  dict(all_items=data_listND, selected=[]))
266
276
 
267
277
  self.connect_detectors(False)
278
+ return datas
268
279
 
269
280
  def get_selected_probed_data(self, dim='0D'):
270
281
  """Get the name of selected data names of a given dimensionality
@@ -276,7 +287,7 @@ class ModulesManager(QObject, ParameterManager):
276
287
  """
277
288
  return self.settings.child('data_dimensions', f'det_data_list{dim.upper()}').value()['selected']
278
289
 
279
- def grab_datas(self, **kwargs):
290
+ def grab_data(self, **kwargs):
280
291
  """Do a single grab of connected and selected detectors"""
281
292
  self.det_done_datas = DataToExport(name=__class__.__name__, control_module='DAQ_Viewer')
282
293
  self._received_data = 0
@@ -300,6 +311,10 @@ class ModulesManager(QObject, ParameterManager):
300
311
  self.det_done_signal.emit(self.det_done_datas)
301
312
  return self.det_done_datas
302
313
 
314
+ def grab_datas(self, **kwargs):
315
+ """ For back compatibility but use self.grab_data"""
316
+ return self.grab_data(**kwargs)
317
+
303
318
  def connect_actuators(self, connect=True, slot=None, signal='move_done'):
304
319
  """Connect the selected actuators signal to a given or default slot
305
320
 
@@ -359,12 +374,12 @@ class ModulesManager(QObject, ParameterManager):
359
374
  sig.connect(slot)
360
375
  else:
361
376
 
362
- for sig in [mod.grab_done_signal for mod in self.detectors_all]:
377
+ for sig in [mod.grab_done_signal for mod in self.detectors]:
363
378
  try:
364
379
  sig.disconnect(slot)
365
380
  except TypeError as e:
366
381
  # means the slot was not previously connected
367
- logger.info(str(e))
382
+ logger.info(f'Could not disconnect grab signal from the {slot} slot', stacklevel=2)
368
383
 
369
384
  self.detectors_connected = connect
370
385
 
@@ -482,11 +497,6 @@ class ModulesManager(QObject, ParameterManager):
482
497
  self.det_done_flag = True
483
498
  self.settings.child('det_done').setValue(self.det_done_flag)
484
499
 
485
- # if data.name not in list(self.det_done_datas.keys()):
486
- # self.det_done_datas[data['name']] = data
487
- # if len(self.det_done_datas.items()) == len(self.detectors):
488
- # self.det_done_flag = True
489
-
490
500
 
491
501
  if __name__ == '__main__':
492
502
  import sys