datalab-platform 0.0.1.dev0__py3-none-any.whl → 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (496) hide show
  1. datalab/__init__.py +35 -2
  2. datalab/adapters_metadata/__init__.py +31 -0
  3. datalab/adapters_metadata/base_adapter.py +316 -0
  4. datalab/adapters_metadata/common.py +422 -0
  5. datalab/adapters_metadata/geometry_adapter.py +98 -0
  6. datalab/adapters_metadata/table_adapter.py +84 -0
  7. datalab/adapters_plotpy/__init__.py +54 -0
  8. datalab/adapters_plotpy/annotations.py +124 -0
  9. datalab/adapters_plotpy/base.py +110 -0
  10. datalab/adapters_plotpy/converters.py +86 -0
  11. datalab/adapters_plotpy/factories.py +80 -0
  12. datalab/adapters_plotpy/objects/__init__.py +0 -0
  13. datalab/adapters_plotpy/objects/base.py +197 -0
  14. datalab/adapters_plotpy/objects/image.py +157 -0
  15. datalab/adapters_plotpy/objects/scalar.py +565 -0
  16. datalab/adapters_plotpy/objects/signal.py +264 -0
  17. datalab/adapters_plotpy/roi/__init__.py +0 -0
  18. datalab/adapters_plotpy/roi/base.py +146 -0
  19. datalab/adapters_plotpy/roi/factory.py +93 -0
  20. datalab/adapters_plotpy/roi/image.py +207 -0
  21. datalab/adapters_plotpy/roi/signal.py +72 -0
  22. datalab/app.py +98 -0
  23. datalab/config.py +817 -0
  24. datalab/control/__init__.py +0 -0
  25. datalab/control/baseproxy.py +776 -0
  26. datalab/control/proxy.py +343 -0
  27. datalab/control/remote.py +1005 -0
  28. datalab/data/doc/DataLab_en.pdf +0 -0
  29. datalab/data/doc/DataLab_fr.pdf +0 -0
  30. datalab/data/icons/analysis/delete_results.svg +109 -0
  31. datalab/data/icons/analysis/fw1e2.svg +156 -0
  32. datalab/data/icons/analysis/fwhm.svg +156 -0
  33. datalab/data/icons/analysis/histogram.svg +49 -0
  34. datalab/data/icons/analysis/peak_detect.svg +160 -0
  35. datalab/data/icons/analysis/plot_results.svg +151 -0
  36. datalab/data/icons/analysis/show_results.svg +83 -0
  37. datalab/data/icons/analysis/stats.svg +49 -0
  38. datalab/data/icons/analysis.svg +120 -0
  39. datalab/data/icons/apply.svg +3 -0
  40. datalab/data/icons/check_all.svg +15 -0
  41. datalab/data/icons/collapse.svg +44 -0
  42. datalab/data/icons/collapse_selection.svg +63 -0
  43. datalab/data/icons/console.svg +101 -0
  44. datalab/data/icons/create/1d-normal.svg +8 -0
  45. datalab/data/icons/create/1d-poisson.svg +9 -0
  46. datalab/data/icons/create/1d-uniform.svg +8 -0
  47. datalab/data/icons/create/1d-zero.svg +57 -0
  48. datalab/data/icons/create/2d-gaussian.svg +56 -0
  49. datalab/data/icons/create/2d-normal.svg +38 -0
  50. datalab/data/icons/create/2d-poisson.svg +38 -0
  51. datalab/data/icons/create/2d-ramp.svg +90 -0
  52. datalab/data/icons/create/2d-sinc.svg +62 -0
  53. datalab/data/icons/create/2d-uniform.svg +38 -0
  54. datalab/data/icons/create/2d-zero.svg +13 -0
  55. datalab/data/icons/create/checkerboard.svg +39 -0
  56. datalab/data/icons/create/cosine.svg +12 -0
  57. datalab/data/icons/create/exponential.svg +55 -0
  58. datalab/data/icons/create/gaussian.svg +12 -0
  59. datalab/data/icons/create/grating.svg +29 -0
  60. datalab/data/icons/create/linear_chirp.svg +7 -0
  61. datalab/data/icons/create/logistic.svg +7 -0
  62. datalab/data/icons/create/lorentzian.svg +12 -0
  63. datalab/data/icons/create/planck.svg +12 -0
  64. datalab/data/icons/create/polynomial.svg +7 -0
  65. datalab/data/icons/create/pulse.svg +12 -0
  66. datalab/data/icons/create/ring.svg +18 -0
  67. datalab/data/icons/create/sawtooth.svg +7 -0
  68. datalab/data/icons/create/siemens.svg +35 -0
  69. datalab/data/icons/create/sinc.svg +12 -0
  70. datalab/data/icons/create/sine.svg +7 -0
  71. datalab/data/icons/create/square.svg +7 -0
  72. datalab/data/icons/create/square_pulse.svg +7 -0
  73. datalab/data/icons/create/step.svg +7 -0
  74. datalab/data/icons/create/step_pulse.svg +12 -0
  75. datalab/data/icons/create/triangle.svg +7 -0
  76. datalab/data/icons/create/voigt.svg +12 -0
  77. datalab/data/icons/edit/annotations.svg +72 -0
  78. datalab/data/icons/edit/annotations_copy.svg +114 -0
  79. datalab/data/icons/edit/annotations_delete.svg +83 -0
  80. datalab/data/icons/edit/annotations_edit.svg +98 -0
  81. datalab/data/icons/edit/annotations_export.svg +85 -0
  82. datalab/data/icons/edit/annotations_import.svg +85 -0
  83. datalab/data/icons/edit/annotations_paste.svg +100 -0
  84. datalab/data/icons/edit/copy_titles.svg +109 -0
  85. datalab/data/icons/edit/delete.svg +84 -0
  86. datalab/data/icons/edit/delete_all.svg +214 -0
  87. datalab/data/icons/edit/duplicate.svg +64 -0
  88. datalab/data/icons/edit/goto_source.svg +60 -0
  89. datalab/data/icons/edit/metadata.svg +60 -0
  90. datalab/data/icons/edit/metadata_add.svg +80 -0
  91. datalab/data/icons/edit/metadata_copy.svg +96 -0
  92. datalab/data/icons/edit/metadata_delete.svg +62 -0
  93. datalab/data/icons/edit/metadata_export.svg +68 -0
  94. datalab/data/icons/edit/metadata_import.svg +68 -0
  95. datalab/data/icons/edit/metadata_paste.svg +79 -0
  96. datalab/data/icons/edit/move_down.svg +55 -0
  97. datalab/data/icons/edit/move_up.svg +54 -0
  98. datalab/data/icons/edit/new_group.svg +76 -0
  99. datalab/data/icons/edit/recompute.svg +60 -0
  100. datalab/data/icons/edit/rename.svg +49 -0
  101. datalab/data/icons/edit.svg +16 -0
  102. datalab/data/icons/expand.svg +44 -0
  103. datalab/data/icons/expand_selection.svg +63 -0
  104. datalab/data/icons/fit/cdf_fit.svg +56 -0
  105. datalab/data/icons/fit/exponential_fit.svg +55 -0
  106. datalab/data/icons/fit/gaussian_fit.svg +62 -0
  107. datalab/data/icons/fit/interactive_fit.svg +101 -0
  108. datalab/data/icons/fit/linear_fit.svg +57 -0
  109. datalab/data/icons/fit/lorentzian_fit.svg +209 -0
  110. datalab/data/icons/fit/multigaussian_fit.svg +85 -0
  111. datalab/data/icons/fit/multilorentzian_fit.svg +85 -0
  112. datalab/data/icons/fit/piecewiseexponential_fit.svg +209 -0
  113. datalab/data/icons/fit/planckian_fit.svg +62 -0
  114. datalab/data/icons/fit/polynomial_fit.svg +59 -0
  115. datalab/data/icons/fit/sigmoid_fit.svg +56 -0
  116. datalab/data/icons/fit/sinusoidal_fit.svg +72 -0
  117. datalab/data/icons/fit/twohalfgaussian_fit.svg +63 -0
  118. datalab/data/icons/fit/voigt_fit.svg +57 -0
  119. datalab/data/icons/group.svg +56 -0
  120. datalab/data/icons/h5/h5array.svg +59 -0
  121. datalab/data/icons/h5/h5attrs.svg +75 -0
  122. datalab/data/icons/h5/h5browser.svg +133 -0
  123. datalab/data/icons/h5/h5file.svg +69 -0
  124. datalab/data/icons/h5/h5group.svg +49 -0
  125. datalab/data/icons/h5/h5scalar.svg +1 -0
  126. datalab/data/icons/help_pdf.svg +46 -0
  127. datalab/data/icons/history.svg +7 -0
  128. datalab/data/icons/image.svg +135 -0
  129. datalab/data/icons/io/fileopen_directory.svg +60 -0
  130. datalab/data/icons/io/fileopen_h5.svg +84 -0
  131. datalab/data/icons/io/fileopen_ima.svg +187 -0
  132. datalab/data/icons/io/fileopen_py.svg +123 -0
  133. datalab/data/icons/io/fileopen_sig.svg +138 -0
  134. datalab/data/icons/io/filesave_h5.svg +97 -0
  135. datalab/data/icons/io/filesave_ima.svg +200 -0
  136. datalab/data/icons/io/filesave_py.svg +136 -0
  137. datalab/data/icons/io/filesave_sig.svg +151 -0
  138. datalab/data/icons/io/import_text.svg +144 -0
  139. datalab/data/icons/io/save_to_directory.svg +134 -0
  140. datalab/data/icons/io.svg +84 -0
  141. datalab/data/icons/libre-camera-flash-off.svg +1 -0
  142. datalab/data/icons/libre-camera-flash-on.svg +1 -0
  143. datalab/data/icons/libre-gui-about.svg +1 -0
  144. datalab/data/icons/libre-gui-action-delete.svg +1 -0
  145. datalab/data/icons/libre-gui-add.svg +1 -0
  146. datalab/data/icons/libre-gui-arrow-down.svg +1 -0
  147. datalab/data/icons/libre-gui-arrow-left.svg +1 -0
  148. datalab/data/icons/libre-gui-arrow-right.svg +1 -0
  149. datalab/data/icons/libre-gui-arrow-up.svg +1 -0
  150. datalab/data/icons/libre-gui-close.svg +40 -0
  151. datalab/data/icons/libre-gui-cogs.svg +1 -0
  152. datalab/data/icons/libre-gui-globe.svg +1 -0
  153. datalab/data/icons/libre-gui-help.svg +1 -0
  154. datalab/data/icons/libre-gui-link.svg +1 -0
  155. datalab/data/icons/libre-gui-menu.svg +1 -0
  156. datalab/data/icons/libre-gui-pencil.svg +1 -0
  157. datalab/data/icons/libre-gui-plugin.svg +1 -0
  158. datalab/data/icons/libre-gui-questions.svg +1 -0
  159. datalab/data/icons/libre-gui-settings.svg +1 -0
  160. datalab/data/icons/libre-gui-unlink.svg +1 -0
  161. datalab/data/icons/libre-tech-ram.svg +1 -0
  162. datalab/data/icons/libre-toolbox.svg +1 -0
  163. datalab/data/icons/logs.svg +1 -0
  164. datalab/data/icons/markers.svg +74 -0
  165. datalab/data/icons/menu.svg +13 -0
  166. datalab/data/icons/new_ima.svg +148 -0
  167. datalab/data/icons/new_sig.svg +123 -0
  168. datalab/data/icons/operations/abs.svg +116 -0
  169. datalab/data/icons/operations/arithmetic.svg +123 -0
  170. datalab/data/icons/operations/average.svg +124 -0
  171. datalab/data/icons/operations/complex_from_magnitude_phase.svg +116 -0
  172. datalab/data/icons/operations/complex_from_real_imag.svg +124 -0
  173. datalab/data/icons/operations/constant.svg +116 -0
  174. datalab/data/icons/operations/constant_add.svg +109 -0
  175. datalab/data/icons/operations/constant_divide.svg +109 -0
  176. datalab/data/icons/operations/constant_multiply.svg +109 -0
  177. datalab/data/icons/operations/constant_subtract.svg +109 -0
  178. datalab/data/icons/operations/convert_dtype.svg +117 -0
  179. datalab/data/icons/operations/convolution.svg +46 -0
  180. datalab/data/icons/operations/deconvolution.svg +57 -0
  181. datalab/data/icons/operations/derivative.svg +127 -0
  182. datalab/data/icons/operations/difference.svg +52 -0
  183. datalab/data/icons/operations/division.svg +139 -0
  184. datalab/data/icons/operations/exp.svg +116 -0
  185. datalab/data/icons/operations/flip_horizontally.svg +69 -0
  186. datalab/data/icons/operations/flip_vertically.svg +74 -0
  187. datalab/data/icons/operations/im.svg +124 -0
  188. datalab/data/icons/operations/integral.svg +50 -0
  189. datalab/data/icons/operations/inverse.svg +143 -0
  190. datalab/data/icons/operations/log10.svg +109 -0
  191. datalab/data/icons/operations/phase.svg +116 -0
  192. datalab/data/icons/operations/power.svg +118 -0
  193. datalab/data/icons/operations/product.svg +124 -0
  194. datalab/data/icons/operations/profile.svg +379 -0
  195. datalab/data/icons/operations/profile_average.svg +399 -0
  196. datalab/data/icons/operations/profile_radial.svg +261 -0
  197. datalab/data/icons/operations/profile_segment.svg +262 -0
  198. datalab/data/icons/operations/quadratic_difference.svg +84 -0
  199. datalab/data/icons/operations/re.svg +124 -0
  200. datalab/data/icons/operations/rotate_left.svg +72 -0
  201. datalab/data/icons/operations/rotate_right.svg +72 -0
  202. datalab/data/icons/operations/signals_to_image.svg +314 -0
  203. datalab/data/icons/operations/sqrt.svg +110 -0
  204. datalab/data/icons/operations/std.svg +124 -0
  205. datalab/data/icons/operations/sum.svg +102 -0
  206. datalab/data/icons/play_demo.svg +9 -0
  207. datalab/data/icons/processing/axis_transform.svg +62 -0
  208. datalab/data/icons/processing/bandpass.svg +79 -0
  209. datalab/data/icons/processing/bandstop.svg +71 -0
  210. datalab/data/icons/processing/binning.svg +126 -0
  211. datalab/data/icons/processing/clip.svg +119 -0
  212. datalab/data/icons/processing/detrending.svg +173 -0
  213. datalab/data/icons/processing/distribute_on_grid.svg +769 -0
  214. datalab/data/icons/processing/edge_detection.svg +46 -0
  215. datalab/data/icons/processing/erase.svg +1 -0
  216. datalab/data/icons/processing/exposure.svg +143 -0
  217. datalab/data/icons/processing/fourier.svg +104 -0
  218. datalab/data/icons/processing/highpass.svg +59 -0
  219. datalab/data/icons/processing/interpolation.svg +71 -0
  220. datalab/data/icons/processing/level_adjustment.svg +70 -0
  221. datalab/data/icons/processing/lowpass.svg +60 -0
  222. datalab/data/icons/processing/morphology.svg +49 -0
  223. datalab/data/icons/processing/noise_addition.svg +114 -0
  224. datalab/data/icons/processing/noise_reduction.svg +38 -0
  225. datalab/data/icons/processing/normalize.svg +84 -0
  226. datalab/data/icons/processing/offset_correction.svg +131 -0
  227. datalab/data/icons/processing/resampling1d.svg +101 -0
  228. datalab/data/icons/processing/resampling2d.svg +240 -0
  229. datalab/data/icons/processing/reset_positions.svg +185 -0
  230. datalab/data/icons/processing/resize.svg +9 -0
  231. datalab/data/icons/processing/reverse_signal_x.svg +171 -0
  232. datalab/data/icons/processing/stability.svg +11 -0
  233. datalab/data/icons/processing/swap_x_y.svg +65 -0
  234. datalab/data/icons/processing/thresholding.svg +63 -0
  235. datalab/data/icons/processing/windowing.svg +45 -0
  236. datalab/data/icons/properties.svg +26 -0
  237. datalab/data/icons/reset.svg +9 -0
  238. datalab/data/icons/restore.svg +40 -0
  239. datalab/data/icons/roi/roi.svg +76 -0
  240. datalab/data/icons/roi/roi_coordinate.svg +78 -0
  241. datalab/data/icons/roi/roi_copy.svg +112 -0
  242. datalab/data/icons/roi/roi_delete.svg +81 -0
  243. datalab/data/icons/roi/roi_export.svg +87 -0
  244. datalab/data/icons/roi/roi_graphical.svg +78 -0
  245. datalab/data/icons/roi/roi_grid.svg +67 -0
  246. datalab/data/icons/roi/roi_ima.svg +188 -0
  247. datalab/data/icons/roi/roi_import.svg +87 -0
  248. datalab/data/icons/roi/roi_new.svg +81 -0
  249. datalab/data/icons/roi/roi_new_circle.svg +95 -0
  250. datalab/data/icons/roi/roi_new_polygon.svg +110 -0
  251. datalab/data/icons/roi/roi_new_rectangle.svg +70 -0
  252. datalab/data/icons/roi/roi_paste.svg +98 -0
  253. datalab/data/icons/roi/roi_sig.svg +124 -0
  254. datalab/data/icons/shapes.svg +134 -0
  255. datalab/data/icons/signal.svg +103 -0
  256. datalab/data/icons/table.svg +85 -0
  257. datalab/data/icons/table_unavailable.svg +102 -0
  258. datalab/data/icons/to_signal.svg +124 -0
  259. datalab/data/icons/tour/next.svg +44 -0
  260. datalab/data/icons/tour/previous.svg +44 -0
  261. datalab/data/icons/tour/rewind.svg +51 -0
  262. datalab/data/icons/tour/stop.svg +47 -0
  263. datalab/data/icons/tour/tour.svg +16 -0
  264. datalab/data/icons/uncheck_all.svg +78 -0
  265. datalab/data/icons/view/curve_antialiasing.svg +50 -0
  266. datalab/data/icons/view/new_window.svg +98 -0
  267. datalab/data/icons/view/refresh-auto.svg +57 -0
  268. datalab/data/icons/view/refresh-manual.svg +51 -0
  269. datalab/data/icons/view/reset_curve_styles.svg +96 -0
  270. datalab/data/icons/view/show_first.svg +55 -0
  271. datalab/data/icons/view/show_titles.svg +46 -0
  272. datalab/data/icons/visualization.svg +51 -0
  273. datalab/data/logo/DataLab-Banner-150.png +0 -0
  274. datalab/data/logo/DataLab-Banner-200.png +0 -0
  275. datalab/data/logo/DataLab-Banner2-100.png +0 -0
  276. datalab/data/logo/DataLab-Splash.png +0 -0
  277. datalab/data/logo/DataLab-watermark.png +0 -0
  278. datalab/data/logo/DataLab.svg +83 -0
  279. datalab/data/tests/reordering_test.h5 +0 -0
  280. datalab/data/tutorials/fabry_perot/fabry-perot1.jpg +0 -0
  281. datalab/data/tutorials/fabry_perot/fabry-perot2.jpg +0 -0
  282. datalab/data/tutorials/laser_beam/TEM00_z_13.jpg +0 -0
  283. datalab/data/tutorials/laser_beam/TEM00_z_18.jpg +0 -0
  284. datalab/data/tutorials/laser_beam/TEM00_z_23.jpg +0 -0
  285. datalab/data/tutorials/laser_beam/TEM00_z_30.jpg +0 -0
  286. datalab/data/tutorials/laser_beam/TEM00_z_35.jpg +0 -0
  287. datalab/data/tutorials/laser_beam/TEM00_z_40.jpg +0 -0
  288. datalab/data/tutorials/laser_beam/TEM00_z_45.jpg +0 -0
  289. datalab/data/tutorials/laser_beam/TEM00_z_50.jpg +0 -0
  290. datalab/data/tutorials/laser_beam/TEM00_z_55.jpg +0 -0
  291. datalab/data/tutorials/laser_beam/TEM00_z_60.jpg +0 -0
  292. datalab/data/tutorials/laser_beam/TEM00_z_65.jpg +0 -0
  293. datalab/data/tutorials/laser_beam/TEM00_z_70.jpg +0 -0
  294. datalab/data/tutorials/laser_beam/TEM00_z_75.jpg +0 -0
  295. datalab/data/tutorials/laser_beam/TEM00_z_80.jpg +0 -0
  296. datalab/env.py +542 -0
  297. datalab/gui/__init__.py +89 -0
  298. datalab/gui/actionhandler.py +1701 -0
  299. datalab/gui/docks.py +473 -0
  300. datalab/gui/h5io.py +150 -0
  301. datalab/gui/macroeditor.py +310 -0
  302. datalab/gui/main.py +2081 -0
  303. datalab/gui/newobject.py +217 -0
  304. datalab/gui/objectview.py +766 -0
  305. datalab/gui/panel/__init__.py +48 -0
  306. datalab/gui/panel/base.py +3254 -0
  307. datalab/gui/panel/image.py +157 -0
  308. datalab/gui/panel/macro.py +607 -0
  309. datalab/gui/panel/signal.py +164 -0
  310. datalab/gui/plothandler.py +800 -0
  311. datalab/gui/processor/__init__.py +84 -0
  312. datalab/gui/processor/base.py +2456 -0
  313. datalab/gui/processor/catcher.py +75 -0
  314. datalab/gui/processor/image.py +1214 -0
  315. datalab/gui/processor/signal.py +755 -0
  316. datalab/gui/profiledialog.py +333 -0
  317. datalab/gui/roieditor.py +633 -0
  318. datalab/gui/roigrideditor.py +208 -0
  319. datalab/gui/settings.py +612 -0
  320. datalab/gui/tour.py +908 -0
  321. datalab/h5/__init__.py +12 -0
  322. datalab/h5/common.py +314 -0
  323. datalab/h5/generic.py +580 -0
  324. datalab/h5/native.py +39 -0
  325. datalab/h5/utils.py +95 -0
  326. datalab/objectmodel.py +640 -0
  327. datalab/plugins/_readme_.txt +9 -0
  328. datalab/plugins/datalab_imageformats.py +175 -0
  329. datalab/plugins/datalab_testdata.py +190 -0
  330. datalab/plugins.py +355 -0
  331. datalab/tests/__init__.py +199 -0
  332. datalab/tests/backbone/__init__.py +1 -0
  333. datalab/tests/backbone/config_unit_test.py +170 -0
  334. datalab/tests/backbone/config_versioning_unit_test.py +34 -0
  335. datalab/tests/backbone/dictlistserial_app_test.py +38 -0
  336. datalab/tests/backbone/errorcatcher_unit_test.py +69 -0
  337. datalab/tests/backbone/errormsgbox_unit_test.py +50 -0
  338. datalab/tests/backbone/execenv_unit.py +262 -0
  339. datalab/tests/backbone/loadtest_gdi.py +147 -0
  340. datalab/tests/backbone/long_callback.py +96 -0
  341. datalab/tests/backbone/main_app_test.py +137 -0
  342. datalab/tests/backbone/memory_leak.py +43 -0
  343. datalab/tests/backbone/procisolation1_unit.py +128 -0
  344. datalab/tests/backbone/procisolation2_unit.py +171 -0
  345. datalab/tests/backbone/procisolation_unit_test.py +22 -0
  346. datalab/tests/backbone/profiling_app.py +27 -0
  347. datalab/tests/backbone/strings_unit_test.py +65 -0
  348. datalab/tests/backbone/title_formatting_unit_test.py +82 -0
  349. datalab/tests/conftest.py +131 -0
  350. datalab/tests/features/__init__.py +1 -0
  351. datalab/tests/features/applauncher/__init__.py +1 -0
  352. datalab/tests/features/applauncher/launcher1_app_test.py +28 -0
  353. datalab/tests/features/applauncher/launcher2_app_test.py +30 -0
  354. datalab/tests/features/common/__init__.py +1 -0
  355. datalab/tests/features/common/add_metadata_app_test.py +134 -0
  356. datalab/tests/features/common/add_metadata_unit_test.py +267 -0
  357. datalab/tests/features/common/annotations_management_unit_test.py +152 -0
  358. datalab/tests/features/common/auto_analysis_recompute_unit_test.py +240 -0
  359. datalab/tests/features/common/createobject_unit_test.py +50 -0
  360. datalab/tests/features/common/geometry_results_app_test.py +135 -0
  361. datalab/tests/features/common/interactive_processing_test.py +1109 -0
  362. datalab/tests/features/common/io_app_test.py +75 -0
  363. datalab/tests/features/common/large_results_app_test.py +187 -0
  364. datalab/tests/features/common/metadata_all_patterns_test.py +103 -0
  365. datalab/tests/features/common/metadata_app_test.py +139 -0
  366. datalab/tests/features/common/metadata_io_unit_test.py +60 -0
  367. datalab/tests/features/common/misc_app_test.py +236 -0
  368. datalab/tests/features/common/multiple_geometry_results_unit_test.py +122 -0
  369. datalab/tests/features/common/multiple_table_results_unit_test.py +64 -0
  370. datalab/tests/features/common/operation_modes_app_test.py +392 -0
  371. datalab/tests/features/common/plot_results_app_test.py +278 -0
  372. datalab/tests/features/common/reorder_app_test.py +75 -0
  373. datalab/tests/features/common/result_deletion_unit_test.py +96 -0
  374. datalab/tests/features/common/result_merged_label_unit_test.py +154 -0
  375. datalab/tests/features/common/result_shape_settings_unit_test.py +223 -0
  376. datalab/tests/features/common/roi_plotitem_unit_test.py +64 -0
  377. datalab/tests/features/common/roieditor_unit_test.py +102 -0
  378. datalab/tests/features/common/save_to_dir_app_test.py +163 -0
  379. datalab/tests/features/common/save_to_dir_unit_test.py +474 -0
  380. datalab/tests/features/common/stat_app_test.py +40 -0
  381. datalab/tests/features/common/stats_tools_unit_test.py +77 -0
  382. datalab/tests/features/common/table_results_app_test.py +52 -0
  383. datalab/tests/features/common/textimport_unit_test.py +131 -0
  384. datalab/tests/features/common/uuid_preservation_test.py +281 -0
  385. datalab/tests/features/common/worker_unit_test.py +402 -0
  386. datalab/tests/features/control/__init__.py +1 -0
  387. datalab/tests/features/control/connect_dialog.py +28 -0
  388. datalab/tests/features/control/embedded1_unit_test.py +304 -0
  389. datalab/tests/features/control/embedded2_unit_test.py +52 -0
  390. datalab/tests/features/control/remoteclient_app_test.py +219 -0
  391. datalab/tests/features/control/remoteclient_unit.py +75 -0
  392. datalab/tests/features/control/simpleclient_unit_test.py +321 -0
  393. datalab/tests/features/hdf5/__init__.py +1 -0
  394. datalab/tests/features/hdf5/h5browser1_unit_test.py +31 -0
  395. datalab/tests/features/hdf5/h5browser2_unit.py +55 -0
  396. datalab/tests/features/hdf5/h5browser_app_test.py +77 -0
  397. datalab/tests/features/hdf5/h5import_app_test.py +25 -0
  398. datalab/tests/features/hdf5/h5importer_app_test.py +34 -0
  399. datalab/tests/features/image/__init__.py +1 -0
  400. datalab/tests/features/image/annotations_app_test.py +28 -0
  401. datalab/tests/features/image/annotations_unit_test.py +80 -0
  402. datalab/tests/features/image/average_app_test.py +46 -0
  403. datalab/tests/features/image/background_dialog_test.py +70 -0
  404. datalab/tests/features/image/blobs_app_test.py +50 -0
  405. datalab/tests/features/image/contour_app_test.py +42 -0
  406. datalab/tests/features/image/contour_fabryperot_app_test.py +51 -0
  407. datalab/tests/features/image/denoise_app_test.py +31 -0
  408. datalab/tests/features/image/distribute_on_grid_app_test.py +95 -0
  409. datalab/tests/features/image/edges_app_test.py +31 -0
  410. datalab/tests/features/image/erase_app_test.py +21 -0
  411. datalab/tests/features/image/fft2d_app_test.py +27 -0
  412. datalab/tests/features/image/flatfield_app_test.py +40 -0
  413. datalab/tests/features/image/geometry_transform_unit_test.py +396 -0
  414. datalab/tests/features/image/imagetools_app_test.py +51 -0
  415. datalab/tests/features/image/imagetools_unit_test.py +27 -0
  416. datalab/tests/features/image/load_app_test.py +73 -0
  417. datalab/tests/features/image/morph_app_test.py +32 -0
  418. datalab/tests/features/image/offsetcorrection_app_test.py +30 -0
  419. datalab/tests/features/image/peak2d_app_test.py +53 -0
  420. datalab/tests/features/image/profile_app_test.py +73 -0
  421. datalab/tests/features/image/profile_dialog_test.py +56 -0
  422. datalab/tests/features/image/roi_app_test.py +98 -0
  423. datalab/tests/features/image/roi_circ_app_test.py +62 -0
  424. datalab/tests/features/image/roi_manipulation_app_test.py +268 -0
  425. datalab/tests/features/image/roigrid_unit_test.py +60 -0
  426. datalab/tests/features/image/side_by_side_app_test.py +52 -0
  427. datalab/tests/features/macro/__init__.py +1 -0
  428. datalab/tests/features/macro/macro_app_test.py +28 -0
  429. datalab/tests/features/macro/macroeditor_unit_test.py +102 -0
  430. datalab/tests/features/signal/__init__.py +1 -0
  431. datalab/tests/features/signal/baseline_dialog_test.py +53 -0
  432. datalab/tests/features/signal/deltax_dialog_unit_test.py +34 -0
  433. datalab/tests/features/signal/fft1d_app_test.py +26 -0
  434. datalab/tests/features/signal/filter_app_test.py +44 -0
  435. datalab/tests/features/signal/fitdialog_unit_test.py +50 -0
  436. datalab/tests/features/signal/interpolation_app_test.py +110 -0
  437. datalab/tests/features/signal/loadbigsignal_app_test.py +80 -0
  438. datalab/tests/features/signal/multiple_rois_unit_test.py +132 -0
  439. datalab/tests/features/signal/pulse_features_app_test.py +118 -0
  440. datalab/tests/features/signal/pulse_features_roi_app_test.py +55 -0
  441. datalab/tests/features/signal/roi_app_test.py +78 -0
  442. datalab/tests/features/signal/roi_manipulation_app_test.py +261 -0
  443. datalab/tests/features/signal/select_xy_cursor_unit_test.py +46 -0
  444. datalab/tests/features/signal/signalpeakdetection_dialog_test.py +33 -0
  445. datalab/tests/features/signal/signals_to_image_app_test.py +98 -0
  446. datalab/tests/features/signal/xarray_compat_app_test.py +128 -0
  447. datalab/tests/features/tour_unit_test.py +22 -0
  448. datalab/tests/features/utilities/__init__.py +1 -0
  449. datalab/tests/features/utilities/installconf_unit_test.py +21 -0
  450. datalab/tests/features/utilities/logview_app_test.py +21 -0
  451. datalab/tests/features/utilities/logview_error.py +24 -0
  452. datalab/tests/features/utilities/logview_unit_test.py +21 -0
  453. datalab/tests/features/utilities/memstatus_app_test.py +42 -0
  454. datalab/tests/features/utilities/settings_unit_test.py +88 -0
  455. datalab/tests/scenarios/__init__.py +1 -0
  456. datalab/tests/scenarios/beautiful_app.py +121 -0
  457. datalab/tests/scenarios/common.py +463 -0
  458. datalab/tests/scenarios/demo.py +212 -0
  459. datalab/tests/scenarios/example_app_test.py +47 -0
  460. datalab/tests/scenarios/scenario_h5_app_test.py +75 -0
  461. datalab/tests/scenarios/scenario_ima1_app_test.py +34 -0
  462. datalab/tests/scenarios/scenario_ima2_app_test.py +34 -0
  463. datalab/tests/scenarios/scenario_mac_app_test.py +58 -0
  464. datalab/tests/scenarios/scenario_sig1_app_test.py +36 -0
  465. datalab/tests/scenarios/scenario_sig2_app_test.py +35 -0
  466. datalab/utils/__init__.py +1 -0
  467. datalab/utils/conf.py +304 -0
  468. datalab/utils/dephash.py +105 -0
  469. datalab/utils/qthelpers.py +633 -0
  470. datalab/utils/strings.py +34 -0
  471. datalab/utils/tests.py +0 -0
  472. datalab/widgets/__init__.py +1 -0
  473. datalab/widgets/connection.py +138 -0
  474. datalab/widgets/filedialog.py +91 -0
  475. datalab/widgets/fileviewer.py +84 -0
  476. datalab/widgets/fitdialog.py +788 -0
  477. datalab/widgets/h5browser.py +1048 -0
  478. datalab/widgets/imagebackground.py +111 -0
  479. datalab/widgets/instconfviewer.py +175 -0
  480. datalab/widgets/logviewer.py +80 -0
  481. datalab/widgets/signalbaseline.py +90 -0
  482. datalab/widgets/signalcursor.py +208 -0
  483. datalab/widgets/signaldeltax.py +151 -0
  484. datalab/widgets/signalpeak.py +199 -0
  485. datalab/widgets/status.py +249 -0
  486. datalab/widgets/textimport.py +786 -0
  487. datalab/widgets/warningerror.py +223 -0
  488. datalab/widgets/wizard.py +286 -0
  489. datalab_platform-1.0.0.dist-info/METADATA +121 -0
  490. datalab_platform-1.0.0.dist-info/RECORD +494 -0
  491. datalab_platform-0.0.1.dev0.dist-info/METADATA +0 -67
  492. datalab_platform-0.0.1.dev0.dist-info/RECORD +0 -7
  493. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/WHEEL +0 -0
  494. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/entry_points.txt +0 -0
  495. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/licenses/LICENSE +0 -0
  496. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,47 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Example of high-level test scenario
