pymodaq 5.1.6__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 (154) hide show
  1. pymodaq/__init__.py +98 -0
  2. pymodaq/control_modules/__init__.py +1 -0
  3. pymodaq/control_modules/daq_move.py +1238 -0
  4. pymodaq/control_modules/daq_move_ui/__init__.py +0 -0
  5. pymodaq/control_modules/daq_move_ui/factory.py +48 -0
  6. pymodaq/control_modules/daq_move_ui/ui_base.py +359 -0
  7. pymodaq/control_modules/daq_move_ui/uis/__init__.py +0 -0
  8. pymodaq/control_modules/daq_move_ui/uis/binary.py +139 -0
  9. pymodaq/control_modules/daq_move_ui/uis/original.py +120 -0
  10. pymodaq/control_modules/daq_move_ui/uis/relative.py +124 -0
  11. pymodaq/control_modules/daq_move_ui/uis/simple.py +126 -0
  12. pymodaq/control_modules/daq_viewer.py +1517 -0
  13. pymodaq/control_modules/daq_viewer_ui.py +407 -0
  14. pymodaq/control_modules/mocks.py +57 -0
  15. pymodaq/control_modules/move_utility_classes.py +1141 -0
  16. pymodaq/control_modules/thread_commands.py +137 -0
  17. pymodaq/control_modules/ui_utils.py +72 -0
  18. pymodaq/control_modules/utils.py +591 -0
  19. pymodaq/control_modules/viewer_utility_classes.py +670 -0
  20. pymodaq/daq_utils/__init__.py +0 -0
  21. pymodaq/daq_utils/daq_utils.py +6 -0
  22. pymodaq/dashboard.py +2396 -0
  23. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_Client.aliases +3 -0
  24. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_Client.lvlps +3 -0
  25. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_Client.lvproj +32 -0
  26. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_Client.vi +0 -0
  27. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_Server_1Dgaussian.vi +0 -0
  28. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_Server_2Dgaussian.vi +0 -0
  29. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_read_cmd.vi +0 -0
  30. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_read_float.vi +0 -0
  31. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_read_int.vi +0 -0
  32. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_send_data.vi +0 -0
  33. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_send_int.vi +0 -0
  34. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_send_scalar.vi +0 -0
  35. pymodaq/examples/Labview_TCP_Client/DAQ_TCP_send_string.vi +0 -0
  36. pymodaq/examples/Labview_TCP_Client/client_state.ctl +0 -0
  37. pymodaq/examples/Labview_TCP_Client/cmd_types.ctl +0 -0
  38. pymodaq/examples/__init__.py +0 -0
  39. pymodaq/examples/function_plotter.py +160 -0
  40. pymodaq/examples/nonlinearscanner.py +126 -0
  41. pymodaq/examples/qt_less_standalone_module.py +165 -0
  42. pymodaq/examples/tcp_client.py +97 -0
  43. pymodaq/extensions/__init__.py +25 -0
  44. pymodaq/extensions/adaptive/__init__.py +2 -0
  45. pymodaq/extensions/adaptive/adaptive_optimization.py +179 -0
  46. pymodaq/extensions/adaptive/loss_function/_1d_loss_functions.py +73 -0
  47. pymodaq/extensions/adaptive/loss_function/_2d_loss_functions.py +73 -0
  48. pymodaq/extensions/adaptive/loss_function/__init__.py +3 -0
  49. pymodaq/extensions/adaptive/loss_function/loss_factory.py +110 -0
  50. pymodaq/extensions/adaptive/utils.py +123 -0
  51. pymodaq/extensions/bayesian/__init__.py +2 -0
  52. pymodaq/extensions/bayesian/acquisition/__init__.py +2 -0
  53. pymodaq/extensions/bayesian/acquisition/acquisition_function_factory.py +80 -0
  54. pymodaq/extensions/bayesian/acquisition/base_acquisition_function.py +105 -0
  55. pymodaq/extensions/bayesian/bayesian_optimization.py +143 -0
  56. pymodaq/extensions/bayesian/utils.py +180 -0
  57. pymodaq/extensions/console.py +73 -0
  58. pymodaq/extensions/daq_logger/__init__.py +1 -0
  59. pymodaq/extensions/daq_logger/abstract.py +52 -0
  60. pymodaq/extensions/daq_logger/daq_logger.py +519 -0
  61. pymodaq/extensions/daq_logger/db/__init__.py +0 -0
  62. pymodaq/extensions/daq_logger/db/db_logger.py +300 -0
  63. pymodaq/extensions/daq_logger/db/db_logger_models.py +100 -0
  64. pymodaq/extensions/daq_logger/h5logging.py +84 -0
  65. pymodaq/extensions/daq_scan.py +1218 -0
  66. pymodaq/extensions/daq_scan_ui.py +241 -0
  67. pymodaq/extensions/data_mixer/__init__.py +0 -0
  68. pymodaq/extensions/data_mixer/daq_0Dviewer_DataMixer.py +97 -0
  69. pymodaq/extensions/data_mixer/data_mixer.py +262 -0
  70. pymodaq/extensions/data_mixer/model.py +108 -0
  71. pymodaq/extensions/data_mixer/models/__init__.py +0 -0
  72. pymodaq/extensions/data_mixer/models/equation_model.py +91 -0
  73. pymodaq/extensions/data_mixer/models/gaussian_fit_model.py +65 -0
  74. pymodaq/extensions/data_mixer/parser.py +53 -0
  75. pymodaq/extensions/data_mixer/utils.py +23 -0
  76. pymodaq/extensions/h5browser.py +9 -0
  77. pymodaq/extensions/optimizers_base/__init__.py +0 -0
  78. pymodaq/extensions/optimizers_base/optimizer.py +1016 -0
  79. pymodaq/extensions/optimizers_base/thread_commands.py +22 -0
  80. pymodaq/extensions/optimizers_base/utils.py +427 -0
  81. pymodaq/extensions/pid/__init__.py +16 -0
  82. pymodaq/extensions/pid/actuator_controller.py +14 -0
  83. pymodaq/extensions/pid/daq_move_PID.py +154 -0
  84. pymodaq/extensions/pid/pid_controller.py +1016 -0
  85. pymodaq/extensions/pid/utils.py +189 -0
  86. pymodaq/extensions/utils.py +111 -0
  87. pymodaq/icon.ico +0 -0
  88. pymodaq/post_treatment/__init__.py +6 -0
  89. pymodaq/post_treatment/load_and_plot.py +352 -0
  90. pymodaq/resources/__init__.py +0 -0
  91. pymodaq/resources/config_template.toml +57 -0
  92. pymodaq/resources/preset_default.xml +1 -0
  93. pymodaq/resources/setup_plugin.py +73 -0
  94. pymodaq/splash.png +0 -0
  95. pymodaq/utils/__init__.py +0 -0
  96. pymodaq/utils/array_manipulation.py +6 -0
  97. pymodaq/utils/calibration_camera.py +180 -0
  98. pymodaq/utils/chrono_timer.py +203 -0
  99. pymodaq/utils/config.py +53 -0
  100. pymodaq/utils/conftests.py +5 -0
  101. pymodaq/utils/daq_utils.py +158 -0
  102. pymodaq/utils/data.py +128 -0
  103. pymodaq/utils/enums.py +6 -0
  104. pymodaq/utils/exceptions.py +38 -0
  105. pymodaq/utils/gui_utils/__init__.py +10 -0
  106. pymodaq/utils/gui_utils/loader_utils.py +75 -0
  107. pymodaq/utils/gui_utils/utils.py +18 -0
  108. pymodaq/utils/gui_utils/widgets/lcd.py +8 -0
  109. pymodaq/utils/h5modules/__init__.py +2 -0
  110. pymodaq/utils/h5modules/module_saving.py +526 -0
  111. pymodaq/utils/leco/__init__.py +25 -0
  112. pymodaq/utils/leco/daq_move_LECODirector.py +217 -0
  113. pymodaq/utils/leco/daq_xDviewer_LECODirector.py +163 -0
  114. pymodaq/utils/leco/director_utils.py +74 -0
  115. pymodaq/utils/leco/leco_director.py +166 -0
  116. pymodaq/utils/leco/pymodaq_listener.py +364 -0
  117. pymodaq/utils/leco/rpc_method_definitions.py +43 -0
  118. pymodaq/utils/leco/utils.py +74 -0
  119. pymodaq/utils/logger.py +6 -0
  120. pymodaq/utils/managers/__init__.py +0 -0
  121. pymodaq/utils/managers/batchscan_manager.py +346 -0
  122. pymodaq/utils/managers/modules_manager.py +589 -0
  123. pymodaq/utils/managers/overshoot_manager.py +242 -0
  124. pymodaq/utils/managers/preset_manager.py +229 -0
  125. pymodaq/utils/managers/preset_manager_utils.py +262 -0
  126. pymodaq/utils/managers/remote_manager.py +484 -0
  127. pymodaq/utils/math_utils.py +6 -0
  128. pymodaq/utils/messenger.py +6 -0
  129. pymodaq/utils/parameter/__init__.py +10 -0
  130. pymodaq/utils/parameter/utils.py +6 -0
  131. pymodaq/utils/scanner/__init__.py +5 -0
  132. pymodaq/utils/scanner/scan_config.py +16 -0
  133. pymodaq/utils/scanner/scan_factory.py +259 -0
  134. pymodaq/utils/scanner/scan_selector.py +477 -0
  135. pymodaq/utils/scanner/scanner.py +324 -0
  136. pymodaq/utils/scanner/scanners/_1d_scanners.py +174 -0
  137. pymodaq/utils/scanner/scanners/_2d_scanners.py +299 -0
  138. pymodaq/utils/scanner/scanners/__init__.py +1 -0
  139. pymodaq/utils/scanner/scanners/sequential.py +224 -0
  140. pymodaq/utils/scanner/scanners/tabular.py +319 -0
  141. pymodaq/utils/scanner/utils.py +110 -0
  142. pymodaq/utils/svg/__init__.py +6 -0
  143. pymodaq/utils/svg/svg_renderer.py +20 -0
  144. pymodaq/utils/svg/svg_view.py +35 -0
  145. pymodaq/utils/svg/svg_viewer2D.py +50 -0
  146. pymodaq/utils/tcp_ip/__init__.py +6 -0
  147. pymodaq/utils/tcp_ip/mysocket.py +12 -0
  148. pymodaq/utils/tcp_ip/serializer.py +13 -0
  149. pymodaq/utils/tcp_ip/tcp_server_client.py +772 -0
  150. pymodaq-5.1.6.dist-info/METADATA +238 -0
  151. pymodaq-5.1.6.dist-info/RECORD +154 -0
  152. pymodaq-5.1.6.dist-info/WHEEL +4 -0
  153. pymodaq-5.1.6.dist-info/entry_points.txt +7 -0
  154. pymodaq-5.1.6.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,364 @@
