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
|
@@ -1,18 +1,24 @@
|
|
|
1
|
-
#
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created the 15/11/2022
|
|
4
|
+
|
|
5
|
+
@author: Sebastien Weber
|
|
6
|
+
"""
|
|
7
|
+
import numpy as np
|
|
2
8
|
import importlib
|
|
3
9
|
import pickle
|
|
10
|
+
from typing import Dict
|
|
4
11
|
|
|
5
|
-
|
|
6
|
-
|
|
12
|
+
from pymodaq.utils.logger import set_logger, get_module_name
|
|
13
|
+
from pymodaq.utils.config import Config
|
|
14
|
+
from pymodaq.utils.daq_utils import capitalize, JsonConverter
|
|
15
|
+
from pymodaq.utils import daq_utils as utils
|
|
16
|
+
from pymodaq.utils.enums import BaseEnum, enum_checker
|
|
7
17
|
|
|
8
|
-
#Project imports
|
|
9
|
-
from pymodaq.daq_utils import daq_utils as utils
|
|
10
|
-
from pymodaq.daq_utils.daq_utils import JsonConverter
|
|
11
|
-
from pymodaq.daq_utils.exceptions import InvalidGroupType
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
config = Config()
|
|
20
|
+
logger = set_logger(get_module_name(__file__))
|
|
14
21
|
|
|
15
|
-
#Initialized at import
|
|
16
22
|
backends_available = []
|
|
17
23
|
|
|
18
24
|
# default backend
|
|
@@ -31,7 +37,7 @@ try:
|
|
|
31
37
|
backends_available.append('h5py')
|
|
32
38
|
except Exception as e: # pragma: no cover
|
|
33
39
|
logger.warning(str(e))
|
|
34
|
-
|
|
40
|
+
is_h5py = False
|
|
35
41
|
|
|
36
42
|
is_h5pyd = True
|
|
37
43
|
# this one is to be used for remote reading/writing towards a HSDS server (or h5serv), see HDFGroup
|
|
@@ -40,12 +46,112 @@ try:
|
|
|
40
46
|
backends_available.append('h5pyd')
|
|
41
47
|
except Exception as e: # pragma: no cover
|
|
42
48
|
logger.warning(str(e))
|
|
43
|
-
|
|
49
|
+
is_h5pyd = False
|
|
44
50
|
|
|
45
51
|
if not (is_tables or is_h5py or is_h5pyd):
|
|
46
52
|
logger.exception('No valid hdf5 backend has been installed, please install either pytables or h5py')
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
|
|
55
|
+
class SaveType(BaseEnum):
|
|
56
|
+
scan = 0
|
|
57
|
+
detector = 1
|
|
58
|
+
logger = 2
|
|
59
|
+
custom = 3
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class GroupType(BaseEnum):
|
|
63
|
+
detector = 0
|
|
64
|
+
actuator = 1
|
|
65
|
+
data = 2
|
|
66
|
+
ch = 3
|
|
67
|
+
scan = 4
|
|
68
|
+
external_h5 = 5
|
|
69
|
+
data_dim = 6
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class InvalidExport(Exception):
|
|
73
|
+
pass
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def check_mandatory_attrs(attr_name, attr):
|
|
77
|
+
"""for cross compatibility between different backends. If these attributes have binary value, then decode them
|
|
78
|
+
|
|
79
|
+
Parameters
|
|
80
|
+
----------
|
|
81
|
+
attr_name
|
|
82
|
+
attr
|
|
83
|
+
|
|
84
|
+
Returns
|
|
85
|
+
-------
|
|
86
|
+
|
|
87
|
+
"""
|
|
88
|
+
if attr_name == 'TITLE' or attr_name == 'CLASS' or attr_name == 'EXTDIM':
|
|
89
|
+
if isinstance(attr, bytes):
|
|
90
|
+
return attr.decode()
|
|
91
|
+
else:
|
|
92
|
+
return attr
|
|
93
|
+
else:
|
|
94
|
+
return attr
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def get_attr(node, attr_name, backend='tables'):
|
|
98
|
+
if backend == 'tables':
|
|
99
|
+
if attr_name is not None:
|
|
100
|
+
attr = node._v_attrs[attr_name]
|
|
101
|
+
attr = check_mandatory_attrs(attr_name, attr)
|
|
102
|
+
return JsonConverter.json2object(attr)
|
|
103
|
+
else:
|
|
104
|
+
attrs = dict([])
|
|
105
|
+
for attr_name in node._v_attrs._v_attrnames:
|
|
106
|
+
attrval = node._v_attrs[attr_name]
|
|
107
|
+
attrval = check_mandatory_attrs(attr_name, attrval)
|
|
108
|
+
attrs[attr_name] = JsonConverter.json2object(attrval)
|
|
109
|
+
return attrs
|
|
110
|
+
else:
|
|
111
|
+
if attr_name is not None:
|
|
112
|
+
attr = node.attrs[attr_name]
|
|
113
|
+
attr = check_mandatory_attrs(attr_name, attr)
|
|
114
|
+
return JsonConverter.json2object(attr)
|
|
115
|
+
else:
|
|
116
|
+
attrs = dict([])
|
|
117
|
+
for attr_name in node.attrs.keys():
|
|
118
|
+
attrval = node.attrs[attr_name]
|
|
119
|
+
attrval = check_mandatory_attrs(attr_name, attrval)
|
|
120
|
+
attrs[attr_name] = JsonConverter.json2object(attrval)
|
|
121
|
+
return attrs
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def set_attr(node, attr_name, attr_value, backend='tables'):
|
|
125
|
+
if backend == 'tables':
|
|
126
|
+
node._v_attrs[attr_name] = JsonConverter.object2json(attr_value)
|
|
127
|
+
else:
|
|
128
|
+
node.attrs[attr_name] = JsonConverter.object2json(attr_value)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class InvalidGroupType(Exception):
|
|
132
|
+
pass
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class InvalidSave(Exception):
|
|
136
|
+
pass
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class InvalidGroupDataType(Exception):
|
|
140
|
+
pass
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class InvalidDataType(Exception):
|
|
144
|
+
pass
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class InvalidDataDimension(Exception):
|
|
148
|
+
pass
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class InvalidScanType(Exception):
|
|
152
|
+
pass
|
|
153
|
+
|
|
154
|
+
|
|
49
155
|
class Node(object):
|
|
50
156
|
def __init__(self, node, backend):
|
|
51
157
|
if isinstance(node, Node): # to ovoid recursion if one call Node(Node()) or even more
|
|
@@ -71,10 +177,10 @@ class Node(object):
|
|
|
71
177
|
return self.node == other.node
|
|
72
178
|
|
|
73
179
|
@property
|
|
74
|
-
def parent_node(self):
|
|
180
|
+
def parent_node(self) -> 'GROUP':
|
|
75
181
|
if self.path == '/':
|
|
76
182
|
return None
|
|
77
|
-
mod = importlib.import_module('.
|
|
183
|
+
mod = importlib.import_module('.backends', 'pymodaq.utils.h5modules')
|
|
78
184
|
|
|
79
185
|
if self.backend == 'tables':
|
|
80
186
|
p = self.node._v_parent
|
|
@@ -107,6 +213,10 @@ class Node(object):
|
|
|
107
213
|
else:
|
|
108
214
|
return path.split('/')[-1]
|
|
109
215
|
|
|
216
|
+
@property
|
|
217
|
+
def title(self):
|
|
218
|
+
return self.attrs['TITLE']
|
|
219
|
+
|
|
110
220
|
@property
|
|
111
221
|
def path(self):
|
|
112
222
|
"""return node path
|
|
@@ -123,15 +233,6 @@ class Node(object):
|
|
|
123
233
|
else:
|
|
124
234
|
return self._node.name
|
|
125
235
|
|
|
126
|
-
def get_file(self):
|
|
127
|
-
""" Return node file. Depending on the backend, will return either a h5py or a pytables object.
|
|
128
|
-
|
|
129
|
-
"""
|
|
130
|
-
if self.backend == 'tables':
|
|
131
|
-
return self.node._v_file
|
|
132
|
-
else:
|
|
133
|
-
return self.node.file
|
|
134
|
-
|
|
135
236
|
|
|
136
237
|
class GROUP(Node):
|
|
137
238
|
def __init__(self, node, backend):
|
|
@@ -158,8 +259,10 @@ class GROUP(Node):
|
|
|
158
259
|
|
|
159
260
|
return "%s\n children := %s" % (str(self), childlist)
|
|
160
261
|
|
|
161
|
-
|
|
162
|
-
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def children(self) -> Dict[str, Node]:
|
|
265
|
+
"""Get a dict containing all children node hanging from self whith their name as keys
|
|
163
266
|
|
|
164
267
|
Returns
|
|
165
268
|
-------
|
|
@@ -169,8 +272,7 @@ class GROUP(Node):
|
|
|
169
272
|
--------
|
|
170
273
|
children_name
|
|
171
274
|
"""
|
|
172
|
-
|
|
173
|
-
mod = importlib.import_module('.h5backend', 'pymodaq.daq_utils')
|
|
275
|
+
mod = importlib.import_module('.backends', 'pymodaq.utils.h5modules')
|
|
174
276
|
children = dict([])
|
|
175
277
|
if self.backend == 'tables':
|
|
176
278
|
for child_name, child in self.node._v_children.items():
|
|
@@ -191,19 +293,30 @@ class GROUP(Node):
|
|
|
191
293
|
children[child_name] = _cls(child, self.backend)
|
|
192
294
|
return children
|
|
193
295
|
|
|
296
|
+
def get_child(self, name: str) -> Node:
|
|
297
|
+
return self.children()[name]
|
|
298
|
+
|
|
194
299
|
def children_name(self):
|
|
195
|
-
"""Gets the list of children name hanging from self
|
|
300
|
+
"""Gets the sorted list of children name hanging from self
|
|
196
301
|
|
|
197
302
|
Returns
|
|
198
303
|
-------
|
|
199
304
|
list: list of name of the children
|
|
200
305
|
"""
|
|
201
306
|
if self.backend == 'tables':
|
|
202
|
-
return list(self.node._v_children.keys())
|
|
307
|
+
return sorted(list(self.node._v_children.keys()))
|
|
203
308
|
else:
|
|
204
|
-
return list(self.node.keys())
|
|
309
|
+
return sorted(list(self.node.keys()))
|
|
205
310
|
pass
|
|
206
311
|
|
|
312
|
+
def remove_children(self):
|
|
313
|
+
children_dict = self.children()
|
|
314
|
+
for child_name in children_dict:
|
|
315
|
+
if self.backend == 'tables':
|
|
316
|
+
children_dict[child_name].node._f_remove(recursive=True)
|
|
317
|
+
else:
|
|
318
|
+
self.node.__delitem__(child_name)
|
|
319
|
+
|
|
207
320
|
|
|
208
321
|
class CARRAY(Node):
|
|
209
322
|
def __init__(self, node, backend):
|
|
@@ -305,14 +418,39 @@ class Attributes(object):
|
|
|
305
418
|
self.backend = backend
|
|
306
419
|
|
|
307
420
|
def __getitem__(self, item):
|
|
421
|
+
if item == 'title':
|
|
422
|
+
item = item.upper()
|
|
308
423
|
attr = get_attr(self._node.node, item, backend=self.backend)
|
|
309
424
|
# if isinstance(attr, bytes):
|
|
310
425
|
# attr = attr.decode()
|
|
311
426
|
return attr
|
|
312
427
|
|
|
313
428
|
def __setitem__(self, key, value):
|
|
429
|
+
if key == 'title':
|
|
430
|
+
key = key.upper()
|
|
314
431
|
set_attr(self._node.node, key, value, backend=self.backend)
|
|
315
432
|
|
|
433
|
+
def __iter__(self):
|
|
434
|
+
self._iter_index = 0
|
|
435
|
+
return self
|
|
436
|
+
|
|
437
|
+
def __next__(self):
|
|
438
|
+
if self._iter_index < len(self):
|
|
439
|
+
self._iter_index += 1
|
|
440
|
+
return self.attrs_name[self._iter_index-1]
|
|
441
|
+
else:
|
|
442
|
+
raise StopIteration
|
|
443
|
+
|
|
444
|
+
def __len__(self):
|
|
445
|
+
return len(self.attrs_name)
|
|
446
|
+
|
|
447
|
+
def to_dict(self) -> dict:
|
|
448
|
+
"""Returns attributes name/value as a dict"""
|
|
449
|
+
attrs_dict = dict()
|
|
450
|
+
for name in self.attrs_name:
|
|
451
|
+
attrs_dict[name] = self[name]
|
|
452
|
+
return attrs_dict
|
|
453
|
+
|
|
316
454
|
@property
|
|
317
455
|
def node(self):
|
|
318
456
|
return self._node
|
|
@@ -351,80 +489,26 @@ class Attributes(object):
|
|
|
351
489
|
return str(self)
|
|
352
490
|
|
|
353
491
|
|
|
354
|
-
def get_attr(node, attr_name, backend='tables'):
|
|
355
|
-
if backend == 'tables':
|
|
356
|
-
if attr_name is not None:
|
|
357
|
-
attr = node._v_attrs[attr_name]
|
|
358
|
-
attr = check_mandatory_attrs(attr_name, attr)
|
|
359
|
-
return JsonConverter.json2object(attr)
|
|
360
|
-
else:
|
|
361
|
-
attrs = dict([])
|
|
362
|
-
for attr_name in node._v_attrs._v_attrnames:
|
|
363
|
-
attrval = node._v_attrs[attr_name]
|
|
364
|
-
attrval = check_mandatory_attrs(attr_name, attrval)
|
|
365
|
-
attrs[attr_name] = JsonConverter.json2object(attrval)
|
|
366
|
-
return attrs
|
|
367
|
-
else:
|
|
368
|
-
if attr_name is not None:
|
|
369
|
-
attr = node.attrs[attr_name]
|
|
370
|
-
attr = check_mandatory_attrs(attr_name, attr)
|
|
371
|
-
return JsonConverter.json2object(attr)
|
|
372
|
-
else:
|
|
373
|
-
attrs = dict([])
|
|
374
|
-
for attr_name in node.attrs.keys():
|
|
375
|
-
attrval = node.attrs[attr_name]
|
|
376
|
-
attrval = check_mandatory_attrs(attr_name, attrval)
|
|
377
|
-
attrs[attr_name] = JsonConverter.json2object(attrval)
|
|
378
|
-
return attrs
|
|
379
|
-
|
|
380
|
-
def set_attr(node, attr_name, attr_value, backend='tables'):
|
|
381
|
-
if backend == 'tables':
|
|
382
|
-
node._v_attrs[attr_name] = JsonConverter.object2json(attr_value)
|
|
383
|
-
else:
|
|
384
|
-
node.attrs[attr_name] = JsonConverter.object2json(attr_value)
|
|
385
|
-
|
|
386
|
-
def check_mandatory_attrs(attr_name, attr):
|
|
387
|
-
"""for cross compatibility between different backends. If these attributes have binary value, then decode them
|
|
388
|
-
|
|
389
|
-
Parameters
|
|
390
|
-
----------
|
|
391
|
-
attr_name
|
|
392
|
-
attr
|
|
393
|
-
|
|
394
|
-
Returns
|
|
395
|
-
-------
|
|
396
|
-
|
|
397
|
-
"""
|
|
398
|
-
if attr_name == 'TITLE' or attr_name == 'CLASS' or attr_name == 'EXTDIM':
|
|
399
|
-
if isinstance(attr, bytes):
|
|
400
|
-
return attr.decode()
|
|
401
|
-
else:
|
|
402
|
-
return attr
|
|
403
|
-
else:
|
|
404
|
-
return attr
|
|
405
|
-
|
|
406
|
-
group_types = ['raw_datas', 'scan', 'detector', 'move', 'data', 'ch', '', 'external_h5']
|
|
407
|
-
|
|
408
492
|
class H5Backend:
|
|
409
493
|
def __init__(self, backend='tables'):
|
|
410
494
|
|
|
411
|
-
self._h5file = None
|
|
495
|
+
self._h5file = None
|
|
412
496
|
self.backend = backend
|
|
413
497
|
self.file_path = None
|
|
414
498
|
self.compression = None
|
|
415
499
|
if backend == 'tables':
|
|
416
500
|
if is_tables:
|
|
417
|
-
self.
|
|
501
|
+
self.h5_library = tables
|
|
418
502
|
else:
|
|
419
503
|
raise ImportError('the pytables module is not present')
|
|
420
504
|
elif backend == 'h5py':
|
|
421
505
|
if is_h5py:
|
|
422
|
-
self.
|
|
506
|
+
self.h5_library = h5py
|
|
423
507
|
else:
|
|
424
508
|
raise ImportError('the h5py module is not present')
|
|
425
509
|
elif backend == 'h5pyd':
|
|
426
510
|
if is_h5pyd:
|
|
427
|
-
self.
|
|
511
|
+
self.h5_library = h5pyd
|
|
428
512
|
else:
|
|
429
513
|
raise ImportError('the h5pyd module is not present')
|
|
430
514
|
|
|
@@ -437,6 +521,10 @@ class H5Backend:
|
|
|
437
521
|
self.file_path = file.filename
|
|
438
522
|
self._h5file = file
|
|
439
523
|
|
|
524
|
+
@property
|
|
525
|
+
def filename(self):
|
|
526
|
+
return self._h5file.filename
|
|
527
|
+
|
|
440
528
|
def isopen(self):
|
|
441
529
|
if self._h5file is None:
|
|
442
530
|
return False
|
|
@@ -461,26 +549,23 @@ class H5Backend:
|
|
|
461
549
|
def open_file(self, fullpathname, mode='r', title='PyMoDAQ file', **kwargs):
|
|
462
550
|
self.file_path = fullpathname
|
|
463
551
|
if self.backend == 'tables':
|
|
464
|
-
self._h5file = self.
|
|
552
|
+
self._h5file = self.h5_library.open_file(str(fullpathname), mode=mode, title=title, **kwargs)
|
|
465
553
|
if mode == 'w':
|
|
466
554
|
self.root().attrs['pymodaq_version'] = utils.get_version()
|
|
467
555
|
return self._h5file
|
|
468
556
|
else:
|
|
469
|
-
self._h5file = self.
|
|
557
|
+
self._h5file = self.h5_library.File(str(fullpathname), mode=mode, **kwargs)
|
|
470
558
|
|
|
471
559
|
if mode == 'w':
|
|
472
560
|
self.root().attrs['TITLE'] = title
|
|
473
561
|
self.root().attrs['pymodaq_version'] = utils.get_version()
|
|
474
562
|
return self._h5file
|
|
475
563
|
|
|
476
|
-
def save_file_as(self, filenamepath='h5copy.
|
|
477
|
-
""""""
|
|
564
|
+
def save_file_as(self, filenamepath='h5copy.txt'):
|
|
478
565
|
if self.backend == 'tables':
|
|
479
566
|
self.h5file.copy_file(str(filenamepath))
|
|
480
567
|
else:
|
|
481
|
-
with
|
|
482
|
-
self.h5file.copy(self.h5file, f_dest)
|
|
483
|
-
# raise Warning(f'Not possible to copy the file with the "{self.backend}" backend')
|
|
568
|
+
raise Warning(f'Not possible to copy the file with the "{self.backend}" backend')
|
|
484
569
|
|
|
485
570
|
def root(self):
|
|
486
571
|
if self.backend == 'tables':
|
|
@@ -498,6 +583,9 @@ class H5Backend:
|
|
|
498
583
|
node = node.node
|
|
499
584
|
return set_attr(node, attr_name, attr_value, self.backend)
|
|
500
585
|
|
|
586
|
+
def has_attr(self, node, attr_name):
|
|
587
|
+
return attr_name in self.get_node(node).attrs.attrs_name
|
|
588
|
+
|
|
501
589
|
def flush(self):
|
|
502
590
|
if self._h5file is not None:
|
|
503
591
|
self._h5file.flush()
|
|
@@ -514,7 +602,7 @@ class H5Backend:
|
|
|
514
602
|
if self.backend == 'tables':
|
|
515
603
|
if compression == 'gzip':
|
|
516
604
|
compression = 'zlib'
|
|
517
|
-
self.compression = self.
|
|
605
|
+
self.compression = self.h5_library.Filters(complevel=compression_opts, complib=compression)
|
|
518
606
|
else:
|
|
519
607
|
if compression == 'zlib':
|
|
520
608
|
compression = 'gzip'
|
|
@@ -585,12 +673,9 @@ class H5Backend:
|
|
|
585
673
|
return name.lower() in [name.lower() for name in self.get_children(where)]
|
|
586
674
|
|
|
587
675
|
def get_node(self, where, name=None) -> Node:
|
|
588
|
-
"""This method returns a node object (for sure?) that"""
|
|
589
|
-
#This casts where into a string object for the pytables backend but otherwise not.
|
|
590
676
|
if isinstance(where, Node):
|
|
591
677
|
where = where.node
|
|
592
678
|
|
|
593
|
-
#Then we get back to a node object but backend-dependent
|
|
594
679
|
if self.backend == 'tables':
|
|
595
680
|
node = self._h5file.get_node(where, name)
|
|
596
681
|
else:
|
|
@@ -666,9 +751,11 @@ class H5Backend:
|
|
|
666
751
|
def get_children(self, where):
|
|
667
752
|
"""Get a dict containing all children node hanging from where with their name as keys and types among Node,
|
|
668
753
|
CARRAY, EARRAY, VLARRAY or StringARRAY
|
|
754
|
+
|
|
669
755
|
Parameters
|
|
670
756
|
----------
|
|
671
|
-
where (str or node instance)
|
|
757
|
+
where (str or node instance)
|
|
758
|
+
see h5py and pytables documentation on nodes, and Node objects of this module
|
|
672
759
|
|
|
673
760
|
Returns
|
|
674
761
|
-------
|
|
@@ -676,14 +763,14 @@ class H5Backend:
|
|
|
676
763
|
|
|
677
764
|
See Also
|
|
678
765
|
--------
|
|
679
|
-
children_name
|
|
766
|
+
:meth:`.GROUP.children_name`
|
|
767
|
+
|
|
680
768
|
"""
|
|
681
769
|
where = self.get_node(where) # return a node object in case where is a string
|
|
682
770
|
if isinstance(where, Node):
|
|
683
771
|
where = where.node
|
|
684
772
|
|
|
685
|
-
mod = importlib.import_module('.
|
|
686
|
-
# mod = importlib.import_module('.h5modules', 'pymodaq.daq_utils')
|
|
773
|
+
mod = importlib.import_module('.backends', 'pymodaq.utils.h5modules')
|
|
687
774
|
children = dict([])
|
|
688
775
|
if self.backend == 'tables':
|
|
689
776
|
for child_name, child in where._v_children.items():
|
|
@@ -773,7 +860,7 @@ class H5Backend:
|
|
|
773
860
|
shape = tuple(shape)
|
|
774
861
|
|
|
775
862
|
if self.backend == 'tables':
|
|
776
|
-
atom = self.
|
|
863
|
+
atom = self.h5_library.Atom.from_dtype(dtype)
|
|
777
864
|
array = EARRAY(self._h5file.create_earray(where, name, atom, shape=shape, title=title,
|
|
778
865
|
filters=self.compression), self.backend)
|
|
779
866
|
else:
|
|
@@ -823,7 +910,7 @@ class H5Backend:
|
|
|
823
910
|
dtype = np.dtype(dtype)
|
|
824
911
|
subdtype = ''
|
|
825
912
|
if self.backend == 'tables':
|
|
826
|
-
atom = self.
|
|
913
|
+
atom = self.h5_library.Atom.from_dtype(dtype)
|
|
827
914
|
if subdtype == 'string':
|
|
828
915
|
array = StringARRAY(self._h5file.create_vlarray(where, name, atom, title=title,
|
|
829
916
|
filters=self.compression), self.backend)
|
|
@@ -833,7 +920,7 @@ class H5Backend:
|
|
|
833
920
|
else:
|
|
834
921
|
maxshape = (None,)
|
|
835
922
|
if self.backend == 'h5py':
|
|
836
|
-
dt = self.
|
|
923
|
+
dt = self.h5_library.vlen_dtype(dtype)
|
|
837
924
|
else:
|
|
838
925
|
dt = h5pyd.special_dtype(dtype)
|
|
839
926
|
if self.compression is not None:
|
|
@@ -861,13 +948,14 @@ class H5Backend:
|
|
|
861
948
|
array.attrs['backend'] = self.backend
|
|
862
949
|
return array
|
|
863
950
|
|
|
864
|
-
def add_group(self, group_name, group_type, where, title='', metadata=dict([])):
|
|
951
|
+
def add_group(self, group_name, group_type, where, title='', metadata=dict([])) -> GROUP:
|
|
865
952
|
"""
|
|
866
953
|
Add a node in the h5 file tree of the group type
|
|
867
954
|
Parameters
|
|
868
955
|
----------
|
|
869
956
|
group_name: (str) a custom name for this group
|
|
870
|
-
group_type:
|
|
957
|
+
group_type: str or GroupType enum
|
|
958
|
+
one of the possible values of GroupType
|
|
871
959
|
where: (str or node) parent node where to create the new group
|
|
872
960
|
metadata: (dict) extra metadata to be saved with this new group node
|
|
873
961
|
|
|
@@ -877,16 +965,16 @@ class H5Backend:
|
|
|
877
965
|
"""
|
|
878
966
|
if isinstance(where, Node):
|
|
879
967
|
where = where.node
|
|
880
|
-
|
|
881
|
-
|
|
968
|
+
|
|
969
|
+
group_type = enum_checker(GroupType, group_type)
|
|
882
970
|
|
|
883
971
|
if group_name in self.get_children(self.get_node(where)):
|
|
884
972
|
node = self.get_node(where, group_name)
|
|
885
973
|
|
|
886
974
|
else:
|
|
887
975
|
node = self.get_set_group(where, utils.capitalize(group_name), title)
|
|
888
|
-
node.attrs['type'] = group_type.lower()
|
|
976
|
+
node.attrs['type'] = group_type.name.lower()
|
|
889
977
|
for metadat in metadata:
|
|
890
978
|
node.attrs[metadat] = metadata[metadat]
|
|
891
979
|
node.attrs['backend'] = self.backend
|
|
892
|
-
return node
|
|
980
|
+
return node
|