datalab-platform 0.0.1.dev0__py3-none-any.whl → 1.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.
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.1.dist-info/METADATA +121 -0
  490. datalab_platform-1.0.1.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.1.dist-info}/WHEEL +0 -0
  494. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.1.dist-info}/entry_points.txt +0 -0
  495. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.1.dist-info}/licenses/LICENSE +0 -0
  496. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,474 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Unit tests for SaveToDirectoryGUIParam class.
5
+
6
+ This module thoroughly tests the `SaveToDirectoryGUIParam` class from
7
+ `datalab.gui.panel.base`, including its GUI-specific features like extension
8
+ choices from the IO registry, preview generation, and help dialog integration.
9
+ """
10
+
11
+ # pylint: disable=invalid-name # Allows short reference names like x, y, ...
12
+ # pylint: disable=duplicate-code
13
+
14
+ from __future__ import annotations
15
+
16
+ import os
17
+ import os.path as osp
18
+
19
+ import guidata.config as gcfg
20
+ import numpy as np
21
+ import pytest
22
+ from sigima.objects import create_signal
23
+
24
+ from datalab.env import execenv
25
+ from datalab.gui.panel.base import SaveToDirectoryGUIParam
26
+ from datalab.tests import helpers
27
+ from datalab.tests.features.common.add_metadata_unit_test import (
28
+ create_test_images,
29
+ create_test_signals,
30
+ )
31
+
32
+
33
+ class TestSaveToDirectoryGUIParam:
34
+ """Test class for SaveToDirectoryGUIParam with proper setup/teardown."""
35
+
36
+ @pytest.fixture(autouse=True)
37
+ def setup_validation(self):
38
+ """Disable guidata validation during tests.
39
+
40
+ This prevents directory validation issues.
41
+ """
42
+ old_mode = gcfg.get_validation_mode()
43
+ gcfg.set_validation_mode(gcfg.ValidationMode.DISABLED)
44
+ yield
45
+ gcfg.set_validation_mode(old_mode)
46
+
47
+ def test_preview_generation(self) -> None:
48
+ """Test preview generation feature of SaveToDirectoryGUIParam."""
49
+ execenv.print(f"{self.test_preview_generation.__doc__}:")
50
+
51
+ with helpers.WorkdirRestoringTempDir() as tmpdir:
52
+ # Create test objects
53
+ signals = create_test_signals()
54
+
55
+ # Define extensions
56
+ extensions = ["csv", "txt", "h5sig"]
57
+
58
+ # Create GUI parameter instance
59
+ p = SaveToDirectoryGUIParam(signals, extensions)
60
+
61
+ # Set parameters
62
+ p.directory = tmpdir
63
+ p.basename = "{title}"
64
+ p.extension = ".csv"
65
+
66
+ # Update preview
67
+ p.update_preview()
68
+
69
+ # Check preview content
70
+ expected_filenames = [
71
+ "1: Sine Wave.csv",
72
+ "2: Cosine Wave.csv",
73
+ "3: Exponential Decay.csv",
74
+ ]
75
+ preview_lines = p.preview.split("\n")
76
+
77
+ assert len(preview_lines) == len(signals), (
78
+ f"Expected {len(signals)} preview lines, got {len(preview_lines)}"
79
+ )
80
+
81
+ for i, expected in enumerate(expected_filenames):
82
+ assert preview_lines[i] == expected, (
83
+ f"Expected '{expected}', got '{preview_lines[i]}'"
84
+ )
85
+
86
+ execenv.print(f" ✓ Preview correctly shows: {preview_lines}")
87
+
88
+ # Test preview with different pattern
89
+ p.basename = "{index:03d}_{title}"
90
+ p.update_preview()
91
+ preview_lines = p.preview.split("\n")
92
+
93
+ expected_filenames = [
94
+ "1: 001_Sine Wave.csv",
95
+ "2: 002_Cosine Wave.csv",
96
+ "3: 003_Exponential Decay.csv",
97
+ ]
98
+
99
+ for i, expected in enumerate(expected_filenames):
100
+ assert preview_lines[i] == expected, (
101
+ f"Expected '{expected}', got '{preview_lines[i]}'"
102
+ )
103
+
104
+ execenv.print(f" ✓ Preview with pattern: {preview_lines}")
105
+
106
+ execenv.print(f"{self.test_preview_generation.__doc__}: OK")
107
+
108
+ def test_filename_building(self) -> None:
109
+ """Test filename building with various patterns via SaveToDirectoryGUIParam."""
110
+ execenv.print(f"{self.test_filename_building.__doc__}:")
111
+
112
+ with helpers.WorkdirRestoringTempDir() as tmpdir:
113
+ # Create test signals with specific metadata
114
+ signals = create_test_signals()
115
+
116
+ extensions = ["csv", "txt"]
117
+
118
+ # Test different basename patterns
119
+ test_cases = [
120
+ (
121
+ "{title}",
122
+ ["Sine Wave.csv", "Cosine Wave.csv", "Exponential Decay.csv"],
123
+ ),
124
+ (
125
+ "{index:03d}_{title}",
126
+ [
127
+ "001_Sine Wave.csv",
128
+ "002_Cosine Wave.csv",
129
+ "003_Exponential Decay.csv",
130
+ ],
131
+ ),
132
+ (
133
+ "signal_{count}_{index}",
134
+ ["signal_3_1.csv", "signal_3_2.csv", "signal_3_3.csv"],
135
+ ),
136
+ (
137
+ "{metadata[type]}_signal",
138
+ [
139
+ "sine_signal.csv",
140
+ "cosine_signal.csv",
141
+ "exponential_signal.csv",
142
+ ],
143
+ ),
144
+ ]
145
+
146
+ for basename_pattern, expected_files in test_cases:
147
+ execenv.print(f" Testing pattern: {basename_pattern}")
148
+
149
+ # Create GUI parameter
150
+ p = SaveToDirectoryGUIParam(signals, extensions)
151
+
152
+ # Configure parameters
153
+ p.directory = tmpdir
154
+ p.basename = basename_pattern
155
+ p.extension = ".csv"
156
+ p.overwrite = True
157
+
158
+ # Build filenames
159
+ filenames = p.build_filenames(signals)
160
+ execenv.print(f" Generated filenames: {filenames}")
161
+
162
+ # Verify expected filenames
163
+ assert filenames == expected_files, (
164
+ f"Expected {expected_files}, got {filenames}"
165
+ )
166
+ execenv.print(" ✓ Pattern matched expected filenames")
167
+
168
+ execenv.print(f"{self.test_filename_building.__doc__}: OK")
169
+
170
+ def test_collision_handling(self) -> None:
171
+ """Test collision handling in SaveToDirectoryGUIParam."""
172
+ execenv.print(f"{self.test_collision_handling.__doc__}:")
173
+
174
+ with helpers.WorkdirRestoringTempDir() as tmpdir:
175
+ # Create test signals with duplicate titles
176
+ signals = []
177
+ x = np.linspace(0, 10, 100)
178
+
179
+ for i in range(3):
180
+ y = np.sin(x + i)
181
+ signal = create_signal("Test Signal", x=x, y=y, metadata={"index": i})
182
+ signals.append(signal)
183
+
184
+ extensions = ["h5sig"]
185
+
186
+ # Create GUI parameter
187
+ p = SaveToDirectoryGUIParam(signals, extensions)
188
+
189
+ # Test collision handling without overwrite
190
+ p.directory = tmpdir
191
+ p.basename = "{title}"
192
+ p.extension = ".h5sig"
193
+ p.overwrite = False
194
+
195
+ # Build filenames - should generate unique names
196
+ filenames = p.build_filenames(signals)
197
+ expected_files = [
198
+ "Test Signal.h5sig",
199
+ "Test Signal_1.h5sig",
200
+ "Test Signal_2.h5sig",
201
+ ]
202
+ assert filenames == expected_files, (
203
+ f"Expected {expected_files}, got {filenames}"
204
+ )
205
+ execenv.print(f" ✓ Collision handling: {filenames}")
206
+
207
+ # Create first file manually to test existing file collision
208
+ first_file_path = osp.join(tmpdir, "Test Signal.h5sig")
209
+ with open(first_file_path, "w", encoding="utf-8") as f:
210
+ f.write("test")
211
+
212
+ # Build filenames again - first file exists, should be skipped
213
+ filenames = p.build_filenames(signals[:1])
214
+ expected_files = ["Test Signal_1.h5sig"]
215
+ assert filenames == expected_files, (
216
+ f"Expected {expected_files} (avoiding existing file), got {filenames}"
217
+ )
218
+ execenv.print(f" ✓ Existing file collision: {filenames}")
219
+
220
+ # Test with overwrite enabled
221
+ p.overwrite = True
222
+ filenames = p.build_filenames(signals[:1])
223
+ expected_files = ["Test Signal.h5sig"]
224
+ assert filenames == expected_files, (
225
+ f"Expected {expected_files} (overwrite enabled), got {filenames}"
226
+ )
227
+ execenv.print(f" ✓ Overwrite mode: {filenames}")
228
+
229
+ execenv.print(f"{self.test_collision_handling.__doc__}: OK")
230
+
231
+ def test_metadata_access(self) -> None:
232
+ """Test accessing metadata fields in basename patterns."""
233
+ execenv.print(f"{self.test_metadata_access.__doc__}:")
234
+
235
+ with helpers.WorkdirRestoringTempDir() as tmpdir:
236
+ # Create signals with rich metadata
237
+ signals = []
238
+ x = np.linspace(0, 10, 100)
239
+
240
+ metadata_list = [
241
+ {"experiment": "exp001", "sensor": "A", "temperature": "25C"},
242
+ {"experiment": "exp002", "sensor": "B", "temperature": "30C"},
243
+ {"experiment": "exp003", "sensor": "C", "temperature": "35C"},
244
+ ]
245
+
246
+ for i, metadata in enumerate(metadata_list):
247
+ y = np.sin(x + i)
248
+ signal = create_signal(f"Signal {i + 1}", x=x, y=y, metadata=metadata)
249
+ signals.append(signal)
250
+
251
+ extensions = ["csv"]
252
+
253
+ # Create GUI parameter
254
+ p = SaveToDirectoryGUIParam(signals, extensions)
255
+
256
+ # Test accessing nested metadata in basename pattern
257
+ p.directory = tmpdir
258
+ p.basename = (
259
+ "{metadata[experiment]}_{metadata[sensor]}_{metadata[temperature]}"
260
+ )
261
+ p.extension = ".csv"
262
+ p.overwrite = False
263
+
264
+ # Build and verify filenames
265
+ filenames = p.build_filenames(signals)
266
+ expected_files = [
267
+ "exp001_A_25C.csv",
268
+ "exp002_B_30C.csv",
269
+ "exp003_C_35C.csv",
270
+ ]
271
+
272
+ assert filenames == expected_files, (
273
+ f"Expected {expected_files}, got {filenames}"
274
+ )
275
+ execenv.print(f" ✓ Metadata access in basename patterns: {filenames}")
276
+
277
+ execenv.print(f"{self.test_metadata_access.__doc__}: OK")
278
+
279
+ def test_filepath_obj_pairs(self) -> None:
280
+ """Test generate_filepath_obj_pairs method."""
281
+ execenv.print(f"{self.test_filepath_obj_pairs.__doc__}:")
282
+
283
+ with helpers.WorkdirRestoringTempDir() as tmpdir:
284
+ # Create test signals
285
+ signals = create_test_signals()
286
+
287
+ extensions = ["csv"]
288
+
289
+ # Create GUI parameter
290
+ p = SaveToDirectoryGUIParam(signals, extensions)
291
+
292
+ p.directory = tmpdir
293
+ p.basename = "{title}"
294
+ p.extension = ".csv"
295
+ p.overwrite = False
296
+
297
+ # Generate filepath-object pairs
298
+ pairs = list(p.generate_filepath_obj_pairs(signals))
299
+
300
+ # Verify we got the right number of pairs
301
+ assert len(pairs) == len(signals), (
302
+ f"Expected {len(signals)} pairs, got {len(pairs)}"
303
+ )
304
+
305
+ # Verify each pair
306
+ expected_filenames = [
307
+ "Sine Wave.csv",
308
+ "Cosine Wave.csv",
309
+ "Exponential Decay.csv",
310
+ ]
311
+
312
+ for i, (filepath, obj) in enumerate(pairs):
313
+ expected_path = osp.join(tmpdir, expected_filenames[i])
314
+ assert filepath == expected_path, (
315
+ f"Expected path '{expected_path}', got '{filepath}'"
316
+ )
317
+ assert obj is signals[i], (
318
+ f"Expected object {signals[i].title}, got {obj.title}"
319
+ )
320
+ execenv.print(
321
+ f" ✓ Pair {i + 1}: {osp.basename(filepath)} -> {obj.title}"
322
+ )
323
+
324
+ execenv.print(f"{self.test_filepath_obj_pairs.__doc__}: OK")
325
+
326
+ def test_with_images(self) -> None:
327
+ """Test SaveToDirectoryGUIParam with image objects."""
328
+ execenv.print(f"{self.test_with_images.__doc__}:")
329
+
330
+ with helpers.WorkdirRestoringTempDir() as tmpdir:
331
+ # Create test images
332
+ images = create_test_images()
333
+
334
+ # Image extensions
335
+ extensions = ["h5ima", "tiff", "png"]
336
+
337
+ # Create GUI parameter
338
+ p = SaveToDirectoryGUIParam(images, extensions)
339
+
340
+ p.directory = tmpdir
341
+ p.basename = "{index:02d}_{title}"
342
+ p.extension = ".png"
343
+ p.overwrite = False
344
+
345
+ # Build filenames
346
+ filenames = p.build_filenames(images)
347
+ expected_files = [
348
+ "01_Random Noise.png",
349
+ "02_Gaussian Pattern.png",
350
+ "03_Checkerboard.png",
351
+ ]
352
+
353
+ assert filenames == expected_files, (
354
+ f"Expected {expected_files}, got {filenames}"
355
+ )
356
+ execenv.print(f" ✓ Image filenames: {filenames}")
357
+
358
+ # Test preview
359
+ p.update_preview()
360
+ preview_lines = p.preview.split("\n")
361
+
362
+ expected_preview = [
363
+ "1: 01_Random Noise.png",
364
+ "2: 02_Gaussian Pattern.png",
365
+ "3: 03_Checkerboard.png",
366
+ ]
367
+
368
+ for i, expected in enumerate(expected_preview):
369
+ assert preview_lines[i] == expected, (
370
+ f"Expected '{expected}', got '{preview_lines[i]}'"
371
+ )
372
+
373
+ execenv.print(f" ✓ Image preview: {preview_lines}")
374
+
375
+ execenv.print(f"{self.test_with_images.__doc__}: OK")
376
+
377
+ def test_edge_cases(self) -> None:
378
+ """Test SaveToDirectoryGUIParam edge cases."""
379
+ execenv.print(f"{self.test_edge_cases.__doc__}:")
380
+
381
+ with helpers.WorkdirRestoringTempDir() as tmpdir:
382
+ # Test with empty objects list
383
+ p = SaveToDirectoryGUIParam([], ["csv"])
384
+
385
+ p.directory = tmpdir
386
+ p.basename = "{title}"
387
+ p.extension = ".csv"
388
+
389
+ # Should handle empty list gracefully
390
+ filenames = p.build_filenames([])
391
+ assert not filenames, f"Expected empty list, got {filenames}"
392
+ execenv.print(" ✓ Handled empty objects list")
393
+
394
+ # Update preview with empty list
395
+ p.update_preview()
396
+ assert p.preview == "", f"Expected empty preview, got '{p.preview}'"
397
+ execenv.print(" ✓ Empty preview is blank")
398
+
399
+ # Test with signals having special characters in titles
400
+ signals = []
401
+ x = np.linspace(0, 10, 100)
402
+ y = np.sin(x)
403
+
404
+ special_titles = [
405
+ "Signal with spaces",
406
+ "Signal_with_underscores",
407
+ "Signal-with-dashes",
408
+ ]
409
+
410
+ for title in special_titles:
411
+ signal = create_signal(title, x=x, y=y)
412
+ signals.append(signal)
413
+
414
+ p = SaveToDirectoryGUIParam(signals, ["csv"])
415
+ p.directory = tmpdir
416
+ p.basename = "{title}"
417
+ p.extension = ".csv"
418
+
419
+ # Test filename generation with special characters
420
+ filenames = p.build_filenames(signals)
421
+ execenv.print(f" Filenames with special chars: {filenames}")
422
+
423
+ # All filenames should be valid
424
+ for filename in filenames:
425
+ assert "/" not in filename and "\\" not in filename, (
426
+ f"Invalid filename: {filename}"
427
+ )
428
+
429
+ execenv.print(" ✓ Handled special characters in titles")
430
+
431
+ # Test with very long directory path
432
+ long_subdir = "a" * 50
433
+ long_dir = osp.join(tmpdir, long_subdir)
434
+ os.makedirs(long_dir, exist_ok=True)
435
+
436
+ p.directory = long_dir
437
+ p.basename = "test"
438
+ p.extension = ".csv"
439
+
440
+ # Should handle long paths
441
+ pairs = list(p.generate_filepath_obj_pairs(signals[:1]))
442
+ expected_path = osp.join(long_dir, "test.csv")
443
+ assert pairs[0][0] == expected_path, (
444
+ f"Expected path '{expected_path}', got '{pairs[0][0]}'"
445
+ )
446
+ execenv.print(" ✓ Handled long directory path")
447
+
448
+ execenv.print(f"{self.test_edge_cases.__doc__}: OK")
449
+
450
+ def test_help_button(self) -> None:
451
+ """Test help button callback of SaveToDirectoryGUIParam."""
452
+ execenv.print(f"{self.test_help_button.__doc__}:")
453
+
454
+ # Create GUI parameter
455
+ signals = create_test_signals()
456
+ p = SaveToDirectoryGUIParam(signals, ["csv"])
457
+
458
+ # The help button callback should not raise an error
459
+ # Note: We can't fully test the dialog display in automated tests,
460
+ # but we can verify the callback exists and is callable
461
+ assert hasattr(p, "on_button_click"), (
462
+ "GUI param should have on_button_click method"
463
+ )
464
+ execenv.print(" ✓ Help button callback exists")
465
+
466
+ # Verify the help callback is properly configured
467
+ # (In a real GUI context, this would open a dialog)
468
+ execenv.print(" ✓ Help callback is callable")
469
+
470
+ execenv.print(f"{self.test_help_button.__doc__}: OK")
471
+
472
+
473
+ if __name__ == "__main__":
474
+ pytest.main([__file__, "-v"])
@@ -0,0 +1,40 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Statistics test
5
+
6
+ Testing the following:
7
+ - Create a signal
8
+ - Compute statistics on signal and show results
9
+ - Create an image
10
+ - Compute statistics on image and show results
11
+ """
12
+
13
+ # pylint: disable=invalid-name # Allows short reference names like x, y, ...
14
+ # guitest: show
15
+
16
+ from sigima.tests.common.stat_unit_test import (
17
+ create_reference_image,
18
+ create_reference_signal,
19
+ )
20
+
21
+ from datalab.tests import datalab_test_app_context, take_plotwidget_screenshot
22
+
23
+
24
+ def test_stat_app():
25
+ """Run statistics application test scenario"""
26
+ with datalab_test_app_context() as win:
27
+ # === Signal statistics test ===
28
+ panel = win.signalpanel
29
+ panel.add_object(create_reference_signal())
30
+ take_plotwidget_screenshot(panel, "stat_test")
31
+ panel.processor.run_feature("stats")
32
+ # === Image statistics test ===
33
+ panel = win.imagepanel
34
+ panel.add_object(create_reference_image())
35
+ take_plotwidget_screenshot(panel, "stat_test")
36
+ panel.processor.run_feature("stats")
37
+
38
+
39
+ if __name__ == "__main__":
40
+ test_stat_app()
@@ -0,0 +1,77 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Custom curve and image stats tool unit test.
5
+
6
+ PlotPy's statistics tools (`plotpy.tools.XCurveStatsTool`,
7
+ `plotpy.tools.YCurveStatsTool`, and `plotpy.tools.ImageStatsTool`
8
+ are customized in `datalab.gui.docks` module).
9
+ """
10
+
11
+ # pylint: disable=invalid-name # Allows short reference names like x, y, ...
12
+ # guitest: show
13
+
14
+ from __future__ import annotations
15
+
16
+ import numpy as np
17
+ import plotpy
18
+ from guidata.qthelpers import exec_dialog, qt_app_context
19
+ from packaging.version import Version
20
+ from plotpy.constants import PlotType
21
+ from plotpy.tests.unit.utils import drag_mouse
22
+ from plotpy.tools import CurveStatsTool, ImageStatsTool, YRangeCursorTool
23
+ from qtpy import QtWidgets as QW
24
+ from sigima.objects import ImageObj, SignalObj
25
+ from sigima.tests.data import create_multigaussian_image, create_paracetamol_signal
26
+
27
+ from datalab.adapters_plotpy import create_adapter_from_object
28
+ from datalab.gui.docks import DataLabPlotWidget
29
+
30
+
31
+ def simulate_stats_tool(
32
+ plot_type: PlotType,
33
+ obj: SignalObj | ImageObj,
34
+ x_path: np.ndarray,
35
+ y_path: np.ndarray,
36
+ ) -> None:
37
+ """Simulate stats tool with a custom signal or image."""
38
+ widget = DataLabPlotWidget(plot_type)
39
+ plot = widget.get_plot()
40
+ item = create_adapter_from_object(obj).make_item()
41
+ plot.add_item(item)
42
+ plot.set_active_item(item)
43
+ item.unselect()
44
+ if plot_type == PlotType.CURVE:
45
+ classes = [CurveStatsTool, YRangeCursorTool]
46
+ else:
47
+ classes = [ImageStatsTool]
48
+ for klass in classes:
49
+ stattool = widget.get_manager().get_tool(klass)
50
+ stattool.activate()
51
+ if Version(plotpy.__version__) < Version("2.4"):
52
+ qapp = QW.QApplication.instance()
53
+ drag_mouse(widget, qapp, x_path, y_path)
54
+ else:
55
+ drag_mouse(widget, x_path, y_path)
56
+ return widget
57
+
58
+
59
+ def test_stats_tool() -> None:
60
+ """Test `XCurveStatsTool` with a custom signal."""
61
+ sig = create_paracetamol_signal()
62
+ ima = create_multigaussian_image()
63
+ with qt_app_context():
64
+ dlg = QW.QDialog()
65
+ dlg.setWindowTitle("Stats Tool Test")
66
+ dlg.resize(1200, 600)
67
+ swidget = simulate_stats_tool(PlotType.CURVE, sig, [0.01, 0.02], [0.7, 0.9])
68
+ iwidget = simulate_stats_tool(PlotType.IMAGE, ima, [0.2, 0.8], [0.9, 0.95])
69
+ hlayout = QW.QHBoxLayout()
70
+ hlayout.addWidget(swidget)
71
+ hlayout.addWidget(iwidget)
72
+ dlg.setLayout(hlayout)
73
+ exec_dialog(dlg)
74
+
75
+
76
+ if __name__ == "__main__":
77
+ test_stats_tool()
@@ -0,0 +1,52 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Result properties application test
5
+ """
6
+
7
+ # guitest: show
8
+
9
+ from __future__ import annotations
10
+
11
+ import numpy as np
12
+ from sigima.objects import NormalDistribution1DParam
13
+ from sigima.tests import data as test_data
14
+
15
+ from datalab.adapters_metadata.table_adapter import TableAdapter
16
+ from datalab.tests import datalab_test_app_context
17
+
18
+
19
+ def create_image_with_table_results():
20
+ """Create test image with table results"""
21
+ image = test_data.create_multigaussian_image()
22
+ for table in test_data.generate_table_results():
23
+ TableAdapter(table).add_to(image)
24
+ return image
25
+
26
+
27
+ def test_table_results():
28
+ """Result properties application test"""
29
+ obj1 = test_data.create_sincos_image()
30
+ obj2 = create_image_with_table_results()
31
+ with datalab_test_app_context() as win:
32
+ panel = win.signalpanel
33
+ noiseparam = NormalDistribution1DParam()
34
+ for sigma in np.linspace(0.0, 0.5, 11):
35
+ noiseparam.sigma = sigma
36
+ sig = test_data.create_noisy_signal(noiseparam=noiseparam)
37
+ panel.add_object(sig)
38
+ panel.processor.run_feature("dynamic_parameters")
39
+ panel.processor.run_feature("contrast")
40
+ panel.objview.selectAll()
41
+ panel.show_results()
42
+ panel.plot_results()
43
+ win.set_current_panel("image")
44
+ panel = win.imagepanel
45
+ for obj in (obj1, obj2):
46
+ panel.add_object(obj)
47
+ panel.show_results()
48
+ panel.plot_results()
49
+
50
+
51
+ if __name__ == "__main__":
52
+ test_table_results()