pymodaq 4.3.7__py3-none-any.whl → 4.4.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.

pymodaq/__init__.py CHANGED
@@ -51,6 +51,7 @@ try:
51
51
  ureg.default_format = '~'
52
52
  Q_ = ureg.Quantity
53
53
  Unit = ureg.Unit
54
+ ureg.define('whatever = 1 = wr') # defining whatever as a dimensionless quantity
54
55
  logger.info('')
55
56
  logger.info('')
56
57
 
@@ -23,7 +23,8 @@ from easydict import EasyDict as edict
23
23
  from pymodaq.utils.logger import set_logger, get_module_name
24
24
  from pymodaq.control_modules.utils import ParameterControlModule
25
25
  from pymodaq.control_modules.daq_move_ui import DAQ_Move_UI, ThreadCommand
26
- from pymodaq.control_modules.move_utility_classes import MoveCommand, DAQ_Move_base, DataActuatorType
26
+ from pymodaq.control_modules.move_utility_classes import (MoveCommand, DAQ_Move_base,
27
+ DataActuatorType, check_units)
27
28
  from pymodaq.control_modules.move_utility_classes import params as daq_move_params
28
29
  from pymodaq.utils import daq_utils as utils
29
30
  from pymodaq.utils.parameter import utils as putils
@@ -32,7 +33,8 @@ from pymodaq.utils import config as config_mod
32
33
  from pymodaq.utils.exceptions import ActuatorError
33
34
  from pymodaq.utils.messenger import deprecation_msg
34
35
  from pymodaq.utils.h5modules import module_saving
35
- from pymodaq.utils.data import DataRaw, DataToExport, DataFromPlugins, DataActuator
36
+ from pymodaq.utils.data import (DataRaw, DataToExport, DataFromPlugins, DataActuator, Unit,
37
+ DataUnitError)
36
38
  from pymodaq.utils.h5modules.backends import Node
37
39
  from pymodaq.utils.parameter import ioxml, Parameter
38
40
 
@@ -161,11 +163,13 @@ class DAQ_Move(ParameterControlModule):
161
163
  self.stop_motion()
162
164
  elif cmd.command == 'move_abs':
163
165
  data_act: DataActuator = cmd.attribute
164
- data_act.force_units(self.units)
166
+ if not Unit(data_act.units).is_compatible_with(self.units) and data_act.units != '':
167
+ data_act.force_units(self.units)
165
168
  self.move_abs(data_act)
166
169
  elif cmd.command == 'move_rel':
167
170
  data_act: DataActuator = cmd.attribute
168
- data_act.force_units(self.units)
171
+ if not Unit(data_act.units).is_compatible_with(self.units) and data_act.units != '':
172
+ data_act.force_units(self.units)
169
173
  self.move_rel(data_act)
170
174
  elif cmd.command == 'show_log':
171
175
  self.show_log()
@@ -591,7 +595,14 @@ class DAQ_Move(ParameterControlModule):
591
595
  def units(self, unit: str):
592
596
  self.settings.child('move_settings', 'units').setValue(unit)
593
597
  if self.ui is not None and config('actuator', 'display_units'):
594
- self.ui.set_unit_as_suffix(unit)
598
+ if unit == '°':
599
+ # special cas as pint base unit for angles are radians
600
+ self.ui.set_unit_as_suffix(unit)
601
+ else:
602
+ # if the controller units are in mm the displayed unit will be m
603
+ # because m is the base unit
604
+ # then the user could ask for mm, km, µm...
605
+ self.ui.set_unit_as_suffix(str(Q_(1, unit).to_base_units().units))
595
606
 
596
607
  def update_settings(self):
597
608
 
@@ -668,8 +679,6 @@ class DAQ_Move_Hardware(QObject):
668
679
  self._title = title
669
680
  self.hardware: Optional[DAQ_Move_base] = None
670
681
  self.actuator_type = actuator_type
671
- self.current_position: DataActuator = position
672
- self._target_value: Optional[DataActuator] = None
673
682
  self.hardware_adress = None
674
683
  self.axis_address = None
675
684
  self.motion_stoped = False
@@ -692,9 +701,8 @@ class DAQ_Move_Hardware(QObject):
692
701
  """
693
702
  pos = self.hardware.get_actuator_value()
694
703
  if self.hardware.data_actuator_type == DataActuatorType.float:
695
- return DataActuator(self._title, data=pos, units=self.units)
696
- else:
697
- return pos
704
+ pos = DataActuator(self._title, data=pos, units=self.hardware.axis_unit)
705
+ return pos
698
706
 
699
707
  def check_position(self):
700
708
  """Get the current position checking the hardware position (deprecated)
@@ -743,6 +751,8 @@ class DAQ_Move_Hardware(QObject):
743
751
  status.initialized = infos[1]
744
752
  status.controller = self.hardware.controller
745
753
  self.hardware.move_done_signal.connect(self.move_done)
754
+ if status.initialized:
755
+ self.status_sig.emit(ThreadCommand('get_actuator_value', [self.get_actuator_value()]))
746
756
 
747
757
  return status
748
758
  except Exception as e:
@@ -753,15 +763,13 @@ class DAQ_Move_Hardware(QObject):
753
763
  """
754
764
 
755
765
  """
756
- # if isinstance(position, Number):
757
- # position = float(position) # because it may be a numpy float and could cause issues
758
- # # see https://github.com/pythonnet/pythonnet/issues/1833
759
- self._target_value = position
766
+ position = check_units(position, self.hardware.axis_unit)
760
767
  self.hardware.move_is_done = False
761
768
  self.hardware.ispolling = polling
762
769
  if self.hardware.data_actuator_type.name == 'float':
763
770
  self.hardware.move_abs(position.value())
764
771
  else:
772
+ position.units = self.hardware.axis_unit # convert to plugin controller current axis units
765
773
  self.hardware.move_abs(position)
766
774
  self.hardware.poll_moving()
767
775
 
@@ -769,14 +777,14 @@ class DAQ_Move_Hardware(QObject):
769
777
  """
770
778
 
771
779
  """
772
-
780
+ rel_position = check_units(rel_position, self.hardware.axis_unit)
773
781
  self.hardware.move_is_done = False
774
- self._target_value = self.current_position + rel_position
775
782
  self.hardware.ispolling = polling
776
783
 
777
784
  if self.hardware.data_actuator_type.name == 'float':
778
785
  self.hardware.move_rel(rel_position.value())
779
786
  else:
787
+ rel_position.units = self.hardware.axis_unit # convert to plugin current axis units
780
788
  self.hardware.move_rel(rel_position)
781
789
 
782
790
  self.hardware.poll_moving()
@@ -798,7 +806,6 @@ class DAQ_Move_Hardware(QObject):
798
806
 
