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.

Files changed (233) hide show
  1. pymodaq/__init__.py +13 -6
  2. pymodaq/control_modules/__init__.py +0 -7
  3. pymodaq/control_modules/daq_move.py +965 -2
  4. pymodaq/control_modules/daq_move_ui.py +319 -0
  5. pymodaq/control_modules/daq_viewer.py +1573 -3
  6. pymodaq/control_modules/daq_viewer_ui.py +393 -0
  7. pymodaq/control_modules/mocks.py +51 -0
  8. pymodaq/control_modules/move_utility_classes.py +709 -8
  9. pymodaq/control_modules/utils.py +256 -0
  10. pymodaq/control_modules/viewer_utility_classes.py +663 -6
  11. pymodaq/daq_utils.py +89 -0
  12. pymodaq/dashboard.py +91 -72
  13. pymodaq/examples/custom_app.py +12 -11
  14. pymodaq/examples/custom_viewer.py +10 -10
  15. pymodaq/examples/function_plotter.py +16 -13
  16. pymodaq/examples/nonlinearscanner.py +8 -6
  17. pymodaq/examples/parameter_ex.py +7 -7
  18. pymodaq/examples/preset_MockCamera.xml +1 -0
  19. pymodaq/extensions/__init__.py +16 -0
  20. pymodaq/extensions/console.py +76 -0
  21. pymodaq/{daq_logger.py → extensions/daq_logger.py} +115 -65
  22. pymodaq/extensions/daq_scan.py +1339 -0
  23. pymodaq/extensions/daq_scan_ui.py +240 -0
  24. pymodaq/extensions/h5browser.py +23 -0
  25. pymodaq/{pid → extensions/pid}/__init__.py +4 -2
  26. pymodaq/{pid → extensions/pid}/daq_move_PID.py +2 -2
  27. pymodaq/{pid → extensions/pid}/pid_controller.py +48 -36
  28. pymodaq/{pid → extensions/pid}/utils.py +52 -6
  29. pymodaq/extensions/utils.py +40 -0
  30. pymodaq/post_treatment/__init__.py +6 -0
  31. pymodaq/{daq_analysis → post_treatment/daq_analysis}/daq_analysis_main.py +17 -17
  32. pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_main.py +8 -14
  33. pymodaq/post_treatment/load_and_plot.py +219 -0
  34. pymodaq/post_treatment/process_to_scalar.py +263 -0
  35. pymodaq/resources/QtDesigner_Ressources/Icon_Library/run_all.png +0 -0
  36. pymodaq/resources/QtDesigner_Ressources/Icon_Library/stop_all.png +0 -0
  37. pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources.bat +1 -1
  38. pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources.qrc +1 -0
  39. pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources_rc.py +109784 -109173
  40. pymodaq/resources/QtDesigner_Ressources/icons.svg +142 -0
  41. pymodaq/resources/VERSION +1 -1
  42. pymodaq/resources/config_template.toml +32 -13
  43. pymodaq/resources/preset_default.xml +1 -1
  44. pymodaq/{daq_utils → utils}/Tuto innosetup/script_full_setup.iss +1 -1
  45. pymodaq/utils/__init__.py +0 -29
  46. pymodaq/utils/abstract/__init__.py +48 -0
  47. pymodaq/{daq_utils → utils}/abstract/logger.py +7 -3
  48. pymodaq/utils/array_manipulation.py +379 -8
  49. pymodaq/{daq_utils → utils}/calibration_camera.py +6 -6
  50. pymodaq/{daq_utils → utils}/chrono_timer.py +1 -1
  51. pymodaq/utils/config.py +448 -0
  52. pymodaq/utils/conftests.py +5 -0
  53. pymodaq/utils/daq_utils.py +828 -8
  54. pymodaq/utils/data.py +1873 -7
  55. pymodaq/{daq_utils → utils}/db/db_logger/db_logger.py +86 -47
  56. pymodaq/{daq_utils → utils}/db/db_logger/db_logger_models.py +31 -10
  57. pymodaq/{daq_utils → utils}/enums.py +12 -7
  58. pymodaq/utils/exceptions.py +37 -0
  59. pymodaq/utils/factory.py +82 -0
  60. pymodaq/{daq_utils → utils}/gui_utils/__init__.py +1 -1
  61. pymodaq/utils/gui_utils/custom_app.py +129 -0
  62. pymodaq/utils/gui_utils/file_io.py +66 -0
  63. pymodaq/{daq_utils → utils}/gui_utils/layout.py +2 -2
  64. pymodaq/{daq_utils → utils}/gui_utils/utils.py +13 -3
  65. pymodaq/{daq_utils → utils}/gui_utils/widgets/__init__.py +2 -2
  66. pymodaq/utils/gui_utils/widgets/label.py +24 -0
  67. pymodaq/{daq_utils → utils}/gui_utils/widgets/lcd.py +12 -7
  68. pymodaq/{daq_utils → utils}/gui_utils/widgets/push.py +66 -2
  69. pymodaq/{daq_utils → utils}/gui_utils/widgets/qled.py +6 -4
  70. pymodaq/utils/gui_utils/widgets/spinbox.py +24 -0
  71. pymodaq/{daq_utils → utils}/gui_utils/widgets/table.py +2 -2
  72. pymodaq/utils/h5modules/__init__.py +1 -0
  73. pymodaq/{daq_utils/h5backend.py → utils/h5modules/backends.py} +200 -112
  74. pymodaq/utils/h5modules/browsing.py +683 -0
  75. pymodaq/utils/h5modules/data_saving.py +839 -0
  76. pymodaq/utils/h5modules/h5logging.py +110 -0
  77. pymodaq/utils/h5modules/module_saving.py +350 -0
  78. pymodaq/utils/h5modules/saving.py +914 -0
  79. pymodaq/utils/h5modules/utils.py +85 -0
  80. pymodaq/utils/logger.py +64 -6
  81. pymodaq/utils/managers/action_manager.py +460 -0
  82. pymodaq/{daq_utils → utils}/managers/batchscan_manager.py +144 -112
  83. pymodaq/{daq_utils → utils}/managers/modules_manager.py +188 -114
  84. pymodaq/{daq_utils → utils}/managers/overshoot_manager.py +3 -3
  85. pymodaq/utils/managers/parameter_manager.py +110 -0
  86. pymodaq/{daq_utils → utils}/managers/preset_manager.py +17 -13
  87. pymodaq/{daq_utils → utils}/managers/preset_manager_utils.py +8 -7
  88. pymodaq/{daq_utils → utils}/managers/remote_manager.py +7 -6
  89. pymodaq/{daq_utils → utils}/managers/roi_manager.py +148 -57
  90. pymodaq/utils/math_utils.py +546 -10
  91. pymodaq/{daq_utils → utils}/messenger.py +5 -1
  92. pymodaq/utils/parameter/__init__.py +2 -15
  93. pymodaq/{daq_utils → utils}/parameter/ioxml.py +12 -6
  94. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/__init__.py +1 -3
  95. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/filedir.py +1 -1
  96. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/itemselect.py +3 -0
  97. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/led.py +1 -1
  98. pymodaq/utils/parameter/pymodaq_ptypes/pixmap.py +161 -0
  99. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/slide.py +1 -1
  100. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/table.py +1 -1
  101. pymodaq/utils/parameter/utils.py +206 -11
  102. pymodaq/utils/plotting/data_viewers/__init__.py +6 -0
  103. pymodaq/utils/plotting/data_viewers/viewer.py +393 -0
  104. pymodaq/utils/plotting/data_viewers/viewer0D.py +251 -0
  105. pymodaq/utils/plotting/data_viewers/viewer1D.py +574 -0
  106. pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer1Dbasic.py +8 -3
  107. pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer2D.py +292 -357
  108. pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer2D_basic.py +58 -75
  109. pymodaq/utils/plotting/data_viewers/viewerND.py +738 -0
  110. pymodaq/{daq_utils → utils}/plotting/gant_chart.py +2 -2
  111. pymodaq/{daq_utils → utils}/plotting/items/axis_scaled.py +4 -2
  112. pymodaq/{daq_utils → utils}/plotting/items/image.py +8 -6
  113. pymodaq/utils/plotting/navigator.py +355 -0
  114. pymodaq/utils/plotting/scan_selector.py +480 -0
  115. pymodaq/utils/plotting/utils/axes_viewer.py +88 -0
  116. pymodaq/utils/plotting/utils/filter.py +538 -0
  117. pymodaq/utils/plotting/utils/lineout.py +224 -0
  118. pymodaq/{daq_utils → utils}/plotting/utils/plot_utils.py +196 -84
  119. pymodaq/{daq_utils → utils}/plotting/utils/signalND.py +21 -13
  120. pymodaq/utils/plotting/widgets.py +76 -0
  121. pymodaq/utils/scanner/__init__.py +10 -0
  122. pymodaq/utils/scanner/scan_factory.py +204 -0
  123. pymodaq/utils/scanner/scanner.py +271 -0
  124. pymodaq/utils/scanner/scanners/_1d_scanners.py +117 -0
  125. pymodaq/utils/scanner/scanners/_2d_scanners.py +293 -0
  126. pymodaq/utils/scanner/scanners/sequential.py +192 -0
  127. pymodaq/utils/scanner/scanners/tabular.py +294 -0
  128. pymodaq/utils/scanner/utils.py +83 -0
  129. pymodaq/utils/slicing.py +47 -0
  130. pymodaq/utils/svg/__init__.py +6 -0
  131. pymodaq/utils/svg/svg_renderer.py +20 -0
  132. pymodaq/utils/svg/svg_view.py +35 -0
  133. pymodaq/utils/svg/svg_viewer2D.py +51 -0
  134. pymodaq/{daq_utils → utils}/tcp_server_client.py +36 -37
  135. pymodaq/{daq_utils → utils}/tree_layout/tree_layout_main.py +50 -35
  136. pymodaq/utils/units.py +216 -0
  137. pymodaq-4.0.1.dist-info/METADATA +159 -0
  138. {pymodaq-3.6.12.dist-info → pymodaq-4.0.1.dist-info}/RECORD +167 -170
  139. {pymodaq-3.6.12.dist-info → pymodaq-4.0.1.dist-info}/WHEEL +1 -2
  140. pymodaq-4.0.1.dist-info/entry_points.txt +8 -0
  141. pymodaq/daq_move/daq_move_gui.py +0 -279
  142. pymodaq/daq_move/daq_move_gui.ui +0 -534
  143. pymodaq/daq_move/daq_move_main.py +0 -1042
  144. pymodaq/daq_move/process_from_QtDesigner_DAQ_Move_GUI.bat +0 -2
  145. pymodaq/daq_move/utility_classes.py +0 -671
  146. pymodaq/daq_scan.py +0 -2160
  147. pymodaq/daq_utils/array_manipulation.py +0 -386
  148. pymodaq/daq_utils/config.py +0 -273
  149. pymodaq/daq_utils/conftests.py +0 -7
  150. pymodaq/daq_utils/custom_parameter_tree.py +0 -9
  151. pymodaq/daq_utils/daq_enums.py +0 -133
  152. pymodaq/daq_utils/daq_utils.py +0 -1402
  153. pymodaq/daq_utils/exceptions.py +0 -71
  154. pymodaq/daq_utils/gui_utils/custom_app.py +0 -103
  155. pymodaq/daq_utils/gui_utils/file_io.py +0 -75
  156. pymodaq/daq_utils/gui_utils/widgets/spinbox.py +0 -9
  157. pymodaq/daq_utils/h5exporter_hyperspy.py +0 -115
  158. pymodaq/daq_utils/h5exporters.py +0 -242
  159. pymodaq/daq_utils/h5modules.py +0 -1559
  160. pymodaq/daq_utils/h5utils.py +0 -241
  161. pymodaq/daq_utils/managers/action_manager.py +0 -236
  162. pymodaq/daq_utils/managers/parameter_manager.py +0 -57
  163. pymodaq/daq_utils/math_utils.py +0 -705
  164. pymodaq/daq_utils/parameter/__init__.py +0 -1
  165. pymodaq/daq_utils/parameter/oldpymodaq_ptypes.py +0 -1626
  166. pymodaq/daq_utils/parameter/pymodaq_ptypes/pixmap.py +0 -85
  167. pymodaq/daq_utils/parameter/utils.py +0 -136
  168. pymodaq/daq_utils/plotting/data_viewers/__init__.py +0 -0
  169. pymodaq/daq_utils/plotting/data_viewers/process_from_QtDesigner_0DViewer_GUI.bat +0 -2
  170. pymodaq/daq_utils/plotting/data_viewers/viewer0D.py +0 -204
  171. pymodaq/daq_utils/plotting/data_viewers/viewer0D_GUI.py +0 -89
  172. pymodaq/daq_utils/plotting/data_viewers/viewer0D_GUI.ui +0 -131
  173. pymodaq/daq_utils/plotting/data_viewers/viewer1D.py +0 -781
  174. pymodaq/daq_utils/plotting/data_viewers/viewerND.py +0 -894
  175. pymodaq/daq_utils/plotting/data_viewers/viewerbase.py +0 -64
  176. pymodaq/daq_utils/plotting/items/__init__.py +0 -0
  177. pymodaq/daq_utils/plotting/navigator.py +0 -500
  178. pymodaq/daq_utils/plotting/scan_selector.py +0 -289
  179. pymodaq/daq_utils/plotting/utils/__init__.py +0 -0
  180. pymodaq/daq_utils/plotting/utils/filter.py +0 -236
  181. pymodaq/daq_utils/plotting/viewer0D/__init__.py +0 -0
  182. pymodaq/daq_utils/plotting/viewer0D/viewer0D_main.py +0 -4
  183. pymodaq/daq_utils/plotting/viewer1D/__init__.py +0 -0
  184. pymodaq/daq_utils/plotting/viewer1D/viewer1D_main.py +0 -4
  185. pymodaq/daq_utils/plotting/viewer1D/viewer1Dbasic.py +0 -4
  186. pymodaq/daq_utils/plotting/viewer2D/viewer_2D_basic.py +0 -4
  187. pymodaq/daq_utils/plotting/viewer2D/viewer_2D_main.py +0 -4
  188. pymodaq/daq_utils/plotting/viewerND/__init__.py +0 -0
  189. pymodaq/daq_utils/plotting/viewerND/viewerND_main.py +0 -4
  190. pymodaq/daq_utils/scanner.py +0 -1289
  191. pymodaq/daq_utils/tree_layout/__init__.py +0 -0
  192. pymodaq/daq_viewer/__init__.py +0 -0
  193. pymodaq/daq_viewer/daq_gui_settings.py +0 -237
  194. pymodaq/daq_viewer/daq_gui_settings.ui +0 -441
  195. pymodaq/daq_viewer/daq_viewer_main.py +0 -2225
  196. pymodaq/daq_viewer/process_from_QtDesigner_DAQ_GUI_settings.bat +0 -2
  197. pymodaq/daq_viewer/utility_classes.py +0 -673
  198. pymodaq/examples/logger_image/__init__.py +0 -0
  199. pymodaq/examples/logger_image/logger_displayer.py +0 -121
  200. pymodaq/examples/logger_image/setup.svg +0 -3119
  201. pymodaq/examples/logger_image/setup_svg.py +0 -114
  202. pymodaq/h5browser.py +0 -39
  203. pymodaq/utils/scanner.py +0 -15
  204. pymodaq-3.6.12.dist-info/METADATA +0 -39
  205. pymodaq-3.6.12.dist-info/entry_points.txt +0 -8
  206. pymodaq-3.6.12.dist-info/top_level.txt +0 -1
  207. /pymodaq/{daq_analysis → post_treatment/daq_analysis}/__init__.py +0 -0
  208. /pymodaq/{daq_measurement → post_treatment/daq_measurement}/__init__.py +0 -0
  209. /pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_GUI.py +0 -0
  210. /pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_GUI.ui +0 -0
  211. /pymodaq/{daq_measurement → post_treatment/daq_measurement}/process_from_QtDesigner_DAQ_Measurement_GUI.bat +0 -0
  212. /pymodaq/{daq_utils → utils}/Tuto innosetup/Tuto innosetup.odt +0 -0
  213. /pymodaq/{daq_utils → utils}/Tuto innosetup/Tuto innosetup.pdf +0 -0
  214. /pymodaq/{daq_move → utils/db}/__init__.py +0 -0
  215. /pymodaq/{daq_utils → utils/db/db_logger}/__init__.py +0 -0
  216. /pymodaq/{daq_utils → utils}/gui_utils/dock.py +0 -0
  217. /pymodaq/{daq_utils → utils}/gui_utils/list_picker.py +0 -0
  218. /pymodaq/{daq_utils/abstract → utils/managers}/__init__.py +0 -0
  219. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/bool.py +0 -0
  220. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/date.py +0 -0
  221. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/list.py +0 -0
  222. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/numeric.py +0 -0
  223. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/tableview.py +0 -0
  224. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/text.py +0 -0
  225. /pymodaq/{daq_utils/db → utils/plotting}/__init__.py +0 -0
  226. /pymodaq/{daq_utils → utils}/plotting/image_viewer.py +0 -0
  227. /pymodaq/{daq_utils/db/db_logger → utils/plotting/items}/__init__.py +0 -0
  228. /pymodaq/{daq_utils → utils}/plotting/items/crosshair.py +0 -0
  229. /pymodaq/{daq_utils/managers → utils/plotting/utils}/__init__.py +0 -0
  230. /pymodaq/{daq_utils → utils}/qvariant.py +0 -0
  231. /pymodaq/{daq_utils/plotting/viewer2D → utils/scanner/scanners}/__init__.py +0 -0
  232. /pymodaq/{daq_utils/plotting → utils/tree_layout}/__init__.py +0 -0
  233. {pymodaq-3.6.12.dist-info → pymodaq-4.0.1.dist-info/licenses}/LICENSE +0 -0
