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,131 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Import wizard test
5
+ """
6
+
7
+ # guitest: show
8
+
9
+ import numpy as np
10
+ from guidata.dataset import update_dataset
11
+ from guidata.qthelpers import exec_dialog, qt_app_context
12
+ from qtpy import QtWidgets as QW
13
+ from sigima.objects import ImageObj, SignalObj
14
+
15
+ from datalab.env import execenv
16
+ from datalab.tests import helpers
17
+ from datalab.widgets.textimport import ImageParam, SignalParam, TextImportWizard
18
+
19
+
20
+ def file_to_clipboard(filename: str) -> None:
21
+ """Copy file content to clipboard"""
22
+ for encoding in ("utf-8", "latin-1"):
23
+ try:
24
+ with open(filename, "r", encoding=encoding) as file:
25
+ text = file.read()
26
+ QW.QApplication.clipboard().setText(text)
27
+ return
28
+ except UnicodeDecodeError:
29
+ pass
30
+
31
+
32
+ TEST_SIGNAL_PARAM = SignalParam.create(
33
+ xlabel="X Signal axis",
34
+ ylabel="Y Signal axis",
35
+ xunit="X Signal unit",
36
+ yunit="Y Signal unit",
37
+ )
38
+
39
+ TEST_IMAGE_PARAM = ImageParam.create(
40
+ xlabel="X Image axis",
41
+ ylabel="Y Image axis",
42
+ zlabel="Z Image axis",
43
+ xunit="X Image unit",
44
+ yunit="Y Image unit",
45
+ zunit="Z Image unit",
46
+ )
47
+
48
+
49
+ def test_import_wizard():
50
+ """Test the import wizard"""
51
+ with qt_app_context():
52
+ for destination, fname, otype in (
53
+ ("image", "fiber.txt", ImageObj),
54
+ ("signal", "multiple_curves.csv", SignalObj),
55
+ ("signal", "paracetamol.txt", SignalObj),
56
+ ("signal", "spectrum.mca", SignalObj),
57
+ ):
58
+ path = helpers.get_test_fnames(fname)[0]
59
+ if not execenv.unattended:
60
+ # Do not test clipboard in unattended mode, would fail:
61
+ # - Windows: OleSetClipboard: Failed to set mime data (text/plain)
62
+ # on clipboard: COM error 0xffffffff800401d0
63
+ # - Linux: QXcbClipboard: Unable to receive an event from the clipboard
64
+ # manager in a reasonable time
65
+ file_to_clipboard(path)
66
+ wizard = TextImportWizard(destination=destination)
67
+ if execenv.unattended:
68
+ wizard.show()
69
+ srcpge = wizard.source_page # `SourcePage`
70
+ srcpge.param.path = path
71
+ srcpge.param_widget.get()
72
+ wizard.go_to_next_page()
73
+ datapge = wizard.data_page # `DataPreviewPage`
74
+ n_objs = 1
75
+ if destination == "image":
76
+ datapge.param.dtype_str = "uint8"
77
+ else:
78
+ datapge.param.dtype_str = "float32"
79
+ if fname == "fiber.txt":
80
+ datapge.param.delimiter_choice = " "
81
+ elif fname == "multiple_curves.csv":
82
+ datapge.param.delimiter_choice = ";"
83
+ datapge.param.skip_rows = 1
84
+ n_objs = 5
85
+ elif fname == "spectrum.mca":
86
+ datapge.param.skip_rows = 18
87
+ datapge.param.max_rows = 2048
88
+ datapge.param.header = None
89
+ datapge.param.first_col_is_x = False
90
+ else:
91
+ datapge.param.skip_rows = 10
92
+ datapge.param_widget.get()
93
+ datapge.update_preview()
94
+ wizard.go_to_next_page() # Go to `GraphicalRepresentationPage`
95
+ wizard.go_to_previous_page() # For test purpose only
96
+ wizard.go_to_next_page() # Go to `GraphicalRepresentationPage`
97
+ labels_page = wizard.labels_page # `LabelsPage`
98
+ if destination == "image":
99
+ assert isinstance(labels_page.param, ImageParam)
100
+ update_dataset(labels_page.param, TEST_IMAGE_PARAM)
101
+ else:
102
+ assert isinstance(labels_page.param, SignalParam)
103
+ update_dataset(labels_page.param, TEST_SIGNAL_PARAM)
104
+ wizard.go_to_next_page() # Go to `LabelsPage`
105
+ wizard.accept()
106
+ objs = wizard.get_objs()
107
+ assert len(objs) == n_objs
108
+ assert isinstance(objs[0], otype)
109
+ # Check that the parameters are set correctly
110
+ for obj in objs:
111
+ if isinstance(obj, ImageObj):
112
+ assert obj.data.dtype == np.uint8
113
+ assert obj.xlabel == TEST_IMAGE_PARAM.xlabel
114
+ assert obj.ylabel == TEST_IMAGE_PARAM.ylabel
115
+ assert obj.zlabel == TEST_IMAGE_PARAM.zlabel
116
+ assert obj.xunit == TEST_IMAGE_PARAM.xunit
117
+ assert obj.yunit == TEST_IMAGE_PARAM.yunit
118
+ assert obj.zunit == TEST_IMAGE_PARAM.zunit
119
+ elif isinstance(obj, SignalObj):
120
+ assert obj.data.dtype == np.float32
121
+ assert obj.xlabel == TEST_SIGNAL_PARAM.xlabel
122
+ assert obj.ylabel == TEST_SIGNAL_PARAM.ylabel
123
+ assert obj.xunit == TEST_SIGNAL_PARAM.xunit
124
+ assert obj.yunit == TEST_SIGNAL_PARAM.yunit
125
+ elif exec_dialog(wizard):
126
+ for obj in wizard.get_objs():
127
+ execenv.print(obj)
128
+
129
+
130
+ if __name__ == "__main__":
131
+ test_import_wizard()
@@ -0,0 +1,281 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Test UUID preservation when reopening workspace
5
+
6
+ This test verifies that when a workspace is saved to HDF5, cleared, and reopened,
7
+ the object UUIDs are preserved so that processing parameter references (source_uuid,
8
+ source_uuids) remain valid. This ensures features like "Show source" and "Recompute"
9
+ continue to work after reopening a workspace.
10
+
11
+ Related issue: Processing tab features don't work after reopening workspace because
12
+ UUIDs are regenerated.
13
+ """
14
+
15
+ # pylint: disable=invalid-name # Allows short reference names like x, y, ...
16
+
17
+ import os.path as osp
18
+
19
+ from guidata.qthelpers import qt_app_context
20
+ from sigima.params import GaussianParam
21
+
22
+ from datalab.gui.processor.base import PROCESSING_PARAMETERS_OPTION
23
+ from datalab.objectmodel import get_uuid
24
+ from datalab.tests import datalab_test_app_context, helpers
25
+
26
+
27
+ def test_uuid_preservation_signals():
28
+ """Test that signal UUIDs are preserved when reopening workspace"""
29
+ with qt_app_context():
30
+ with helpers.WorkdirRestoringTempDir() as tmpdir:
31
+ with datalab_test_app_context(console=False) as win:
32
+ panel = win.signalpanel
33
+ processor = panel.processor
34
+
35
+ # Step 1: Create a test signal
36
+ panel.new_object()
37
+ signal = panel.objview.get_current_object()
38
+ assert signal is not None
39
+ original_signal_uuid = get_uuid(signal)
40
+
41
+ # Step 2: Apply a processing operation with parameters
42
+ param = GaussianParam.create(sigma=2.0)
43
+ processor.compute_1_to_1(
44
+ processor.get_feature("gaussian_filter").function,
45
+ param=param,
46
+ title="Gaussian filter",
47
+ )
48
+
49
+ # Step 3: Get the filtered signal and verify metadata
50
+ filtered_sig = panel.objview.get_current_object()
51
+ assert filtered_sig is not None
52
+ original_filtered_uuid = get_uuid(filtered_sig)
53
+
54
+ # Verify processing metadata was stored correctly
55
+ assert (
56
+ PROCESSING_PARAMETERS_OPTION in filtered_sig.get_metadata_options()
57
+ )
58
+ option_dict = filtered_sig.get_metadata_option(
59
+ PROCESSING_PARAMETERS_OPTION
60
+ )
61
+ assert option_dict["source_uuid"] == original_signal_uuid
62
+ assert option_dict["func_name"] == "gaussian_filter"
63
+
64
+ # Step 4: Save workspace to HDF5
65
+ fname = osp.join(tmpdir, "test_uuid_preservation.h5")
66
+ win.save_to_h5_file(fname)
67
+
68
+ # Step 5: Remove all objects (clear workspace)
69
+ panel.remove_all_objects()
70
+ assert len(panel.objmodel) == 0
71
+
72
+ # Step 6: Reopen workspace
73
+ win.open_h5_files([fname], import_all=True, reset_all=True)
74
+
75
+ # Step 7: Verify UUIDs are preserved
76
+ signal_after = panel.objmodel.get_object_from_number(1)
77
+ filtered_sig_after = panel.objmodel.get_object_from_number(2)
78
+
79
+ signal_uuid_after = get_uuid(signal_after)
80
+ filtered_uuid_after = get_uuid(filtered_sig_after)
81
+
82
+ # CRITICAL: UUIDs must be preserved after reload
83
+ assert signal_uuid_after == original_signal_uuid, (
84
+ f"Signal UUID changed after reload: "
85
+ f"{original_signal_uuid} -> {signal_uuid_after}"
86
+ )
87
+ assert filtered_uuid_after == original_filtered_uuid, (
88
+ f"Filtered signal UUID changed after reload: "
89
+ f"{original_filtered_uuid} -> {filtered_uuid_after}"
90
+ )
91
+
92
+ # Step 8: Verify processing parameters still reference correct source
93
+ option_dict_after = filtered_sig_after.get_metadata_option(
94
+ PROCESSING_PARAMETERS_OPTION
95
+ )
96
+ assert option_dict_after["source_uuid"] == signal_uuid_after, (
97
+ f"Processing parameter source_uuid doesn't match: "
98
+ f"{option_dict_after['source_uuid']} != {signal_uuid_after}"
99
+ )
100
+
101
+ # Step 9: Verify "Show source" feature would work
102
+ # (by checking that the source object can be found)
103
+ source_obj = win.find_object_by_uuid(option_dict_after["source_uuid"])
104
+ assert source_obj is signal_after, (
105
+ "Cannot find source object by UUID - "
106
+ "'Show source' feature would fail"
107
+ )
108
+
109
+
110
+ def test_uuid_preservation_images():
111
+ """Test that image UUIDs are preserved when reopening workspace"""
112
+ with qt_app_context():
113
+ with helpers.WorkdirRestoringTempDir() as tmpdir:
114
+ with datalab_test_app_context(console=False) as win:
115
+ panel = win.imagepanel
116
+ processor = panel.processor
117
+
118
+ # Step 1: Create a test image
119
+ panel.new_object()
120
+ image = panel.objview.get_current_object()
121
+ assert image is not None
122
+ original_image_uuid = get_uuid(image)
123
+
124
+ # Step 2: Apply a processing operation
125
+ param = GaussianParam.create(sigma=1.5)
126
+ processor.compute_1_to_1(
127
+ processor.get_feature("gaussian_filter").function,
128
+ param=param,
129
+ title="Gaussian filter",
130
+ )
131
+
132
+ # Step 3: Get the filtered image and verify metadata
133
+ filtered_img = panel.objview.get_current_object()
134
+ assert filtered_img is not None
135
+ original_filtered_uuid = get_uuid(filtered_img)
136
+
137
+ # Verify processing metadata
138
+ option_dict = filtered_img.get_metadata_option(
139
+ PROCESSING_PARAMETERS_OPTION
140
+ )
141
+ assert option_dict["source_uuid"] == original_image_uuid
142
+
143
+ # Step 4: Save, clear, and reopen workspace
144
+ fname = osp.join(tmpdir, "test_uuid_preservation_images.h5")
145
+ win.save_to_h5_file(fname)
146
+ panel.remove_all_objects()
147
+ win.open_h5_files([fname], import_all=True, reset_all=True)
148
+
149
+ # Step 5: Verify UUIDs are preserved
150
+ image_after = panel.objmodel.get_object_from_number(1)
151
+ filtered_img_after = panel.objmodel.get_object_from_number(2)
152
+
153
+ assert get_uuid(image_after) == original_image_uuid
154
+ assert get_uuid(filtered_img_after) == original_filtered_uuid
155
+
156
+ # Step 6: Verify processing parameters still work
157
+ option_dict_after = filtered_img_after.get_metadata_option(
158
+ PROCESSING_PARAMETERS_OPTION
159
+ )
160
+ assert option_dict_after["source_uuid"] == get_uuid(image_after)
161
+ source_obj = win.find_object_by_uuid(option_dict_after["source_uuid"])
162
+ assert source_obj is image_after
163
+
164
+
165
+ def test_uuid_regeneration_on_import():
166
+ """Test that UUIDs are regenerated only when conflicts exist during import"""
167
+ with qt_app_context():
168
+ with helpers.WorkdirRestoringTempDir() as tmpdir:
169
+ with datalab_test_app_context(console=False) as win:
170
+ panel = win.signalpanel
171
+
172
+ # Step 1: Create and save a signal
173
+ panel.new_object()
174
+ signal1 = panel.objview.get_current_object()
175
+ uuid1 = get_uuid(signal1)
176
+
177
+ fname = osp.join(tmpdir, "test_import.h5")
178
+ win.save_to_h5_file(fname)
179
+
180
+ # Step 2: Import the same file (reset_all=False, import_all=True)
181
+ # This should regenerate UUID only for the conflicting object
182
+ win.open_h5_files([fname], import_all=True, reset_all=False)
183
+
184
+ # Step 3: Verify we now have 2 signals with different UUIDs
185
+ assert len(panel.objmodel) == 2
186
+
187
+ signal1_after = panel.objmodel.get_object_from_number(1)
188
+ signal2_imported = panel.objmodel.get_object_from_number(2)
189
+
190
+ uuid1_after = get_uuid(signal1_after)
191
+ uuid2 = get_uuid(signal2_imported)
192
+
193
+ # Original signal should keep its UUID
194
+ assert uuid1_after == uuid1
195
+
196
+ # Imported signal should have a NEW UUID (different from original)
197
+ assert uuid2 != uuid1, (
198
+ "Imported signal should have a new UUID, "
199
+ f"but got same as original: {uuid2} == {uuid1}"
200
+ )
201
+
202
+ # Step 4: Import the same file again
203
+ win.open_h5_files([fname], import_all=True, reset_all=False)
204
+
205
+ # Step 5: Verify we now have 3 signals, all with different UUIDs
206
+ assert len(panel.objmodel) == 3
207
+
208
+ signal3_imported = panel.objmodel.get_object_from_number(3)
209
+ uuid3 = get_uuid(signal3_imported)
210
+
211
+ # Third signal should have yet another different UUID
212
+ assert uuid3 != uuid1
213
+ assert uuid3 != uuid2
214
+ assert len({uuid1, uuid2, uuid3}) == 3, (
215
+ "All three signals should have unique UUIDs"
216
+ )
217
+
218
+
219
+ def test_uuid_preservation_empty_workspace():
220
+ """Test that UUIDs are preserved when opening HDF5 in empty workspace"""
221
+ with qt_app_context():
222
+ with helpers.WorkdirRestoringTempDir() as tmpdir:
223
+ # Create and save a workspace with processing history
224
+ with datalab_test_app_context(console=False) as win1:
225
+ panel = win1.signalpanel
226
+ processor = panel.processor
227
+
228
+ # Create signal and apply processing
229
+ panel.new_object()
230
+ signal = panel.objview.get_current_object()
231
+ original_uuid = get_uuid(signal)
232
+
233
+ param = GaussianParam.create(sigma=2.0)
234
+ processor.compute_1_to_1(
235
+ processor.get_feature("gaussian_filter").function,
236
+ param=param,
237
+ title="Gaussian filter",
238
+ )
239
+
240
+ filtered_sig = panel.objview.get_current_object()
241
+ original_filtered_uuid = get_uuid(filtered_sig)
242
+
243
+ # Save workspace
244
+ fname = osp.join(tmpdir, "test_empty_workspace.h5")
245
+ win1.save_to_h5_file(fname)
246
+
247
+ # Open the file in a NEW empty workspace (simulating startup)
248
+ with datalab_test_app_context(console=False) as win2:
249
+ panel = win2.signalpanel
250
+
251
+ # Workspace is empty - UUIDs should be preserved (reset_all=True)
252
+ # Note: reset_all is None, so it should auto-detect empty workspace
253
+ win2.open_h5_files([fname], import_all=True, reset_all=None)
254
+
255
+ # Verify UUIDs are preserved
256
+ signal_loaded = panel.objmodel.get_object_from_number(1)
257
+ filtered_loaded = panel.objmodel.get_object_from_number(2)
258
+
259
+ assert get_uuid(signal_loaded) == original_uuid, (
260
+ "Signal UUID should be preserved when opening in empty workspace"
261
+ )
262
+ assert get_uuid(filtered_loaded) == original_filtered_uuid, (
263
+ "Filtered signal UUID should be preserved "
264
+ "when opening in empty workspace"
265
+ )
266
+
267
+ # Verify processing parameters still work
268
+ option_dict = filtered_loaded.get_metadata_option(
269
+ PROCESSING_PARAMETERS_OPTION
270
+ )
271
+ assert option_dict["source_uuid"] == get_uuid(signal_loaded)
272
+ source_obj = win2.find_object_by_uuid(option_dict["source_uuid"])
273
+ assert source_obj is signal_loaded
274
+
275
+
276
+ if __name__ == "__main__":
277
+ test_uuid_preservation_signals()
278
+ test_uuid_preservation_images()
279
+ test_uuid_regeneration_on_import()
280
+ test_uuid_preservation_empty_workspace()
281
+ print("All UUID preservation tests passed!")