799
807
  """
800
808
  self.hardware.move_is_done = False
801
- self._target_value = 0
802
809
  self.hardware.move_home()
803
810
 
804
811
  @Slot(DataActuator)
@@ -7,6 +7,7 @@ Created the 28/07/2022
7
7
 
8
8
  from typing import List
9
9
  import sys
10
+ from pint.errors import DimensionalityError
10
11
 
11
12
  from qtpy import QtWidgets
12
13
  from qtpy.QtCore import Signal, Qt
@@ -65,12 +66,17 @@ class DAQ_Move_UI(ControlModuleUI):
65
66
 
66
67
  super().__init__(parent)
67
68
  self.title = title
69
+ self._unit = ''
68
70
  self.setup_ui()
69
71
 
70
72
  self.enable_move_buttons(False)
71
73
 
72
74
  def display_value(self, value: DataActuator):
73
- self.current_value_sb.setValue(value.value())
75
+ try:
76
+ self.current_value_sb.setValue(value.value(self._unit))
77
+ except DimensionalityError as e:
78
+ value.force_units(self._unit)
79
+ self.current_value_sb.setValue(value.value())
74
80
 
75
81
  @property
76
82
  def actuator_init(self):
@@ -193,9 +199,9 @@ class DAQ_Move_UI(ControlModuleUI):
193
199
  self.main_ui.layout().addWidget(self.toolbar, 0, 0, 1, 2)
194
200
  self.main_ui.layout().addWidget(self.move_toolbar, 1, 0, 1, 2)
195
201
 
196
- self.abs_value_sb = SpinBox(step=0.1, dec=True)
202
+ self.abs_value_sb = SpinBox(step=0.1, dec=True, siPrefix=config('actuator', 'siprefix'))
197
203
  self.abs_value_sb.setStyleSheet("background-color : lightgreen; color: black")
198
- self.abs_value_sb_2 = SpinBox(step=0.1, dec=True)
204
+ self.abs_value_sb_2 = SpinBox(step=0.1, dec=True, siPrefix=config('actuator', 'siprefix'))
199
205
  self.abs_value_sb_2.setStyleSheet("background-color : lightcoral; color: black")
200
206
  self.move_toolbar.addWidget(self.abs_value_sb)
201
207
  self.move_toolbar.addWidget(self.abs_value_sb_2)
@@ -221,7 +227,7 @@ class DAQ_Move_UI(ControlModuleUI):
221
227
  self.control_ui.layout().addWidget(LabelWithFont('Abs. Value'), 0, 0)
222
228
  self.find_home_pb = PushButtonIcon('home2', 'Find Home')
223
229
  self.control_ui.layout().addWidget(self.find_home_pb, 0, 1)
224
- self.abs_value_sb_bis = SpinBox(step=0.1, dec=True)
230
+ self.abs_value_sb_bis = SpinBox(step=0.1, dec=True, siPrefix=config('actuator', 'siprefix'))
225
231
  self.control_ui.layout().addWidget(self.abs_value_sb_bis, 1, 0)
226
232
  self.move_abs_pb = PushButtonIcon('Move', 'Set Abs.',
227
233
  tip='Set the value of the actuator to the set absolute value')
@@ -230,7 +236,7 @@ class DAQ_Move_UI(ControlModuleUI):
230
236
  self.move_rel_plus_pb = PushButtonIcon('MoveUp', 'Set Rel. (+)')
231
237
  self.control_ui.layout().addWidget(self.move_rel_plus_pb, 2, 1)
232
238
 
233
- self.rel_value_sb = SpinBox(step=0.1, dec=True)
239
+ self.rel_value_sb = SpinBox(step=0.1, dec=True, siPrefix=config('actuator', 'siprefix'))
234
240
  self.control_ui.layout().addWidget(self.rel_value_sb, 3, 0)
235
241
  self.move_rel_minus_pb = PushButtonIcon('MoveDown', 'Set Rel. (-)')
236
242
  self.control_ui.layout().addWidget(self.move_rel_minus_pb, 3, 1)
@@ -252,6 +258,7 @@ class DAQ_Move_UI(ControlModuleUI):
252
258
 
253
259
  def set_unit_as_suffix(self, unit: str):
254
260
  """Will append the actuator units in the value display"""
261
+ self._unit = unit
255
262
  self.current_value_sb.setOpts(suffix=unit)
256
263
  self.abs_value_sb_bis.setOpts(suffix=unit)
257
264
  self.abs_value_sb.setOpts(suffix=unit)
@@ -328,12 +335,14 @@ class DAQ_Move_UI(ControlModuleUI):
328
335
 
329
336
  def emit_move_abs(self, spinbox):
330
337
  spinbox.editingFinished.emit()
331
- self.command_sig.emit(ThreadCommand('move_abs', DataActuator(data=spinbox.value())))
338
+ self.command_sig.emit(ThreadCommand('move_abs', DataActuator(data=spinbox.value(),
339
+ units=self._unit)))
332
340
 
333
341
  def emit_move_rel(self, sign):
334
- self.command_sig.emit(ThreadCommand('move_rel',
335
- DataActuator(data=self.rel_value_sb.value() * (1 if sign == '+'
336
- else -1))))
342
+ self.command_sig.emit(ThreadCommand(
343
+ 'move_rel',
344
+ DataActuator(data=self.rel_value_sb.value() * (1 if sign == '+' else -1),
345
+ units=self._unit)))
337
346
 
338
347
  def close(self):
339
348
  self.graph_ui.close()
@@ -1,6 +1,9 @@
1
+ import numbers
2
+
1
3
  from time import perf_counter
2
4
  from typing import Union, List, Dict, TYPE_CHECKING, Optional
3
5
  from numbers import Number
6
+ from collections.abc import Iterable
4
7
 
5
8
  from easydict import EasyDict as edict
6
9
  import numpy as np
@@ -30,13 +33,45 @@ logger = set_logger(get_module_name(__file__))
30
33
  config = configmod.Config()
31
34
 
32
35
 
36
+ def check_units(dwa: DataActuator, units: str):
37
+ """ Check if dwa units is compatible with the units argument
38
+
39
+ If it is incompatible and has dimensionless units, brute force change the dwa units to units,
40
+ otherwise raise a DataUnitError
41
+
42
+ Parameters
43
+ ----------
44
+ dwa: DataActuator
45
+ units: str
46
+
47
+ Returns
48
+ -------
49
+ DataActuator
50
+ """
51
+ if Unit(dwa.units).is_compatible_with(units):
52
+ return dwa
53
+ elif Unit(dwa.units).dimensionless: # dimensionless
54
+ dwa.force_units(units)
55
+ return dwa
56
+ else:
57
+ raise DataUnitError(f'Units incompatibility between {dwa} and "{units}" units')
58
+
59
+
33
60
  class DataActuatorType(BaseEnum):
34
61
  """Enum for new or old style holding the value of the actuator"""
35
62
  float = 0
36
63
  DataActuator = 1
37
64
 
38
65
 
39
- def comon_parameters(epsilon=config('actuator', 'epsilon_default')):
66
+ def comon_parameters(epsilon=config('actuator', 'epsilon_default'),
67
+ epsilons=None):
68
+ if epsilons is not None:
69
+ epsilon=epsilons
70
+ if isinstance(epsilon, list):
71
+ epsilon=epsilon[0]
72
+ elif isinstance(epsilon, dict):
73
+ epsilon=epsilon[list[epsilon.keys()][0]]
74
+
40
75
  return [{'title': 'Units:', 'name': 'units', 'type': 'str', 'value': '', 'readonly': True},
41
76
  {'title': 'Epsilon:', 'name': 'epsilon', 'type': 'float',
42
77
  'value': epsilon,
@@ -79,32 +114,45 @@ class MoveCommand:
79
114
  self.value = value
80
115
 
81
116
 
82
- def comon_parameters_fun(is_multiaxes = False,
83
- axes_names = [],
117
+ def comon_parameters_fun(is_multiaxes=False, axes_names=None,
84
118
  axis_names: Union[List, Dict] = [],
85
- master = True,
86
- epsilon = config('actuator', 'epsilon_default')):
119
+ master=True,
120
+ epsilon: float = config('actuator', 'epsilon_default')):
121
+
87
122
  """Function returning the common and mandatory parameters that should be on the actuator plugin level
