pymodaq 4.1.4__py3-none-any.whl → 4.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pymodaq might be problematic. Click here for more details.
- pymodaq/__init__.py +41 -4
- pymodaq/control_modules/daq_move.py +33 -74
- pymodaq/control_modules/daq_viewer.py +73 -98
- pymodaq/control_modules/daq_viewer_ui.py +2 -1
- pymodaq/control_modules/move_utility_classes.py +17 -7
- pymodaq/control_modules/utils.py +153 -5
- pymodaq/control_modules/viewer_utility_classes.py +31 -20
- pymodaq/dashboard.py +23 -5
- pymodaq/examples/tcp_client.py +97 -0
- pymodaq/extensions/__init__.py +4 -0
- pymodaq/extensions/bayesian/__init__.py +2 -0
- pymodaq/extensions/bayesian/bayesian_optimisation.py +673 -0
- pymodaq/extensions/bayesian/utils.py +403 -0
- pymodaq/extensions/daq_scan.py +4 -4
- pymodaq/extensions/daq_scan_ui.py +2 -1
- pymodaq/extensions/pid/pid_controller.py +12 -7
- pymodaq/extensions/pid/utils.py +9 -26
- pymodaq/extensions/utils.py +3 -0
- pymodaq/post_treatment/load_and_plot.py +42 -19
- pymodaq/resources/VERSION +1 -1
- pymodaq/resources/config_template.toml +9 -24
- pymodaq/resources/setup_plugin.py +1 -1
- pymodaq/utils/config.py +103 -5
- pymodaq/utils/daq_utils.py +37 -138
- pymodaq/utils/data.py +614 -95
- pymodaq/utils/enums.py +17 -1
- pymodaq/utils/factory.py +2 -2
- pymodaq/utils/gui_utils/custom_app.py +5 -2
- pymodaq/utils/gui_utils/dock.py +33 -4
- pymodaq/utils/gui_utils/file_io.py +3 -2
- pymodaq/utils/gui_utils/utils.py +14 -1
- pymodaq/utils/h5modules/backends.py +9 -1
- pymodaq/utils/h5modules/data_saving.py +254 -57
- pymodaq/utils/h5modules/saving.py +1 -0
- pymodaq/utils/leco/daq_move_LECODirector.py +172 -0
- pymodaq/utils/leco/daq_xDviewer_LECODirector.py +170 -0
- pymodaq/utils/leco/desktop.ini +2 -0
- pymodaq/utils/leco/director_utils.py +58 -0
- pymodaq/utils/leco/leco_director.py +88 -0
- pymodaq/utils/leco/pymodaq_listener.py +279 -0
- pymodaq/utils/leco/utils.py +41 -0
- pymodaq/utils/managers/action_manager.py +20 -6
- pymodaq/utils/managers/parameter_manager.py +6 -4
- pymodaq/utils/managers/roi_manager.py +64 -55
- pymodaq/utils/math_utils.py +1 -1
- pymodaq/utils/plotting/data_viewers/__init__.py +3 -1
- pymodaq/utils/plotting/data_viewers/base.py +286 -0
- pymodaq/utils/plotting/data_viewers/viewer.py +29 -202
- pymodaq/utils/plotting/data_viewers/viewer0D.py +94 -47
- pymodaq/utils/plotting/data_viewers/viewer1D.py +341 -174
- pymodaq/utils/plotting/data_viewers/viewer1Dbasic.py +1 -1
- pymodaq/utils/plotting/data_viewers/viewer2D.py +271 -181
- pymodaq/utils/plotting/data_viewers/viewerND.py +26 -22
- pymodaq/utils/plotting/items/crosshair.py +3 -3
- pymodaq/utils/plotting/items/image.py +2 -1
- pymodaq/utils/plotting/plotter/plotter.py +94 -0
- pymodaq/utils/plotting/plotter/plotters/__init__.py +0 -0
- pymodaq/utils/plotting/plotter/plotters/matplotlib_plotters.py +134 -0
- pymodaq/utils/plotting/plotter/plotters/qt_plotters.py +78 -0
- pymodaq/utils/plotting/utils/axes_viewer.py +1 -1
- pymodaq/utils/plotting/utils/filter.py +194 -147
- pymodaq/utils/plotting/utils/lineout.py +13 -11
- pymodaq/utils/plotting/utils/plot_utils.py +89 -12
- pymodaq/utils/scanner/__init__.py +0 -3
- pymodaq/utils/scanner/scan_config.py +1 -9
- pymodaq/utils/scanner/scan_factory.py +10 -36
- pymodaq/utils/scanner/scanner.py +3 -2
- pymodaq/utils/scanner/scanners/_1d_scanners.py +7 -5
- pymodaq/utils/scanner/scanners/_2d_scanners.py +36 -49
- pymodaq/utils/scanner/scanners/sequential.py +10 -4
- pymodaq/utils/scanner/scanners/tabular.py +10 -5
- pymodaq/utils/slicing.py +1 -1
- pymodaq/utils/tcp_ip/serializer.py +38 -5
- pymodaq/utils/tcp_ip/tcp_server_client.py +25 -17
- {pymodaq-4.1.4.dist-info → pymodaq-4.2.0.dist-info}/METADATA +4 -2
- {pymodaq-4.1.4.dist-info → pymodaq-4.2.0.dist-info}/RECORD +79 -64
- {pymodaq-4.1.4.dist-info → pymodaq-4.2.0.dist-info}/WHEEL +1 -1
- pymodaq/resources/config_scan_template.toml +0 -42
- {pymodaq-4.1.4.dist-info → pymodaq-4.2.0.dist-info}/entry_points.txt +0 -0
- {pymodaq-4.1.4.dist-info → pymodaq-4.2.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -6,15 +6,20 @@ Created the 22/01/2023
|
|
|
6
6
|
"""
|
|
7
7
|
import os
|
|
8
8
|
import sys
|
|
9
|
-
from typing import List, Union, Callable, Iterable
|
|
9
|
+
from typing import List, Union, Callable, Iterable, Dict
|
|
10
10
|
|
|
11
11
|
from qtpy import QtWidgets, QtCore
|
|
12
12
|
|
|
13
13
|
from pymodaq.utils.data import DataToExport, DataFromPlugins, DataDim, enum_checker
|
|
14
14
|
from pymodaq.utils.h5modules.data_saving import DataLoader
|
|
15
15
|
from pymodaq.utils.h5modules.saving import H5Saver
|
|
16
|
-
from pymodaq.utils.plotting.data_viewers.viewer import ViewerBase,
|
|
16
|
+
from pymodaq.utils.plotting.data_viewers.viewer import ViewerBase, ViewerDispatcher
|
|
17
|
+
from pymodaq.utils.plotting.data_viewers import ViewersEnum, Viewer1D, Viewer2D, ViewerND
|
|
17
18
|
from pymodaq.utils.gui_utils import Dock, DockArea
|
|
19
|
+
from pymodaq.utils.logger import set_logger, get_module_name
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
logger = set_logger(get_module_name(__file__))
|
|
18
23
|
|
|
19
24
|
|
|
20
25
|
class LoaderPlotter:
|
|
@@ -182,20 +187,25 @@ class LoaderPlotter:
|
|
|
182
187
|
|
|
183
188
|
target_at = kwargs.pop('target_at') if 'target_at' in kwargs else None
|
|
184
189
|
last_step = kwargs.pop('last_step') if 'last_step' in kwargs else False
|
|
190
|
+
crosshair_at = kwargs.pop('crosshair_at') if 'crosshair_at' in kwargs else None
|
|
185
191
|
|
|
186
192
|
self.load_data(**kwargs)
|
|
187
|
-
self.show_data(target_at=target_at
|
|
193
|
+
self.show_data(target_at=target_at,
|
|
194
|
+
crosshair_at=crosshair_at)
|
|
188
195
|
if (last_step and 'average_index' in kwargs and kwargs['average_index']
|
|
189
196
|
is not None):
|
|
190
197
|
kwargs['last_step'] = last_step
|
|
191
198
|
self.load_data(**kwargs)
|
|
192
|
-
self.show_data(target_at=target_at
|
|
199
|
+
self.show_data(target_at=target_at,
|
|
200
|
+
crosshair_at=crosshair_at)
|
|
193
201
|
|
|
194
202
|
def show_data(self, **kwargs):
|
|
195
203
|
"""Send data to their dedicated viewers
|
|
196
204
|
"""
|
|
197
|
-
|
|
198
|
-
|
|
205
|
+
try:
|
|
206
|
+
self.set_data_to_viewers(self._data, **kwargs)
|
|
207
|
+
except Exception as e:
|
|
208
|
+
logger.warning(f'Could not show data: {str(e)}')
|
|
199
209
|
|
|
200
210
|
def _init_show_data(self, data: DataToExport):
|
|
201
211
|
"""Processing before showing data
|
|
@@ -203,7 +213,9 @@ class LoaderPlotter:
|
|
|
203
213
|
self._viewer_types = [ViewersEnum(data.dim.name) for data in data]
|
|
204
214
|
self.prepare_viewers(self._viewer_types)
|
|
205
215
|
|
|
206
|
-
def prepare_viewers(self, viewers_enum: List[ViewersEnum
|
|
216
|
+
def prepare_viewers(self, viewers_enum: List[Union[ViewersEnum, str]],
|
|
217
|
+
viewers_name: List[str] = None) -> List[ViewerBase]:
|
|
218
|
+
|
|
207
219
|
if self._viewers is not None:
|
|
208
220
|
while len(self._viewers) > 0:
|
|
209
221
|
self._viewers.pop(list(self._viewers.keys())[0])
|
|
@@ -214,13 +226,16 @@ class LoaderPlotter:
|
|
|
214
226
|
viewers_name = [f'DataPlot{ind:02d}' for ind in range(len(self._viewer_types))]
|
|
215
227
|
|
|
216
228
|
if self.dispatcher.viewer_types != self._viewer_types:
|
|
217
|
-
self.dispatcher.update_viewers(self._viewer_types
|
|
229
|
+
self.dispatcher.update_viewers(self._viewer_types,
|
|
230
|
+
viewers_name=viewers_name)
|
|
218
231
|
|
|
219
232
|
self._viewers = dict(zip(viewers_name, self.dispatcher.viewers))
|
|
220
233
|
self._viewer_docks = dict(zip(viewers_name, self.dispatcher.viewer_docks))
|
|
234
|
+
return self.dispatcher.viewers
|
|
221
235
|
|
|
222
236
|
def set_data_to_viewers(self, data: DataToExport, temp=False,
|
|
223
|
-
target_at: Iterable[float] = None
|
|
237
|
+
target_at: Iterable[float] = None,
|
|
238
|
+
crosshair_at: Iterable[float] = None):
|
|
224
239
|
"""Process data dimensionality and send appropriate data to their data viewers
|
|
225
240
|
|
|
226
241
|
Parameters
|
|
@@ -230,6 +245,8 @@ class LoaderPlotter:
|
|
|
230
245
|
if True notify the data viewers to display data as temporary (meaning not exporting processed data from roi)
|
|
231
246
|
target_at: Iterable[float]
|
|
232
247
|
if specified show and plot the roi_target of each viewer at the given position
|
|
248
|
+
crosshair_at: Iterable[float]
|
|
249
|
+
if specified show and plot the viewer crosshair of each viewer at the given position
|
|
233
250
|
See Also
|
|
234
251
|
--------
|
|
235
252
|
ViewerBase, Viewer0D, Viewer1D, Viewer2D
|
|
@@ -246,21 +263,27 @@ class LoaderPlotter:
|
|
|
246
263
|
viewer.show_data_temp(_data)
|
|
247
264
|
else:
|
|
248
265
|
viewer.show_data(_data)
|
|
266
|
+
if crosshair_at is not None:
|
|
267
|
+
if not viewer.is_action_checked('crosshair'):
|
|
268
|
+
viewer.get_action('crosshair').trigger()
|
|
269
|
+
viewer.double_clicked(*crosshair_at)
|
|
249
270
|
if target_at is not None:
|
|
250
271
|
viewer.show_roi_target(True)
|
|
251
|
-
if
|
|
272
|
+
if isinstance(viewer, Viewer1D):
|
|
252
273
|
viewer.move_roi_target(target_at)
|
|
253
|
-
elif
|
|
274
|
+
elif isinstance(viewer, Viewer2D):
|
|
254
275
|
_target_at = target_at.copy()
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
276
|
+
if _data.distribution == 'uniform':
|
|
277
|
+
size = [_data.get_axis_from_index(1)[0].scaling]
|
|
278
|
+
if len(_target_at) == 1: # means concatenation of 1D data
|
|
279
|
+
axis = _data.get_axis_from_index(0)[0]
|
|
280
|
+
size.append(axis.scaling * axis.size)
|
|
281
|
+
_target_at = list(_target_at) + [axis.offset]
|
|
282
|
+
else:
|
|
283
|
+
size.append(_data.get_axis_from_index(0)[0].scaling)
|
|
284
|
+
viewer.move_roi_target(_target_at, size)
|
|
261
285
|
else:
|
|
262
|
-
|
|
263
|
-
viewer.move_roi_target(_target_at, size)
|
|
286
|
+
viewer.move_roi_target(_target_at)
|
|
264
287
|
|
|
265
288
|
def main(init_qt=True):
|
|
266
289
|
if init_qt: # used for the test suite
|
pymodaq/resources/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
version = '4.
|
|
1
|
+
version = '4.2.0'
|
|
@@ -41,6 +41,9 @@ viewer_in_thread = true
|
|
|
41
41
|
timeout = 10000 # default duration in ms to wait for data to be acquirred
|
|
42
42
|
allow_settings_edition = false
|
|
43
43
|
|
|
44
|
+
[plotting]
|
|
45
|
+
backend = 'matplotlib' # either 'matplotlib' or 'qt' or any other custom backend
|
|
46
|
+
|
|
44
47
|
[network]
|
|
45
48
|
[network.logging]
|
|
46
49
|
[network.logging.user]
|
|
@@ -55,6 +58,11 @@ allow_settings_edition = false
|
|
|
55
58
|
ip = "10.47.0.39"
|
|
56
59
|
port = 6341
|
|
57
60
|
|
|
61
|
+
[network.leco-server]
|
|
62
|
+
run_coordinator_at_startup = false
|
|
63
|
+
host = "localhost"
|
|
64
|
+
port = 12300 # pyleco default Coordinator port
|
|
65
|
+
|
|
58
66
|
[presets]
|
|
59
67
|
default_preset_for_scan = "preset_default"
|
|
60
68
|
default_preset_for_logger = "preset_default"
|
|
@@ -62,7 +70,7 @@ default_preset_for_pid = "beam_steering_mock"
|
|
|
62
70
|
|
|
63
71
|
[actuator]
|
|
64
72
|
epsilon_default = 1
|
|
65
|
-
polling_interval_ms = 100 # ms
|
|
73
|
+
polling_interval_ms = 100 # ms Careful when using TCP/IP connection as you can saturate the connection with too much polling
|
|
66
74
|
polling_timeout_s = 20 # s
|
|
67
75
|
refresh_timeout_ms = 500 # ms
|
|
68
76
|
timeout = 10000 # default duration in ms to wait for data to be acquirred
|
|
@@ -80,26 +88,3 @@ default_preset_for_pid = "beam_steering_mock"
|
|
|
80
88
|
wait_time_between = 0
|
|
81
89
|
timeout = 10000 # in millisecond
|
|
82
90
|
|
|
83
|
-
[scan.scan1D]
|
|
84
|
-
type = "Linear" # either "Linear", "Adaptive", "Linear back to start", "Random" see pymodaq.utils.scanner.py
|
|
85
|
-
start = 1.0
|
|
86
|
-
stop = 2.0
|
|
87
|
-
step = 0.01
|
|
88
|
-
[scan.scan2D]
|
|
89
|
-
type = "Spiral" # either "Spiral", "Linear", "Adaptive", "Back&Forth", "Random" see pymodaq.utils.scanner.py
|
|
90
|
-
[scan.scan2D.spiral]
|
|
91
|
-
center1 = -5
|
|
92
|
-
center2 = 5
|
|
93
|
-
rmax1 = 10
|
|
94
|
-
rmax2 = 5
|
|
95
|
-
npts = 10
|
|
96
|
-
[scan.scan2D.linear]
|
|
97
|
-
start1 = -5
|
|
98
|
-
start2 = -5
|
|
99
|
-
stop1 = 5
|
|
100
|
-
stop2 = 5
|
|
101
|
-
step1 = 0.5
|
|
102
|
-
step2 = 0.5
|
|
103
|
-
[scan.tabular]
|
|
104
|
-
type = "Linear" #either "Linear", "Adaptive" see pymodaq.utils.scanner.py
|
|
105
|
-
curvilinear = 0.1
|
|
@@ -47,7 +47,7 @@ def setup(path: Path):
|
|
|
47
47
|
entrypoints['pymodaq.instruments'] = f'{SHORT_PLUGIN_NAME} = {PLUGIN_NAME}'
|
|
48
48
|
if config['features'].get('extensions', False):
|
|
49
49
|
entrypoints['pymodaq.extensions'] = f'{SHORT_PLUGIN_NAME} = {PLUGIN_NAME}'
|
|
50
|
-
if config['features'].get('pid_models', False):
|
|
50
|
+
if config['features'].get('pid_models', False): # deprecated use 'models'
|
|
51
51
|
entrypoints['pymodaq.pid_models'] = f'{SHORT_PLUGIN_NAME} = {PLUGIN_NAME}'
|
|
52
52
|
if config['features'].get('models', False):
|
|
53
53
|
entrypoints['pymodaq.models'] = f'{SHORT_PLUGIN_NAME} = {PLUGIN_NAME}'
|
pymodaq/utils/config.py
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
from abc import abstractproperty
|
|
2
|
+
from collections.abc import Iterable
|
|
2
3
|
|
|
3
4
|
from os import environ
|
|
4
5
|
import sys
|
|
5
6
|
import datetime
|
|
6
7
|
from pathlib import Path
|
|
7
|
-
from typing import Union, Dict, TypeVar, Any
|
|
8
|
+
from typing import Union, Dict, TypeVar, Any, List, TYPE_CHECKING
|
|
9
|
+
from typing import Iterable as IterableType
|
|
8
10
|
|
|
9
11
|
import toml
|
|
10
12
|
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from pymodaq.utils.parameter import Parameter
|
|
15
|
+
|
|
11
16
|
|
|
12
17
|
try:
|
|
13
18
|
USER = environ['USERNAME'] if sys.platform == 'win32' else environ['USER']
|
|
@@ -80,6 +85,16 @@ def getitem_recursive(dic, *args, ndepth=0, create_if_missing=False):
|
|
|
80
85
|
return dic
|
|
81
86
|
|
|
82
87
|
|
|
88
|
+
def recursive_iterable_flattening(aniterable: IterableType):
|
|
89
|
+
flatten_iter = []
|
|
90
|
+
for elt in aniterable:
|
|
91
|
+
if not isinstance(elt, str) and isinstance(elt, Iterable):
|
|
92
|
+
flatten_iter.extend(recursive_iterable_flattening(elt))
|
|
93
|
+
else:
|
|
94
|
+
flatten_iter.append(elt)
|
|
95
|
+
return flatten_iter
|
|
96
|
+
|
|
97
|
+
|
|
83
98
|
def get_set_path(a_base_path: Path, dir_name: str) -> Path:
|
|
84
99
|
path_to_get = a_base_path.joinpath(dir_name)
|
|
85
100
|
if not path_to_get.is_dir():
|
|
@@ -249,7 +264,7 @@ def copy_template_config(config_file_name: str = 'config', source_path: Union[Pa
|
|
|
249
264
|
dest_path_with_filename = dest_path.joinpath(file_name)
|
|
250
265
|
|
|
251
266
|
if source_path is None:
|
|
252
|
-
config_template_dict =
|
|
267
|
+
config_template_dict = {}
|
|
253
268
|
else:
|
|
254
269
|
config_template_dict = toml.load(Path(source_path))
|
|
255
270
|
|
|
@@ -322,9 +337,18 @@ class BaseConfig:
|
|
|
322
337
|
else:
|
|
323
338
|
return self._config[item]
|
|
324
339
|
|
|
340
|
+
# def __setitem__(self, key, value):
|
|
341
|
+
# if isinstance(key, tuple):
|
|
342
|
+
# dic = getitem_recursive(self._config, *key, ndepth=1, create_if_missing=False)
|
|
343
|
+
# dic[key[-1]] = value
|
|
344
|
+
# else:
|
|
345
|
+
# self._config[key] = value
|
|
346
|
+
|
|
325
347
|
def __setitem__(self, key, value):
|
|
326
348
|
if isinstance(key, tuple):
|
|
327
|
-
dic = getitem_recursive(self._config, *key, ndepth=1, create_if_missing=
|
|
349
|
+
dic = getitem_recursive(self._config, *key, ndepth=1, create_if_missing=True)
|
|
350
|
+
if value is None: # means the setting is a group
|
|
351
|
+
value = {}
|
|
328
352
|
dic[key[-1]] = value
|
|
329
353
|
else:
|
|
330
354
|
self._config[key] = value
|
|
@@ -337,7 +361,10 @@ class BaseConfig:
|
|
|
337
361
|
toml_user_path = get_config_file(config_file_name, user=True)
|
|
338
362
|
if toml_base_path.is_file():
|
|
339
363
|
config = toml.load(toml_base_path)
|
|
340
|
-
|
|
364
|
+
if template_path is not None:
|
|
365
|
+
config_template = toml.load(template_path)
|
|
366
|
+
else:
|
|
367
|
+
config_template = {}
|
|
341
368
|
if check_config(config_template, config): # check if all fields from template are there
|
|
342
369
|
# (could have been modified by some commits)
|
|
343
370
|
create_toml_from_dict(config, toml_base_path)
|
|
@@ -383,8 +410,79 @@ class Config(BaseConfig):
|
|
|
383
410
|
return dict(user=dict(name=USER))
|
|
384
411
|
|
|
385
412
|
|
|
413
|
+
class ConfigSaverLoader:
|
|
414
|
+
""" Allows to set Parameters values from previously saved one in a configuration file
|
|
415
|
+
|
|
416
|
+
This plays the role of a cache for these Parameters
|
|
417
|
+
|
|
418
|
+
Parameters
|
|
419
|
+
----------
|
|
420
|
+
base_param: Parameter
|
|
421
|
+
The parent Parameter whose children should be cached in the config file
|
|
422
|
+
config: BaseConfig
|
|
423
|
+
The Config object that will cache the Parameter values
|
|
424
|
+
base_path: Iterable[str]
|
|
425
|
+
an iterable of string defining a "category"
|
|
426
|
+
"""
|
|
427
|
+
|
|
428
|
+
def __init__(self, base_param: 'Parameter', config: BaseConfig,
|
|
429
|
+
base_path: IterableType[str] = None):
|
|
430
|
+
self.config = config
|
|
431
|
+
if base_path is None:
|
|
432
|
+
base_path = []
|
|
433
|
+
self._base_path: List[str] = list(recursive_iterable_flattening(base_path))
|
|
434
|
+
self._base_param = base_param
|
|
435
|
+
|
|
436
|
+
@property
|
|
437
|
+
def base_path(self):
|
|
438
|
+
""" Get/Set the iterable of string defining a particular configuration to be loaded/saved"""
|
|
439
|
+
return self._base_path
|
|
440
|
+
|
|
441
|
+
@base_path.setter
|
|
442
|
+
def base_path(self, path: IterableType[str]):
|
|
443
|
+
self._base_path = list(recursive_iterable_flattening(path))
|
|
444
|
+
|
|
445
|
+
@property
|
|
446
|
+
def base_param(self):
|
|
447
|
+
""" Get/Set the parent Parameter whose children should be saved in the config file"""
|
|
448
|
+
return self._base_param
|
|
449
|
+
|
|
450
|
+
@base_param.setter
|
|
451
|
+
def base_param(self, param: 'Parameter'):
|
|
452
|
+
self._base_param = param
|
|
453
|
+
|
|
454
|
+
def load_config(self, param: 'Parameter' = None):
|
|
455
|
+
from pymodaq.utils.parameter import utils as putils
|
|
456
|
+
|
|
457
|
+
if param is None:
|
|
458
|
+
param = self.base_param
|
|
459
|
+
base_path = self.base_path[:]
|
|
460
|
+
for child in putils.iter_children_params(param, []):
|
|
461
|
+
if len(child.children()) == 0: # means it is not a group parameter
|
|
462
|
+
|
|
463
|
+
path = base_path + putils.get_param_path(child)[1:]
|
|
464
|
+
|
|
465
|
+
try:
|
|
466
|
+
child.setValue(self.config(
|
|
467
|
+
*path)) # first try to load the config including the actuators name
|
|
468
|
+
except ConfigError as e:
|
|
469
|
+
pass
|
|
470
|
+
else:
|
|
471
|
+
self.load_config(child)
|
|
472
|
+
|
|
473
|
+
def save_config(self):
|
|
474
|
+
from pymodaq.utils.parameter import utils as putils
|
|
475
|
+
|
|
476
|
+
for param in putils.iter_children_params(self.base_param, []):
|
|
477
|
+
path_param = self.base_path[:]
|
|
478
|
+
path_param.extend(putils.get_param_path(param)[1:])
|
|
479
|
+
try:
|
|
480
|
+
self.config[tuple(path_param)] = param.value()
|
|
481
|
+
except Exception as e:
|
|
482
|
+
pass
|
|
483
|
+
self.config.save()
|
|
484
|
+
|
|
386
485
|
|
|
387
|
-
|
|
388
486
|
if __name__ == '__main__':
|
|
389
487
|
|
|
390
488
|
config = Config()
|
pymodaq/utils/daq_utils.py
CHANGED
|
@@ -15,6 +15,8 @@ import pkgutil
|
|
|
15
15
|
import traceback
|
|
16
16
|
import platform
|
|
17
17
|
from typing import Union, List
|
|
18
|
+
from typing import Iterable as IterableType
|
|
19
|
+
from collections.abc import Iterable
|
|
18
20
|
|
|
19
21
|
import numpy as np
|
|
20
22
|
from qtpy import QtCore
|
|
@@ -38,44 +40,12 @@ else:
|
|
|
38
40
|
from functools import lru_cache as cache
|
|
39
41
|
|
|
40
42
|
|
|
41
|
-
if version_mod.parse(platform.python_version()) >= version_mod.parse('3.9'):
|
|
42
|
-
# from version 3.9 the cache decorator is available
|
|
43
|
-
from functools import cache
|
|
44
|
-
else:
|
|
45
|
-
from functools import lru_cache as cache
|
|
46
|
-
|
|
47
43
|
logger = logger_module.set_logger(logger_module.get_module_name(__file__))
|
|
48
44
|
|
|
49
45
|
plot_colors = [(255, 255, 255), (255, 0, 0), (0, 255, 0), (0, 0, 255), (14, 207, 189), (207, 14, 166), (207, 204, 14)]
|
|
50
46
|
config = Config()
|
|
51
47
|
|
|
52
48
|
|
|
53
|
-
def __getattr__(name):
|
|
54
|
-
if name in ['Axis', 'NavAxis', 'ScaledAxis', 'ScalingOptions', 'Data', 'DataTimeStamped', 'DataFromPlugins',
|
|
55
|
-
'DataToEmit', 'DataToExport']:
|
|
56
|
-
data_mod = importlib.import_module('.data', 'pymodaq.utils')
|
|
57
|
-
deprecation_msg('Loading Axis or Data and their derived classes from daq_utils is deprecated, import them from'
|
|
58
|
-
' pymodaq.utils.data module', 3)
|
|
59
|
-
return getattr(data_mod, name)
|
|
60
|
-
else:
|
|
61
|
-
raise AttributeError
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def load_config():
|
|
65
|
-
deprecation_msg(f'config methods must now be imported from the pymodaq.utils.messenger.cnfig module')
|
|
66
|
-
return Config()
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
def set_logger(*args, **kwargs):
|
|
70
|
-
deprecation_msg(f'Logger methods must now be imported from the pymodaq.utils.logger module', 3)
|
|
71
|
-
return logger_module.set_logger(*args, **kwargs)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def get_module_name(*args, **kwargs):
|
|
75
|
-
deprecation_msg(f'Logger methods must now be imported from the pymodaq.utils.logger module', 3)
|
|
76
|
-
return logger_module.get_module_name(*args, **kwargs)
|
|
77
|
-
|
|
78
|
-
|
|
79
49
|
def is_64bits():
|
|
80
50
|
return sys.maxsize > 2**32
|
|
81
51
|
|
|
@@ -261,7 +231,7 @@ class ThreadCommand:
|
|
|
261
231
|
raise TypeError(f'The command in a Threadcommand object should be a string, not a {type(command)}')
|
|
262
232
|
self.command = command
|
|
263
233
|
if attribute is None and attributes is not None:
|
|
264
|
-
deprecation_msg('ThreadCommand signature changed, use attribute in place of
|
|
234
|
+
deprecation_msg('ThreadCommand signature changed, use attribute in place of attributes')
|
|
265
235
|
self.attribute = attributes
|
|
266
236
|
self.attributes = attributes
|
|
267
237
|
self.attribute = attribute
|
|
@@ -554,7 +524,7 @@ def find_dict_in_list_from_key_val(dicts, key, value, return_index=False):
|
|
|
554
524
|
return None
|
|
555
525
|
|
|
556
526
|
|
|
557
|
-
def get_entrypoints(group='pymodaq.plugins'):
|
|
527
|
+
def get_entrypoints(group='pymodaq.plugins') -> List[metadata.EntryPoint]:
|
|
558
528
|
""" Get the list of modules defined from a group entry point
|
|
559
529
|
|
|
560
530
|
Because of evolution in the package, one or another of the forms below may be deprecated.
|
|
@@ -574,6 +544,8 @@ def get_entrypoints(group='pymodaq.plugins'):
|
|
|
574
544
|
discovered_entrypoints = metadata.entry_points().get(group, [])
|
|
575
545
|
if isinstance(discovered_entrypoints, tuple): # API for python > 3.8
|
|
576
546
|
discovered_entrypoints = list(discovered_entrypoints)
|
|
547
|
+
if not isinstance(discovered_entrypoints, list):
|
|
548
|
+
discovered_entrypoints = list(discovered_entrypoints)
|
|
577
549
|
return discovered_entrypoints
|
|
578
550
|
|
|
579
551
|
|
|
@@ -592,16 +564,18 @@ def get_instrument_plugins(): # pragma: no cover
|
|
|
592
564
|
"""
|
|
593
565
|
plugins_import = []
|
|
594
566
|
discovered_plugins = []
|
|
595
|
-
discovered_plugins_all = get_entrypoints(group='pymodaq.plugins') # old naming of the instrument plugins
|
|
596
|
-
discovered_plugins_all.extend(get_entrypoints(group='pymodaq.instruments')) # new naming convention
|
|
567
|
+
discovered_plugins_all = list(get_entrypoints(group='pymodaq.plugins')) # old naming of the instrument plugins
|
|
568
|
+
discovered_plugins_all.extend(list(get_entrypoints(group='pymodaq.instruments'))) # new naming convention
|
|
597
569
|
for entry in discovered_plugins_all:
|
|
598
570
|
if entry.name not in [ent.name for ent in discovered_plugins]:
|
|
599
571
|
discovered_plugins.append(entry)
|
|
572
|
+
discovered_plugins = list(set(discovered_plugins))
|
|
600
573
|
logger.debug(f'Found {len(discovered_plugins)} installed plugins, trying to import them')
|
|
601
574
|
viewer_types = ['0D', '1D', '2D', 'ND']
|
|
575
|
+
plugin_list = []
|
|
602
576
|
for entrypoint in discovered_plugins:
|
|
603
577
|
#print(f'Looking for valid instrument plugins in package: {module.value}')
|
|
604
|
-
|
|
578
|
+
|
|
605
579
|
try:
|
|
606
580
|
try:
|
|
607
581
|
movemodule = importlib.import_module(f'{entrypoint.value}.daq_move_plugins', entrypoint.value)
|
|
@@ -611,8 +585,12 @@ def get_instrument_plugins(): # pragma: no cover
|
|
|
611
585
|
'type': 'daq_move'}
|
|
612
586
|
for mod in [mod[1] for mod in pkgutil.iter_modules([str(movemodule.path.parent)])]
|
|
613
587
|
if 'daq_move' in mod])
|
|
588
|
+
if len(plugin_list) > 0:
|
|
589
|
+
logger.debug(f"Found Move Instrument:"
|
|
590
|
+
f" {plugin_list[-1]['module'].__name__}/{plugin_list[-1]['name']}")
|
|
614
591
|
except ModuleNotFoundError:
|
|
615
592
|
pass
|
|
593
|
+
|
|
616
594
|
viewer_modules = {}
|
|
617
595
|
for vtype in viewer_types:
|
|
618
596
|
try:
|
|
@@ -624,27 +602,32 @@ def get_instrument_plugins(): # pragma: no cover
|
|
|
624
602
|
'type': f'daq_{vtype}viewer'}
|
|
625
603
|
for mod in [mod[1] for mod in pkgutil.iter_modules([str(viewer_modules[vtype].path.parent)])]
|
|
626
604
|
if f'daq_{vtype}viewer' in mod])
|
|
605
|
+
if len(plugin_list) > 0:
|
|
606
|
+
logger.debug(f"Found Viewer Instrument: "
|
|
607
|
+
f"{plugin_list[-1]['module'].__name__}/{plugin_list[-1]['name']}")
|
|
627
608
|
except ModuleNotFoundError:
|
|
628
609
|
pass
|
|
629
610
|
|
|
630
|
-
# check if modules are importable
|
|
631
|
-
for mod in plugin_list:
|
|
632
|
-
try:
|
|
633
|
-
plugin_type = mod['type']
|
|
634
|
-
if plugin_type == 'daq_move':
|
|
635
|
-
submodule = mod['module']
|
|
636
|
-
importlib.import_module(f'{submodule.__package__}.daq_move_{mod["name"]}')
|
|
637
|
-
else:
|
|
638
|
-
submodule = mod['module']
|
|
639
|
-
importlib.import_module(f'{submodule.__package__}.daq_{plugin_type[4:6]}viewer_{mod["name"]}')
|
|
640
|
-
plugins_import.append(mod)
|
|
641
|
-
except Exception as e: # pragma: no cover
|
|
642
|
-
"""If an error is generated at the import, then exclude this plugin"""
|
|
643
|
-
logger.debug(f'Impossible to import Instrument plugin {mod["name"]}'
|
|
644
|
-
f' from module: {mod["parent_module"].__package__}')
|
|
645
611
|
except Exception as e: # pragma: no cover
|
|
646
612
|
logger.debug(str(e))
|
|
647
|
-
|
|
613
|
+
|
|
614
|
+
for mod in plugin_list:
|
|
615
|
+
try:
|
|
616
|
+
plugin_type = mod['type']
|
|
617
|
+
if plugin_type == 'daq_move':
|
|
618
|
+
submodule = mod['module']
|
|
619
|
+
importlib.import_module(f'{submodule.__package__}.daq_move_{mod["name"]}')
|
|
620
|
+
else:
|
|
621
|
+
submodule = mod['module']
|
|
622
|
+
importlib.import_module(f'{submodule.__package__}.daq_{plugin_type[4:6]}viewer_{mod["name"]}')
|
|
623
|
+
plugins_import.append(mod)
|
|
624
|
+
logger.info(f"{mod['module'].__name__}/{mod['name']} available")
|
|
625
|
+
except Exception as e: # pragma: no cover
|
|
626
|
+
"""If an error is generated at the import, then exclude this plugin"""
|
|
627
|
+
logger.debug(f'Impossible to import Instrument plugin {mod["name"]}'
|
|
628
|
+
f' from module: {mod["parent_module"].__package__}')
|
|
629
|
+
|
|
630
|
+
|
|
648
631
|
# add utility plugin for PID
|
|
649
632
|
try:
|
|
650
633
|
pidmodule = importlib.import_module('pymodaq.extensions.pid')
|
|
@@ -660,6 +643,7 @@ def get_instrument_plugins(): # pragma: no cover
|
|
|
660
643
|
|
|
661
644
|
return plugins_import
|
|
662
645
|
|
|
646
|
+
|
|
663
647
|
def get_plugins(plugin_type='daq_0Dviewer'): # pragma: no cover
|
|
664
648
|
"""
|
|
665
649
|
Get plugins names as a list
|
|
@@ -768,91 +752,6 @@ def get_new_file_name(base_path=Path(config('data_saving', 'h5file', 'save_path'
|
|
|
768
752
|
return file, curr_dir
|
|
769
753
|
|
|
770
754
|
|
|
771
|
-
# ##############
|
|
772
|
-
# Math utilities
|
|
773
|
-
# math utility functions, should now be imported from the math_utils module
|
|
774
|
-
import pymodaq.utils.math_utils as mutils
|
|
775
|
-
|
|
776
|
-
def my_moment(x, y):
|
|
777
|
-
deprecation_msg(f'my_moment function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
778
|
-
return mutils.my_moment(x, y)
|
|
779
|
-
|
|
780
|
-
def normalize(x):
|
|
781
|
-
deprecation_msg(f'normalize function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
782
|
-
return mutils.normalize(x)
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
def odd_even(x):
|
|
786
|
-
deprecation_msg(f'odd_even function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
787
|
-
return mutils.odd_even(x)
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
def greater2n(x):
|
|
791
|
-
deprecation_msg(f'greater2n function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
792
|
-
return mutils.greater2n(x)
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
def linspace_step(start, stop, step):
|
|
796
|
-
deprecation_msg(f'linspace_step function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
797
|
-
return mutils.linspace_step(start, stop, step)
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
def linspace_step_N(start, step, Npts):
|
|
801
|
-
deprecation_msg(f'linspace_step_N function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
802
|
-
return mutils.linspace_step_N(start, step, Npts)
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
def find_index(x, threshold):
|
|
806
|
-
deprecation_msg(f'find_index function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
807
|
-
return mutils.find_index(x, threshold)
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
def find_common_index(x, y, x0, y0):
|
|
811
|
-
deprecation_msg(f'find_common_index function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
812
|
-
return mutils.find_common_index(x, y, x0, y0)
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
def gauss1D(x, x0, dx, n=1):
|
|
816
|
-
deprecation_msg(f'gauss1D function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
817
|
-
return mutils.gauss1D(x, x0, dx, n=n)
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
def gauss2D(x, x0, dx, y, y0, dy, n=1, angle=0):
|
|
821
|
-
deprecation_msg(f'gauss2D function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
822
|
-
return mutils.gauss2D(x, x0, dx, y, y0, dy, n, angle)
|
|
823
|
-
|
|
824
|
-
def ftAxis(Npts, omega_max):
|
|
825
|
-
deprecation_msg(f'ftAxis function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
826
|
-
return mutils.ftAxis(Npts, omega_max)
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
def ftAxis_time(Npts, time_max):
|
|
830
|
-
deprecation_msg(f'ftAxis_time function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
831
|
-
return mutils.ftAxis_time(Npts, time_max)
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
def ft(x, dim=-1):
|
|
835
|
-
deprecation_msg(f'ft function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
836
|
-
return mutils.ft(x, dim)
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
def ift(x, dim=0):
|
|
840
|
-
deprecation_msg(f'ift function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
841
|
-
return mutils.ift(x, dim)
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
def ft2(x, dim=(-2, -1)):
|
|
845
|
-
deprecation_msg(f'ft2 function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
846
|
-
return mutils.ft2(x, dim)
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
def ift2(x, dim=(-2, -1)):
|
|
850
|
-
deprecation_msg(f'ift2 function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
851
|
-
return mutils.ift2(x, dim)
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
755
|
if __name__ == '__main__':
|
|
857
756
|
#paths = recursive_find_expr_in_files('C:\\Users\\weber\\Labo\\Programmes Python\\PyMoDAQ_Git', 'visa')
|
|
858
757
|
# for p in paths:
|