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,236 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Miscellaneous application test
5
+ ------------------------------
6
+
7
+ Whenever we have a test that does not fit in any of the other test files,
8
+ we put it here...
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 os.path as osp
17
+ from typing import TYPE_CHECKING, Any
18
+
19
+ import sigima.params
20
+ import sigima.proc.signal as sips
21
+ from sigima.tests.data import (
22
+ create_2dstep_image,
23
+ create_paracetamol_signal,
24
+ get_test_fnames,
25
+ )
26
+
27
+ from datalab.env import execenv
28
+ from datalab.objectmodel import get_uuid
29
+ from datalab.tests import datalab_test_app_context, helpers
30
+
31
+ if TYPE_CHECKING:
32
+ from datalab.gui.main import DLMainWindow
33
+
34
+
35
+ def __print_test_result(title: str, result: Any = None) -> None:
36
+ """Print a test result"""
37
+ execenv.print(f"Testing {title}{'' if result is None else ':'}")
38
+ if result is not None:
39
+ execenv.print(str(result))
40
+ execenv.print("")
41
+
42
+
43
+ def __misc_unit_function(win: DLMainWindow) -> None:
44
+ """Run miscellaneous unit tests
45
+
46
+ Args:
47
+ win: DLMainWindow instance
48
+ """
49
+ panel = win.signalpanel
50
+ objview = panel.objview
51
+
52
+ sig = create_paracetamol_signal()
53
+ panel.add_object(sig)
54
+ panel.processor.run_feature(sips.derivative)
55
+ panel.processor.run_feature(
56
+ sips.moving_average, sigima.params.MovingAverageParam.create(n=5)
57
+ )
58
+
59
+ __print_test_result("`SimpleObjectTree.__str__` method", objview)
60
+
61
+ # Updated metadata view settings:
62
+ __print_test_result("Updated metadata view settings")
63
+ panel.update_metadata_view_settings()
64
+
65
+ # Double click on the first signal item in object view:
66
+ __print_test_result("Double click on the first signal item in object view")
67
+ tree_item = objview.currentItem()
68
+ objview.itemDoubleClicked.emit(tree_item, 0)
69
+
70
+ # Open context menu on current item:
71
+ __print_test_result("Open context menu on current item")
72
+ tree_item_pos = objview.mapToGlobal(objview.visualItemRect(tree_item).center())
73
+ objview.SIG_CONTEXT_MENU.emit(tree_item_pos)
74
+
75
+ # Plot item parameters changed:
76
+ __print_test_result("Plot item parameters changed")
77
+ objview.select_objects([get_uuid(sig)])
78
+ item = panel.plothandler[get_uuid(sig)]
79
+ panel.plot_item_parameters_changed(item)
80
+
81
+ # Duplicate group:
82
+ __print_test_result("Duplicate group")
83
+ objview.select_groups([1])
84
+ panel.duplicate_object()
85
+
86
+ # Delete group:
87
+ __print_test_result("Delete group")
88
+ objview.select_groups([2])
89
+ panel.remove_object()
90
+
91
+ # Exec import wizard:
92
+ __print_test_result("Exec signal import wizard")
93
+ win.signalpanel.exec_import_wizard()
94
+ __print_test_result("Exec image import wizard")
95
+ win.imagepanel.exec_import_wizard()
96
+
97
+ # Properties changed:
98
+ __print_test_result("Properties changed")
99
+ objview.select_objects([get_uuid(sig)])
100
+ panel.properties_changed()
101
+
102
+ # Get object titles:
103
+ __print_test_result("Get object titles")
104
+ execenv.print(win.get_object_titles())
105
+
106
+ # Get object titles with info:
107
+ __print_test_result("Get group titles with object info")
108
+ execenv.print(win.get_group_titles_with_object_info())
109
+
110
+ # Pop up tab menu:
111
+ __print_test_result("Pop up tab menu")
112
+ win.tabmenu.popup(win.mapToGlobal(win.tabmenu.pos()))
113
+
114
+ # Repopulate panel trees:
115
+ __print_test_result("Repopulate panel trees")
116
+ win.repopulate_panel_trees()
117
+
118
+ # Browse HDF5 files:
119
+ __print_test_result("Browse HDF5 files")
120
+ win.browse_h5_files([], False)
121
+
122
+ # Open object
123
+ __print_test_result("Open object")
124
+ fname = get_test_fnames("*.csv")[0]
125
+ win.load_from_files([fname])
126
+
127
+ # Open directory
128
+ __print_test_result("Open directory (signals)")
129
+ path = osp.dirname(get_test_fnames("curve_formats/*.*")[0])
130
+ win.signalpanel.load_from_directory(path)
131
+
132
+ # Select all signals and save them to a temporary directory
133
+ __print_test_result("Select first group and save signals to a temporary directory")
134
+ win.signalpanel.objview.select_groups([1])
135
+ with helpers.WorkdirRestoringTempDir() as tmpdir:
136
+ param = sigima.params.SaveToDirectoryParam.create(
137
+ directory=tmpdir, basename="{title}_test", extension=".csv", overwrite=True
138
+ )
139
+ win.signalpanel.save_to_directory(param)
140
+
141
+ # Open objects from signal panel
142
+ __print_test_result("Open objects from signal panel")
143
+ fnames = [f for f in get_test_fnames("curve_formats/*.*") if not f.endswith(".mca")]
144
+ win.signalpanel.load_from_files(fnames)
145
+
146
+ # Get version
147
+ __print_test_result("Get version")
148
+ execenv.print(win.get_version())
149
+
150
+ # Add signal
151
+ __print_test_result("Add signal")
152
+ win.add_signal(
153
+ sig.title, sig.x, sig.y, sig.xunit, sig.yunit, sig.xlabel, sig.ylabel
154
+ )
155
+ gp2 = win.signalpanel.add_group("group2")
156
+ win.add_signal(
157
+ sig.title,
158
+ sig.x,
159
+ sig.y,
160
+ sig.xunit,
161
+ sig.yunit,
162
+ sig.xlabel,
163
+ sig.ylabel,
164
+ group_id=get_uuid(gp2),
165
+ set_current=False,
166
+ )
167
+
168
+ # Add image
169
+ __print_test_result("Add image")
170
+ ima = create_2dstep_image()
171
+ win.add_image(
172
+ ima.title,
173
+ ima.data,
174
+ ima.xunit,
175
+ ima.yunit,
176
+ ima.zunit,
177
+ ima.xlabel,
178
+ ima.ylabel,
179
+ ima.zlabel,
180
+ )
181
+ gp3 = win.imagepanel.add_group("group3")
182
+ win.add_image(
183
+ ima.title,
184
+ ima.data,
185
+ ima.xunit,
186
+ ima.yunit,
187
+ ima.zunit,
188
+ ima.xlabel,
189
+ ima.ylabel,
190
+ ima.zlabel,
191
+ group_id=get_uuid(gp3),
192
+ set_current=False,
193
+ )
194
+
195
+ # Get selected object UUIDs
196
+ __print_test_result("Get selected object UUIDs")
197
+ uuids = win.get_sel_object_uuids()
198
+ execenv.print(uuids)
199
+
200
+ # Select objects by UUIDs
201
+ __print_test_result("Select objects by UUIDs")
202
+ win.select_objects(uuids)
203
+
204
+ # Get object shapes
205
+ __print_test_result("Get object shapes")
206
+ win.get_object_shapes(uuids[0])
207
+
208
+ # Select groups by UUIDs
209
+ __print_test_result("Select groups by UUIDs")
210
+ win.select_groups([1])
211
+ uuids = win.get_sel_object_uuids()
212
+ win.select_groups(uuids)
213
+
214
+ # Delete metadata
215
+ __print_test_result("Delete metadata")
216
+ win.delete_metadata()
217
+
218
+ # Close application
219
+ __print_test_result("Close application")
220
+ win.close_application()
221
+
222
+
223
+ def test_misc_app() -> None:
224
+ """Run misc. application test scenario"""
225
+ with datalab_test_app_context(console=False) as win:
226
+ execenv.print("Miscellaneous application test")
227
+ execenv.print("==============================")
228
+ execenv.print("")
229
+
230
+ # We don't need to refresh the GUI during those tests (that's faster!)
231
+ with win.context_no_refresh():
232
+ __misc_unit_function(win)
233
+
234
+
235
+ if __name__ == "__main__":
236
+ test_misc_app()
@@ -0,0 +1,122 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Test for multiple geometry results of the same kind
5
+ ====================================================
6
+
7
+ This test verifies that multiple geometry results of the same kind (e.g., multiple
8
+ segment results like FWHM and FW1e2) can coexist on the same object.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import numpy as np
14
+ import sigima.objects as sio
15
+ from sigima.objects.scalar import GeometryResult, KindShape
16
+
17
+ from datalab.adapters_metadata import GeometryAdapter
18
+
19
+
20
+ def test_multiple_segment_results():
21
+ """Test that multiple segment geometry results can coexist."""
22
+ # Create a simple signal object
23
+ x = np.linspace(0, 10, 100)
24
+ y = np.exp(-((x - 5) ** 2) / 2)
25
+ obj = sio.create_signal("Test Signal", x, y)
26
+
27
+ # Create two different segment results (simulating FWHM and FW1e2)
28
+ fwhm_result = GeometryResult(
29
+ title="fwhm",
30
+ func_name="fwhm",
31
+ kind=KindShape.SEGMENT,
32
+ coords=np.array([[3.5, 0.6, 6.5, 0.6]]), # x0, y0, x1, y1
33
+ roi_indices=None,
34
+ attrs={"method": "zero-crossing"},
35
+ )
36
+
37
+ fw1e2_result = GeometryResult(
38
+ title="fw1e2",
39
+ func_name="fw1e2",
40
+ kind=KindShape.SEGMENT,
41
+ coords=np.array([[3.0, 0.37, 7.0, 0.37]]), # Different coordinates
42
+ roi_indices=None,
43
+ attrs={"method": "gaussian"},
44
+ )
45
+
46
+ # Add both results to the object
47
+ GeometryAdapter(fwhm_result).add_to(obj)
48
+ GeometryAdapter(fw1e2_result).add_to(obj)
49
+
50
+ # Verify both results are stored
51
+ results = list(GeometryAdapter.iterate_from_obj(obj))
52
+ assert len(results) == 2, f"Expected 2 results, got {len(results)}"
53
+
54
+ # Verify we can retrieve both results by title
55
+ titles = {adapter.title for adapter in results}
56
+ assert "fwhm" in titles, "FWHM result not found"
57
+ assert "fw1e2" in titles, "FW1e2 result not found"
58
+
59
+ # Verify the results have different coordinates
60
+ for adapter in results:
61
+ if adapter.title == "fwhm":
62
+ assert np.allclose(adapter.result.coords[0], [3.5, 0.6, 6.5, 0.6])
63
+ elif adapter.title == "fw1e2":
64
+ assert np.allclose(adapter.result.coords[0], [3.0, 0.37, 7.0, 0.37])
65
+
66
+ print("✓ Multiple segment results can coexist")
67
+
68
+
69
+ def test_replace_same_title():
70
+ """Test that adding a result with the same title replaces the old one."""
71
+ # Create a simple signal object
72
+ x = np.linspace(0, 10, 100)
73
+ y = np.exp(-((x - 5) ** 2) / 2)
74
+ obj = sio.create_signal("Test Signal", x, y)
75
+
76
+ # Create first FWHM result
77
+ fwhm_result_1 = GeometryResult(
78
+ title="fwhm",
79
+ kind=KindShape.SEGMENT,
80
+ coords=np.array([[3.5, 0.6, 6.5, 0.6]]),
81
+ roi_indices=None,
82
+ func_name="fwhm",
83
+ attrs={"method": "zero-crossing"},
84
+ )
85
+
86
+ # Create second FWHM result (same title, different coords)
87
+ fwhm_result_2 = GeometryResult(
88
+ title="fwhm",
89
+ kind=KindShape.SEGMENT,
90
+ coords=np.array([[3.6, 0.6, 6.6, 0.6]]), # Slightly different
91
+ roi_indices=None,
92
+ func_name="fwhm",
93
+ attrs={"method": "gaussian"},
94
+ )
95
+
96
+ # Add first result
97
+ GeometryAdapter(fwhm_result_1).add_to(obj)
98
+
99
+ # Verify one result
100
+ results = list(GeometryAdapter.iterate_from_obj(obj))
101
+ assert len(results) == 1, f"Expected 1 result after first add, got {len(results)}"
102
+
103
+ # Add second result (should replace the first)
104
+ GeometryAdapter(fwhm_result_2).add_to(obj)
105
+
106
+ # Verify still only one result
107
+ results = list(GeometryAdapter.iterate_from_obj(obj))
108
+ assert len(results) == 1, f"Expected 1 result after second add, got {len(results)}"
109
+
110
+ # Verify it's the second one (with updated coordinates)
111
+ adapter = results[0]
112
+ assert adapter.title == "fwhm"
113
+ assert np.allclose(adapter.result.coords[0], [3.6, 0.6, 6.6, 0.6])
114
+ assert adapter.result.attrs["method"] == "gaussian"
115
+
116
+ print("✓ Results with same title are properly replaced")
117
+
118
+
119
+ if __name__ == "__main__":
120
+ test_multiple_segment_results()
121
+ test_replace_same_title()
122
+ print("\n✅ All tests passed!")
@@ -0,0 +1,64 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Test for multiple table results of the same kind
5
+ ==================================================
6
+
7
+ This test verifies that multiple table results of the same kind can coexist
8
+ on the same object.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import numpy as np
14
+ import sigima.objects as sio
15
+ from sigima.objects.scalar import TableResult
16
+
17
+ from datalab.adapters_metadata import TableAdapter
18
+
19
+
20
+ def test_multiple_table_results():
21
+ """Test that multiple table results with different titles can coexist."""
22
+ # Create a simple signal object
23
+ x = np.linspace(0, 10, 100)
24
+ y = np.exp(-((x - 5) ** 2) / 2)
25
+ obj = sio.create_signal("Test Signal", x, y)
26
+
27
+ # Create two different table results (simulating different statistics)
28
+ stats1 = TableResult(
29
+ title="basic_stats",
30
+ func_name="basic_stats",
31
+ headers=["Mean", "Std", "Min", "Max"],
32
+ data=[[5.0, 1.5, 0.0, 10.0]],
33
+ roi_indices=None,
34
+ attrs={"method": "basic"},
35
+ )
36
+
37
+ stats2 = TableResult(
38
+ title="advanced_stats",
39
+ func_name="advanced_stats",
40
+ headers=["Median", "Q1", "Q3", "IQR"],
41
+ data=[[5.0, 3.5, 6.5, 3.0]],
42
+ roi_indices=None,
43
+ attrs={"method": "advanced"},
44
+ )
45
+
46
+ # Add both results to the object
47
+ TableAdapter(stats1).add_to(obj)
48
+ TableAdapter(stats2).add_to(obj)
49
+
50
+ # Verify both results are stored
51
+ results = list(TableAdapter.iterate_from_obj(obj))
52
+ assert len(results) == 2, f"Expected 2 results, got {len(results)}"
53
+
54
+ # Verify we can retrieve both results by title
55
+ titles = {adapter.title for adapter in results}
56
+ assert "basic_stats" in titles, "Basic stats result not found"
57
+ assert "advanced_stats" in titles, "Advanced stats result not found"
58
+
59
+ print("✓ Multiple table results can coexist")
60
+
61
+
62
+ if __name__ == "__main__":
63
+ test_multiple_table_results()
64
+ print("\n✅ All tests passed!")