88
123
 
89
124
  Parameters
90
125
  ----------
91
- is_multiaxes: bool
126
+ is_multiaxes: bool # deprecated not need anymore
92
127
  If True, display the particular settings to define which axis the controller is driving
93
- axis_names: list of str
128
+ axes_names: deprecated, use axis_names
129
+ axis_names: list of str or dictionnary of string as key and integer as value
94
130
  The string identifier of every axis the controller can drive
95
131
  master: bool
96
132
  If True consider this plugin has to init the controller, otherwise use an already initialized instance
133
+ epsilon: float
134
+ deprecated (< 5.0.0) no more used here
135
+
97
136
  """
98
- if axis_names == [] and len(axes_names) != 0:
137
+ if axes_names is not None and len(axis_names) == 0:
138
+ if len(axes_names) == 0:
139
+ axes_names = ['']
99
140
  axis_names = axes_names
100
141
 
142
+ is_multiaxes = len(axis_names) > 1
143
+ if isinstance(axis_names, list):
144
+ axis_name = axis_names[0]
145
+ elif isinstance(axis_names, dict):
146
+ axis_name = axis_names[list(axis_names.keys())[0]]
101
147
  params = [
102
- {'title': 'MultiAxes:', 'name': 'multiaxes', 'type': 'group', 'visible': is_multiaxes, 'children': [
103
- {'title': 'is Multiaxes:', 'name': 'ismultiaxes', 'type': 'bool', 'value': is_multiaxes,
104
- 'default': False},
148
+ {'title': 'MultiAxes:', 'name': 'multiaxes', 'type': 'group',
149
+ 'visible': is_multiaxes, 'children': [
150
+ {'title': 'is Multiaxes:', 'name': 'ismultiaxes', 'type': 'bool',
151
+ 'value': is_multiaxes, 'default': False},
105
152
  {'title': 'Status:', 'name': 'multi_status', 'type': 'list',
106
153
  'value': 'Master' if master else 'Slave', 'limits': ['Master', 'Slave']},
107
- {'title': 'Axis:', 'name': 'axis', 'type': 'list', 'limits': axis_names},
154
+ {'title': 'Axis:', 'name': 'axis', 'type': 'list', 'limits': axis_names,
155
+ 'value': axis_name},
108
156
  ]},
109
157
  ] + comon_parameters(epsilon)
110
158
  return params
@@ -204,10 +252,16 @@ class DAQ_Move_base(QObject):
204
252
 
205
253
  move_done_signal = Signal(DataActuator)
206
254
  is_multiaxes = False
207
- stage_names = []
255
+ stage_names = [] # deprecated
256
+
257
+ _axis_names: Union[list, Dict[str, int]] = None
258
+ _controller_units: Union[str, List[str], Dict[str, int]] = ''
259
+ _epsilons: Union[float, List[float], Dict[str, float]] = None
260
+ _epsilon = 1.0 # deprecated
261
+
262
+
208
263
  params = []
209
- _controller_units = ''
210
- _epsilon = 1
264
+
211
265
  data_actuator_type = DataActuatorType.float
212
266
  data_shape = (1, ) # expected shape of the underlying actuator's value (in general a float so shape = (1, ))
213
267
 
@@ -237,18 +291,19 @@ class DAQ_Move_base(QObject):
237
291
  else:
238
292
  self._title = "myactuator"
239
293
 
240
- if isinstance(self._controller_units, list):
241
- # for backcompatibility
242
- # in case an actuator has multiple units properly handled in future version of pymodaq
243
- self._controller_units = self._controller_units[self.axis_names.index(self.axis_name)]
294
+ self._axis_units: Union[Dict[str, str], List[str]] = None
295
+ self.axis_units = self._controller_units
296
+ if self._epsilons is None:
297
+ self._epsilons = self._epsilon
298
+ self.epsilons = self._epsilons
299
+ self.axis_name = self.axis_name # to trigger some actions on units and epsilons
244
300
 
245
301
  self._current_value = DataActuator(self._title,
246
302
  data=[np.zeros(self.data_shape, dtype=float)],
247
- units=self.controller_units)
303
+ units=self.axis_unit)
248
304
  self._target_value = DataActuator(self._title,
249
305
  data=[np.zeros(self.data_shape, dtype=float)],
250
- units=self.controller_units)
251
- self.controller_units = self._controller_units
306
+ units=self.axis_unit)
252
307
 
253
308
  self.poll_timer = QTimer()
254
309
  self.poll_timer.setInterval(config('actuator', 'polling_interval_ms'))
@@ -258,7 +313,108 @@ class DAQ_Move_base(QObject):
258
313
  self.ini_attributes()
259
314
 
260
315
  @property
261
- def axis_name(self) -> Union[str, object]:
316
+ def axis_unit(self) -> str:
317
+ """ Get/set the unit of the currently chosen axis
318
+
319
+ Will update the printed controller unit in the UI
320
+
321
+ New in 4.4.0
322
+ """
323
+ return self.axis_units[self.axis_index_key]
324
+
325
+ @axis_unit.setter
326
+ def axis_unit(self, unit: str):
327
+ self.axis_units[self.axis_index_key] = unit
328
+ self.settings.child('units').setValue(unit)
329
+ self.emit_status(ThreadCommand('units', unit))
330
+
331
+ @property
332
+ def axis_units(self) -> Union[List[str], Dict[str, str]]:
333
+ """ Get/Set the units for each axis of the controller
334
+
335
+ New in 4.4.0
336
+ """
337
+ return self._axis_units
338
+
339
+ @axis_units.setter
340
+ def axis_units(self, units: Union[str, List[str], Dict[str, str]]):
341
+ if isinstance(units, str):
342
+ if isinstance(self.axis_names, list):
343
+ units_tmp = [units for _ in range(len(self.axis_names))]
344
+ else:
345
+ units_tmp = {}
346
+ for key in self.axis_names:
347
+ units_tmp[key] = units
348
+ else:
349
+ if not isinstance(units, type(self.axis_names)):
350
+ raise TypeError('units should be defined just like axis_names: a str, list of string or'
351
+ 'dict of string')
352
+ if len(units) != len(self.axis_names):
353
+ raise ValueError('Units should be defined either as a single str or a list/dict with'
354
+ 'a str defined for each axis')
355
+ units_tmp = units
356
+ self._axis_units = units_tmp
357
+
358
+ @property
359
+ def epsilon(self) -> float:
360
+ """ Get/Set the epsilon of the currently chosen axis
361
+
362
+ New in 4.4.0
363
+ """
364
+ return self.epsilons[self.axis_index_key]
365
+
366
+ @epsilon.setter
367
+ def epsilon(self, eps: float):
368
+ self.epsilons[self.axis_index_key] = eps
369
+
370
+ @property
371
+ def epsilons(self) -> Union[List[float], Dict[str, float]]:
372
+ """ Get/Set the epsilon for each axis of the controller
373
+
374
+ New in 4.4.0
375
+ """
376
+ return self._epsilons
377
+
378
+ @epsilons.setter
379
+ def epsilons(self, epsilons: Union[float, List[float], Dict[str, float]]):
380
+ if isinstance(epsilons, numbers.Number):
381
+ if isinstance(self.axis_names, list):
382
+ epsilons_tmp = [epsilons for _ in range(len(self.axis_names))]
383
+ else:
384
+ epsilons_tmp = {}
385
+ for key in self.axis_names:
386
+ epsilons_tmp[key] = epsilons
387
+ else:
388
+ if not isinstance(epsilons, type(self.axis_names)):
389
+ raise TypeError('units should be defined just like axis_names: a float, list of '
390
+ 'float or dict of float')
391
+ if len(epsilons) != len(self.axis_names):
392
+ raise ValueError('epsilons should be defined either as a single float or a '
393
+ 'list/dict with'
394
+ 'a float defined for each axis')
395
+ epsilons_tmp = epsilons
396
+ self._epsilons = epsilons_tmp
397
+
398
+ @property
399
+ def controller_units(self):
400
+ """ Get/Set the units of the currently chosen axis of the controller
401
+
402
+ Deprecated with pymodaq >= 4.4.0
403
+
404
+ The property controller_units is deprecated please use the axis_unit property
405
+ """
406
+ deprecation_msg('The property controller_units is deprecated please use the'
407
+ 'axis_unit property.')
408
+ return self.axis_unit
409
+
410
+ @controller_units.setter
411
+ def controller_units(self, units: str = ''):
412
+ deprecation_msg('The property controller_units is deprecated please use the'
413
+ 'axis_unit property.')
414
+ self._axis_units[self.axis_index_key] = units
415
+
416
+ @property
417
+ def axis_name(self) -> Union[str]:
262
418
  """Get/Set the current axis using its string identifier"""
263
419
  limits = self.settings.child('multiaxes', 'axis').opts['limits']
264
420
  if isinstance(limits, list):
@@ -275,6 +431,9 @@ class DAQ_Move_base(QObject):
275
431
  elif isinstance(limits, dict):
276
432
  self.settings.child('multiaxes', 'axis').setValue(limits[name])
277
433
  QtWidgets.QApplication.processEvents()
434
+ self.axis_unit = self.axis_unit
435
+ self.settings.child('epsilon').setValue(self.epsilon)
436
+
278
437
 
279
438
  @property
280
439
  def axis_names(self) -> Union[List, Dict]:
@@ -292,9 +451,29 @@ class DAQ_Move_base(QObject):
292
451
  QtWidgets.QApplication.processEvents()
293
452
 
294
453
  @property
295
- def axis_value(self) -> object:
296
- """Get the current value selected from the current axis"""
297
- return self.settings['multiaxes', 'axis']
454
+ def axis_value(self) -> int:
455
+ """Get the current value selected from the current axis
456
+
457
+ In case axis_names is a list, return the element of the list: self.axis_name
458
+ In case axis_names is a dict, return the value of the dict self.axis_names[self.axis_name]
459
+ """
460
+ if isinstance(self.axis_names, list):
461
+ return self.axis_name
462
+ else:
463
+ return self.axis_names[self.axis_name]
464
+
465
+ @property
466
+ def axis_index_key(self) -> Union[int, str]:
467
+ """ Get the current index or key correspondingto the current axis
468
+
469
+ In case axis_names is a list, return the index wihtin the list
470
+ In case axis_names is a dict, return the key of the dict self.axis_name
471
+
472
+ """
473
+ if isinstance(self.axis_names, list):
474
+ return self.axis_names.index(self.axis_name)
475
+ else:
476
+ return self.axis_name
298
477
 
299
478
  def ini_attributes(self):
300
479
  """ To be subclassed, in order to init specific attributes needed by the real implementation"""
@@ -334,40 +513,40 @@ class DAQ_Move_base(QObject):
334
513
 
335
514
  @property
336
515
  def current_value(self):
337
- if self.data_actuator_type.name == 'float':
516
+ if self.data_actuator_type == self.data_actuator_type.float:
338
517
  return self._current_value.value()
339
518
  else:
340
519
  return self._current_value
341
520
 
342
521
  @current_value.setter
343
522
  def current_value(self, value: Union[float, DataActuator]):
344
- if not isinstance(value, DataActuator):
523
+ if isinstance(value, numbers.Number):
345
524
  self._current_value = DataActuator(self._title, data=value,
346
- units=self.controller_units)
525
+ units=self.axis_unit)
347
526
  else:
348
- if (not Unit(self.controller_units).is_compatible_with(
527
+ if (not Unit(self.axis_unit).is_compatible_with(
349
528
  Unit(value.units)) and
350
529
  value.units == ''):
351
- value.force_units(self.controller_units)
530
+ value.force_units(self.axis_unit)
352
531
  self._current_value = value
353
532
 
354
533
  @property
355
534
  def target_value(self):
356
- if self.data_actuator_type.name == 'float':
535
+ if self.data_actuator_type.name == self.data_actuator_type.float:
357
536
  return self._target_value.value()
358
537
  else:
359
538
  return self._target_value
360
539
 
361
540
  @target_value.setter
362
- def target_value(self, value: Union[float, DataActuator]):
363
- if not isinstance(value, DataActuator):
541
+ def target_value(self, value: Union[numbers.Number, DataActuator]):
542
+ if isinstance(value, numbers.Number):
364
543
  self._target_value = DataActuator(self._title, data=value,
365
- units=self.controller_units)
544
+ units=self.axis_unit)
366
545
  else:
367
- if (not Unit(self.controller_units).is_compatible_with(
546
+ if (not Unit(self.axis_unit).is_compatible_with(
368
547
  Unit(value.units)) and
369
548
  value.units == ''):
370
- value.force_units(self.controller_units)
549
+ value.force_units(self.axis_unit)
371
550
  self._target_value = value
372
551
 
373
552
  @property
@@ -396,19 +575,6 @@ class DAQ_Move_base(QObject):
396
575
  """
