pymodaq 3.6.12__py3-none-any.whl → 4.0.1__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 +13 -6
- pymodaq/control_modules/__init__.py +0 -7
- pymodaq/control_modules/daq_move.py +965 -2
- pymodaq/control_modules/daq_move_ui.py +319 -0
- pymodaq/control_modules/daq_viewer.py +1573 -3
- pymodaq/control_modules/daq_viewer_ui.py +393 -0
- pymodaq/control_modules/mocks.py +51 -0
- pymodaq/control_modules/move_utility_classes.py +709 -8
- pymodaq/control_modules/utils.py +256 -0
- pymodaq/control_modules/viewer_utility_classes.py +663 -6
- pymodaq/daq_utils.py +89 -0
- pymodaq/dashboard.py +91 -72
- pymodaq/examples/custom_app.py +12 -11
- pymodaq/examples/custom_viewer.py +10 -10
- pymodaq/examples/function_plotter.py +16 -13
- pymodaq/examples/nonlinearscanner.py +8 -6
- pymodaq/examples/parameter_ex.py +7 -7
- pymodaq/examples/preset_MockCamera.xml +1 -0
- pymodaq/extensions/__init__.py +16 -0
- pymodaq/extensions/console.py +76 -0
- pymodaq/{daq_logger.py → extensions/daq_logger.py} +115 -65
- pymodaq/extensions/daq_scan.py +1339 -0
- pymodaq/extensions/daq_scan_ui.py +240 -0
- pymodaq/extensions/h5browser.py +23 -0
- pymodaq/{pid → extensions/pid}/__init__.py +4 -2
- pymodaq/{pid → extensions/pid}/daq_move_PID.py +2 -2
- pymodaq/{pid → extensions/pid}/pid_controller.py +48 -36
- pymodaq/{pid → extensions/pid}/utils.py +52 -6
- pymodaq/extensions/utils.py +40 -0
- pymodaq/post_treatment/__init__.py +6 -0
- pymodaq/{daq_analysis → post_treatment/daq_analysis}/daq_analysis_main.py +17 -17
- pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_main.py +8 -14
- pymodaq/post_treatment/load_and_plot.py +219 -0
- pymodaq/post_treatment/process_to_scalar.py +263 -0
- pymodaq/resources/QtDesigner_Ressources/Icon_Library/run_all.png +0 -0
- pymodaq/resources/QtDesigner_Ressources/Icon_Library/stop_all.png +0 -0
- pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources.bat +1 -1
- pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources.qrc +1 -0
- pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources_rc.py +109784 -109173
- pymodaq/resources/QtDesigner_Ressources/icons.svg +142 -0
- pymodaq/resources/VERSION +1 -1
- pymodaq/resources/config_template.toml +32 -13
- pymodaq/resources/preset_default.xml +1 -1
- pymodaq/{daq_utils → utils}/Tuto innosetup/script_full_setup.iss +1 -1
- pymodaq/utils/__init__.py +0 -29
- pymodaq/utils/abstract/__init__.py +48 -0
- pymodaq/{daq_utils → utils}/abstract/logger.py +7 -3
- pymodaq/utils/array_manipulation.py +379 -8
- pymodaq/{daq_utils → utils}/calibration_camera.py +6 -6
- pymodaq/{daq_utils → utils}/chrono_timer.py +1 -1
- pymodaq/utils/config.py +448 -0
- pymodaq/utils/conftests.py +5 -0
- pymodaq/utils/daq_utils.py +828 -8
- pymodaq/utils/data.py +1873 -7
- pymodaq/{daq_utils → utils}/db/db_logger/db_logger.py +86 -47
- pymodaq/{daq_utils → utils}/db/db_logger/db_logger_models.py +31 -10
- pymodaq/{daq_utils → utils}/enums.py +12 -7
- pymodaq/utils/exceptions.py +37 -0
- pymodaq/utils/factory.py +82 -0
- pymodaq/{daq_utils → utils}/gui_utils/__init__.py +1 -1
- pymodaq/utils/gui_utils/custom_app.py +129 -0
- pymodaq/utils/gui_utils/file_io.py +66 -0
- pymodaq/{daq_utils → utils}/gui_utils/layout.py +2 -2
- pymodaq/{daq_utils → utils}/gui_utils/utils.py +13 -3
- pymodaq/{daq_utils → utils}/gui_utils/widgets/__init__.py +2 -2
- pymodaq/utils/gui_utils/widgets/label.py +24 -0
- pymodaq/{daq_utils → utils}/gui_utils/widgets/lcd.py +12 -7
- pymodaq/{daq_utils → utils}/gui_utils/widgets/push.py +66 -2
- pymodaq/{daq_utils → utils}/gui_utils/widgets/qled.py +6 -4
- pymodaq/utils/gui_utils/widgets/spinbox.py +24 -0
- pymodaq/{daq_utils → utils}/gui_utils/widgets/table.py +2 -2
- pymodaq/utils/h5modules/__init__.py +1 -0
- pymodaq/{daq_utils/h5backend.py → utils/h5modules/backends.py} +200 -112
- pymodaq/utils/h5modules/browsing.py +683 -0
- pymodaq/utils/h5modules/data_saving.py +839 -0
- pymodaq/utils/h5modules/h5logging.py +110 -0
- pymodaq/utils/h5modules/module_saving.py +350 -0
- pymodaq/utils/h5modules/saving.py +914 -0
- pymodaq/utils/h5modules/utils.py +85 -0
- pymodaq/utils/logger.py +64 -6
- pymodaq/utils/managers/action_manager.py +460 -0
- pymodaq/{daq_utils → utils}/managers/batchscan_manager.py +144 -112
- pymodaq/{daq_utils → utils}/managers/modules_manager.py +188 -114
- pymodaq/{daq_utils → utils}/managers/overshoot_manager.py +3 -3
- pymodaq/utils/managers/parameter_manager.py +110 -0
- pymodaq/{daq_utils → utils}/managers/preset_manager.py +17 -13
- pymodaq/{daq_utils → utils}/managers/preset_manager_utils.py +8 -7
- pymodaq/{daq_utils → utils}/managers/remote_manager.py +7 -6
- pymodaq/{daq_utils → utils}/managers/roi_manager.py +148 -57
- pymodaq/utils/math_utils.py +546 -10
- pymodaq/{daq_utils → utils}/messenger.py +5 -1
- pymodaq/utils/parameter/__init__.py +2 -15
- pymodaq/{daq_utils → utils}/parameter/ioxml.py +12 -6
- pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/__init__.py +1 -3
- pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/filedir.py +1 -1
- pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/itemselect.py +3 -0
- pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/led.py +1 -1
- pymodaq/utils/parameter/pymodaq_ptypes/pixmap.py +161 -0
- pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/slide.py +1 -1
- pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/table.py +1 -1
- pymodaq/utils/parameter/utils.py +206 -11
- pymodaq/utils/plotting/data_viewers/__init__.py +6 -0
- pymodaq/utils/plotting/data_viewers/viewer.py +393 -0
- pymodaq/utils/plotting/data_viewers/viewer0D.py +251 -0
- pymodaq/utils/plotting/data_viewers/viewer1D.py +574 -0
- pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer1Dbasic.py +8 -3
- pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer2D.py +292 -357
- pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer2D_basic.py +58 -75
- pymodaq/utils/plotting/data_viewers/viewerND.py +738 -0
- pymodaq/{daq_utils → utils}/plotting/gant_chart.py +2 -2
- pymodaq/{daq_utils → utils}/plotting/items/axis_scaled.py +4 -2
- pymodaq/{daq_utils → utils}/plotting/items/image.py +8 -6
- pymodaq/utils/plotting/navigator.py +355 -0
- pymodaq/utils/plotting/scan_selector.py +480 -0
- pymodaq/utils/plotting/utils/axes_viewer.py +88 -0
- pymodaq/utils/plotting/utils/filter.py +538 -0
- pymodaq/utils/plotting/utils/lineout.py +224 -0
- pymodaq/{daq_utils → utils}/plotting/utils/plot_utils.py +196 -84
- pymodaq/{daq_utils → utils}/plotting/utils/signalND.py +21 -13
- pymodaq/utils/plotting/widgets.py +76 -0
- pymodaq/utils/scanner/__init__.py +10 -0
- pymodaq/utils/scanner/scan_factory.py +204 -0
- pymodaq/utils/scanner/scanner.py +271 -0
- pymodaq/utils/scanner/scanners/_1d_scanners.py +117 -0
- pymodaq/utils/scanner/scanners/_2d_scanners.py +293 -0
- pymodaq/utils/scanner/scanners/sequential.py +192 -0
- pymodaq/utils/scanner/scanners/tabular.py +294 -0
- pymodaq/utils/scanner/utils.py +83 -0
- pymodaq/utils/slicing.py +47 -0
- pymodaq/utils/svg/__init__.py +6 -0
- pymodaq/utils/svg/svg_renderer.py +20 -0
- pymodaq/utils/svg/svg_view.py +35 -0
- pymodaq/utils/svg/svg_viewer2D.py +51 -0
- pymodaq/{daq_utils → utils}/tcp_server_client.py +36 -37
- pymodaq/{daq_utils → utils}/tree_layout/tree_layout_main.py +50 -35
- pymodaq/utils/units.py +216 -0
- pymodaq-4.0.1.dist-info/METADATA +159 -0
- {pymodaq-3.6.12.dist-info → pymodaq-4.0.1.dist-info}/RECORD +167 -170
- {pymodaq-3.6.12.dist-info → pymodaq-4.0.1.dist-info}/WHEEL +1 -2
- pymodaq-4.0.1.dist-info/entry_points.txt +8 -0
- pymodaq/daq_move/daq_move_gui.py +0 -279
- pymodaq/daq_move/daq_move_gui.ui +0 -534
- pymodaq/daq_move/daq_move_main.py +0 -1042
- pymodaq/daq_move/process_from_QtDesigner_DAQ_Move_GUI.bat +0 -2
- pymodaq/daq_move/utility_classes.py +0 -671
- pymodaq/daq_scan.py +0 -2160
- pymodaq/daq_utils/array_manipulation.py +0 -386
- pymodaq/daq_utils/config.py +0 -273
- pymodaq/daq_utils/conftests.py +0 -7
- pymodaq/daq_utils/custom_parameter_tree.py +0 -9
- pymodaq/daq_utils/daq_enums.py +0 -133
- pymodaq/daq_utils/daq_utils.py +0 -1402
- pymodaq/daq_utils/exceptions.py +0 -71
- pymodaq/daq_utils/gui_utils/custom_app.py +0 -103
- pymodaq/daq_utils/gui_utils/file_io.py +0 -75
- pymodaq/daq_utils/gui_utils/widgets/spinbox.py +0 -9
- pymodaq/daq_utils/h5exporter_hyperspy.py +0 -115
- pymodaq/daq_utils/h5exporters.py +0 -242
- pymodaq/daq_utils/h5modules.py +0 -1559
- pymodaq/daq_utils/h5utils.py +0 -241
- pymodaq/daq_utils/managers/action_manager.py +0 -236
- pymodaq/daq_utils/managers/parameter_manager.py +0 -57
- pymodaq/daq_utils/math_utils.py +0 -705
- pymodaq/daq_utils/parameter/__init__.py +0 -1
- pymodaq/daq_utils/parameter/oldpymodaq_ptypes.py +0 -1626
- pymodaq/daq_utils/parameter/pymodaq_ptypes/pixmap.py +0 -85
- pymodaq/daq_utils/parameter/utils.py +0 -136
- pymodaq/daq_utils/plotting/data_viewers/__init__.py +0 -0
- pymodaq/daq_utils/plotting/data_viewers/process_from_QtDesigner_0DViewer_GUI.bat +0 -2
- pymodaq/daq_utils/plotting/data_viewers/viewer0D.py +0 -204
- pymodaq/daq_utils/plotting/data_viewers/viewer0D_GUI.py +0 -89
- pymodaq/daq_utils/plotting/data_viewers/viewer0D_GUI.ui +0 -131
- pymodaq/daq_utils/plotting/data_viewers/viewer1D.py +0 -781
- pymodaq/daq_utils/plotting/data_viewers/viewerND.py +0 -894
- pymodaq/daq_utils/plotting/data_viewers/viewerbase.py +0 -64
- pymodaq/daq_utils/plotting/items/__init__.py +0 -0
- pymodaq/daq_utils/plotting/navigator.py +0 -500
- pymodaq/daq_utils/plotting/scan_selector.py +0 -289
- pymodaq/daq_utils/plotting/utils/__init__.py +0 -0
- pymodaq/daq_utils/plotting/utils/filter.py +0 -236
- pymodaq/daq_utils/plotting/viewer0D/__init__.py +0 -0
- pymodaq/daq_utils/plotting/viewer0D/viewer0D_main.py +0 -4
- pymodaq/daq_utils/plotting/viewer1D/__init__.py +0 -0
- pymodaq/daq_utils/plotting/viewer1D/viewer1D_main.py +0 -4
- pymodaq/daq_utils/plotting/viewer1D/viewer1Dbasic.py +0 -4
- pymodaq/daq_utils/plotting/viewer2D/viewer_2D_basic.py +0 -4
- pymodaq/daq_utils/plotting/viewer2D/viewer_2D_main.py +0 -4
- pymodaq/daq_utils/plotting/viewerND/__init__.py +0 -0
- pymodaq/daq_utils/plotting/viewerND/viewerND_main.py +0 -4
- pymodaq/daq_utils/scanner.py +0 -1289
- pymodaq/daq_utils/tree_layout/__init__.py +0 -0
- pymodaq/daq_viewer/__init__.py +0 -0
- pymodaq/daq_viewer/daq_gui_settings.py +0 -237
- pymodaq/daq_viewer/daq_gui_settings.ui +0 -441
- pymodaq/daq_viewer/daq_viewer_main.py +0 -2225
- pymodaq/daq_viewer/process_from_QtDesigner_DAQ_GUI_settings.bat +0 -2
- pymodaq/daq_viewer/utility_classes.py +0 -673
- pymodaq/examples/logger_image/__init__.py +0 -0
- pymodaq/examples/logger_image/logger_displayer.py +0 -121
- pymodaq/examples/logger_image/setup.svg +0 -3119
- pymodaq/examples/logger_image/setup_svg.py +0 -114
- pymodaq/h5browser.py +0 -39
- pymodaq/utils/scanner.py +0 -15
- pymodaq-3.6.12.dist-info/METADATA +0 -39
- pymodaq-3.6.12.dist-info/entry_points.txt +0 -8
- pymodaq-3.6.12.dist-info/top_level.txt +0 -1
- /pymodaq/{daq_analysis → post_treatment/daq_analysis}/__init__.py +0 -0
- /pymodaq/{daq_measurement → post_treatment/daq_measurement}/__init__.py +0 -0
- /pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_GUI.py +0 -0
- /pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_GUI.ui +0 -0
- /pymodaq/{daq_measurement → post_treatment/daq_measurement}/process_from_QtDesigner_DAQ_Measurement_GUI.bat +0 -0
- /pymodaq/{daq_utils → utils}/Tuto innosetup/Tuto innosetup.odt +0 -0
- /pymodaq/{daq_utils → utils}/Tuto innosetup/Tuto innosetup.pdf +0 -0
- /pymodaq/{daq_move → utils/db}/__init__.py +0 -0
- /pymodaq/{daq_utils → utils/db/db_logger}/__init__.py +0 -0
- /pymodaq/{daq_utils → utils}/gui_utils/dock.py +0 -0
- /pymodaq/{daq_utils → utils}/gui_utils/list_picker.py +0 -0
- /pymodaq/{daq_utils/abstract → utils/managers}/__init__.py +0 -0
- /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/bool.py +0 -0
- /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/date.py +0 -0
- /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/list.py +0 -0
- /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/numeric.py +0 -0
- /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/tableview.py +0 -0
- /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/text.py +0 -0
- /pymodaq/{daq_utils/db → utils/plotting}/__init__.py +0 -0
- /pymodaq/{daq_utils → utils}/plotting/image_viewer.py +0 -0
- /pymodaq/{daq_utils/db/db_logger → utils/plotting/items}/__init__.py +0 -0
- /pymodaq/{daq_utils → utils}/plotting/items/crosshair.py +0 -0
- /pymodaq/{daq_utils/managers → utils/plotting/utils}/__init__.py +0 -0
- /pymodaq/{daq_utils → utils}/qvariant.py +0 -0
- /pymodaq/{daq_utils/plotting/viewer2D → utils/scanner/scanners}/__init__.py +0 -0
- /pymodaq/{daq_utils/plotting → utils/tree_layout}/__init__.py +0 -0
- {pymodaq-3.6.12.dist-info → pymodaq-4.0.1.dist-info/licenses}/LICENSE +0 -0
pymodaq/daq_utils/daq_utils.py
DELETED
|
@@ -1,1402 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import sys
|
|
3
|
-
from collections import OrderedDict
|
|
4
|
-
from ctypes import CFUNCTYPE
|
|
5
|
-
|
|
6
|
-
from pymodaq.daq_utils.config import get_set_config_path, get_set_preset_path, Config
|
|
7
|
-
from pymodaq.daq_utils.messenger import deprecation_msg
|
|
8
|
-
if 'win32' in sys.platform:
|
|
9
|
-
from ctypes import WINFUNCTYPE
|
|
10
|
-
import datetime
|
|
11
|
-
import importlib
|
|
12
|
-
import inspect
|
|
13
|
-
import json
|
|
14
|
-
import logging
|
|
15
|
-
import functools
|
|
16
|
-
import time
|
|
17
|
-
from logging.handlers import TimedRotatingFileHandler
|
|
18
|
-
from packaging import version as version_mod
|
|
19
|
-
from pathlib import Path
|
|
20
|
-
import pkgutil
|
|
21
|
-
import traceback
|
|
22
|
-
import warnings
|
|
23
|
-
import numbers
|
|
24
|
-
|
|
25
|
-
import numpy as np
|
|
26
|
-
from qtpy import QtCore
|
|
27
|
-
from qtpy.QtCore import QLocale
|
|
28
|
-
from pymodaq.daq_utils.qvariant import QVariant
|
|
29
|
-
|
|
30
|
-
python_version = f'{str(sys.version_info.major)}.{str(sys.version_info.minor)}'
|
|
31
|
-
if version_mod.parse(python_version) >= version_mod.parse('3.8'): # from version 3.8 this feature is included in the
|
|
32
|
-
# standard lib
|
|
33
|
-
from importlib import metadata
|
|
34
|
-
else:
|
|
35
|
-
import importlib_metadata as metadata # pragma: no cover
|
|
36
|
-
|
|
37
|
-
from pymodaq.daq_utils.exceptions import DataSourceError
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
plot_colors = [(255, 255, 255), (255, 0, 0), (0, 255, 0), (0, 0, 255), (14, 207, 189), (207, 14, 166), (207, 204, 14)]
|
|
41
|
-
config = Config()
|
|
42
|
-
|
|
43
|
-
Cb = 1.602176e-19 # coulomb
|
|
44
|
-
h = 6.626068e-34 # J.s
|
|
45
|
-
c = 2.997924586e8 # m.s-1
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
DATASOURCES = ('raw', 'roi')
|
|
49
|
-
DATADIMS = ('Data0D', 'Data1D', 'Data2D', 'DataND')
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def load_config():
|
|
53
|
-
deprecation_msg(f'Configuration file must now be imported from the pymodaq.daq_utils.messenger module')
|
|
54
|
-
return Config()
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def is_64bits():
|
|
58
|
-
return sys.maxsize > 2**32
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def timer(func):
|
|
62
|
-
"""Print the runtime of the decorated function"""
|
|
63
|
-
@functools.wraps(func)
|
|
64
|
-
def wrapper_timer(*args, **kwargs):
|
|
65
|
-
start_time = time.perf_counter() # 1
|
|
66
|
-
value = func(*args, **kwargs)
|
|
67
|
-
end_time = time.perf_counter() # 2
|
|
68
|
-
run_time = end_time - start_time # 3
|
|
69
|
-
print(f"Finished {func.__name__!r} in {run_time:.4f} secs")
|
|
70
|
-
return value
|
|
71
|
-
return wrapper_timer
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def set_logger(logger_name, add_handler=False, base_logger=False, add_to_console=False, log_level=None):
|
|
75
|
-
"""defines a logger of a given name and eventually add an handler to it
|
|
76
|
-
|
|
77
|
-
Parameters
|
|
78
|
-
----------
|
|
79
|
-
logger_name: (str) the name of the logger (usually it is the module name as returned by get_module_name
|
|
80
|
-
add_handler (bool) if True adds a TimedRotatingFileHandler to the logger instance (should be True if logger set from
|
|
81
|
-
main app
|
|
82
|
-
base_logger: (bool) specify if this is the parent logger (usually where one defines the handler)
|
|
83
|
-
|
|
84
|
-
Returns
|
|
85
|
-
-------
|
|
86
|
-
logger: (logging.logger) logger instance
|
|
87
|
-
See Also
|
|
88
|
-
--------
|
|
89
|
-
get_module_name, logging.handlers.TimedRotatingFileHandler
|
|
90
|
-
"""
|
|
91
|
-
if not base_logger:
|
|
92
|
-
logger_name = f'pymodaq.{logger_name}'
|
|
93
|
-
|
|
94
|
-
logger = logging.getLogger(logger_name)
|
|
95
|
-
log_path = get_set_config_path('log')
|
|
96
|
-
if add_handler:
|
|
97
|
-
if log_level is None:
|
|
98
|
-
log_level = config('general', 'debug_level')
|
|
99
|
-
logger.setLevel(log_level)
|
|
100
|
-
handler = TimedRotatingFileHandler(log_path.joinpath('pymodaq.log'), when='midnight')
|
|
101
|
-
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
102
|
-
handler.setFormatter(formatter)
|
|
103
|
-
logger.addHandler(handler)
|
|
104
|
-
|
|
105
|
-
logging.captureWarnings(True)
|
|
106
|
-
if log_level == 'DEBUG':
|
|
107
|
-
warnings.filterwarnings('default', category=DeprecationWarning)
|
|
108
|
-
else:
|
|
109
|
-
warnings.filterwarnings('ignore', category=DeprecationWarning)
|
|
110
|
-
|
|
111
|
-
warnings_logger = logging.getLogger("py.warnings")
|
|
112
|
-
warnings_logger.addHandler(handler)
|
|
113
|
-
|
|
114
|
-
if add_to_console:
|
|
115
|
-
console_handler = logging.StreamHandler()
|
|
116
|
-
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
117
|
-
console_handler.setFormatter(formatter)
|
|
118
|
-
logger.addHandler(console_handler)
|
|
119
|
-
return logger
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
logger = set_logger('daq_utils')
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def get_version():
|
|
126
|
-
with open(str(Path(__file__).parent.parent.joinpath('resources/VERSION')), 'r') as fvers:
|
|
127
|
-
version = fvers.read().strip()
|
|
128
|
-
return version
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
def copy_preset(): # pragma: no cover
|
|
132
|
-
path = get_set_preset_path().joinpath('preset_default.xml')
|
|
133
|
-
if not path.exists(): # copy the preset_default from pymodaq folder and create one in pymodad's local folder
|
|
134
|
-
with open(str(Path(__file__).parent.parent.joinpath('resources/preset_default.xml')), 'r') as file:
|
|
135
|
-
path.write_text(file.read())
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
def set_qt_backend():
|
|
139
|
-
backend_present = True
|
|
140
|
-
if config('qtbackend', 'backend').lower() not in [mod.lower() for mod in sys.modules]:
|
|
141
|
-
backend_present = False
|
|
142
|
-
logger.warning(f"The chosen Qt backend ({config('qtbackend', 'backend')}) has not been installed...\n"
|
|
143
|
-
f"Trying another...")
|
|
144
|
-
backends = config('qtbackend', 'backends')
|
|
145
|
-
backends.pop(backends.index(config('qtbackend', 'backend')))
|
|
146
|
-
for backend in backends:
|
|
147
|
-
if backend.lower() in [mod.lower() for mod in sys.modules]:
|
|
148
|
-
backend_present = True
|
|
149
|
-
break
|
|
150
|
-
|
|
151
|
-
if backend_present:
|
|
152
|
-
os.environ['QT_API'] = config('qtbackend', 'backend')
|
|
153
|
-
logger.info('************************')
|
|
154
|
-
logger.info(f"{config('qtbackend', 'backend')} Qt backend loaded")
|
|
155
|
-
logger.info('************************')
|
|
156
|
-
else:
|
|
157
|
-
msg = f"No Qt backend could be found in your system, please install either pyqt5/6 or pyside2/6." \
|
|
158
|
-
f"pyqt5 is still preferred, while pyqt6 should mostly work."
|
|
159
|
-
logger.critical(msg)
|
|
160
|
-
print(msg.upper())
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
class JsonConverter:
|
|
164
|
-
def __init__(self):
|
|
165
|
-
super().__init__()
|
|
166
|
-
|
|
167
|
-
@classmethod
|
|
168
|
-
def trusted_types(cls):
|
|
169
|
-
return ['float', 'int', 'str', 'datetime', 'date', 'time', 'tuple', 'list', 'bool', 'bytes']
|
|
170
|
-
|
|
171
|
-
@classmethod
|
|
172
|
-
def istrusted(cls, type_name):
|
|
173
|
-
return type_name in cls.trusted_types()
|
|
174
|
-
|
|
175
|
-
@classmethod
|
|
176
|
-
def object2json(cls, obj):
|
|
177
|
-
dic = dict(module=type(obj).__module__, type=type(obj).__name__, data=repr(obj))
|
|
178
|
-
return json.dumps(dic)
|
|
179
|
-
|
|
180
|
-
@classmethod
|
|
181
|
-
def json2object(cls, jsonstring):
|
|
182
|
-
try:
|
|
183
|
-
dic = json.loads(jsonstring)
|
|
184
|
-
if isinstance(dic, dict):
|
|
185
|
-
if dic['type'] in cls.trusted_types():
|
|
186
|
-
return eval(dic['data'])
|
|
187
|
-
else:
|
|
188
|
-
return dic
|
|
189
|
-
else: # pragma: no cover
|
|
190
|
-
return dic
|
|
191
|
-
except Exception:
|
|
192
|
-
return jsonstring
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
def decode_data(encoded_data):
|
|
196
|
-
"""
|
|
197
|
-
Decode QbyteArrayData generated when drop items in table/tree/list view
|
|
198
|
-
Parameters
|
|
199
|
-
----------
|
|
200
|
-
encoded_data: QByteArray
|
|
201
|
-
Encoded data of the mime data to be dropped
|
|
202
|
-
Returns
|
|
203
|
-
-------
|
|
204
|
-
data: list
|
|
205
|
-
list of dict whose key is the QtRole in the Model, and the value a QVariant
|
|
206
|
-
|
|
207
|
-
"""
|
|
208
|
-
data = []
|
|
209
|
-
|
|
210
|
-
ds = QtCore.QDataStream(encoded_data, QtCore.QIODevice.ReadOnly)
|
|
211
|
-
while not ds.atEnd():
|
|
212
|
-
row = ds.readInt32()
|
|
213
|
-
col = ds.readInt32()
|
|
214
|
-
|
|
215
|
-
map_items = ds.readInt32()
|
|
216
|
-
item = {}
|
|
217
|
-
for ind in range(map_items):
|
|
218
|
-
key = ds.readInt32()
|
|
219
|
-
#TODO check this is fine
|
|
220
|
-
value = QVariant()
|
|
221
|
-
#value = None
|
|
222
|
-
ds >> value
|
|
223
|
-
item[QtCore.Qt.ItemDataRole(key)] = value.value()
|
|
224
|
-
data.append(item)
|
|
225
|
-
return data
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
# ###################################
|
|
229
|
-
# # Units conversion
|
|
230
|
-
def Enm2cmrel(E_nm, ref_wavelength=515):
|
|
231
|
-
"""Converts energy in nm to cm-1 relative to a ref wavelength
|
|
232
|
-
|
|
233
|
-
Parameters
|
|
234
|
-
----------
|
|
235
|
-
E_nm: float
|
|
236
|
-
photon energy in wavelength (nm)
|
|
237
|
-
ref_wavelength: float
|
|
238
|
-
reference wavelength in nm from which calculate the photon relative energy
|
|
239
|
-
|
|
240
|
-
Returns
|
|
241
|
-
-------
|
|
242
|
-
float
|
|
243
|
-
photon energy in cm-1 relative to the ref wavelength
|
|
244
|
-
|
|
245
|
-
Examples
|
|
246
|
-
--------
|
|
247
|
-
>>> Enm2cmrel(530, 515)
|
|
248
|
-
549.551199853453
|
|
249
|
-
"""
|
|
250
|
-
return 1 / (ref_wavelength * 1e-7) - 1 / (E_nm * 1e-7)
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
def Ecmrel2Enm(Ecmrel, ref_wavelength=515):
|
|
254
|
-
"""Converts energy from cm-1 relative to a ref wavelength to an energy in wavelength (nm)
|
|
255
|
-
|
|
256
|
-
Parameters
|
|
257
|
-
----------
|
|
258
|
-
Ecmrel: float
|
|
259
|
-
photon energy in cm-1
|
|
260
|
-
ref_wavelength: float
|
|
261
|
-
reference wavelength in nm from which calculate the photon relative energy
|
|
262
|
-
|
|
263
|
-
Returns
|
|
264
|
-
-------
|
|
265
|
-
float
|
|
266
|
-
photon energy in nm
|
|
267
|
-
|
|
268
|
-
Examples
|
|
269
|
-
--------
|
|
270
|
-
>>> Ecmrel2Enm(500, 515)
|
|
271
|
-
528.6117526302285
|
|
272
|
-
"""
|
|
273
|
-
Ecm = 1 / (ref_wavelength * 1e-7) - Ecmrel
|
|
274
|
-
return 1 / (Ecm * 1e-7)
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
def eV2nm(E_eV):
|
|
278
|
-
"""Converts photon energy from electronvolt to wavelength in nm
|
|
279
|
-
|
|
280
|
-
Parameters
|
|
281
|
-
----------
|
|
282
|
-
E_eV: float
|
|
283
|
-
Photon energy in eV
|
|
284
|
-
|
|
285
|
-
Returns
|
|
286
|
-
-------
|
|
287
|
-
float
|
|
288
|
-
photon energy in nm
|
|
289
|
-
|
|
290
|
-
Examples
|
|
291
|
-
--------
|
|
292
|
-
>>> eV2nm(1.55)
|
|
293
|
-
799.898112990037
|
|
294
|
-
"""
|
|
295
|
-
E_J = E_eV * Cb
|
|
296
|
-
E_freq = E_J / h
|
|
297
|
-
E_nm = c / E_freq * 1e9
|
|
298
|
-
return E_nm
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
def nm2eV(E_nm):
|
|
302
|
-
"""Converts photon energy from wavelength in nm to electronvolt
|
|
303
|
-
|
|
304
|
-
Parameters
|
|
305
|
-
----------
|
|
306
|
-
E_nm: float
|
|
307
|
-
Photon energy in nm
|
|
308
|
-
|
|
309
|
-
Returns
|
|
310
|
-
-------
|
|
311
|
-
float
|
|
312
|
-
photon energy in eV
|
|
313
|
-
|
|
314
|
-
Examples
|
|
315
|
-
--------
|
|
316
|
-
>>> nm2eV(800)
|
|
317
|
-
1.549802593918197
|
|
318
|
-
"""
|
|
319
|
-
E_freq = c / E_nm * 1e9
|
|
320
|
-
E_J = E_freq * h
|
|
321
|
-
E_eV = E_J / Cb
|
|
322
|
-
return E_eV
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
def E_J2eV(E_J):
|
|
326
|
-
E_eV = E_J / Cb
|
|
327
|
-
return E_eV
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
def eV2cm(E_eV):
|
|
331
|
-
"""Converts photon energy from electronvolt to absolute cm-1
|
|
332
|
-
|
|
333
|
-
Parameters
|
|
334
|
-
----------
|
|
335
|
-
E_eV: float
|
|
336
|
-
Photon energy in eV
|
|
337
|
-
|
|
338
|
-
Returns
|
|
339
|
-
-------
|
|
340
|
-
float
|
|
341
|
-
photon energy in cm-1
|
|
342
|
-
|
|
343
|
-
Examples
|
|
344
|
-
--------
|
|
345
|
-
>>> eV2cm(0.07)
|
|
346
|
-
564.5880342655984
|
|
347
|
-
"""
|
|
348
|
-
E_nm = eV2nm(E_eV)
|
|
349
|
-
E_cm = 1 / (E_nm * 1e-7)
|
|
350
|
-
return E_cm
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
def nm2cm(E_nm):
|
|
354
|
-
"""Converts photon energy from wavelength to absolute cm-1
|
|
355
|
-
|
|
356
|
-
Parameters
|
|
357
|
-
----------
|
|
358
|
-
E_nm: float
|
|
359
|
-
Photon energy in nm
|
|
360
|
-
|
|
361
|
-
Returns
|
|
362
|
-
-------
|
|
363
|
-
float
|
|
364
|
-
photon energy in cm-1
|
|
365
|
-
|
|
366
|
-
Examples
|
|
367
|
-
--------
|
|
368
|
-
>>> nm2cm(0.04)
|
|
369
|
-
0.000025
|
|
370
|
-
"""
|
|
371
|
-
return 1 / (E_nm * 1e7)
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
def cm2nm(E_cm):
|
|
375
|
-
"""Converts photon energy from absolute cm-1 to wavelength
|
|
376
|
-
|
|
377
|
-
Parameters
|
|
378
|
-
----------
|
|
379
|
-
E_cm: float
|
|
380
|
-
photon energy in cm-1
|
|
381
|
-
|
|
382
|
-
Returns
|
|
383
|
-
-------
|
|
384
|
-
float
|
|
385
|
-
Photon energy in nm
|
|
386
|
-
|
|
387
|
-
Examples
|
|
388
|
-
--------
|
|
389
|
-
>>> cm2nm(1e5)
|
|
390
|
-
100
|
|
391
|
-
"""
|
|
392
|
-
return 1 / (E_cm * 1e-7)
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
def eV2E_J(E_eV):
|
|
396
|
-
E_J = E_eV * Cb
|
|
397
|
-
return E_J
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
def eV2radfs(E_eV):
|
|
401
|
-
E_J = E_eV * Cb
|
|
402
|
-
E_freq = E_J / h
|
|
403
|
-
E_radfs = E_freq * 2 * np.pi / 1e15
|
|
404
|
-
return E_radfs
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
def l2w(x, speedlight=300):
|
|
408
|
-
"""Converts photon energy in rad/fs to nm (and vice-versa)
|
|
409
|
-
|
|
410
|
-
Parameters
|
|
411
|
-
----------
|
|
412
|
-
x: float
|
|
413
|
-
photon energy in wavelength or rad/fs
|
|
414
|
-
speedlight: float, optional
|
|
415
|
-
the speed of light, by default 300 nm/fs
|
|
416
|
-
|
|
417
|
-
Returns
|
|
418
|
-
-------
|
|
419
|
-
float
|
|
420
|
-
|
|
421
|
-
Examples
|
|
422
|
-
--------
|
|
423
|
-
>>> l2w(800)
|
|
424
|
-
2.356194490192345
|
|
425
|
-
>>> l2w(800,3e8)
|
|
426
|
-
2356194.490192345
|
|
427
|
-
"""
|
|
428
|
-
y = 2 * np.pi * speedlight / x
|
|
429
|
-
return y
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
#############################
|
|
433
|
-
|
|
434
|
-
def capitalize(string, Nfirst=1):
|
|
435
|
-
"""
|
|
436
|
-
Returns same string but with first Nfirst letters upper
|
|
437
|
-
Parameters
|
|
438
|
-
----------
|
|
439
|
-
string: (str)
|
|
440
|
-
Nfirst: (int)
|
|
441
|
-
Returns
|
|
442
|
-
-------
|
|
443
|
-
str
|
|
444
|
-
"""
|
|
445
|
-
return string[:Nfirst].upper() + string[Nfirst:]
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
def uncapitalize(string, Nfirst=1):
|
|
449
|
-
return string[:Nfirst].lower() + string[Nfirst:]
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
def get_data_dimension(arr, scan_type='scan1D', remove_scan_dimension=False):
|
|
453
|
-
dimension = len(arr.shape)
|
|
454
|
-
if dimension == 1:
|
|
455
|
-
if arr.size == 1:
|
|
456
|
-
dimension = 0
|
|
457
|
-
|
|
458
|
-
if remove_scan_dimension:
|
|
459
|
-
if scan_type.lower() == 'scan1d':
|
|
460
|
-
dimension -= 1
|
|
461
|
-
elif scan_type.lower() == 'scan2d':
|
|
462
|
-
dimension -= 2
|
|
463
|
-
else:
|
|
464
|
-
if dimension > 2:
|
|
465
|
-
dimension = 'N'
|
|
466
|
-
return arr.shape, f'{dimension}D', arr.size
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
def scroll_log(scroll_val, min_val, max_val):
|
|
470
|
-
"""
|
|
471
|
-
Convert a scroll value [0-100] to a log scale between min_val and max_val
|
|
472
|
-
Parameters
|
|
473
|
-
----------
|
|
474
|
-
scroll
|
|
475
|
-
min_val
|
|
476
|
-
max_val
|
|
477
|
-
Returns
|
|
478
|
-
-------
|
|
479
|
-
|
|
480
|
-
"""
|
|
481
|
-
assert scroll_val >= 0
|
|
482
|
-
assert scroll_val <= 100
|
|
483
|
-
value = scroll_val * (np.log10(max_val) - np.log10(min_val)) / 100 + np.log10(min_val)
|
|
484
|
-
return 10 ** value
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
def scroll_linear(scroll_val, min_val, max_val):
|
|
488
|
-
"""
|
|
489
|
-
Convert a scroll value [0-100] to a linear scale between min_val and max_val
|
|
490
|
-
Parameters
|
|
491
|
-
----------
|
|
492
|
-
scroll
|
|
493
|
-
min_val
|
|
494
|
-
max_val
|
|
495
|
-
Returns
|
|
496
|
-
-------
|
|
497
|
-
|
|
498
|
-
"""
|
|
499
|
-
assert scroll_val >= 0
|
|
500
|
-
assert scroll_val <= 100
|
|
501
|
-
value = scroll_val * (max_val - min_val) / 100 + min_val
|
|
502
|
-
return value
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
def getLineInfo():
|
|
506
|
-
"""get information about where the Exception has been triggered"""
|
|
507
|
-
tb = sys.exc_info()[2]
|
|
508
|
-
res = ''
|
|
509
|
-
for t in traceback.format_tb(tb):
|
|
510
|
-
res += t
|
|
511
|
-
return res
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
class ThreadCommand(object):
|
|
515
|
-
""" | Micro class managing the thread commands.
|
|
516
|
-
|
|
|
517
|
-
| A thread command is composed of a string name defining the command to execute and an attribute list splitable making arguments of the called function.
|
|
518
|
-
|
|
519
|
-
=============== =============
|
|
520
|
-
**Attributes** **Type**
|
|
521
|
-
*command* string
|
|
522
|
-
*attributes* generic list
|
|
523
|
-
=============== =============
|
|
524
|
-
|
|
525
|
-
"""
|
|
526
|
-
|
|
527
|
-
def __init__(self, command="", attributes=[]):
|
|
528
|
-
self.command = command
|
|
529
|
-
self.attributes = attributes
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
class AxisBase(dict):
|
|
533
|
-
"""
|
|
534
|
-
Utility class defining an axis for pymodaq's viewers, attributes can be accessed as dictionary keys or class
|
|
535
|
-
type attributes
|
|
536
|
-
"""
|
|
537
|
-
|
|
538
|
-
def __init__(self, label='', units='', **kwargs):
|
|
539
|
-
"""
|
|
540
|
-
|
|
541
|
-
Parameters
|
|
542
|
-
----------
|
|
543
|
-
data
|
|
544
|
-
label
|
|
545
|
-
units
|
|
546
|
-
"""
|
|
547
|
-
if units is None:
|
|
548
|
-
units = ''
|
|
549
|
-
if label is None:
|
|
550
|
-
label = ''
|
|
551
|
-
if not isinstance(label, str):
|
|
552
|
-
raise TypeError('label for the Axis class should be a string')
|
|
553
|
-
self['label'] = label
|
|
554
|
-
if not isinstance(units, str):
|
|
555
|
-
raise TypeError('units for the Axis class should be a string')
|
|
556
|
-
self['units'] = units
|
|
557
|
-
self.update(kwargs)
|
|
558
|
-
|
|
559
|
-
def __getattr__(self, item):
|
|
560
|
-
if item in self:
|
|
561
|
-
return self[item]
|
|
562
|
-
else:
|
|
563
|
-
raise AttributeError(f'{item} is not a valid attribute')
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
class Axis(AxisBase):
|
|
567
|
-
"""
|
|
568
|
-
Utility class defining an axis for pymodaq's viewers, attributes can be accessed as dictionary keys
|
|
569
|
-
"""
|
|
570
|
-
|
|
571
|
-
def __init__(self, data=None, label='', units='', **kwargs):
|
|
572
|
-
"""
|
|
573
|
-
|
|
574
|
-
Parameters
|
|
575
|
-
----------
|
|
576
|
-
data
|
|
577
|
-
label
|
|
578
|
-
units
|
|
579
|
-
"""
|
|
580
|
-
super().__init__(label=label, units=units, **kwargs)
|
|
581
|
-
if data is None or isinstance(data, np.ndarray):
|
|
582
|
-
self['data'] = data
|
|
583
|
-
else:
|
|
584
|
-
raise TypeError('data for the Axis class should be a ndarray')
|
|
585
|
-
self.update(kwargs)
|
|
586
|
-
|
|
587
|
-
def __mul__(self, other):
|
|
588
|
-
if isinstance(other, numbers.Number):
|
|
589
|
-
return Axis(data=self['data'] * other, label=self['label'], units=self['units'])
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
class NavAxis(Axis):
|
|
593
|
-
def __init__(self, data=None, label='', units='', nav_index=-1, **kwargs):
|
|
594
|
-
super().__init__(data=data, label=label, units=units, **kwargs)
|
|
595
|
-
|
|
596
|
-
if nav_index < 0:
|
|
597
|
-
raise ValueError('nav_index should be a positive integer representing the index of this axis among all'
|
|
598
|
-
'navigation axes')
|
|
599
|
-
self['nav_index'] = nav_index
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
class ScaledAxis(AxisBase):
|
|
603
|
-
def __init__(self, label='', units='', offset=0, scaling=1):
|
|
604
|
-
super().__init__(label=label, units=units)
|
|
605
|
-
if not (isinstance(offset, float) or isinstance(offset, int)):
|
|
606
|
-
raise TypeError('offset for the ScalingAxis class should be a float (or int)')
|
|
607
|
-
self['offset'] = offset
|
|
608
|
-
if not (isinstance(scaling, float) or isinstance(scaling, int)):
|
|
609
|
-
raise TypeError('scaling for the ScalingAxis class should be a non null float (or int)')
|
|
610
|
-
if scaling == 0 or scaling == 0.:
|
|
611
|
-
raise ValueError('scaling for the ScalingAxis class should be a non null float (or int)')
|
|
612
|
-
self['scaling'] = scaling
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
class ScalingOptions(dict):
|
|
616
|
-
def __init__(self, scaled_xaxis: ScaledAxis, scaled_yaxis: ScaledAxis):
|
|
617
|
-
assert isinstance(scaled_xaxis, ScaledAxis)
|
|
618
|
-
assert isinstance(scaled_yaxis, ScaledAxis)
|
|
619
|
-
self['scaled_xaxis'] = scaled_xaxis
|
|
620
|
-
self['scaled_yaxis'] = scaled_yaxis
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
class Data(OrderedDict):
|
|
624
|
-
def __init__(self, name='', source='raw', distribution='uniform', x_axis=Axis(), y_axis=Axis(), **kwargs):
|
|
625
|
-
"""
|
|
626
|
-
Generic class subclassing from OrderedDict defining data being exported from pymodaq's plugin or viewers,
|
|
627
|
-
attributes can be accessed as dictionary keys. Should be subclassed from for real datas
|
|
628
|
-
Parameters
|
|
629
|
-
----------
|
|
630
|
-
source: (str) either 'raw' or 'roi...' if straight from a plugin or data processed within a viewer
|
|
631
|
-
distribution: (str) either 'uniform' or 'spread'
|
|
632
|
-
x_axis: (Axis) Axis class defining the corresponding axis (if any) (with data either linearly spaced or containing the
|
|
633
|
-
x positions of the spread points)
|
|
634
|
-
y_axis: (Axis) Axis class defining the corresponding axis (if any) (with data either linearly spaced or containing the
|
|
635
|
-
x positions of the spread points)
|
|
636
|
-
"""
|
|
637
|
-
|
|
638
|
-
if not isinstance(name, str):
|
|
639
|
-
raise TypeError(f'name for the {self.__class__.__name__} class should be a string')
|
|
640
|
-
self['name'] = name
|
|
641
|
-
if not isinstance(source, str):
|
|
642
|
-
raise TypeError(f'source for the {self.__class__.__name__} class should be a string')
|
|
643
|
-
elif not ('raw' in source or 'roi' in source):
|
|
644
|
-
raise ValueError(f'Invalid "source" for the {self.__class__.__name__} class')
|
|
645
|
-
self['source'] = source
|
|
646
|
-
|
|
647
|
-
if not isinstance(distribution, str):
|
|
648
|
-
raise TypeError(f'distribution for the {self.__class__.__name__} class should be a string')
|
|
649
|
-
elif distribution not in ('uniform', 'spread'):
|
|
650
|
-
raise ValueError(f'Invalid "distribution" for the {self.__class__.__name__} class')
|
|
651
|
-
self['distribution'] = distribution
|
|
652
|
-
|
|
653
|
-
if not isinstance(x_axis, Axis):
|
|
654
|
-
if isinstance(x_axis, np.ndarray):
|
|
655
|
-
x_axis = Axis(data=x_axis)
|
|
656
|
-
else:
|
|
657
|
-
raise TypeError(f'x_axis for the {self.__class__.__name__} class should be a Axis class')
|
|
658
|
-
self['x_axis'] = x_axis
|
|
659
|
-
elif x_axis['data'] is not None:
|
|
660
|
-
self['x_axis'] = x_axis
|
|
661
|
-
|
|
662
|
-
if not isinstance(y_axis, Axis):
|
|
663
|
-
if isinstance(y_axis, np.ndarray):
|
|
664
|
-
y_axis = Axis(data=y_axis)
|
|
665
|
-
else:
|
|
666
|
-
raise TypeError(f'y_axis for the {self.__class__.__name__} class should be a Axis class')
|
|
667
|
-
self['y_axis'] = y_axis
|
|
668
|
-
elif y_axis['data'] is not None:
|
|
669
|
-
self['y_axis'] = y_axis
|
|
670
|
-
|
|
671
|
-
for k in kwargs:
|
|
672
|
-
self[k] = kwargs[k]
|
|
673
|
-
|
|
674
|
-
def __getattr__(self, name):
|
|
675
|
-
if name in self:
|
|
676
|
-
return self[name]
|
|
677
|
-
else:
|
|
678
|
-
raise AttributeError(f'{name} if not a key of {self}')
|
|
679
|
-
|
|
680
|
-
def __repr__(self):
|
|
681
|
-
return f'{self.__class__.__name__}: <name: {self.name}> - <distribution: {self.distribution}> - <source: {self.source}>'
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
class DataFromPlugins(Data):
|
|
685
|
-
|
|
686
|
-
def __init__(self, data=None, dim='', labels=[], nav_axes=[], nav_x_axis=Axis(), nav_y_axis=Axis(), **kwargs):
|
|
687
|
-
"""
|
|
688
|
-
Parameters
|
|
689
|
-
----------
|
|
690
|
-
dim: (str) data dimensionality (either Data0D, Data1D, Data2D or DataND)
|
|
691
|
-
"""
|
|
692
|
-
super().__init__(**kwargs)
|
|
693
|
-
self['labels'] = labels
|
|
694
|
-
if len(nav_axes) != 0:
|
|
695
|
-
self['nav_axes'] = nav_axes
|
|
696
|
-
if nav_x_axis['data'] is not None:
|
|
697
|
-
self['nav_x_axis'] = nav_x_axis
|
|
698
|
-
if nav_y_axis['data'] is not None:
|
|
699
|
-
self['nav_y_axis'] = nav_y_axis
|
|
700
|
-
|
|
701
|
-
iscorrect = True
|
|
702
|
-
if data is not None:
|
|
703
|
-
if isinstance(data, list):
|
|
704
|
-
for dat in data:
|
|
705
|
-
if not isinstance(dat, np.ndarray):
|
|
706
|
-
iscorrect = False
|
|
707
|
-
else:
|
|
708
|
-
iscorrect = False
|
|
709
|
-
|
|
710
|
-
if iscorrect:
|
|
711
|
-
self['data'] = data
|
|
712
|
-
else:
|
|
713
|
-
raise TypeError('data for the DataFromPlugins class should be None or a list of numpy arrays')
|
|
714
|
-
|
|
715
|
-
if dim not in DATADIMS and data is not None:
|
|
716
|
-
ndim = len(data[0].shape)
|
|
717
|
-
if ndim == 1:
|
|
718
|
-
if data[0].size == 1:
|
|
719
|
-
dim = 'Data0D'
|
|
720
|
-
else:
|
|
721
|
-
dim = 'Data1D'
|
|
722
|
-
elif ndim == 2:
|
|
723
|
-
dim = 'Data2D'
|
|
724
|
-
else:
|
|
725
|
-
dim = 'DataND'
|
|
726
|
-
self['dim'] = dim
|
|
727
|
-
|
|
728
|
-
def __repr__(self):
|
|
729
|
-
return f'{self.__class__.__name__}: <name: {self.name}> - <distribution: {self.distribution}>' \
|
|
730
|
-
f' - <source: {self.source}> - <dim: {self.dim}>'
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
class DataToExport(Data):
|
|
734
|
-
def __init__(self, data=None, dim='', source='raw', **kwargs):
|
|
735
|
-
"""
|
|
736
|
-
Utility class defining a data being exported from pymodaq's viewers, attributes can be accessed as dictionary keys
|
|
737
|
-
Parameters
|
|
738
|
-
----------
|
|
739
|
-
data: (ndarray or a scalar)
|
|
740
|
-
dim: (str) data dimensionality (either Data0D, Data1D, Data2D or DataND)
|
|
741
|
-
source: (str) either 'raw' for raw data or 'roi' for data extracted from a roi
|
|
742
|
-
"""
|
|
743
|
-
super().__init__(source=source, **kwargs)
|
|
744
|
-
if data is None or isinstance(data, np.ndarray) or isinstance(data, numbers.Number):
|
|
745
|
-
self['data'] = data
|
|
746
|
-
else:
|
|
747
|
-
raise TypeError('data for the DataToExport class should be a scalar or a ndarray')
|
|
748
|
-
|
|
749
|
-
if dim not in ('Data0D', 'Data1D', 'Data2D', 'DataND') or data is not None:
|
|
750
|
-
if isinstance(data, np.ndarray):
|
|
751
|
-
ndim = len(data.shape)
|
|
752
|
-
if ndim == 1:
|
|
753
|
-
if data.size == 1:
|
|
754
|
-
dim = 'Data0D'
|
|
755
|
-
else:
|
|
756
|
-
dim = 'Data1D'
|
|
757
|
-
elif ndim == 2:
|
|
758
|
-
dim = 'Data2D'
|
|
759
|
-
else:
|
|
760
|
-
dim = 'DataND'
|
|
761
|
-
else:
|
|
762
|
-
dim = 'Data0D'
|
|
763
|
-
self['dim'] = dim
|
|
764
|
-
if source not in DATASOURCES:
|
|
765
|
-
raise DataSourceError(f'Data source should be in {DATASOURCES}')
|
|
766
|
-
|
|
767
|
-
def __repr__(self):
|
|
768
|
-
return f'{self.__class__.__name__}: <name: {self.name}> - <distribution: {self.distribution}>' \
|
|
769
|
-
f' - <source: {self.source}> - <dim: {self.dim}>'
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
def ensure_ndarray(data):
|
|
773
|
-
"""
|
|
774
|
-
Make sure data is returned as a numpy array
|
|
775
|
-
Parameters
|
|
776
|
-
----------
|
|
777
|
-
data
|
|
778
|
-
|
|
779
|
-
Returns
|
|
780
|
-
-------
|
|
781
|
-
ndarray
|
|
782
|
-
"""
|
|
783
|
-
if not isinstance(data, np.ndarray):
|
|
784
|
-
if isinstance(data, list):
|
|
785
|
-
data = np.array(data)
|
|
786
|
-
else:
|
|
787
|
-
data = np.array([data])
|
|
788
|
-
return data
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
def setLocale():
|
|
792
|
-
"""
|
|
793
|
-
defines the Locale to use to convert numbers to strings representation using language/country conventions
|
|
794
|
-
Default is English and US
|
|
795
|
-
"""
|
|
796
|
-
language = getattr(QLocale, config('style', 'language'))
|
|
797
|
-
country = getattr(QLocale, config('style', 'country'))
|
|
798
|
-
QLocale.setDefault(QLocale(language, country))
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
def recursive_find_files_extension(ini_path, ext, paths=[]):
|
|
802
|
-
with os.scandir(ini_path) as it:
|
|
803
|
-
for entry in it:
|
|
804
|
-
if os.path.splitext(entry.name)[1][1:] == ext and entry.is_file():
|
|
805
|
-
paths.append(entry.path)
|
|
806
|
-
elif entry.is_dir():
|
|
807
|
-
recursive_find_files_extension(entry.path, ext, paths)
|
|
808
|
-
return paths
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
def recursive_find_files(ini_path, exp='make_enum', paths=[],
|
|
812
|
-
filters=['build']):
|
|
813
|
-
for child in Path(ini_path).iterdir():
|
|
814
|
-
if child.is_dir():
|
|
815
|
-
recursive_find_files(child, exp, paths, filters)
|
|
816
|
-
else:
|
|
817
|
-
if exp in child.stem:
|
|
818
|
-
if not any([filt in str(child) for filt in filters]):
|
|
819
|
-
paths.append(child)
|
|
820
|
-
return paths
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
def recursive_find_expr_in_files(ini_path, exp='make_enum', paths=[],
|
|
824
|
-
filters=['.git', '.idea', '__pycache__', 'build', 'egg', 'documentation', '.tox'],
|
|
825
|
-
replace=False, replace_str=''):
|
|
826
|
-
|
|
827
|
-
for child in Path(ini_path).iterdir():
|
|
828
|
-
if not any(filt in str(child) for filt in filters):
|
|
829
|
-
if child.is_dir():
|
|
830
|
-
recursive_find_expr_in_files(child, exp, paths, filters, replace=replace, replace_str=replace_str)
|
|
831
|
-
else:
|
|
832
|
-
try:
|
|
833
|
-
found = False
|
|
834
|
-
with child.open('r') as f:
|
|
835
|
-
replacement = ''
|
|
836
|
-
for ind, line in enumerate(f):
|
|
837
|
-
if exp in line:
|
|
838
|
-
found = True
|
|
839
|
-
paths.append([child, ind, line])
|
|
840
|
-
if replace:
|
|
841
|
-
replacement += line.replace(exp, replace_str)
|
|
842
|
-
else:
|
|
843
|
-
if replace:
|
|
844
|
-
replacement += line
|
|
845
|
-
if replace and found:
|
|
846
|
-
with child.open('w') as f:
|
|
847
|
-
f.write(replacement)
|
|
848
|
-
except Exception:
|
|
849
|
-
pass
|
|
850
|
-
return paths
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
def count_lines(ini_path, count=0, filters=['lextab', 'yacctab','pycache', 'pyc']):
|
|
854
|
-
# if Path(ini_path).is_file():
|
|
855
|
-
# with Path(ini_path).open('r') as f:
|
|
856
|
-
# count += len(f.readlines())
|
|
857
|
-
# return count
|
|
858
|
-
for child in Path(ini_path).iterdir():
|
|
859
|
-
if child.is_dir():
|
|
860
|
-
count = count_lines(child, count)
|
|
861
|
-
else:
|
|
862
|
-
try:
|
|
863
|
-
if not any([filt in child.name for filt in filters]):
|
|
864
|
-
if '.py' in child.name:
|
|
865
|
-
with child.open('r') as f:
|
|
866
|
-
count += len(f.readlines())
|
|
867
|
-
else:
|
|
868
|
-
print(child.stem)
|
|
869
|
-
except Exception:
|
|
870
|
-
pass
|
|
871
|
-
return count
|
|
872
|
-
|
|
873
|
-
def remove_spaces(string):
|
|
874
|
-
"""
|
|
875
|
-
return a string without any white spaces in it
|
|
876
|
-
Parameters
|
|
877
|
-
----------
|
|
878
|
-
string
|
|
879
|
-
|
|
880
|
-
Returns
|
|
881
|
-
-------
|
|
882
|
-
|
|
883
|
-
"""
|
|
884
|
-
return ''.join(string.split())
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
def rint(x):
|
|
888
|
-
"""
|
|
889
|
-
almost same as numpy rint function but return an integer
|
|
890
|
-
Parameters
|
|
891
|
-
----------
|
|
892
|
-
x: (float or integer)
|
|
893
|
-
|
|
894
|
-
Returns
|
|
895
|
-
-------
|
|
896
|
-
nearest integer
|
|
897
|
-
"""
|
|
898
|
-
return int(np.rint(x))
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
def elt_as_first_element(elt_list, match_word='Mock'):
|
|
902
|
-
if not hasattr(elt_list, '__iter__'):
|
|
903
|
-
raise TypeError('elt_list must be an iterable')
|
|
904
|
-
if elt_list:
|
|
905
|
-
ind_elt = 0
|
|
906
|
-
for ind, elt in enumerate(elt_list):
|
|
907
|
-
if not isinstance(elt, str):
|
|
908
|
-
raise TypeError('elt_list must be a list of str')
|
|
909
|
-
if match_word in elt:
|
|
910
|
-
ind_elt = ind
|
|
911
|
-
break
|
|
912
|
-
plugin_match = elt_list[ind_elt]
|
|
913
|
-
elt_list.remove(plugin_match)
|
|
914
|
-
plugins = [plugin_match]
|
|
915
|
-
plugins.extend(elt_list)
|
|
916
|
-
else:
|
|
917
|
-
plugins = []
|
|
918
|
-
return plugins
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
def elt_as_first_element_dicts(elt_list, match_word='Mock', key='name'):
|
|
922
|
-
if not hasattr(elt_list, '__iter__'):
|
|
923
|
-
raise TypeError('elt_list must be an iterable')
|
|
924
|
-
if elt_list:
|
|
925
|
-
ind_elt = 0
|
|
926
|
-
for ind, elt in enumerate(elt_list):
|
|
927
|
-
if not isinstance(elt, dict):
|
|
928
|
-
raise TypeError('elt_list must be a list of dicts')
|
|
929
|
-
if match_word in elt[key]:
|
|
930
|
-
ind_elt = ind
|
|
931
|
-
break
|
|
932
|
-
plugin_match = elt_list[ind_elt]
|
|
933
|
-
elt_list.remove(plugin_match)
|
|
934
|
-
plugins = [plugin_match]
|
|
935
|
-
plugins.extend(elt_list)
|
|
936
|
-
else:
|
|
937
|
-
plugins = []
|
|
938
|
-
return plugins
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
def get_extensions():
|
|
942
|
-
"""
|
|
943
|
-
Get pymodaq extensions as a list
|
|
944
|
-
|
|
945
|
-
Returns
|
|
946
|
-
-------
|
|
947
|
-
list: list of disct containting the name and module of the found extension
|
|
948
|
-
"""
|
|
949
|
-
extension_import = []
|
|
950
|
-
entry_points = metadata.entry_points()
|
|
951
|
-
if 'pymodaq.extensions' in entry_points:
|
|
952
|
-
discovered_extension = entry_points['pymodaq.extensions']
|
|
953
|
-
|
|
954
|
-
for pkg in discovered_extension:
|
|
955
|
-
try:
|
|
956
|
-
module = importlib.import_module(pkg.value)
|
|
957
|
-
if hasattr(module, 'NICE_NAME'):
|
|
958
|
-
name = module.NICE_NAME
|
|
959
|
-
else:
|
|
960
|
-
name = pkg.value
|
|
961
|
-
extension = {'name': name, 'module': module}
|
|
962
|
-
extension_import.append(extension)
|
|
963
|
-
|
|
964
|
-
except Exception as e: # pragma: no cover
|
|
965
|
-
logger.warning(f'Impossible to import the {pkg.value} extension: {str(e)}')
|
|
966
|
-
|
|
967
|
-
return extension_import
|
|
968
|
-
|
|
969
|
-
def find_dict_if_matched_key_val(dict_tmp, key, value):
|
|
970
|
-
"""
|
|
971
|
-
check if a key/value pair match in a given dictionnary
|
|
972
|
-
Parameters
|
|
973
|
-
----------
|
|
974
|
-
dict_tmp: (dict) the dictionnary to be tested
|
|
975
|
-
key: (str) a key string to look for in dict_tmp
|
|
976
|
-
value: (object) any python object
|
|
977
|
-
|
|
978
|
-
Returns
|
|
979
|
-
-------
|
|
980
|
-
bool: True if the key/value pair has been found in dict_tmp
|
|
981
|
-
|
|
982
|
-
"""
|
|
983
|
-
if key in dict_tmp:
|
|
984
|
-
if dict_tmp[key] == value:
|
|
985
|
-
return True
|
|
986
|
-
return False
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
def find_dict_in_list_from_key_val(dicts, key, value, return_index=False):
|
|
990
|
-
""" lookup within a list of dicts. Look for the dict within the list which has the correct key, value pair
|
|
991
|
-
|
|
992
|
-
Parameters
|
|
993
|
-
----------
|
|
994
|
-
dicts: (list) list of dictionnaries
|
|
995
|
-
key: (str) specific key to look for in each dict
|
|
996
|
-
value: value to match
|
|
997
|
-
|
|
998
|
-
Returns
|
|
999
|
-
-------
|
|
1000
|
-
dict: if found otherwise returns None
|
|
1001
|
-
"""
|
|
1002
|
-
for ind, dict_tmp in enumerate(dicts):
|
|
1003
|
-
if find_dict_if_matched_key_val(dict_tmp, key, value):
|
|
1004
|
-
if return_index:
|
|
1005
|
-
return dict_tmp, ind
|
|
1006
|
-
else:
|
|
1007
|
-
return dict_tmp
|
|
1008
|
-
if return_index:
|
|
1009
|
-
return None, -1
|
|
1010
|
-
else:
|
|
1011
|
-
return None
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
def get_models(model_name=None):
|
|
1015
|
-
"""
|
|
1016
|
-
Get PID Models as a list to instantiate Control Actuators per degree of liberty in the model
|
|
1017
|
-
|
|
1018
|
-
Returns
|
|
1019
|
-
-------
|
|
1020
|
-
list: list of disct containting the name and python module of the found models
|
|
1021
|
-
"""
|
|
1022
|
-
from pymodaq.pid.utils import PIDModelGeneric
|
|
1023
|
-
models_import = []
|
|
1024
|
-
entry_points = metadata.entry_points()
|
|
1025
|
-
if 'pymodaq.pid_models' in entry_points:
|
|
1026
|
-
discovered_models = entry_points['pymodaq.pid_models']
|
|
1027
|
-
for pkg in discovered_models:
|
|
1028
|
-
try:
|
|
1029
|
-
module = importlib.import_module(pkg.value)
|
|
1030
|
-
module_name = pkg.value
|
|
1031
|
-
|
|
1032
|
-
for mod in pkgutil.iter_modules([str(Path(module.__file__).parent.joinpath('models'))]):
|
|
1033
|
-
try:
|
|
1034
|
-
model_module = importlib.import_module(f'{module_name}.models.{mod.name}', module)
|
|
1035
|
-
classes = inspect.getmembers(model_module, inspect.isclass)
|
|
1036
|
-
for name, klass in classes:
|
|
1037
|
-
if klass.__base__ is PIDModelGeneric:
|
|
1038
|
-
models_import.append({'name': mod.name, 'module': model_module, 'class': klass})
|
|
1039
|
-
break
|
|
1040
|
-
|
|
1041
|
-
except Exception as e: # pragma: no cover
|
|
1042
|
-
logger.warning(str(e))
|
|
1043
|
-
|
|
1044
|
-
except Exception as e: # pragma: no cover
|
|
1045
|
-
logger.warning(f'Impossible to import the {pkg.value} extension: {str(e)}')
|
|
1046
|
-
|
|
1047
|
-
if model_name is None:
|
|
1048
|
-
return models_import
|
|
1049
|
-
else:
|
|
1050
|
-
return find_dict_in_list_from_key_val(models_import, 'name', model_name)
|
|
1051
|
-
|
|
1052
|
-
def get_plugins(plugin_type='daq_0Dviewer'): # pragma: no cover
|
|
1053
|
-
"""
|
|
1054
|
-
Get plugins names as a list
|
|
1055
|
-
Parameters
|
|
1056
|
-
----------
|
|
1057
|
-
plugin_type: (str) plugin type either 'daq_0Dviewer', 'daq_1Dviewer', 'daq_2Dviewer', 'daq_NDviewer' or 'daq_move'
|
|
1058
|
-
module: (module) parent module of the plugins
|
|
1059
|
-
|
|
1060
|
-
Returns
|
|
1061
|
-
-------
|
|
1062
|
-
|
|
1063
|
-
"""
|
|
1064
|
-
plugins_import = []
|
|
1065
|
-
discovered_plugins = metadata.entry_points()['pymodaq.plugins']
|
|
1066
|
-
|
|
1067
|
-
for module in discovered_plugins:
|
|
1068
|
-
try:
|
|
1069
|
-
if plugin_type == 'daq_move':
|
|
1070
|
-
submodule = importlib.import_module(f'{module.value}.daq_move_plugins', module.value)
|
|
1071
|
-
else:
|
|
1072
|
-
submodule = importlib.import_module(f'{module.value}.daq_viewer_plugins.plugins_{plugin_type[4:6]}',
|
|
1073
|
-
module.value)
|
|
1074
|
-
plugin_list = [{'name': mod[len(plugin_type) + 1:],
|
|
1075
|
-
'module': submodule} for mod in [mod[1] for
|
|
1076
|
-
mod in pkgutil.iter_modules([submodule.path.parent])]
|
|
1077
|
-
if plugin_type in mod]
|
|
1078
|
-
# check if modules are importable
|
|
1079
|
-
|
|
1080
|
-
for mod in plugin_list:
|
|
1081
|
-
try:
|
|
1082
|
-
if plugin_type == 'daq_move':
|
|
1083
|
-
importlib.import_module(f'{submodule.__package__}.daq_move_{mod["name"]}')
|
|
1084
|
-
else:
|
|
1085
|
-
importlib.import_module(f'{submodule.__package__}.daq_{plugin_type[4:6]}viewer_{mod["name"]}')
|
|
1086
|
-
plugins_import.append(mod)
|
|
1087
|
-
except Exception as e: # pragma: no cover
|
|
1088
|
-
pass
|
|
1089
|
-
except Exception as e: # pragma: no cover
|
|
1090
|
-
pass
|
|
1091
|
-
|
|
1092
|
-
#add utility plugin for PID
|
|
1093
|
-
if plugin_type == 'daq_move':
|
|
1094
|
-
try:
|
|
1095
|
-
submodule = importlib.import_module('pymodaq.pid')
|
|
1096
|
-
|
|
1097
|
-
plugins_import.append({'name': 'PID', 'module': submodule})
|
|
1098
|
-
|
|
1099
|
-
except Exception: # pragma: no cover
|
|
1100
|
-
pass
|
|
1101
|
-
|
|
1102
|
-
plugins_import = elt_as_first_element_dicts(plugins_import, match_word='Mock', key='name')
|
|
1103
|
-
return plugins_import
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
def check_vals_in_iterable(iterable1, iterable2):
|
|
1107
|
-
assert len(iterable1) == len(iterable2)
|
|
1108
|
-
iterable1 = list(iterable1) # so the assertion below is valid for any kind of iterable, list, tuple, ndarray...
|
|
1109
|
-
iterable2 = list(iterable2)
|
|
1110
|
-
for val1, val2 in zip(iterable1, iterable2):
|
|
1111
|
-
assert val1 == val2
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
def get_module_name(module__file__path):
|
|
1115
|
-
"""from the full path of a module extract its name"""
|
|
1116
|
-
path = Path(module__file__path)
|
|
1117
|
-
return path.stem
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
def caller_name(skip=2):
|
|
1121
|
-
"""Get a name of a caller in the format module.class.method
|
|
1122
|
-
|
|
1123
|
-
`skip` specifies how many levels of stack to skip while getting caller
|
|
1124
|
-
name. skip=1 means "who calls me", skip=2 "who calls my caller" etc.
|
|
1125
|
-
|
|
1126
|
-
An empty string is returned if skipped levels exceed stack height
|
|
1127
|
-
"""
|
|
1128
|
-
stack = inspect.stack()
|
|
1129
|
-
start = 0 + skip
|
|
1130
|
-
if len(stack) < start + 1:
|
|
1131
|
-
return ''
|
|
1132
|
-
parentframe = stack[start][0]
|
|
1133
|
-
|
|
1134
|
-
name = []
|
|
1135
|
-
module = inspect.getmodule(parentframe)
|
|
1136
|
-
# `modname` can be None when frame is executed directly in console
|
|
1137
|
-
# TODO(techtonik): consider using __main__
|
|
1138
|
-
if module:
|
|
1139
|
-
name.append(module.__name__)
|
|
1140
|
-
# detect classname
|
|
1141
|
-
if 'self' in parentframe.f_locals:
|
|
1142
|
-
# I don't know any way to detect call from the object method
|
|
1143
|
-
# XXX: there seems to be no way to detect static method call - it will
|
|
1144
|
-
# be just a function call
|
|
1145
|
-
name.append(parentframe.f_locals['self'].__class__.__name__)
|
|
1146
|
-
codename = parentframe.f_code.co_name
|
|
1147
|
-
if codename != '<module>': # top level usually
|
|
1148
|
-
name.append(codename) # function or a method
|
|
1149
|
-
del parentframe
|
|
1150
|
-
return ".".join(name)
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
def zeros_aligned(n, align, dtype=np.uint32):
|
|
1154
|
-
"""
|
|
1155
|
-
Get aligned memory array wih alignment align.
|
|
1156
|
-
Parameters
|
|
1157
|
-
----------
|
|
1158
|
-
n: (int) length in dtype bytes of memory
|
|
1159
|
-
align: (int) memory alignment
|
|
1160
|
-
dtype: (numpy.dtype) type of the stored memory elements
|
|
1161
|
-
|
|
1162
|
-
Returns
|
|
1163
|
-
-------
|
|
1164
|
-
|
|
1165
|
-
"""
|
|
1166
|
-
dtype = np.dtype(dtype)
|
|
1167
|
-
nbytes = n * dtype.itemsize
|
|
1168
|
-
buff = np.zeros(nbytes + align, dtype=np.uint8)
|
|
1169
|
-
start_index = -buff.ctypes.data % align
|
|
1170
|
-
return buff[start_index:start_index + nbytes].view(dtype)
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
def cfunc(name, dll, result, *args):
|
|
1174
|
-
"""build and apply a ctypes prototype complete with parameter flags
|
|
1175
|
-
|
|
1176
|
-
Parameters
|
|
1177
|
-
----------
|
|
1178
|
-
name: (str) function name in the dll
|
|
1179
|
-
dll: (ctypes.windll) dll object
|
|
1180
|
-
result : result is the type of the result (c_int,..., python function handle,...)
|
|
1181
|
-
args: list of tuples with 3 or 4 elements each like (argname, argtype, in/out, default) where argname is the
|
|
1182
|
-
name of the argument, argtype is the type, in/out is 1 for input and 2 for output, and default is an optional
|
|
1183
|
-
default value.
|
|
1184
|
-
|
|
1185
|
-
Returns
|
|
1186
|
-
-------
|
|
1187
|
-
python function
|
|
1188
|
-
"""
|
|
1189
|
-
atypes = []
|
|
1190
|
-
aflags = []
|
|
1191
|
-
for arg in args:
|
|
1192
|
-
atypes.append(arg[1])
|
|
1193
|
-
aflags.append((arg[2], arg[0]) + arg[3:])
|
|
1194
|
-
return CFUNCTYPE(result, *atypes)((name, dll), tuple(aflags))
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
def winfunc(name, dll, result, *args):
|
|
1198
|
-
"""build and apply a ctypes prototype complete with parameter flags
|
|
1199
|
-
Parameters
|
|
1200
|
-
----------
|
|
1201
|
-
name:(str) function name in the dll
|
|
1202
|
-
dll: (ctypes.windll) dll object
|
|
1203
|
-
result: result is the type of the result (c_int,..., python function handle,...)
|
|
1204
|
-
args: list of tuples with 3 or 4 elements each like (argname, argtype, in/out, default) where argname is the
|
|
1205
|
-
name of the argument, argtype is the type, in/out is 1 for input and 2 for output, and default is an optional
|
|
1206
|
-
default value.
|
|
1207
|
-
|
|
1208
|
-
Returns
|
|
1209
|
-
-------
|
|
1210
|
-
python function
|
|
1211
|
-
"""
|
|
1212
|
-
atypes = []
|
|
1213
|
-
aflags = []
|
|
1214
|
-
for arg in args:
|
|
1215
|
-
atypes.append(arg[1])
|
|
1216
|
-
aflags.append((arg[2], arg[0]) + arg[3:])
|
|
1217
|
-
return WINFUNCTYPE(result, *atypes)((name, dll), tuple(aflags))
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
def set_param_from_param(param_old, param_new):
|
|
1221
|
-
"""
|
|
1222
|
-
Walk through parameters children and set values using new parameter values.
|
|
1223
|
-
"""
|
|
1224
|
-
for child_old in param_old.children():
|
|
1225
|
-
# try:
|
|
1226
|
-
path = param_old.childPath(child_old)
|
|
1227
|
-
child_new = param_new.child(*path)
|
|
1228
|
-
param_type = child_old.type()
|
|
1229
|
-
|
|
1230
|
-
if 'group' not in param_type: # covers 'group', custom 'groupmove'...
|
|
1231
|
-
# try:
|
|
1232
|
-
if 'list' in param_type: # check if the value is in the limits of the old params (limits are usually set at initialization)
|
|
1233
|
-
if child_new.value() not in child_old.opts['limits']:
|
|
1234
|
-
child_old.opts['limits'].append(child_new.value())
|
|
1235
|
-
|
|
1236
|
-
child_old.setValue(child_new.value())
|
|
1237
|
-
elif 'str' in param_type or 'browsepath' in param_type or 'text' in param_type:
|
|
1238
|
-
if child_new.value() != "": # to make sure one doesnt overwrite something
|
|
1239
|
-
child_old.setValue(child_new.value())
|
|
1240
|
-
else:
|
|
1241
|
-
child_old.setValue(child_new.value())
|
|
1242
|
-
# except Exception as e:
|
|
1243
|
-
# print(str(e))
|
|
1244
|
-
else:
|
|
1245
|
-
set_param_from_param(child_old, child_new)
|
|
1246
|
-
# except Exception as e:
|
|
1247
|
-
# print(str(e))
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
# ########################
|
|
1251
|
-
# #File management
|
|
1252
|
-
|
|
1253
|
-
def get_new_file_name(base_path=Path(config('data_saving', 'h5file', 'save_path')), base_name='tttr_data'):
|
|
1254
|
-
if isinstance(base_path, str):
|
|
1255
|
-
base_path = Path(base_path)
|
|
1256
|
-
|
|
1257
|
-
today = datetime.datetime.now()
|
|
1258
|
-
|
|
1259
|
-
date = today.strftime('%Y%m%d')
|
|
1260
|
-
year = today.strftime('%Y')
|
|
1261
|
-
year_dir = base_path.joinpath(year)
|
|
1262
|
-
if not year_dir.is_dir():
|
|
1263
|
-
year_dir.mkdir()
|
|
1264
|
-
curr_dir = base_path.joinpath(year, date)
|
|
1265
|
-
if not curr_dir.is_dir():
|
|
1266
|
-
curr_dir.mkdir()
|
|
1267
|
-
|
|
1268
|
-
files = []
|
|
1269
|
-
for entry in curr_dir.iterdir():
|
|
1270
|
-
if entry.name.startswith(base_name) and entry.is_file():
|
|
1271
|
-
files.append(entry.stem)
|
|
1272
|
-
files.sort()
|
|
1273
|
-
if not files:
|
|
1274
|
-
index = 0
|
|
1275
|
-
else:
|
|
1276
|
-
index = int(files[-1][-3:]) + 1
|
|
1277
|
-
|
|
1278
|
-
file = f'{base_name}_{index:03d}'
|
|
1279
|
-
return file, curr_dir
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
# ##############
|
|
1283
|
-
# Math utilities
|
|
1284
|
-
|
|
1285
|
-
# math utility functions, should now be imported from the math_utils module
|
|
1286
|
-
import pymodaq.daq_utils.math_utils as mutils
|
|
1287
|
-
|
|
1288
|
-
def my_moment(x, y):
|
|
1289
|
-
deprecation_msg(f'my_moment function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
1290
|
-
return mutils.my_moment(x, y)
|
|
1291
|
-
|
|
1292
|
-
def normalize(x):
|
|
1293
|
-
deprecation_msg(f'normalize function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
1294
|
-
return mutils.normalize(x)
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
def odd_even(x):
|
|
1298
|
-
deprecation_msg(f'odd_even function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
1299
|
-
return mutils.odd_even(x)
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
def greater2n(x):
|
|
1303
|
-
deprecation_msg(f'greater2n function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
1304
|
-
return mutils.greater2n(x)
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
def linspace_step(start, stop, step):
|
|
1308
|
-
deprecation_msg(f'linspace_step function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
1309
|
-
return mutils.linspace_step(start, stop, step)
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
def linspace_step_N(start, step, Npts):
|
|
1313
|
-
deprecation_msg(f'linspace_step_N function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
1314
|
-
return mutils.linspace_step_N(start, step, Npts)
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
def find_index(x, threshold):
|
|
1318
|
-
deprecation_msg(f'find_index function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
1319
|
-
return mutils.find_index(x, threshold)
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
def find_common_index(x, y, x0, y0):
|
|
1323
|
-
deprecation_msg(f'find_common_index function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
1324
|
-
return mutils.find_common_index(x, y, x0, y0)
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
def gauss1D(x, x0, dx, n=1):
|
|
1328
|
-
deprecation_msg(f'gauss1D function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
1329
|
-
return mutils.gauss1D(x, x0, dx, n=n)
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
def gauss2D(x, x0, dx, y, y0, dy, n=1, angle=0):
|
|
1333
|
-
deprecation_msg(f'gauss2D function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
1334
|
-
return mutils.gauss2D(x, x0, dx, y, y0, dy, n, angle)
|
|
1335
|
-
|
|
1336
|
-
def ftAxis(Npts, omega_max):
|
|
1337
|
-
deprecation_msg(f'ftAxis function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
1338
|
-
return mutils.ftAxis(Npts, omega_max)
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
def ftAxis_time(Npts, time_max):
|
|
1342
|
-
deprecation_msg(f'ftAxis_time function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
1343
|
-
return mutils.ftAxis_time(Npts, time_max)
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
def ft(x, dim=-1):
|
|
1347
|
-
deprecation_msg(f'ft function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
1348
|
-
return mutils.ft(x, dim)
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
def ift(x, dim=0):
|
|
1352
|
-
deprecation_msg(f'ift function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
1353
|
-
return mutils.ift(x, dim)
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
def ft2(x, dim=(-2, -1)):
|
|
1357
|
-
deprecation_msg(f'ft2 function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
1358
|
-
return mutils.ft2(x, dim)
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
def ift2(x, dim=(-2, -1)):
|
|
1362
|
-
deprecation_msg(f'ift2 function should now be imported from the {mutils.__name__} module', stacklevel=3)
|
|
1363
|
-
return mutils.ift2(x, dim)
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
if __name__ == '__main__':
|
|
1367
|
-
#paths = recursive_find_expr_in_files('C:\\Users\\weber\\Labo\\Programmes Python\\PyMoDAQ_Git', 'visa')
|
|
1368
|
-
# for p in paths:
|
|
1369
|
-
# print(str(p))
|
|
1370
|
-
# v = get_version()
|
|
1371
|
-
# pass
|
|
1372
|
-
#plugins = get_plugins() # pragma: no cover
|
|
1373
|
-
#extensions = get_extension()
|
|
1374
|
-
#models = get_models()
|
|
1375
|
-
#count = count_lines('C:\\Users\\weber\\Labo\\Programmes Python\\PyMoDAQ_Git\\pymodaq\src')
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
# import license
|
|
1379
|
-
# mit = license.find('MIT')
|
|
1380
|
-
#
|
|
1381
|
-
# paths = recursive_find_expr_in_files('C:\\Users\\weber\\Labo\\Programmes Python\\PyMoDAQ_Git',
|
|
1382
|
-
# exp='https://github.com/CEMES-CNRS',
|
|
1383
|
-
# paths=[],
|
|
1384
|
-
# filters=['.git', '.idea', '__pycache__', 'build', 'egg',
|
|
1385
|
-
# '.tox', 'daq_utils.py'],
|
|
1386
|
-
# replace=False, replace_str="https://github.com/PyMoDAQ")
|
|
1387
|
-
pass
|
|
1388
|
-
# paths = recursive_find_files('C:\\Users\\weber\\Labo\\Programmes Python\\PyMoDAQ_Git',
|
|
1389
|
-
# exp='VERSION', paths=[])
|
|
1390
|
-
# import version
|
|
1391
|
-
# for file in paths:
|
|
1392
|
-
# with open(str(file), 'r') as f:
|
|
1393
|
-
# v = version.Version(f.read())
|
|
1394
|
-
# v.minor += 1
|
|
1395
|
-
# v.patch = 0
|
|
1396
|
-
# with open(str(file), 'w') as f:
|
|
1397
|
-
# f.write(str(v))
|
|
1398
|
-
|
|
1399
|
-
# for file in paths:
|
|
1400
|
-
# with open(str(file), 'w') as f:
|
|
1401
|
-
# f.write(mit.render(name='Sebastien Weber', email='sebastien.weber@cemes.fr'))
|
|
1402
|
-
|