5
+
6
+ Create an image object from Scikit-image human mitosis sample,
7
+ then open DataLab to show it.
8
+ """
9
+
10
+ # pylint: disable=invalid-name # Allows short reference names like x, y, ...
11
+ # guitest: show
12
+
13
+ import sigima.objects
14
+ import sigima.params
15
+ from sigima.tests.data import get_test_image
16
+
17
+ from datalab.control.proxy import proxy_context
18
+ from datalab.tests import skip_if_opencv_missing
19
+
20
+
21
+ def test_example_app() -> None:
22
+ """Example of high-level test scenario using proxy interface"""
23
+ with proxy_context("local") as proxy:
24
+ data = get_test_image("flower.npy").data
25
+ image = sigima.objects.create_image("Test image with peaks", data)
26
+ proxy.add_object(image)
27
+ proxy.calc("roberts")
28
+ data_size = data.shape[0]
29
+ n = data_size // 5
30
+ roi = sigima.objects.create_image_roi(
31
+ "rectangle", [n, n, data_size - 2 * n, data_size - 2 * n]
32
+ )
33
+ proxy.calc("compute_roi_extraction", roi)
34
+ param = sigima.params.BlobOpenCVParam.create(
35
+ min_dist_between_blobs=0.1,
36
+ filter_by_color=False,
37
+ min_area=500,
38
+ max_area=2000,
39
+ filter_by_circularity=True,
40
+ min_circularity=0.2,
41
+ )
42
+ with skip_if_opencv_missing():
43
+ proxy.calc("blob_opencv", param)
44
+
45
+
46
+ if __name__ == "__main__":
47
+ test_example_app()
@@ -0,0 +1,75 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ DataLab mainwindow automation test
5
+ ----------------------------------
6
+
7
+ This test scenario shows how to use the DataLab application in a test
8
+ scenario. It also validates the HDF5 file format.
9
+
10
+ This scenario executes the following steps:
11
+
12
+ - Creating two test signals
13
+ - Creating two test images
14
+ - Creating a macro
15
+ - Saving current project (h5 file)
16
+ - Removing all objects
17
+ - Opening another project (h5 file)
18
+ - Access current image metadata
19
+ - Checking macro code
20
+ """
21
+
22
+ # pylint: disable=invalid-name # Allows short reference names like x, y, ...
23
+ # guitest: show
24
+
25
+ import os.path as osp
26
+
27
+ from sigima.params import ClipParam
28
+ from sigima.tests.data import create_noisy_gaussian_image, create_paracetamol_signal
29
+
30
+ from datalab.env import execenv
31
+ from datalab.tests import datalab_test_app_context, helpers
32
+ from datalab.tests.scenarios import scenario_mac_app_test
33
+ from datalab.utils.strings import save_html_diff
34
+
35
+
36
+ def test_scenario_h5():
37
+ """Example of high-level test scenario with HDF5 file"""
38
+ with helpers.WorkdirRestoringTempDir() as tmpdir:
39
+ with datalab_test_app_context(console=False) as win:
40
+ # === Creating two test signals
41
+ panel = win.signalpanel
42
+ sig1 = create_paracetamol_signal()
43
+ panel.add_object(sig1)
44
+ panel.processor.run_feature("derivative")
45
+ # === Creating two test images
46
+ panel = win.imagepanel
47
+ ima1 = create_noisy_gaussian_image(add_annotations=True)
48
+ panel.add_object(ima1)
49
+ param = ClipParam.create(upper=ima1.data.mean())
50
+ panel.processor.run_feature("clip", param)
51
+ # === Creating a macro
52
+ scode = scenario_mac_app_test.add_macro_sample(win, 0).get_code()
53
+ scenario_mac_app_test.add_macro_sample(win, 1)
54
+ # === Saving project
55
+ fname = osp.join(tmpdir, "test.h5")
56
+ win.save_to_h5_file(fname)
57
+ # === Removing all objects
58
+ for panel in win.panels:
59
+ panel.remove_all_objects()
60
+ # === Reopening previously saved project
61
+ win.open_h5_files([fname], import_all=True, reset_all=True)
62
+ # === Accessing object metadata
63
+ obj = win.imagepanel.objmodel.get_groups()[0][0]
64
+ execenv.print(f"Image '{obj.title}':")
65
+ for key, value in obj.metadata.items():
66
+ execenv.print(f' metadata["{key}"] = {value}')
67
+ # === Checking macro code
68
+ lcode = win.macropanel.get_macro(1).get_code()
69
+ if lcode != scode:
70
+ save_html_diff(scode, lcode, "Saved code", "Loaded code", "macro0.html")
71
+ raise AssertionError("Macro code is not the same as saved")
72
+
73
+
74
+ if __name__ == "__main__":
75
+ test_scenario_h5()
@@ -0,0 +1,34 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Image processing test scenario
5
+ ------------------------------
6
+
7
+ Testing all the image processing features, without process isolation.
8
+ """
9
+
10
+ # pylint: disable=duplicate-code
11
+ # guitest: show
12
+
13
+ from datalab.config import Conf
14
+ from datalab.env import execenv
15
+ from datalab.tests import datalab_test_app_context
16
+ from datalab.tests.scenarios import common
17
+
18
+
19
+ def test_scenario_image() -> None:
20
+ """Run image unit test scenario 1 (no process isolation)"""
21
+ assert Conf.main.process_isolation_enabled.get(), (
22
+ "Process isolation must be enabled"
23
+ )
24
+ with datalab_test_app_context(save=True) as win:
25
+ with win.context_no_refresh():
26
+ execenv.print("Testing image features without process isolation...")
27
+ win.set_process_isolation_enabled(False)
28
+ common.run_image_computations(win)
29
+ win.imagepanel.remove_all_objects()
30
+ execenv.print("==> OK")
31
+
32
+
33
+ if __name__ == "__main__":
34
+ test_scenario_image()
@@ -0,0 +1,34 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Image processing test scenario
5
+ ------------------------------
6
+
7
+ Testing all the image processing features, with process isolation.
8
+ """
9
+
10
+ # pylint: disable=duplicate-code
11
+ # guitest: show
12
+
13
+ from datalab.config import Conf
14
+ from datalab.env import execenv
15
+ from datalab.tests import datalab_test_app_context
16
+ from datalab.tests.scenarios import common
17
+
18
+
19
+ def test_scenario_image2() -> None:
20
+ """Run image unit test scenario 2 (process isolation)"""
21
+ assert Conf.main.process_isolation_enabled.get(), (
22
+ "Process isolation must be enabled"
23
+ )
24
+
25
+ with datalab_test_app_context(save=True) as win:
26
+ execenv.print("Testing image features *with* process isolation...")
27
+ common.run_image_computations(win, all_types=False)
28
+ oids = win.imagepanel.objmodel.get_object_ids()
29
+ win.imagepanel.open_separate_view(oids[:4])
30
+ execenv.print("==> OK")
31
+
32
+
33
+ if __name__ == "__main__":
34
+ test_scenario_image2()
@@ -0,0 +1,58 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Macro-commands test scenario
5
+ ----------------------------
6
+
7
+ Testing all the macro-commands features.
8
+ """
9
+
10
+ # pylint: disable=invalid-name # Allows short reference names like x, y, ...
11
+ # guitest: show
12
+
13
+ import os.path as osp
14
+ import time
15
+
16
+ from datalab.gui.macroeditor import Macro
17
+ from datalab.gui.main import DLMainWindow
18
+ from datalab.tests import datalab_test_app_context, helpers
19
+
20
+
21
+ def add_macro_sample(win: DLMainWindow, index: int) -> Macro:
22
+ """Add a macro sample to the macro panel
23
+
24
+ Args:
25
+ win: DLMainWindow
26
+ index: index of the macro sample to add
27
+ """
28
+ macro = win.macropanel.add_macro()
29
+ macro.title = f"Test macro {index}"
30
+ samples = [
31
+ "import time; [print(f'{i}:{time.sleep(.1)}') for i in range(50)]",
32
+ "print('Hello world')",
33
+ ]
34
+ assert index < len(samples), f"index={index} is out of range"
35
+ macro.set_code(samples[index])
36
+ return macro
37
+
38
+
39
+ def test_scenario_macro() -> None:
40
+ """Example of high-level test scenario with HDF5 file"""
41
+ with helpers.WorkdirRestoringTempDir() as tmpdir:
42
+ with datalab_test_app_context(console=False) as win:
43
+ win.set_current_panel("macro")
44
+ add_macro_sample(win, 0)
45
+ win.macropanel.run_macro()
46
+ time.sleep(1)
47
+ win.macropanel.stop_macro()
48
+ code2 = add_macro_sample(win, 1).get_code()
49
+ fname = osp.join(tmpdir, "test.macro")
50
+ win.macropanel.export_macro_to_file(2, fname)
51
+ win.macropanel.remove_macro()
52
+ macro_nb = win.macropanel.import_macro_from_file(fname)
53
+ macro2 = win.macropanel.get_macro(macro_nb)
54
+ assert macro2.get_code() == code2, "Macro code is not the same"
55
+
56
+
57
+ if __name__ == "__main__":
58
+ test_scenario_macro()
@@ -0,0 +1,36 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Signal processing test scenario
5
+ -------------------------------
6
+
7
+ Testing all the signal processing features, without process isolation.
8
+ """
9
+
10
+ # pylint: disable=duplicate-code
11
+ # guitest: show
12
+
13
+ from __future__ import annotations
14
+
15
+ from datalab.config import Conf
16
+ from datalab.env import execenv
17
+ from datalab.tests import datalab_test_app_context
18
+ from datalab.tests.scenarios import common
19
+
20
+
21
+ def test_scenario_signal1() -> None:
22
+ """Run signal unit test scenario 1 (no process isolation)"""
23
+ assert Conf.main.process_isolation_enabled.get(), (
24
+ "Process isolation must be enabled"
25
+ )
26
+ with datalab_test_app_context(save=True) as win:
27
+ with win.context_no_refresh():
28
+ execenv.print("Testing signal features (process isolation: off)...")
29
+ win.set_process_isolation_enabled(False)
30
+ common.run_signal_computations(win, all_types=True)
31
+ win.signalpanel.remove_all_objects()
32
+ execenv.print("==> OK")
33
+
34
+
35
+ if __name__ == "__main__":
36
+ test_scenario_signal1()
@@ -0,0 +1,35 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Signal processing test scenario
5
+ -------------------------------
6
+
7
+ Testing all the signal processing features, with process isolation.
8
+ """
9
+
10
+ # pylint: disable=duplicate-code
11
+ # guitest: show
12
+
13
+ from __future__ import annotations
14
+
15
+ from datalab.config import Conf
16
+ from datalab.env import execenv
17
+ from datalab.tests import datalab_test_app_context
18
+ from datalab.tests.scenarios import common
19
+
20
+
21
+ def test_scenario_signal2() -> None:
22
+ """Run signal unit test scenario 2 (process isolation)"""
23
+ assert Conf.main.process_isolation_enabled.get(), (
24
+ "Process isolation must be enabled"
25
+ )
26
+ with datalab_test_app_context(save=True) as win:
27
+ execenv.print("Testing signal features (process isolation: on)...")
28
+ common.run_signal_computations(win, all_types=False)
29
+ oids = win.signalpanel.objmodel.get_object_ids()
30
+ win.signalpanel.open_separate_view(oids[:3])
31
+ execenv.print("==> OK")
32
+
33
+
34
+ if __name__ == "__main__":
35
+ test_scenario_signal2()
@@ -0,0 +1 @@
1
+ #
datalab/utils/conf.py ADDED
@@ -0,0 +1,304 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ DataLab Configuration utilities
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ import os.path as osp
11
+ import warnings
12
+ from collections.abc import Generator
13
+ from contextlib import contextmanager
14
+ from typing import TYPE_CHECKING, Any
15
+
16
+ import guidata.dataset as gds
17
+ from guidata.configtools import MONOSPACE, get_family
18
+ from guidata.userconfig import NoDefault, UserConfig
19
+
20
+ if TYPE_CHECKING:
21
+ import qtpy.QtGui as QG
22
+
23
+
24
+ class AppUserConfig(UserConfig):
25
+ """Application user configuration"""
26
+
27
+ def to_dict(self) -> dict:
28
+ """Return configuration as a dictionary"""
29
+ confdict = {}
30
+ for section in self.sections():
31
+ secdict = {}
32
+ for option, value in self.items(section, raw=self.raw):
33
+ secdict[option] = value
34
+ confdict[section] = secdict
35
+ return confdict
36
+
37
+
38
+ CONF = AppUserConfig({})
39
+
40
+
41
+ class Configuration:
42
+ """Configuration file"""
43
+
44
+ @classmethod
45
+ def initialize(cls, name: str, version: str, load: bool) -> None:
46
+ """Initialize configuration"""
47
+ CONF.set_application(name, version, load=load)
48
+
49
+ @classmethod
50
+ def reset(cls) -> None:
51
+ """Reset configuration"""
52
+ global CONF # pylint: disable=global-statement
53
+ CONF.cleanup() # Remove configuration file
54
+ CONF = AppUserConfig({})
55
+
56
+ @classmethod
57
+ def get_filename(cls) -> str:
58
+ """Return configuration file name"""
59
+ return CONF.filename()
60
+
61
+ @classmethod
62
+ def get_path(cls, basename: str) -> str:
63
+ """Return filename path inside configuration directory"""
64
+ return CONF.get_path(basename)
65
+
66
+ @classmethod
67
+ def to_dict(cls) -> dict:
68
+ """Return configuration as a dictionary"""
69
+ return CONF.to_dict()
70
+
71
+
72
+ class Section:
73
+ """Configuration section"""
74
+
75
+ @classmethod
76
+ def set_name(cls, section: str) -> None:
77
+ """Set section name"""
78
+ cls._name = section
79
+
80
+ @classmethod
81
+ def get_name(cls) -> str:
82
+ """Return section name"""
83
+ return cls._name
84
+
85
+
86
+ class Option:
87
+ """Configuration option handler"""
88
+
89
+ def __init__(self) -> None:
90
+ self.section = None
91
+ self.option = None
92
+
93
+ def get(self, default=NoDefault) -> Any:
94
+ """Get configuration option value"""
95
+ return CONF.get(self.section, self.option, default)
96
+
97
+ def set(self, value: Any) -> None:
98
+ """Set configuration option value"""
99
+ CONF.set(self.section, self.option, value)
100
+
101
+ def remove(self) -> None:
102
+ """Remove configuration option"""
103
+ # No use case for this method yet (quite dangerous!)
104
+ CONF.remove_option(self.section, self.option)
105
+
106
+ @contextmanager
107
+ def temp(self, value: Any) -> Generator[None, None, None]:
108
+ """Temporarily set configuration option value
109
+
110
+ Args:
111
+ value: new value
112
+ """
113
+ old_value = self.get()
114
+ self.set(value)
115
+ yield
116
+ self.set(old_value)
117
+
118
+
119
+ class FontOption(Option):
120
+ """Font configuration option handler"""
121
+
122
+ def get(self, default=NoDefault) -> str:
123
+ """Get font name from configuration"""
124
+ if default is NoDefault:
125
+ default = (MONOSPACE, 9, False)
126
+ family = CONF.get(self.section, self.option + "_family", default[0])
127
+ size = CONF.get(self.section, self.option + "_size", default[1])
128
+ bold = CONF.get(self.section, self.option + "_bold", default[2])
129
+ return family, size, bold
130
+
131
+ def set(self, value: tuple[str | list[str], int, bool]) -> None:
132
+ """Set font name in configuration"""
133
+ assert isinstance(value, tuple), (
134
+ "Font value must be a tuple (family, size, bold)"
135
+ )
136
+ CONF.set(self.section, self.option + "_family", value[0])
137
+ CONF.set(self.section, self.option + "_size", value[1])
138
+ CONF.set(self.section, self.option + "_bold", value[2])
139
+
140
+ def get_font(self) -> QG.QFont:
141
+ """Get QFont from configuration"""
142
+ # Import here to avoid having to create a Qt application when
143
+ # just manipulating configuration files
144
+ from qtpy import QtGui as QG # pylint: disable=import-outside-toplevel
145
+
146
+ family, size, bold = self.get()
147
+ if isinstance(family, (list, tuple)):
148
+ family = get_family(family)
149
+ return QG.QFont(family, size, QG.QFont.Bold if bold else QG.QFont.Normal)
150
+
151
+
152
+ class ConfigPathOption(Option):
153
+ """Configuration file path configuration option handler"""
154
+
155
+ def get(self, default=NoDefault) -> str:
156
+ """Get configuration file path from configuration"""
157
+ if default is NoDefault:
158
+ default = ""
159
+ fname = super().get(default)
160
+ if osp.basename(fname) != fname:
161
+ raise ValueError(f"Invalid configuration file name {fname}")
162
+ return CONF.get_path(osp.basename(fname))
163
+
164
+
165
+ class WorkingDirOption(Option):
166
+ """Working directory configuration option handler"""
167
+
168
+ def get(self, default=NoDefault) -> str:
169
+ """Get working directory from configuration"""
170
+ if default is NoDefault:
171
+ default = ""
172
+ path = super().get(default)
173
+ if osp.isdir(path):
174
+ return path
175
+ return ""
176
+
177
+ def set(self, value: str) -> None:
178
+ """Set working directory in configuration"""
179
+ if not osp.isdir(value):
180
+ value = osp.dirname(value)
181
+ if not osp.isdir(value):
182
+ raise FileNotFoundError(f"Invalid working directory name {value}")
183
+ os.chdir(value)
184
+ super().set(value)
185
+
186
+
187
+ class EnumOption(Option):
188
+ """Enumeration option handler"""
189
+
190
+ def __init__(self, values: list[Any], default: Any = NoDefault) -> None:
191
+ super().__init__()
192
+ if default is NoDefault:
193
+ default = values[0]
194
+ self.values = values
195
+ self.default = default
196
+
197
+ def get(self, default: Any = NoDefault) -> Any:
198
+ """Get configuration option value"""
199
+ value = super().get(default)
200
+ if value not in self.values:
201
+ # Only show a warning here, as the configuration file may be edited manually
202
+ warnings.warn(
203
+ f"Invalid value {value} for option {self.option}, "
204
+ f"expected {self.values}"
205
+ )
206
+ return self.default
207
+ return value
208
+
209
+ def set(self, value: Any) -> None:
210
+ """Set configuration option value"""
211
+ if value not in self.values:
212
+ raise ValueError(
213
+ f"Invalid value {value} for option {self.option}, "
214
+ f"expected {self.values}"
215
+ )
216
+ super().set(value)
217
+
218
+
219
+ class DataSetOption(Option):
220
+ """DataSet option handler"""
221
+
222
+ def __init__(self, default_instance: gds.DataSet | None = None) -> None:
223
+ super().__init__()
224
+ self.default_instance = default_instance
225
+
226
+ def set_default_instance(self, default_instance: gds.DataSet) -> None:
227
+ """Set the default instance (for lazy initialization)"""
228
+ self.default_instance = default_instance
229
+
230
+ def get(self, default: Any = NoDefault) -> gds.DataSet:
231
+ """Get configuration option value"""
232
+ # Use provided default or fall back to default_instance
233
+ effective_default = (
234
+ default if default is not NoDefault else self.default_instance
235
+ )
236
+ try:
237
+ json_str = super().get(default)
238
+ except RuntimeError as exc:
239
+ # Option not yet registered in CONF - register it with default
240
+ if effective_default is None:
241
+ raise ValueError(
242
+ f"No default instance set for option '{self.option}' "
243
+ f"in section '{self.section}'"
244
+ ) from exc
245
+ # Register the default value in CONF (writes to config file)
246
+ self.set(effective_default)
247
+ return effective_default
248
+ # If the option doesn't exist, super().get() returns the default parameter
249
+ if not isinstance(json_str, str):
250
+ return json_str
251
+ if json_str is NoDefault or not json_str:
252
+ if effective_default is None:
253
+ raise ValueError(
254
+ f"No default instance set for option '{self.option}' "
255
+ f"in section '{self.section}'"
256
+ )
257
+ return effective_default
258
+ # Unescape percent signs that were escaped for ConfigParser
259
+ json_str = json_str.replace("%%", "%")
260
+ try:
261
+ return gds.json_to_dataset(json_str)
262
+ except Exception as exc: # pylint: disable=broad-except
263
+ # Corrupted JSON: remove the option and return default
264
+ self.remove()
265
+ if effective_default is None:
266
+ raise ValueError(
267
+ f"No default instance set for option '{self.option}' "
268
+ f"in section '{self.section}'"
269
+ ) from exc
270
+ return effective_default
271
+
272
+ def set(self, value: gds.DataSet) -> None:
273
+ """Set configuration option value"""
274
+ json_str = gds.dataset_to_json(value)
275
+ # Escape percent signs for ConfigParser (which uses % for interpolation)
276
+ json_str = json_str.replace("%", "%%")
277
+ super().set(json_str)
278
+
279
+
280
+ class SectionMeta(type):
281
+ """Configuration metaclass"""
282
+
283
+ # pylint: disable=bad-mcs-classmethod-argument
284
+ def __new__(cls, name, bases, dct):
285
+ optlist = []
286
+ for attrname, obj in list(dct.items()):
287
+ if isinstance(obj, Option):
288
+ obj.option = attrname
289
+ optlist.append(obj)
290
+ dct["_options"] = optlist
291
+ return type.__new__(cls, name, bases, dct)
292
+
293
+
294
+ class ConfMeta(type):
295
+ """Configuration metaclass"""
296
+
297
+ # pylint: disable=bad-mcs-classmethod-argument
298
+ def __new__(cls, name, bases, dct):
299
+ for attrname, obj in list(dct.items()):
300
+ if isinstance(obj, Section):
301
+ obj.set_name(attrname)
302
+ for option in obj._options:
303
+ option.section = attrname
304
+ return type.__new__(cls, name, bases, dct)