397
576
  return self.settings['multiaxes', 'multi_status'] == 'Master'
398
577
 
399
- @property
400
- def controller_units(self):
401
- """ Get/Set the units of this plugin"""
402
- return self._controller_units
403
-
404
- @controller_units.setter
405
- def controller_units(self, units: str = ''):
406
- self._controller_units = units
407
- try:
408
- self.settings.child('units').setValue(units)
409
- self.emit_status(ThreadCommand('units', units))
410
- except Exception:
411
- pass
412
578
 
413
579
  @property
414
580
  def ispolling(self):
@@ -428,12 +594,12 @@ class DAQ_Move_base(QObject):
428
594
  if position > self.settings.child('bounds', 'max_bound').value():
429
595
  position = DataActuator(self._title,
430
596
  data=self.settings.child('bounds', 'max_bound').value(),
431
- units = self.controller_units)
597
+ units=self.axis_unit)
432
598
  self.emit_status(ThreadCommand('outofbounds', []))
433
599
  elif position < self.settings.child('bounds', 'min_bound').value():
434
600
  position = DataActuator(self._title,
435
601
  data=self.settings.child('bounds', 'min_bound').value(),
436
- units=self.controller_units
602
+ units=self.axis_unit
437
603
  )
438
604
  self.emit_status(ThreadCommand('outofbounds', []))