@@ -1,18 +1,24 @@
1
- #Standard imports
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
- #3rd party imports
6
- import numpy as np
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
- logger = utils.set_logger(utils.get_module_name(__file__))
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
- is_h5y = False
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
- is_h5yd = False
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
- #As I understand, the Node object should never be instanciated
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('.h5backend', 'pymodaq.daq_utils')
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
- def children(self):
162
- """Get a dict containing all children node hanging from self with their name as keys
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
- # mod = importlib.import_module('.h5modules', 'pymodaq.daq_utils')
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 # _h5file is the object created by one of the backends. Typically a tables.File
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.h5module = tables
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.h5module = h5py
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.h5module = h5pyd
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.h5module.open_file(str(fullpathname), mode=mode, title=title, **kwargs)
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.h5module.File(str(fullpathname), mode=mode, **kwargs)
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.h5'):
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 h5py.File(filenamepath, 'w') as f_dest:
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.h5module.Filters(complevel=compression_opts, complib=compression)
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), see h5py and pytables documentation on nodes, and Node objects of this module
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, Node, CARRAY, EARRAY, VLARRAY or StringARRAY
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('.h5backend', 'pymodaq.daq_utils')
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.h5module.Atom.from_dtype(dtype)
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.h5module.Atom.from_dtype(dtype)
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.h5module.vlen_dtype(dtype)
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: (str) one of the possible values of **group_types**
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
- if group_type not in group_types:
881
- raise InvalidGroupType('Invalid group type')
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