1
+
2
+ from pymodaq_utils.enums import StrEnum
3
+
4
+ import logging
5
+ from threading import Event
6
+ from typing import cast, Optional, Union, List, Sequence, Type
7
+
8
+ from pyleco.core import COORDINATOR_PORT
9
+ from pyleco.json_utils.errors import JSONRPCError, RECEIVER_UNKNOWN, NODE_UNKNOWN
10
+ from pyleco.utils.listener import Listener, PipeHandler
11
+ from qtpy.QtCore import QObject, Signal # type: ignore
12
+
13
+ from pymodaq_data.data import DataWithAxes
14
+ from pymodaq_utils.serialize.factory import SerializableFactory, SerializableBase
15
+ from pymodaq_utils.utils import ThreadCommand
16
+ from pymodaq_gui.parameter import ioxml
17
+ from pymodaq_gui.parameter.utils import ParameterWithPath
18
+
19
+ from pymodaq.utils.leco.utils import binary_serialization_to_kwargs
20
+ from pymodaq.utils.leco.rpc_method_definitions import (
21
+ GenericMethods,
22
+ MoveMethods,
23
+ ViewerMethods,
24
+ GenericDirectorMethods,
25
+ MoveDirectorMethods,
26
+ ViewerDirectorMethods,
27
+ )
28
+
29
+
30
+ # Commands for ThreadCommand
31
+ class LECOClientCommands(StrEnum):
32
+ LECO_CONNECTED = "leco_connected"
33
+ LECO_DISCONNECTED = "leco_disconnected"
34
+
35
+
36
+ class LECOCommands(StrEnum):
37
+ CONNECT = "ini_connection"
38
+ QUIT = "quit"
39
+ GET_SETTINGS = 'get_settings'
40
+ SET_DIRECTOR_SETTINGS = 'set_director_settings'
41
+ SET_INFO = 'set_info'
42
+ SEND_INFO = 'send_info'
43
+
44
+
45
+ class LECOMoveCommands(StrEnum):
46
+ POSITION = 'position_is'
47
+ MOVE_DONE = 'move_done'
48
+ UNITS_CHANGED = 'units_changed'
49
+ STOP = 'stop_motion'
50
+ MOVE_ABS = 'move_abs'
51
+ MOVE_REL = 'move_rel'
52
+ MOVE_HOME = 'move_home'
53
+ GET_ACTUATOR_VALUE = 'get_actuator_value'
54
+
55
+
56
+ class LECOViewerCommands(StrEnum):
57
+ DATA_READY = 'data_ready'
58
+ GRAB = 'grab'
59
+ SNAP = 'snap'
60
+ STOP = 'stop_grab'
61
+
62
+
63
+ class ListenerSignals(QObject):
64
+ cmd_signal = Signal(ThreadCommand)
65
+ """
66
+ Possible messages sendable via `cmd_signal`
67
+ For all modules: Info, Infos, Info_xml, set_info
68
+
69
+ For a detector: Send Data 0D, Send Data 1D, Send Data 2D
70
+
71
+ For an actuator: move_abs, move_home, move_rel, check_position, stop_motion
72
+ """
73
+ # message = Signal(Message)
74
+
75
+
76
+ class PymodaqPipeHandler(PipeHandler):
77
+
78
+ def __init__(self, name: str, signals: ListenerSignals, **kwargs) -> None:
79
+ super().__init__(name, **kwargs)
80
+ self.signals = signals
81
+ self.register_data_types_for_deserialization()
82
+
83
+ def register_data_types_for_deserialization(
84
+ self, types: Optional[Sequence[type[SerializableBase]]] = None
85
+ ) -> None:
86
+ """Register different data types for deserialization in subclasses."""
87
+ if types is None:
88
+ return
89
+ for cls in types:
90
+ SerializableFactory().register_from_type(
91
+ cls, cls.serialize, cls.deserialize
92
+ )
93
+
94
+ class ActorHandler(PymodaqPipeHandler):
95
+ def register_data_types_for_deserialization(
96
+ self, types: Optional[Sequence[type[SerializableBase]]] = None
97
+ ) -> None:
98
+ all_types: Sequence[type[SerializableBase]] = [DataWithAxes]
99
+ if types:
100
+ all_types.extend(types) # type: ignore
101
+ super().register_data_types_for_deserialization(all_types)
102
+
103
+ def register_rpc_methods(self) -> None:
104
+ super().register_rpc_methods()
105
+ self.register_binary_rpc_method(
106
+ self.set_info, name=GenericMethods.SET_INFO, accept_binary_input=True
107
+ )
108
+ self.register_rpc_method(self.send_data_grab, name=ViewerMethods.GRAB)
109
+ self.register_rpc_method(self.send_data_snap, name=ViewerMethods.SNAP)
110
+ self.register_binary_rpc_method(
111
+ self.move_abs, accept_binary_input=True, name=MoveMethods.MOVE_ABS
112
+ )
113
+ self.register_binary_rpc_method(
114
+ self.move_rel, accept_binary_input=True, name=MoveMethods.MOVE_REL
115
+ )
116
+ self.register_rpc_method(self.move_home, name=MoveMethods.MOVE_HOME)
117
+ self.register_rpc_method(self.get_actuator_value, name=MoveMethods.GET_ACTUATOR_VALUE)
118
+ self.register_rpc_method(self.stop_motion, name=MoveMethods.STOP_MOTION)
119
+ self.register_rpc_method(self.stop_grab, name=ViewerMethods.STOP)
120
+ self.register_rpc_method(self.get_settings, name=GenericMethods.GET_SETTINGS)
121
+
122
+ @staticmethod
123
+ def extract_pymodaq_object(
124
+ value: Optional[Union[float, str]], additional_payload: Optional[List[bytes]]
125
+ ):
126
+ if value is None and additional_payload:
127
+ return cast(
128
+ DataWithAxes, SerializableFactory().get_apply_deserializer(additional_payload[0])
129
+ )
130
+ else:
131
+ return value
132
+
133
+ # generic commands
134
+ def set_info(self,
135
+ parameter: Optional[Union[float, str]],
136
+ additional_payload: Optional[List[bytes]] = None,
137
+ ) -> None:
138
+ assert additional_payload
139
+ param = cast(
140
+ ParameterWithPath, SerializableFactory().get_apply_deserializer(additional_payload[0])
141
+ )
142
+ self.signals.cmd_signal.emit(ThreadCommand(LECOCommands.SET_INFO, attribute=param))
143
+
144
+ def get_settings(self):
145
+ self.signals.cmd_signal.emit(ThreadCommand(LECOCommands.GET_SETTINGS))
146
+
147
+ # detector commands
148
+ def send_data_grab(self,) -> None:
149
+ self.signals.cmd_signal.emit(ThreadCommand(LECOViewerCommands.GRAB))
150
+
151
+ # detector commands
152
+ def send_data_snap(self,) -> None:
153
+ self.signals.cmd_signal.emit(ThreadCommand(LECOViewerCommands.SNAP))
154
+
155
+ # actuator commands
156
+ def move_abs(
157
+ self,
158
+ position: Optional[Union[float, str]],
159
+ additional_payload: Optional[List[bytes]] = None,
160
+ ) -> None:
161
+ """Move to an absolute position.
162
+
163
+ :param position: Deprecated, should be None and content transferred binary.
164
+ :param additional_payload: binary frames containing the position as PyMoDAQ `DataActuator`.
165
+ """
166
+ pos = self.extract_pymodaq_object(position, additional_payload)
167
+ self.signals.cmd_signal.emit(ThreadCommand(LECOMoveCommands.MOVE_ABS, pos))
168
+
169
+ def move_rel(
170
+ self,
171
+ position: Optional[Union[float, str]],
172
+ additional_payload: Optional[List[bytes]] = None,
173
+ ) -> None:
174
+ """Move by a relative position.
175
+
176
+ :param position: Deprecated, should be None and content transferred binary.
177
+ :param additional_payload: binary frames containing the position as PyMoDAQ `DataActuator`.
178
+ """
179
+ pos = self.extract_pymodaq_object(position, additional_payload)
180
+ self.signals.cmd_signal.emit(ThreadCommand(LECOMoveCommands.MOVE_REL, pos))
181
+
182
+ def move_home(self) -> None:
183
+ self.signals.cmd_signal.emit(ThreadCommand(LECOMoveCommands.MOVE_HOME))
184
+
185
+ def get_actuator_value(self) -> None:
186
+ """Request that the actuator value is sent later on."""
187
+ # according to DAQ_Move, this supersedes "check_position"
188
+ self.signals.cmd_signal.emit(ThreadCommand(LECOMoveCommands.GET_ACTUATOR_VALUE))
189
+
190
+ def stop_motion(self,) -> None:
191
+ self.signals.cmd_signal.emit(ThreadCommand(LECOMoveCommands.STOP))
192
+
193
+ def stop_grab(self,) -> None:
194
+ self.signals.cmd_signal.emit(ThreadCommand(LECOViewerCommands.STOP))
195
+
196
+
197
+ # to be able to separate them later on
198
+ MoveActorHandler = ActorHandler
199
+ ViewerActorHandler = ActorHandler
200
+
201
+
202
+ class PymodaqListener(Listener):
203
+ """A Listener prepared for PyMoDAQ.
204
+
205
+ :param name: Name of this module.
206
+ :param host: Host name of the communication server.
207
+ :param port: Port number of the communication server.
208
+ """
209
+ remote_names: set[str]
210
+
211
+ local_methods = ["pong", "set_log_level"]
212
+
213
+ def __init__(self,
214
+ name: str,
215
+ handler_class: Type[PymodaqPipeHandler] = PymodaqPipeHandler,
216
+ host: str = "localhost",
217
+ port: int = COORDINATOR_PORT,
218
+ logger: Optional[logging.Logger] = None,
219
+ timeout: float = 1,
220
+ **kwargs) -> None:
221
+ super().__init__(name, host, port, logger=logger, timeout=timeout,
222
+ **kwargs)
223
+ self.remote_names = set()
224
+ self.signals = ListenerSignals()
225
+ # self.signals.message.connect(self.handle_message)
226
+ self.cmd_signal = self.signals.cmd_signal
227
+ self._handler_class = handler_class
228
+
229
+ def _listen(self, name: str, stop_event: Event, coordinator_host: str, coordinator_port: int,
230
+ data_host: str, data_port: int) -> None:
231
+ self.message_handler = self._handler_class(name,
232
+ host=coordinator_host, port=coordinator_port,
233
+ data_host=data_host, data_port=data_port,
234
+ signals=self.signals,
235
+ )
236
+ self.message_handler.register_on_name_change_method(self.indicate_sign_in_out)
237
+ self.message_handler.listen(stop_event=stop_event)
238
+
239
+ def stop_listen(self) -> None:
240
+ super().stop_listen()
241
+ try:
242
+ del self.communicator
243
+ except AttributeError:
244
+ pass
245
+ self.signals.cmd_signal.emit(ThreadCommand(LECOClientCommands.LECO_DISCONNECTED))
246
+
247
+ def indicate_sign_in_out(self, full_name: str):
248
+ if "." in full_name:
249
+ self.signals.cmd_signal.emit(ThreadCommand(LECOClientCommands.LECO_CONNECTED))
250
+ else:
251
+ self.signals.cmd_signal.emit(ThreadCommand(LECOClientCommands.LECO_DISCONNECTED))
252
+
253
+
254
+ class ActorListener(PymodaqListener):
255
+ """Listener for modules being an Actor (being remote controlled)."""
256
+
257
+ def __init__(self,
258
+ name: str,
259
+ handler_class: Type[ActorHandler] = ActorHandler,
260
+ host: str = "localhost",
261
+ port: int = COORDINATOR_PORT,
262
+ logger: Optional[logging.Logger] = None,
263
+ timeout: float = 1,
264
+ **kwargs) -> None:
265
+ super().__init__(name, handler_class=handler_class, host=host, port=port,
266
+ logger=logger, timeout=timeout,
267
+ **kwargs)
268
+
269
+ def start_listen(self) -> None:
270
+ super().start_listen()
271
+ self.message_handler.register_rpc_method(
272
+ self.set_remote_name, name=GenericMethods.SET_REMOTE_NAME
273
+ )
274
+
275
+ def set_remote_name(self, name: str) -> None:
276
+ """Define what the name of the remote for answers is."""
277
+ self.remote_names.add(name)
278
+
279
+ def remove_remote_name(self, name: str) -> None:
280
+ self.remote_names.discard(name)
281
+
282
+ def queue_command(self, command: ThreadCommand) -> None:
283
+ """Queue a command to send it via LECO to the server."""
284
+
285
+ # generic commands
286
+ if command.command == LECOCommands.CONNECT:
287
+ try:
288
+ if self.thread.is_alive():
289
+ return # already started
290
+ except AttributeError:
291
+ pass # start later on, as there is no thread.
292
+ self.start_listen()
293
+
294
+ elif command.command == LECOCommands.QUIT:
295
+ try:
296
+ self.stop_listen()
297
+ except Exception:
298
+ pass
299
+ finally:
300
+ self.cmd_signal.emit(ThreadCommand('disconnected'))
301
+
302
+ elif command.attribute is not None:
303
+ # here are all methods requiring an attribute in the ThreadCommand
304
+
305
+ if command.command == LECOViewerCommands.DATA_READY:
306
+ value = command.attribute
307
+ self.send_rpc_message_to_remote(
308
+ method=ViewerDirectorMethods.SET_DATA,
309
+ **binary_serialization_to_kwargs(value),
310
+ )
311
+
312
+ elif command.command == LECOCommands.SEND_INFO:
313
+ self.send_rpc_message_to_remote(
314
+ method=GenericDirectorMethods.SET_DIRECTOR_INFO,
315
+ **binary_serialization_to_kwargs(command.attribute, data_key='parameter'))
316
+
317
+ elif command.command == LECOMoveCommands.POSITION:
318
+ value = command.attribute
319
+ if isinstance(value, (list, tuple)):
320
+ value = value[0] # for backward compatibility with attributes list
321
+ self.send_rpc_message_to_remote(
322
+ method=MoveDirectorMethods.SEND_POSITION,
323
+ **binary_serialization_to_kwargs(pymodaq_object=value, data_key="position"),
324
+ )
325
+
326
+ elif command.command == LECOMoveCommands.MOVE_DONE:
327
+ value = command.attribute
328
+ if isinstance(value, (list, tuple)):
329
+ value = value[0] # for backward compatibility with attributes list
330
+ self.send_rpc_message_to_remote(
331
+ method=MoveDirectorMethods.SET_MOVE_DONE,
332
+ **binary_serialization_to_kwargs(value, data_key="position"),
333
+ )
334
+
335
+ elif command.command == LECOMoveCommands.UNITS_CHANGED:
336
+ units: str = command.attribute
337
+ self.send_rpc_message_to_remote(
338
+ method=MoveDirectorMethods.SET_UNITS,
339
+ units=units.encode(),
340
+ )
341
+
342
+ elif command.command == LECOCommands.SET_DIRECTOR_SETTINGS:
343
+ self.send_rpc_message_to_remote(
344
+ method=GenericDirectorMethods.SET_DIRECTOR_SETTINGS,
345
+ settings=command.attribute.decode(),
346
+ )
347
+
348
+ else:
349
+ raise IOError("Unknown TCP client command")
350
+
351
+ def send_rpc_message_to_remote(self, method: str, **kwargs) -> None:
352
+ if not self.remote_names:
353
+ return
354
+ for name in list(self.remote_names):
355
+ try:
356
+ self.communicator.ask_rpc(receiver=name, method=method, **kwargs)
357
+ except JSONRPCError as exc:
358
+ if exc.rpc_error.code in (RECEIVER_UNKNOWN.code, NODE_UNKNOWN.code):
359
+ self.remove_remote_name(name)
360
+
361
+
362
+ # to be able to separate them later on
363
+ MoveActorListener = ActorListener
364
+ ViewerActorListener = ActorListener
@@ -0,0 +1,43 @@
1
+ """
2
+ Names of methods used between remotely controlled modules and
3
+ remote controlling director modules.
4
+ """
5
+
6
+ from pymodaq_utils.enums import StrEnum
7
+
8
+
9
+ # Methods for all PyMoDAQ modules
10
+ class GenericMethods(StrEnum):
11
+ SET_INFO = "set_info"
12
+ GET_SETTINGS = "get_settings"
13
+ SET_REMOTE_NAME = "set_remote_name"
14
+
15
+
16
+ class MoveMethods(StrEnum):
17
+ MOVE_ABS = "move_abs"
18
+ MOVE_REL = "move_rel"
19
+ MOVE_HOME = "move_home"
20
+ STOP_MOTION = "stop_motion"
21
+ GET_ACTUATOR_VALUE = "get_actuator_value"
22
+
23
+
24
+ class ViewerMethods(StrEnum):
25
+ GRAB = "send_data_grab"
26
+ SNAP = "send_data_snap"
27
+ STOP = "stop_grab"
28
+
29
+
30
+ # Director module methods
31
+ class GenericDirectorMethods(StrEnum):
32
+ SET_DIRECTOR_SETTINGS = "set_director_settings"
33
+ SET_DIRECTOR_INFO = "set_director_info"
34
+
35
+
36
+ class MoveDirectorMethods(StrEnum):
37
+ SET_UNITS = "set_units"
38
+ SEND_POSITION = "send_position"
39
+ SET_MOVE_DONE = "set_move_done"
40
+
41
+
42
+ class ViewerDirectorMethods(StrEnum):
43
+ SET_DATA = "set_data"
@@ -0,0 +1,74 @@
1
+ from __future__ import annotations
2
+ import subprocess
3
+ import sys
4
+ from typing import Any, Optional, Union, get_args, TypeVar
5
+
6
+
7
+ from pymodaq.utils import data
8
+ from pymodaq_utils.serialize.factory import SerializableFactory
9
+
10
+ from pymodaq_utils.logger import set_logger
11
+
12
+
13
+ logger = set_logger('leco_utils')
14
+ JSON_TYPES = Union[str, int, float, list]
15
+
16
+ ser_factory = SerializableFactory()
17
+
18
+
19
+ ## this form below is to be compatible with python <= 3.10
20
+ ## for py>= 3.11 this could be written SERIALIZABLE = Union[ser_factory.get_serializables()]
21
+ SERIALIZABLE = Union[ser_factory.get_serializables()[0]]
22
+ for klass in ser_factory.get_serializables()[1:]:
23
+ SERIALIZABLE = Union[SERIALIZABLE, klass]
24
+
25
+
26
+ def binary_serialization(
27
+ pymodaq_object: Union[SERIALIZABLE, Any],
28
+ ) -> tuple[Optional[Any], Optional[list[bytes]]]:
29
+ """Serialize (binary) a pymodaq object, if it is not JSON compatible.
30
+
31
+ If an object is JSON serializable, we can send it as a value to the JSON
32
+ encoder and do not need a binary value.
33
+ Otherwise, the JSON value is None and the serialized object is returned.
34
+
35
+ :param pymodaq_object: the object which shall be sent via LECO protocol.
36
+ :return: tuple of the JSON value and a list of additional payload frames.
37
+ """
38
+ if isinstance(pymodaq_object, get_args(JSON_TYPES)):
39
+ return pymodaq_object, None
40
+ return None, [SerializableFactory().get_apply_serializer(pymodaq_object)]
41
+
42
+
43
+
44
+ def binary_serialization_to_kwargs(
45
+ pymodaq_object: Union[SERIALIZABLE, Any], data_key: str = "data"
46
+ ) -> dict[str, Any]:
47
+ """Create a dictionary of data parameters and of additional payload to send.
48
+
49
+ This method prepares arguments for PyLECO's :meth:`Communicator.ask_rpc` method.
50
+ In order to send a binary value as an argument `data_key` for a method, the
51
+ argument has to be None, which is JSON describable.
52
+ The binary data has to be sent via the `additional_payload` parameter.
53
+ If the data can be sent as JSON, it is sent directly (`data_key`) and no
54
+ additional frames are sent.
55
+ """
56
+ d, b = binary_serialization(pymodaq_object=pymodaq_object)
57
+ return {data_key: d, "additional_payload": b}
58
+
59
+
60
+ def run_coordinator():
61
+ command = [sys.executable, '-m', 'pyleco.coordinators.coordinator']
62
+ subprocess.Popen(command)
63
+
64
+
65
+ def start_coordinator():
66
+ from pyleco.directors.director import Director
67
+ try:
68
+ with Director(actor="COORDINATOR") as director:
69
+ if director.communicator.namespace is None:
70
+ run_coordinator()
71
+ else:
72
+ logger.info('Coordinator already running')
73
+ except ConnectionRefusedError:
74
+ run_coordinator()
@@ -0,0 +1,6 @@
1
+ from pymodaq_utils.logger import set_logger, get_module_name, get_set_config_dir, get_base_logger
2
+
3
+ from pymodaq_utils.warnings import deprecation_msg
4
+
5
+ deprecation_msg('Importing logger stuff from pymodaq is deprecated in pymodaq>5.0.0,'
6
+ 'please use the pymodaq_utils package')
File without changes