439
605
  return position
@@ -502,13 +668,13 @@ class DAQ_Move_base(QObject):
502
668
  if position is None:
503
669
  if self.data_actuator_type.name == 'float':
504
670
  position = DataActuator(self._title, data=self.get_actuator_value(),
505
- units = self.controller_units)
671
+ units=self.axis_unit)
506
672
  else:
507
673
  position = self.get_actuator_value()
508
674
  if position.name != self._title: # make sure the emitted DataActuator has the name of the real implementation
509
675
  #of the plugin
510
676
  position = DataActuator(self._title, data=position.value(),
511
- units = self.controller_units)
677
+ units=self.axis_unit)
512
678
  self.move_done_signal.emit(position)
513
679
  self.move_is_done = True
514
680
 
@@ -526,32 +692,59 @@ class DAQ_Move_base(QObject):
526
692
  else:
527
693
  if self.data_actuator_type == DataActuatorType.float:
528
694
  self._current_value = DataActuator(data=self.get_actuator_value(),
529
- units=self.controller_units)
695
+ units=self.axis_unit)
530
696
  else:
531
697
  self._current_value = self.get_actuator_value()
532
- if (not Unit(self.controller_units).is_compatible_with(
698
+ if (not Unit(self.axis_unit).is_compatible_with(
533
699
  Unit(self._current_value.units)) and
534
700
  self._current_value.units == ''):
535
701
  # this happens if the units have not been specified in
536
702
  # the plugin
537
- self._current_value.force_units(self.controller_units)
703
+ self._current_value.force_units(self.axis_unit)
538
704
 
539
705
  logger.debug(f'Current position: {self._current_value}')
540
706
  self.move_done(self._current_value)
541
707
 
542
- def check_target_reached(self):
543
- logger.debug(f"epsilon value is {self.settings['epsilon']}")
544
- logger.debug(f"current_value value is {self._current_value}")
545
- logger.debug(f"target_value value is {self._target_value}")
708
+ def _condition_to_reach_target(self) -> bool:
709
+ """ Implement the condition for exiting the polling mechanism and specifying that the
710
+ target value has been reached
711
+
712
+ Returns
713
+ -------
714
+ bool: if True, PyMoDAQ considers the target value has been reached at epsilon
546
715
 
716
+ See Also
717
+ --------
718
+ user_condition_to_reach_target
719
+ """
547
720
  try:
548
- epsilon_calculated = (self._current_value - self._target_value).abs()
721
+ epsilon_calculated = (
722
+ self._current_value - self._target_value).abs().value(self.axis_unit)
549
723
  except DataUnitError as e:
550
724
  epsilon_calculated = abs(self._current_value.value() - self._target_value.value())
551
- logger.warning(f'Unit issue when calculating epsilon, units are not the same between'
725
+ logger.warning(f'Unit issue when calculating epsilon, units are not compatible between'
552
726
  f'target and current values')
553
727
 
554
- if not epsilon_calculated < self.settings['epsilon']:
728
+ return (epsilon_calculated < self.epsilon) and self.user_condition_to_reach_target()
729
+
730
+ def user_condition_to_reach_target(self) -> bool:
731
+ """ Implement a user defined condition for exiting the polling mechanism and specifying
732
+ that the target value has been reached (on top of the existing epsilon mechanism)
733
+
734
+ Should be reimplemented in plugins to implement other conditions
735
+
736
+ Returns
737
+ -------
738
+ bool: if True, PyMoDAQ considers the target value has been reached
739
+ """
740
+ return True
741
+
742
+ def check_target_reached(self):
743
+ logger.debug(f"epsilon value is {self.epsilon}")
744
+ logger.debug(f"current_value value is {self._current_value}")
745
+ logger.debug(f"target_value value is {self._target_value}")
746
+
747
+ if not self._condition_to_reach_target():
555
748
 
556
749
  logger.debug(f'Check move_is_done: {self.move_is_done}')
557
750
  if self.move_is_done:
@@ -647,6 +840,11 @@ class DAQ_Move_base(QObject):
647
840
  self.commit_common_settings(param)
648
841
  self.commit_settings(param)
649
842
 
843
+ if param.name() == 'axis':
844
+ self.axis_name = param.value()
845
+ elif param.name() == 'epsilon':
846
+ self.epsilon = param.value()
847
+
650
848
 
651
849
  class DAQ_Move_TCP_server(DAQ_Move_base, TCPServer):
652
850
  """
@@ -22,6 +22,8 @@ class ParameterEx(ParameterManager):
22
22
  {'title': 'Numbers:', 'name': 'numbers', 'type': 'group', 'children': [
23
23
  {'title': 'Standard float', 'name': 'afloat', 'type': 'float', 'value': 20., 'min': 1.,
24
24
  'tip': 'displays this text as a tooltip'},
25
+ {'title': 'Standard float with Si prefix', 'name': 'afloatprefix', 'type': 'float', 'value': 20.,
26
+ 'tip': 'displays this text as a tooltip', 'siPrefix': True, 'suffix': 'V'},
25
27
  {'title': 'Linear Slide float', 'name': 'linearslidefloat', 'type': 'slide', 'value': 50, 'default': 50,
26
28
  'min': 0,
27
29
  'max': 123, 'subtype': 'linear'},
pymodaq/resources/VERSION CHANGED
@@ -1,2 +1,2 @@
1
- version = '4.3.7'
1
+ version = '4.4.2'
2
2
 
pymodaq/utils/config.py CHANGED
@@ -20,7 +20,7 @@ except:
20
20
  USER = 'unknown_user'
21
21
 
22
22
  CONFIG_BASE_PATH = Path(environ['PROGRAMDATA']) if sys.platform == 'win32' else \
23
- Path('/Library/Application Support') if sys.platform == 'darwin' else Path('/etc')
23
+ Path('Library/Application Support') if sys.platform == 'darwin' else Path('/etc')
24
24
 
25
25
 
26
26
  KeyType = TypeVar('KeyType')
pymodaq/utils/data.py CHANGED
@@ -2413,21 +2413,48 @@ class DataActuator(DataRaw):
2413
2413
  else:
2414
2414
  return f'<{self.__class__.__name__} ({self.shape} {self.units})>'
2415
2415
 
2416
- def value(self) -> float:
2416
+ def value(self, units: str = None) -> float:
2417
2417
  """Returns the underlying float value (of the first elt in the data list) if this data
2418
- holds only a float otherwise returns a mean of the underlying data"""
2418
+ holds only a float otherwise returns a mean of the underlying data
2419
+
2420
+ Parameters
2421
+ ----------
2422
+
2423
+ units: str
2424
+ if unit is compatible with self.units, convert the data to these new units before
2425
+ getting the value
2426
+
2427
+
2428
+ """
2419
2429
  if self.length == 1 and self.size == 1:
2420
- return float(self.data[0][0])
2430
+ if units is not None:
2431
+ data = Q_(float(self.data[0][0]), self.units)
2432
+ return data.m_as(units)
2433
+ else:
2434
+ return float(self.data[0][0])
2421
2435
  else:
2422
- return float(np.mean(self.data))
2436
+ if units is not None:
2437
+ data = Q_(float(np.mean(self.data[0])), self.units)
2438
+ return data.m_as(units)
2439
+ else:
2440
+ return float(np.mean(self.data[0]))
2423
2441
 
2424
- def values(self) -> List[float]:
2442
+ def values(self, units: str = None) -> List[float]:
2425
2443
  """Returns the underlying float value (for each data array in the data list) if this data
2426
2444
  holds only a float otherwise returns a mean of the underlying data"""
2427
2445
  if self.length == 1 and self.size == 1:
2428
- return [float(data_array[0]) for data_array in self.data]
2446
+ if units is not None:
2447
+ return [float(Q_(data_array[0], self.units).m_as(units))
2448
+ for data_array in self.data]
2449
+ else:
2450
+ return [float(data_array[0])
2451
+ for data_array in self.data]
2429
2452
  else:
2430
- return [float(np.mean(data_array)) for data_array in self.data]
2453
+ if units is not None:
2454
+ return [float(Q_(np.mean(data_array), self.units).m_as(units))
2455
+ for data_array in self.data]
2456
+ else:
2457
+ return [float(np.mean(data_array)) for data_array in self.data]
2431
2458
 
2432
2459
 
2433
2460
  class DataFromPlugins(DataRaw):
@@ -12,7 +12,7 @@ def load_dashboard_with_preset(preset_name: str, extension_name: str):
12
12
  area = DockArea()
13
13
  win.setCentralWidget(area)
14
14
  win.resize(1000, 500)
15
- win.setWindowTitle('PyMoDAQ Dashboard')
15
+ win.setWindowTitle('extension_name')
16
16
  win.show()
17
17
 
18
18
  # win.setVisible(False)
@@ -420,6 +420,7 @@ class Serializer:
420
420
  * serialize the string type: 'DataWithAxes'
421
421
  * serialize the timestamp: float
422
422
  * serialize the name
423
+ * serialize the units
423
424
  * serialize the source enum as a string
424
425
  * serialize the dim enum as a string
425
426
  * serialize the distribution enum as a string
@@ -439,6 +440,7 @@ class Serializer:
439
440
  bytes_string += self.object_type_serialization(dwa)
440
441
  bytes_string += self.scalar_serialization(dwa.timestamp)
441
442
  bytes_string += self.string_serialization(dwa.name)
443
+ bytes_string += self.string_serialization(dwa.units)
442
444
  bytes_string += self.string_serialization(dwa.source.name)
443
445
  bytes_string += self.string_serialization(dwa.dim.name)
444
446
  bytes_string += self.string_serialization(dwa.distribution.name)
@@ -731,9 +733,11 @@ class DeSerializer:
731
733
  """
732
734
  class_name = self.string_deserialization()
733
735
  if class_name not in DwaType.names():
734
- raise TypeError(f'Attempting to deserialize a DataWithAxes flavor but got the bytes for a {class_name}')
736
+ raise TypeError(f'Attempting to deserialize a DataWithAxes '
737
+ f'flavor but got the bytes for a {class_name}')
735
738
  timestamp = self.scalar_deserialization()
736
739
  dwa = getattr(data_mod, class_name)(self.string_deserialization(),
740
+ units=self.string_deserialization(),
737
741
  source=self.string_deserialization(),
738
742
  dim=self.string_deserialization(),
739
743
  distribution=self.string_deserialization(),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pymodaq
3
- Version: 4.3.7
3
+ Version: 4.4.2
4
4
  Summary: Modular Data Acquisition with Python
5
5
  Project-URL: Homepage, http://pymodaq.cnrs.fr
6
6
  Project-URL: Source, https://github.com/PyMoDAQ/PyMoDAQ
@@ -77,7 +77,7 @@ PyMoDAQ
77
77
  :target: https://pymodaq.readthedocs.io/en/stable/?badge=latest
78
78
  :alt: Documentation Status
79
79
 
80
- .. image:: https://codecov.io/gh/PyMoDAQ/PyMoDAQ/branch/pymodaq-dev/graph/badge.svg?token=IQNJRCQDM2
80
+ .. image:: https://codecov.io/gh/PyMoDAQ/PyMoDAQ/branch/4.4.x/graph/badge.svg?token=IQNJRCQDM2
81
81
  :target: https://codecov.io/gh/PyMoDAQ/PyMoDAQ
82
82
 
83
83
  ====== ========== ======= ======
@@ -93,25 +93,25 @@ Python Qt Backend OS Passed
93
93
  ====== ========== ======= ======
94
94
 
95
95
 
96
- .. |38Qt5| image:: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp38pyqt5.yml/badge.svg?branch=4.3.x_dev
96
+ .. |38Qt5| image:: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp38pyqt5.yml/badge.svg?branch=4.4.x
97
97
  :target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp38pyqt5.yml
98
98
 
99
- .. |39Qt5| image:: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp39pyqt5.yml/badge.svg?branch=4.3.x_dev
99
+ .. |39Qt5| image:: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp39pyqt5.yml/badge.svg?branch=4.4.x
100
100
  :target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp39pyqt5.yml
101
101
 
102
- .. |310Qt5| image:: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp310pyqt5.yml/badge.svg?branch=4.3.x_dev
102
+ .. |310Qt5| image:: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp310pyqt5.yml/badge.svg?branch=4.4.x
103
103
  :target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp310pyqt5.yml
104
104
 
105
- .. |311Qt5| image:: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp311pyqt5.yml/badge.svg?branch=4.3.x_dev
105
+ .. |311Qt5| image:: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp311pyqt5.yml/badge.svg?branch=4.4.x
106
106
  :target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp311pyqt5.yml
107
107
 
108
- .. |38Qt5win| image:: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp38pyqt5_win.yml/badge.svg?branch=4.3.x_dev
108
+ .. |38Qt5win| image:: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp38pyqt5_win.yml/badge.svg?branch=4.4.x
109
109
  :target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp38pyqt5_win.yml
110
110
 
111
- .. |38pyside| image:: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp38pyside2.yml/badge.svg?branch=4.3.x_dev
111
+ .. |38pyside| image:: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp38pyside2.yml/badge.svg?branch=4.4.x
112
112
  :target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp38pyside2.yml
113
113
 
114
- .. |39Qt6| image:: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp39pyqt6.yml/badge.svg?branch=4.3.x_dev
114
+ .. |39Qt6| image:: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp39pyqt6.yml/badge.svg?branch=4.4.x
115
115
  :target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/Testp39pyqt6.yml
116
116
 
117
117
 
@@ -1,14 +1,14 @@
1
- pymodaq/__init__.py,sha256=boHjxPnKEAQUmOHKbnxlI8DHP1eM5IKSrrnd1EqkvHg,4295
1
+ pymodaq/__init__.py,sha256=e4pcKgxrhCVtCuq3t-gcfkwCWtV72K6jhPa-0zAtRfs,4382
2
2
  pymodaq/dashboard.py,sha256=4fbV92erom0yWwqPMtx3KW1q-d6QYflV-EhOZMg24a4,64476
3
3
  pymodaq/icon.ico,sha256=hOHHfNDENKphQvG1WDleSEYcHukneR2eRFJu8isIlD4,74359
4
4
  pymodaq/splash.png,sha256=ow8IECF3tPRUMA4tf2tMu1aRiMaxx91_Y2ckVxkrmF0,53114
5
5
  pymodaq/control_modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- pymodaq/control_modules/daq_move.py,sha256=dq29GbNf-8BpquR3z8ZuqvKaP-0p14LLrAAVg75pIis,36590
7
- pymodaq/control_modules/daq_move_ui.py,sha256=euA8_utFfiscd9ahZxRTqqTiCSrNB4CKCLqgdbUKSlI,15307
6
+ pymodaq/control_modules/daq_move.py,sha256=L4lW_VfdBKmrlpLkKwbNitDeLHbFWk6Lbq4T5k-6xiM,37323
7
+ pymodaq/control_modules/daq_move_ui.py,sha256=IbqNAErwXGjKUbYEptvZUz3J8MapNBFIbQnUf9nQrMw,15753
8
8
  pymodaq/control_modules/daq_viewer.py,sha256=5CYmdWHGE7sQApeMfdWNV3zbPyoxxYtzFlQ1PaEw4fI,57883
9
9
  pymodaq/control_modules/daq_viewer_ui.py,sha256=FWP3jdIOR9vTgYqNaaodteGZ3dwgQ1GdWKrOpOAuSrs,15693
10
10
  pymodaq/control_modules/mocks.py,sha256=hh_xSWp9g1UV3NAQVD9Ft9tNWfTsSvKU0OU0trgzP2w,1956
11
- pymodaq/control_modules/move_utility_classes.py,sha256=g_Q8eOPetwFuVbQfWTk4gX5XMsJoTvf_a7vdOrR5DoU,35731
11
+ pymodaq/control_modules/move_utility_classes.py,sha256=WwZku-xFsyqun25IG9570_OU5x1frA9rIrxVu6XJKIk,42599
12
12
  pymodaq/control_modules/utils.py,sha256=5YdSwq_lFJm7IalYWe_Hn1U4LUoUmo1gedvV9UguU0Y,20016
13
13
  pymodaq/control_modules/viewer_utility_classes.py,sha256=OHxwue1t3z2AXyeqNjnwPT2pMc8yXhnqyiWc9IdCI2c,26841
14
14
  pymodaq/examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -16,7 +16,7 @@ pymodaq/examples/custom_app.py,sha256=2wQR0hlPWjZrWK0abNF6ASv8iQyJqRn2CKnBa_nAgN
16
16
  pymodaq/examples/custom_viewer.py,sha256=nUj5n6l7DSyh-qaXboNBfXKa9mAiXrHSiOcuFL1ayRE,4814
17
17
  pymodaq/examples/function_plotter.py,sha256=T-VT0Rd3jHP9GcR2h6Nao6lwZE06P8zWUbOlz8b8Rxk,6104
18
18
  pymodaq/examples/nonlinearscanner.py,sha256=x0R2_FP0YnuOCCAmYRiAiZ1jfUdRxu5RqIYLyGQMZ0U,3790
19
- pymodaq/examples/parameter_ex.py,sha256=AVzs9aeZFe3U5SkFvC9VZuRZPoB-UMCxYYEnFH6if40,8357
19
+ pymodaq/examples/parameter_ex.py,sha256=NmFUvUByNtm3j4leN_MkufQsKlNU8Rx5lmpsVG58IIM,8556
20
20
  pymodaq/examples/preset_MockCamera.xml,sha256=quQlMsX6YSoqqc9_9Y-9zu3TDM6Xvnuc2JSWwg9f948,15774
21
21
  pymodaq/examples/tcp_client.py,sha256=FSdPlb3R_rxxNIqPqHVU8PxJzNZeFk_93l4TqsB5SnA,2584
22
22
  pymodaq/examples/Labview_TCP_Client/DAQ_TCP_Client.aliases,sha256=t0eKH9Uq_AMk4wQ-6Pm5mKUjGcCvfT9GtvMsvDhkCUk,47
@@ -58,7 +58,7 @@ pymodaq/post_treatment/daq_measurement/daq_measurement_GUI.py,sha256=1u7hWDaiwsZ
58
58
  pymodaq/post_treatment/daq_measurement/daq_measurement_GUI.ui,sha256=PyzbCWPMkh5oIYYteZczXyWMeHKW9EJmM1QlzXhnyTk,7037
59
59
  pymodaq/post_treatment/daq_measurement/daq_measurement_main.py,sha256=CAKwcWMOD86aXB8mbdxOK7e8nZRos5d59FzDtqK1QoY,17093
60
60
  pymodaq/post_treatment/daq_measurement/process_from_QtDesigner_DAQ_Measurement_GUI.bat,sha256=e1tu2A67MS9fk3jhriF6saQgRxWIucIvNW92iWXFP6E,164
61
- pymodaq/resources/VERSION,sha256=fP37ke9RfdHBjYyyxWc1kXW6-Gg-gr80uqzn0qTdrE8,19
61
+ pymodaq/resources/VERSION,sha256=u7UAa-_KS1Q9ODCq7-42m4PKdNLnm3M_qQLvikeM9Hc,19
62
62
  pymodaq/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
63
  pymodaq/resources/config_template.toml,sha256=d3pofgIK5FxaRMELAI1qEsRcMD3GlYd87zZjDj9G9m0,3210
64
64
  pymodaq/resources/preset_default.xml,sha256=Dt8iWLwPPOPtcG00JCVP-mh-G7KC6B0YN8hd8RQdnNI,27256
@@ -308,10 +308,10 @@ pymodaq/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
308
308
  pymodaq/utils/array_manipulation.py,sha256=uMdiVVR2mU7j6Z4DKL5VGhUPqiWvFX2YK7RLMGdLyC8,10415
309
309
  pymodaq/utils/calibration_camera.py,sha256=d3aAu0izXOdeLs-vyBaFfBuvyDGT3O-SreTuyd0Kvs4,8921
310
310
  pymodaq/utils/chrono_timer.py,sha256=rwX8apS8B-IKhA0Cp2H9tLz0BRN7G3Pg5ptozvd3MKM,7244
311
- pymodaq/utils/config.py,sha256=u-Q4af-tgXG7h8YitMGSPkigDxGoOYSEMHERQCF9mAM,16203
311
+ pymodaq/utils/config.py,sha256=0QqoBJC4ECuIeh1UsvUQqhxkKl7Vfgi4iERp-6qNWAc,16202
312
312
  pymodaq/utils/conftests.py,sha256=3Ak8WEpa3EhAp73Yb1LLq8YFONhPqiL7gG9eSDIoTNc,58
313
313
  pymodaq/utils/daq_utils.py,sha256=0jTrbT0aaZr3KaTgeDicmK9FbVnu3iaWBmNHnNJpr3A,28050
314
- pymodaq/utils/data.py,sha256=QPPFs57Eu1cEvF_QYJamjrPmickBVgsggg_bSkbd0P0,110621
314
+ pymodaq/utils/data.py,sha256=V4F_H-sUPmCwrcNDuF7JxzcJtnOlQX7fChSoyXdd6ng,111572
315
315
  pymodaq/utils/enums.py,sha256=wpRipioUJkKcEfoaY2NrDQ2WhGxZTZiZoJty5f2Ljpc,2236
316
316
  pymodaq/utils/exceptions.py,sha256=wLO6VlofzfwWkOOWMN2B-3NEWMfpgygyeEdakIx_rAs,668
317
317
  pymodaq/utils/factory.py,sha256=QLqAPFnTZ93eUpmAAIr7kESDk2enD57RNSuFUsjxE4E,2311
@@ -333,7 +333,7 @@ pymodaq/utils/gui_utils/dock.py,sha256=6AcxC9HqM45bt20vJgP6QgGAhkW8mynuOuWhL7gep
333
333
  pymodaq/utils/gui_utils/file_io.py,sha256=mJI_30p986rLZk44FsPjesMazE1tq7HEFLenW-dnmOI,3367
334
334
  pymodaq/utils/gui_utils/layout.py,sha256=6oczLLGwwEN4EQ8yUDnz0-4Ue2wlyCRklKsVD1GNcz8,1099
335
335
  pymodaq/utils/gui_utils/list_picker.py,sha256=ddYnRTlRlgwdJSy0Q98IzYWHzIf2GS6ABl8XSS9kVXM,1190
336
- pymodaq/utils/gui_utils/loader_utils.py,sha256=7sfAvktORgF1DAcYCHsWrl57koaO8v4D4UCqXgUPxbU,1301
336
+ pymodaq/utils/gui_utils/loader_utils.py,sha256=Gg0d31fjkqDq3l1WuRMbLzKiKPOIYdbUrcfGOgoXRk0,1298
337
337
  pymodaq/utils/gui_utils/utils.py,sha256=aPxFCnG4skDp-0UuhAudq6BPZnEXoAf6FOEJyrhUjx0,6089
338
338
  pymodaq/utils/gui_utils/widgets/__init__.py,sha256=LThGzmbFKbp2FtTTF_L7pHjyBzfB7F_bhMF4rPTwrUY,195
339
339
  pymodaq/utils/gui_utils/widgets/label.py,sha256=C2MU8i_Yy_oVRW7yal_ghB1Y5Bj_a9o8IFZWW3br-KM,600
@@ -436,10 +436,10 @@ pymodaq/utils/svg/svg_view.py,sha256=bmXpDqnw9S-Bp3F8Hi_oeYB5Y9gebiCNsQWVJzCq-PA
436
436
  pymodaq/utils/svg/svg_viewer2D.py,sha256=LTJ3Ulb5zWXdRPr7vqcWumbpq7ZctzrYUMtD5QV3x60,1523
437
437
  pymodaq/utils/tcp_ip/__init__.py,sha256=1e_EK0AgvdoLAD_CSGGEaITZdy6OWCO7ih9IAIp7HT4,81
438
438
  pymodaq/utils/tcp_ip/mysocket.py,sha256=StAWj8dzHeMnbLj68Sel81uWFy-YkKVNRnVf7gXrESI,3452
439
- pymodaq/utils/tcp_ip/serializer.py,sha256=oTQ24JNln_vRX4YADitTYiJplwFIdsta1ZDp6TOGMCA,27562
439
+ pymodaq/utils/tcp_ip/serializer.py,sha256=htVQCE4saRBMeIcseEyxTt5G58A341m6OGkaJUA34Wk,27766
440
440
  pymodaq/utils/tcp_ip/tcp_server_client.py,sha256=xIMTNgVW_rKK0yTi4FDNFLf85-Akb27Jz2LdrvOrP68,30660
441
- pymodaq-4.3.7.dist-info/METADATA,sha256=jrLMgm6DJyOZdZaK-32Cxe4h_-ikdS4vDVKW6e8ozRc,7657
442
- pymodaq-4.3.7.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
443
- pymodaq-4.3.7.dist-info/entry_points.txt,sha256=RAzdYNjvUT28I2eiCKki_g2NzXq0woWxhev6lwzwRv8,348
444
- pymodaq-4.3.7.dist-info/licenses/LICENSE,sha256=VKOejxexXAe3XwfhAhcFGqeXQ12irxVHdeAojZwFEI8,1108
445
- pymodaq-4.3.7.dist-info/RECORD,,
441
+ pymodaq-4.4.2.dist-info/METADATA,sha256=wc6QZZgW3pBAs85kQQ88JdPtJ8omKojHa1RDSgtuR3s,7623
442
+ pymodaq-4.4.2.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
443
+ pymodaq-4.4.2.dist-info/entry_points.txt,sha256=RAzdYNjvUT28I2eiCKki_g2NzXq0woWxhev6lwzwRv8,348
444
+ pymodaq-4.4.2.dist-info/licenses/LICENSE,sha256=VKOejxexXAe3XwfhAhcFGqeXQ12irxVHdeAojZwFEI8,1108
445
+ pymodaq-4.4.2.dist-info/RECORD,,