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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (496) hide show
  1. datalab/__init__.py +35 -2
  2. datalab/adapters_metadata/__init__.py +31 -0
  3. datalab/adapters_metadata/base_adapter.py +316 -0
  4. datalab/adapters_metadata/common.py +422 -0
  5. datalab/adapters_metadata/geometry_adapter.py +98 -0
  6. datalab/adapters_metadata/table_adapter.py +84 -0
  7. datalab/adapters_plotpy/__init__.py +54 -0
  8. datalab/adapters_plotpy/annotations.py +124 -0
  9. datalab/adapters_plotpy/base.py +110 -0
  10. datalab/adapters_plotpy/converters.py +86 -0
  11. datalab/adapters_plotpy/factories.py +80 -0
  12. datalab/adapters_plotpy/objects/__init__.py +0 -0
  13. datalab/adapters_plotpy/objects/base.py +197 -0
  14. datalab/adapters_plotpy/objects/image.py +157 -0
  15. datalab/adapters_plotpy/objects/scalar.py +565 -0
  16. datalab/adapters_plotpy/objects/signal.py +264 -0
  17. datalab/adapters_plotpy/roi/__init__.py +0 -0
  18. datalab/adapters_plotpy/roi/base.py +146 -0
  19. datalab/adapters_plotpy/roi/factory.py +93 -0
  20. datalab/adapters_plotpy/roi/image.py +207 -0
  21. datalab/adapters_plotpy/roi/signal.py +72 -0
  22. datalab/app.py +98 -0
  23. datalab/config.py +817 -0
  24. datalab/control/__init__.py +0 -0
  25. datalab/control/baseproxy.py +776 -0
  26. datalab/control/proxy.py +343 -0
  27. datalab/control/remote.py +1005 -0
  28. datalab/data/doc/DataLab_en.pdf +0 -0
  29. datalab/data/doc/DataLab_fr.pdf +0 -0
  30. datalab/data/icons/analysis/delete_results.svg +109 -0
  31. datalab/data/icons/analysis/fw1e2.svg +156 -0
  32. datalab/data/icons/analysis/fwhm.svg +156 -0
  33. datalab/data/icons/analysis/histogram.svg +49 -0
  34. datalab/data/icons/analysis/peak_detect.svg +160 -0
  35. datalab/data/icons/analysis/plot_results.svg +151 -0
  36. datalab/data/icons/analysis/show_results.svg +83 -0
  37. datalab/data/icons/analysis/stats.svg +49 -0
  38. datalab/data/icons/analysis.svg +120 -0
  39. datalab/data/icons/apply.svg +3 -0
  40. datalab/data/icons/check_all.svg +15 -0
  41. datalab/data/icons/collapse.svg +44 -0
  42. datalab/data/icons/collapse_selection.svg +63 -0
  43. datalab/data/icons/console.svg +101 -0
  44. datalab/data/icons/create/1d-normal.svg +8 -0
  45. datalab/data/icons/create/1d-poisson.svg +9 -0
  46. datalab/data/icons/create/1d-uniform.svg +8 -0
  47. datalab/data/icons/create/1d-zero.svg +57 -0
  48. datalab/data/icons/create/2d-gaussian.svg +56 -0
  49. datalab/data/icons/create/2d-normal.svg +38 -0
  50. datalab/data/icons/create/2d-poisson.svg +38 -0
  51. datalab/data/icons/create/2d-ramp.svg +90 -0
  52. datalab/data/icons/create/2d-sinc.svg +62 -0
  53. datalab/data/icons/create/2d-uniform.svg +38 -0
  54. datalab/data/icons/create/2d-zero.svg +13 -0
  55. datalab/data/icons/create/checkerboard.svg +39 -0
  56. datalab/data/icons/create/cosine.svg +12 -0
  57. datalab/data/icons/create/exponential.svg +55 -0
  58. datalab/data/icons/create/gaussian.svg +12 -0
  59. datalab/data/icons/create/grating.svg +29 -0
  60. datalab/data/icons/create/linear_chirp.svg +7 -0
  61. datalab/data/icons/create/logistic.svg +7 -0
  62. datalab/data/icons/create/lorentzian.svg +12 -0
  63. datalab/data/icons/create/planck.svg +12 -0
  64. datalab/data/icons/create/polynomial.svg +7 -0
  65. datalab/data/icons/create/pulse.svg +12 -0
  66. datalab/data/icons/create/ring.svg +18 -0
  67. datalab/data/icons/create/sawtooth.svg +7 -0
  68. datalab/data/icons/create/siemens.svg +35 -0
  69. datalab/data/icons/create/sinc.svg +12 -0
  70. datalab/data/icons/create/sine.svg +7 -0
  71. datalab/data/icons/create/square.svg +7 -0
  72. datalab/data/icons/create/square_pulse.svg +7 -0
  73. datalab/data/icons/create/step.svg +7 -0
  74. datalab/data/icons/create/step_pulse.svg +12 -0
  75. datalab/data/icons/create/triangle.svg +7 -0
  76. datalab/data/icons/create/voigt.svg +12 -0
  77. datalab/data/icons/edit/annotations.svg +72 -0
  78. datalab/data/icons/edit/annotations_copy.svg +114 -0
  79. datalab/data/icons/edit/annotations_delete.svg +83 -0
  80. datalab/data/icons/edit/annotations_edit.svg +98 -0
  81. datalab/data/icons/edit/annotations_export.svg +85 -0
  82. datalab/data/icons/edit/annotations_import.svg +85 -0
  83. datalab/data/icons/edit/annotations_paste.svg +100 -0
  84. datalab/data/icons/edit/copy_titles.svg +109 -0
  85. datalab/data/icons/edit/delete.svg +84 -0
  86. datalab/data/icons/edit/delete_all.svg +214 -0
  87. datalab/data/icons/edit/duplicate.svg +64 -0
  88. datalab/data/icons/edit/goto_source.svg +60 -0
  89. datalab/data/icons/edit/metadata.svg +60 -0
  90. datalab/data/icons/edit/metadata_add.svg +80 -0
  91. datalab/data/icons/edit/metadata_copy.svg +96 -0
  92. datalab/data/icons/edit/metadata_delete.svg +62 -0
  93. datalab/data/icons/edit/metadata_export.svg +68 -0
  94. datalab/data/icons/edit/metadata_import.svg +68 -0
  95. datalab/data/icons/edit/metadata_paste.svg +79 -0
  96. datalab/data/icons/edit/move_down.svg +55 -0
  97. datalab/data/icons/edit/move_up.svg +54 -0
  98. datalab/data/icons/edit/new_group.svg +76 -0
  99. datalab/data/icons/edit/recompute.svg +60 -0
  100. datalab/data/icons/edit/rename.svg +49 -0
  101. datalab/data/icons/edit.svg +16 -0
  102. datalab/data/icons/expand.svg +44 -0
  103. datalab/data/icons/expand_selection.svg +63 -0
  104. datalab/data/icons/fit/cdf_fit.svg +56 -0
  105. datalab/data/icons/fit/exponential_fit.svg +55 -0
  106. datalab/data/icons/fit/gaussian_fit.svg +62 -0
  107. datalab/data/icons/fit/interactive_fit.svg +101 -0
  108. datalab/data/icons/fit/linear_fit.svg +57 -0
  109. datalab/data/icons/fit/lorentzian_fit.svg +209 -0
  110. datalab/data/icons/fit/multigaussian_fit.svg +85 -0
  111. datalab/data/icons/fit/multilorentzian_fit.svg +85 -0
  112. datalab/data/icons/fit/piecewiseexponential_fit.svg +209 -0
  113. datalab/data/icons/fit/planckian_fit.svg +62 -0
  114. datalab/data/icons/fit/polynomial_fit.svg +59 -0
  115. datalab/data/icons/fit/sigmoid_fit.svg +56 -0
  116. datalab/data/icons/fit/sinusoidal_fit.svg +72 -0
  117. datalab/data/icons/fit/twohalfgaussian_fit.svg +63 -0
  118. datalab/data/icons/fit/voigt_fit.svg +57 -0
  119. datalab/data/icons/group.svg +56 -0
  120. datalab/data/icons/h5/h5array.svg +59 -0
  121. datalab/data/icons/h5/h5attrs.svg +75 -0
  122. datalab/data/icons/h5/h5browser.svg +133 -0
  123. datalab/data/icons/h5/h5file.svg +69 -0
  124. datalab/data/icons/h5/h5group.svg +49 -0
  125. datalab/data/icons/h5/h5scalar.svg +1 -0
  126. datalab/data/icons/help_pdf.svg +46 -0
  127. datalab/data/icons/history.svg +7 -0
  128. datalab/data/icons/image.svg +135 -0
  129. datalab/data/icons/io/fileopen_directory.svg +60 -0
  130. datalab/data/icons/io/fileopen_h5.svg +84 -0
  131. datalab/data/icons/io/fileopen_ima.svg +187 -0
  132. datalab/data/icons/io/fileopen_py.svg +123 -0
  133. datalab/data/icons/io/fileopen_sig.svg +138 -0
  134. datalab/data/icons/io/filesave_h5.svg +97 -0
  135. datalab/data/icons/io/filesave_ima.svg +200 -0
  136. datalab/data/icons/io/filesave_py.svg +136 -0
  137. datalab/data/icons/io/filesave_sig.svg +151 -0
  138. datalab/data/icons/io/import_text.svg +144 -0
  139. datalab/data/icons/io/save_to_directory.svg +134 -0
  140. datalab/data/icons/io.svg +84 -0
  141. datalab/data/icons/libre-camera-flash-off.svg +1 -0
  142. datalab/data/icons/libre-camera-flash-on.svg +1 -0
  143. datalab/data/icons/libre-gui-about.svg +1 -0
  144. datalab/data/icons/libre-gui-action-delete.svg +1 -0
  145. datalab/data/icons/libre-gui-add.svg +1 -0
  146. datalab/data/icons/libre-gui-arrow-down.svg +1 -0
  147. datalab/data/icons/libre-gui-arrow-left.svg +1 -0
  148. datalab/data/icons/libre-gui-arrow-right.svg +1 -0
  149. datalab/data/icons/libre-gui-arrow-up.svg +1 -0
  150. datalab/data/icons/libre-gui-close.svg +40 -0
  151. datalab/data/icons/libre-gui-cogs.svg +1 -0
  152. datalab/data/icons/libre-gui-globe.svg +1 -0
  153. datalab/data/icons/libre-gui-help.svg +1 -0
  154. datalab/data/icons/libre-gui-link.svg +1 -0
  155. datalab/data/icons/libre-gui-menu.svg +1 -0
  156. datalab/data/icons/libre-gui-pencil.svg +1 -0
  157. datalab/data/icons/libre-gui-plugin.svg +1 -0
  158. datalab/data/icons/libre-gui-questions.svg +1 -0
  159. datalab/data/icons/libre-gui-settings.svg +1 -0
  160. datalab/data/icons/libre-gui-unlink.svg +1 -0
  161. datalab/data/icons/libre-tech-ram.svg +1 -0
  162. datalab/data/icons/libre-toolbox.svg +1 -0
  163. datalab/data/icons/logs.svg +1 -0
  164. datalab/data/icons/markers.svg +74 -0
  165. datalab/data/icons/menu.svg +13 -0
  166. datalab/data/icons/new_ima.svg +148 -0
  167. datalab/data/icons/new_sig.svg +123 -0
  168. datalab/data/icons/operations/abs.svg +116 -0
  169. datalab/data/icons/operations/arithmetic.svg +123 -0
  170. datalab/data/icons/operations/average.svg +124 -0
  171. datalab/data/icons/operations/complex_from_magnitude_phase.svg +116 -0
  172. datalab/data/icons/operations/complex_from_real_imag.svg +124 -0
  173. datalab/data/icons/operations/constant.svg +116 -0
  174. datalab/data/icons/operations/constant_add.svg +109 -0
  175. datalab/data/icons/operations/constant_divide.svg +109 -0
  176. datalab/data/icons/operations/constant_multiply.svg +109 -0
  177. datalab/data/icons/operations/constant_subtract.svg +109 -0
  178. datalab/data/icons/operations/convert_dtype.svg +117 -0
  179. datalab/data/icons/operations/convolution.svg +46 -0
  180. datalab/data/icons/operations/deconvolution.svg +57 -0
  181. datalab/data/icons/operations/derivative.svg +127 -0
  182. datalab/data/icons/operations/difference.svg +52 -0
  183. datalab/data/icons/operations/division.svg +139 -0
  184. datalab/data/icons/operations/exp.svg +116 -0
  185. datalab/data/icons/operations/flip_horizontally.svg +69 -0
  186. datalab/data/icons/operations/flip_vertically.svg +74 -0
  187. datalab/data/icons/operations/im.svg +124 -0
  188. datalab/data/icons/operations/integral.svg +50 -0
  189. datalab/data/icons/operations/inverse.svg +143 -0
  190. datalab/data/icons/operations/log10.svg +109 -0
  191. datalab/data/icons/operations/phase.svg +116 -0
  192. datalab/data/icons/operations/power.svg +118 -0
  193. datalab/data/icons/operations/product.svg +124 -0
  194. datalab/data/icons/operations/profile.svg +379 -0
  195. datalab/data/icons/operations/profile_average.svg +399 -0
  196. datalab/data/icons/operations/profile_radial.svg +261 -0
  197. datalab/data/icons/operations/profile_segment.svg +262 -0
  198. datalab/data/icons/operations/quadratic_difference.svg +84 -0
  199. datalab/data/icons/operations/re.svg +124 -0
  200. datalab/data/icons/operations/rotate_left.svg +72 -0
  201. datalab/data/icons/operations/rotate_right.svg +72 -0
  202. datalab/data/icons/operations/signals_to_image.svg +314 -0
  203. datalab/data/icons/operations/sqrt.svg +110 -0
  204. datalab/data/icons/operations/std.svg +124 -0
  205. datalab/data/icons/operations/sum.svg +102 -0
  206. datalab/data/icons/play_demo.svg +9 -0
  207. datalab/data/icons/processing/axis_transform.svg +62 -0
  208. datalab/data/icons/processing/bandpass.svg +79 -0
  209. datalab/data/icons/processing/bandstop.svg +71 -0
  210. datalab/data/icons/processing/binning.svg +126 -0
  211. datalab/data/icons/processing/clip.svg +119 -0
  212. datalab/data/icons/processing/detrending.svg +173 -0
  213. datalab/data/icons/processing/distribute_on_grid.svg +769 -0
  214. datalab/data/icons/processing/edge_detection.svg +46 -0
  215. datalab/data/icons/processing/erase.svg +1 -0
  216. datalab/data/icons/processing/exposure.svg +143 -0
  217. datalab/data/icons/processing/fourier.svg +104 -0
  218. datalab/data/icons/processing/highpass.svg +59 -0
  219. datalab/data/icons/processing/interpolation.svg +71 -0
  220. datalab/data/icons/processing/level_adjustment.svg +70 -0
  221. datalab/data/icons/processing/lowpass.svg +60 -0
  222. datalab/data/icons/processing/morphology.svg +49 -0
  223. datalab/data/icons/processing/noise_addition.svg +114 -0
  224. datalab/data/icons/processing/noise_reduction.svg +38 -0
  225. datalab/data/icons/processing/normalize.svg +84 -0
  226. datalab/data/icons/processing/offset_correction.svg +131 -0
  227. datalab/data/icons/processing/resampling1d.svg +101 -0
  228. datalab/data/icons/processing/resampling2d.svg +240 -0
  229. datalab/data/icons/processing/reset_positions.svg +185 -0
  230. datalab/data/icons/processing/resize.svg +9 -0
  231. datalab/data/icons/processing/reverse_signal_x.svg +171 -0
  232. datalab/data/icons/processing/stability.svg +11 -0
  233. datalab/data/icons/processing/swap_x_y.svg +65 -0
  234. datalab/data/icons/processing/thresholding.svg +63 -0
  235. datalab/data/icons/processing/windowing.svg +45 -0
  236. datalab/data/icons/properties.svg +26 -0
  237. datalab/data/icons/reset.svg +9 -0
  238. datalab/data/icons/restore.svg +40 -0
  239. datalab/data/icons/roi/roi.svg +76 -0
  240. datalab/data/icons/roi/roi_coordinate.svg +78 -0
  241. datalab/data/icons/roi/roi_copy.svg +112 -0
  242. datalab/data/icons/roi/roi_delete.svg +81 -0
  243. datalab/data/icons/roi/roi_export.svg +87 -0
  244. datalab/data/icons/roi/roi_graphical.svg +78 -0
  245. datalab/data/icons/roi/roi_grid.svg +67 -0
  246. datalab/data/icons/roi/roi_ima.svg +188 -0
  247. datalab/data/icons/roi/roi_import.svg +87 -0
  248. datalab/data/icons/roi/roi_new.svg +81 -0
  249. datalab/data/icons/roi/roi_new_circle.svg +95 -0
  250. datalab/data/icons/roi/roi_new_polygon.svg +110 -0
  251. datalab/data/icons/roi/roi_new_rectangle.svg +70 -0
  252. datalab/data/icons/roi/roi_paste.svg +98 -0
  253. datalab/data/icons/roi/roi_sig.svg +124 -0
  254. datalab/data/icons/shapes.svg +134 -0
  255. datalab/data/icons/signal.svg +103 -0
  256. datalab/data/icons/table.svg +85 -0
  257. datalab/data/icons/table_unavailable.svg +102 -0
  258. datalab/data/icons/to_signal.svg +124 -0
  259. datalab/data/icons/tour/next.svg +44 -0
  260. datalab/data/icons/tour/previous.svg +44 -0
  261. datalab/data/icons/tour/rewind.svg +51 -0
  262. datalab/data/icons/tour/stop.svg +47 -0
  263. datalab/data/icons/tour/tour.svg +16 -0
  264. datalab/data/icons/uncheck_all.svg +78 -0
  265. datalab/data/icons/view/curve_antialiasing.svg +50 -0
  266. datalab/data/icons/view/new_window.svg +98 -0
  267. datalab/data/icons/view/refresh-auto.svg +57 -0
  268. datalab/data/icons/view/refresh-manual.svg +51 -0
  269. datalab/data/icons/view/reset_curve_styles.svg +96 -0
  270. datalab/data/icons/view/show_first.svg +55 -0
  271. datalab/data/icons/view/show_titles.svg +46 -0
  272. datalab/data/icons/visualization.svg +51 -0
  273. datalab/data/logo/DataLab-Banner-150.png +0 -0
  274. datalab/data/logo/DataLab-Banner-200.png +0 -0
  275. datalab/data/logo/DataLab-Banner2-100.png +0 -0
  276. datalab/data/logo/DataLab-Splash.png +0 -0
  277. datalab/data/logo/DataLab-watermark.png +0 -0
  278. datalab/data/logo/DataLab.svg +83 -0
  279. datalab/data/tests/reordering_test.h5 +0 -0
  280. datalab/data/tutorials/fabry_perot/fabry-perot1.jpg +0 -0
  281. datalab/data/tutorials/fabry_perot/fabry-perot2.jpg +0 -0
  282. datalab/data/tutorials/laser_beam/TEM00_z_13.jpg +0 -0
  283. datalab/data/tutorials/laser_beam/TEM00_z_18.jpg +0 -0
  284. datalab/data/tutorials/laser_beam/TEM00_z_23.jpg +0 -0
  285. datalab/data/tutorials/laser_beam/TEM00_z_30.jpg +0 -0
  286. datalab/data/tutorials/laser_beam/TEM00_z_35.jpg +0 -0
  287. datalab/data/tutorials/laser_beam/TEM00_z_40.jpg +0 -0
  288. datalab/data/tutorials/laser_beam/TEM00_z_45.jpg +0 -0
  289. datalab/data/tutorials/laser_beam/TEM00_z_50.jpg +0 -0
  290. datalab/data/tutorials/laser_beam/TEM00_z_55.jpg +0 -0
  291. datalab/data/tutorials/laser_beam/TEM00_z_60.jpg +0 -0
  292. datalab/data/tutorials/laser_beam/TEM00_z_65.jpg +0 -0
  293. datalab/data/tutorials/laser_beam/TEM00_z_70.jpg +0 -0
  294. datalab/data/tutorials/laser_beam/TEM00_z_75.jpg +0 -0
  295. datalab/data/tutorials/laser_beam/TEM00_z_80.jpg +0 -0
  296. datalab/env.py +542 -0
  297. datalab/gui/__init__.py +89 -0
  298. datalab/gui/actionhandler.py +1701 -0
  299. datalab/gui/docks.py +473 -0
  300. datalab/gui/h5io.py +150 -0
  301. datalab/gui/macroeditor.py +310 -0
  302. datalab/gui/main.py +2081 -0
  303. datalab/gui/newobject.py +217 -0
  304. datalab/gui/objectview.py +766 -0
  305. datalab/gui/panel/__init__.py +48 -0
  306. datalab/gui/panel/base.py +3254 -0
  307. datalab/gui/panel/image.py +157 -0
  308. datalab/gui/panel/macro.py +607 -0
  309. datalab/gui/panel/signal.py +164 -0
  310. datalab/gui/plothandler.py +800 -0
  311. datalab/gui/processor/__init__.py +84 -0
  312. datalab/gui/processor/base.py +2456 -0
  313. datalab/gui/processor/catcher.py +75 -0
  314. datalab/gui/processor/image.py +1214 -0
  315. datalab/gui/processor/signal.py +755 -0
  316. datalab/gui/profiledialog.py +333 -0
  317. datalab/gui/roieditor.py +633 -0
  318. datalab/gui/roigrideditor.py +208 -0
  319. datalab/gui/settings.py +612 -0
  320. datalab/gui/tour.py +908 -0
  321. datalab/h5/__init__.py +12 -0
  322. datalab/h5/common.py +314 -0
  323. datalab/h5/generic.py +580 -0
  324. datalab/h5/native.py +39 -0
  325. datalab/h5/utils.py +95 -0
  326. datalab/objectmodel.py +640 -0
  327. datalab/plugins/_readme_.txt +9 -0
  328. datalab/plugins/datalab_imageformats.py +175 -0
  329. datalab/plugins/datalab_testdata.py +190 -0
  330. datalab/plugins.py +355 -0
  331. datalab/tests/__init__.py +199 -0
  332. datalab/tests/backbone/__init__.py +1 -0
  333. datalab/tests/backbone/config_unit_test.py +170 -0
  334. datalab/tests/backbone/config_versioning_unit_test.py +34 -0
  335. datalab/tests/backbone/dictlistserial_app_test.py +38 -0
  336. datalab/tests/backbone/errorcatcher_unit_test.py +69 -0
  337. datalab/tests/backbone/errormsgbox_unit_test.py +50 -0
  338. datalab/tests/backbone/execenv_unit.py +262 -0
  339. datalab/tests/backbone/loadtest_gdi.py +147 -0
  340. datalab/tests/backbone/long_callback.py +96 -0
  341. datalab/tests/backbone/main_app_test.py +137 -0
  342. datalab/tests/backbone/memory_leak.py +43 -0
  343. datalab/tests/backbone/procisolation1_unit.py +128 -0
  344. datalab/tests/backbone/procisolation2_unit.py +171 -0
  345. datalab/tests/backbone/procisolation_unit_test.py +22 -0
  346. datalab/tests/backbone/profiling_app.py +27 -0
  347. datalab/tests/backbone/strings_unit_test.py +65 -0
  348. datalab/tests/backbone/title_formatting_unit_test.py +82 -0
  349. datalab/tests/conftest.py +131 -0
  350. datalab/tests/features/__init__.py +1 -0
  351. datalab/tests/features/applauncher/__init__.py +1 -0
  352. datalab/tests/features/applauncher/launcher1_app_test.py +28 -0
  353. datalab/tests/features/applauncher/launcher2_app_test.py +30 -0
  354. datalab/tests/features/common/__init__.py +1 -0
  355. datalab/tests/features/common/add_metadata_app_test.py +134 -0
  356. datalab/tests/features/common/add_metadata_unit_test.py +267 -0
  357. datalab/tests/features/common/annotations_management_unit_test.py +152 -0
  358. datalab/tests/features/common/auto_analysis_recompute_unit_test.py +240 -0
  359. datalab/tests/features/common/createobject_unit_test.py +50 -0
  360. datalab/tests/features/common/geometry_results_app_test.py +135 -0
  361. datalab/tests/features/common/interactive_processing_test.py +1109 -0
  362. datalab/tests/features/common/io_app_test.py +75 -0
  363. datalab/tests/features/common/large_results_app_test.py +187 -0
  364. datalab/tests/features/common/metadata_all_patterns_test.py +103 -0
  365. datalab/tests/features/common/metadata_app_test.py +139 -0
  366. datalab/tests/features/common/metadata_io_unit_test.py +60 -0
  367. datalab/tests/features/common/misc_app_test.py +236 -0
  368. datalab/tests/features/common/multiple_geometry_results_unit_test.py +122 -0
  369. datalab/tests/features/common/multiple_table_results_unit_test.py +64 -0
  370. datalab/tests/features/common/operation_modes_app_test.py +392 -0
  371. datalab/tests/features/common/plot_results_app_test.py +278 -0
  372. datalab/tests/features/common/reorder_app_test.py +75 -0
  373. datalab/tests/features/common/result_deletion_unit_test.py +96 -0
  374. datalab/tests/features/common/result_merged_label_unit_test.py +154 -0
  375. datalab/tests/features/common/result_shape_settings_unit_test.py +223 -0
  376. datalab/tests/features/common/roi_plotitem_unit_test.py +64 -0
  377. datalab/tests/features/common/roieditor_unit_test.py +102 -0
  378. datalab/tests/features/common/save_to_dir_app_test.py +163 -0
  379. datalab/tests/features/common/save_to_dir_unit_test.py +474 -0
  380. datalab/tests/features/common/stat_app_test.py +40 -0
  381. datalab/tests/features/common/stats_tools_unit_test.py +77 -0
  382. datalab/tests/features/common/table_results_app_test.py +52 -0
  383. datalab/tests/features/common/textimport_unit_test.py +131 -0
  384. datalab/tests/features/common/uuid_preservation_test.py +281 -0
  385. datalab/tests/features/common/worker_unit_test.py +402 -0
  386. datalab/tests/features/control/__init__.py +1 -0
  387. datalab/tests/features/control/connect_dialog.py +28 -0
  388. datalab/tests/features/control/embedded1_unit_test.py +304 -0
  389. datalab/tests/features/control/embedded2_unit_test.py +52 -0
  390. datalab/tests/features/control/remoteclient_app_test.py +219 -0
  391. datalab/tests/features/control/remoteclient_unit.py +75 -0
  392. datalab/tests/features/control/simpleclient_unit_test.py +321 -0
  393. datalab/tests/features/hdf5/__init__.py +1 -0
  394. datalab/tests/features/hdf5/h5browser1_unit_test.py +31 -0
  395. datalab/tests/features/hdf5/h5browser2_unit.py +55 -0
  396. datalab/tests/features/hdf5/h5browser_app_test.py +77 -0
  397. datalab/tests/features/hdf5/h5import_app_test.py +25 -0
  398. datalab/tests/features/hdf5/h5importer_app_test.py +34 -0
  399. datalab/tests/features/image/__init__.py +1 -0
  400. datalab/tests/features/image/annotations_app_test.py +28 -0
  401. datalab/tests/features/image/annotations_unit_test.py +80 -0
  402. datalab/tests/features/image/average_app_test.py +46 -0
  403. datalab/tests/features/image/background_dialog_test.py +70 -0
  404. datalab/tests/features/image/blobs_app_test.py +50 -0
  405. datalab/tests/features/image/contour_app_test.py +42 -0
  406. datalab/tests/features/image/contour_fabryperot_app_test.py +51 -0
  407. datalab/tests/features/image/denoise_app_test.py +31 -0
  408. datalab/tests/features/image/distribute_on_grid_app_test.py +95 -0
  409. datalab/tests/features/image/edges_app_test.py +31 -0
  410. datalab/tests/features/image/erase_app_test.py +21 -0
  411. datalab/tests/features/image/fft2d_app_test.py +27 -0
  412. datalab/tests/features/image/flatfield_app_test.py +40 -0
  413. datalab/tests/features/image/geometry_transform_unit_test.py +396 -0
  414. datalab/tests/features/image/imagetools_app_test.py +51 -0
  415. datalab/tests/features/image/imagetools_unit_test.py +27 -0
  416. datalab/tests/features/image/load_app_test.py +73 -0
  417. datalab/tests/features/image/morph_app_test.py +32 -0
  418. datalab/tests/features/image/offsetcorrection_app_test.py +30 -0
  419. datalab/tests/features/image/peak2d_app_test.py +53 -0
  420. datalab/tests/features/image/profile_app_test.py +73 -0
  421. datalab/tests/features/image/profile_dialog_test.py +56 -0
  422. datalab/tests/features/image/roi_app_test.py +98 -0
  423. datalab/tests/features/image/roi_circ_app_test.py +62 -0
  424. datalab/tests/features/image/roi_manipulation_app_test.py +268 -0
  425. datalab/tests/features/image/roigrid_unit_test.py +60 -0
  426. datalab/tests/features/image/side_by_side_app_test.py +52 -0
  427. datalab/tests/features/macro/__init__.py +1 -0
  428. datalab/tests/features/macro/macro_app_test.py +28 -0
  429. datalab/tests/features/macro/macroeditor_unit_test.py +102 -0
  430. datalab/tests/features/signal/__init__.py +1 -0
  431. datalab/tests/features/signal/baseline_dialog_test.py +53 -0
  432. datalab/tests/features/signal/deltax_dialog_unit_test.py +34 -0
  433. datalab/tests/features/signal/fft1d_app_test.py +26 -0
  434. datalab/tests/features/signal/filter_app_test.py +44 -0
  435. datalab/tests/features/signal/fitdialog_unit_test.py +50 -0
  436. datalab/tests/features/signal/interpolation_app_test.py +110 -0
  437. datalab/tests/features/signal/loadbigsignal_app_test.py +80 -0
  438. datalab/tests/features/signal/multiple_rois_unit_test.py +132 -0
  439. datalab/tests/features/signal/pulse_features_app_test.py +118 -0
  440. datalab/tests/features/signal/pulse_features_roi_app_test.py +55 -0
  441. datalab/tests/features/signal/roi_app_test.py +78 -0
  442. datalab/tests/features/signal/roi_manipulation_app_test.py +261 -0
  443. datalab/tests/features/signal/select_xy_cursor_unit_test.py +46 -0
  444. datalab/tests/features/signal/signalpeakdetection_dialog_test.py +33 -0
  445. datalab/tests/features/signal/signals_to_image_app_test.py +98 -0
  446. datalab/tests/features/signal/xarray_compat_app_test.py +128 -0
  447. datalab/tests/features/tour_unit_test.py +22 -0
  448. datalab/tests/features/utilities/__init__.py +1 -0
  449. datalab/tests/features/utilities/installconf_unit_test.py +21 -0
  450. datalab/tests/features/utilities/logview_app_test.py +21 -0
  451. datalab/tests/features/utilities/logview_error.py +24 -0
  452. datalab/tests/features/utilities/logview_unit_test.py +21 -0
  453. datalab/tests/features/utilities/memstatus_app_test.py +42 -0
  454. datalab/tests/features/utilities/settings_unit_test.py +88 -0
  455. datalab/tests/scenarios/__init__.py +1 -0
  456. datalab/tests/scenarios/beautiful_app.py +121 -0
  457. datalab/tests/scenarios/common.py +463 -0
  458. datalab/tests/scenarios/demo.py +212 -0
  459. datalab/tests/scenarios/example_app_test.py +47 -0
  460. datalab/tests/scenarios/scenario_h5_app_test.py +75 -0
  461. datalab/tests/scenarios/scenario_ima1_app_test.py +34 -0
  462. datalab/tests/scenarios/scenario_ima2_app_test.py +34 -0
  463. datalab/tests/scenarios/scenario_mac_app_test.py +58 -0
  464. datalab/tests/scenarios/scenario_sig1_app_test.py +36 -0
  465. datalab/tests/scenarios/scenario_sig2_app_test.py +35 -0
  466. datalab/utils/__init__.py +1 -0
  467. datalab/utils/conf.py +304 -0
  468. datalab/utils/dephash.py +105 -0
  469. datalab/utils/qthelpers.py +633 -0
  470. datalab/utils/strings.py +34 -0
  471. datalab/utils/tests.py +0 -0
  472. datalab/widgets/__init__.py +1 -0
  473. datalab/widgets/connection.py +138 -0
  474. datalab/widgets/filedialog.py +91 -0
  475. datalab/widgets/fileviewer.py +84 -0
  476. datalab/widgets/fitdialog.py +788 -0
  477. datalab/widgets/h5browser.py +1048 -0
  478. datalab/widgets/imagebackground.py +111 -0
  479. datalab/widgets/instconfviewer.py +175 -0
  480. datalab/widgets/logviewer.py +80 -0
  481. datalab/widgets/signalbaseline.py +90 -0
  482. datalab/widgets/signalcursor.py +208 -0
  483. datalab/widgets/signaldeltax.py +151 -0
  484. datalab/widgets/signalpeak.py +199 -0
  485. datalab/widgets/status.py +249 -0
  486. datalab/widgets/textimport.py +786 -0
  487. datalab/widgets/warningerror.py +223 -0
  488. datalab/widgets/wizard.py +286 -0
  489. datalab_platform-1.0.0.dist-info/METADATA +121 -0
  490. datalab_platform-1.0.0.dist-info/RECORD +494 -0
  491. datalab_platform-0.0.1.dev0.dist-info/METADATA +0 -67
  492. datalab_platform-0.0.1.dev0.dist-info/RECORD +0 -7
  493. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/WHEEL +0 -0
  494. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/entry_points.txt +0 -0
  495. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/licenses/LICENSE +0 -0
  496. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1005 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ DataLab remote control
5
+ ----------------------
6
+
7
+ This module provides utilities to control DataLab from a Python script (e.g. with
8
+ Spyder) or from a Jupyter notebook.
9
+
10
+ The :class:`RemoteClient` class provides the main interface to DataLab XML-RPC server.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import functools
16
+ import sys
17
+ import threading
18
+ import time
19
+ import warnings
20
+ from collections.abc import Callable
21
+ from typing import TYPE_CHECKING
22
+ from xmlrpc.client import Binary, ServerProxy
23
+ from xmlrpc.server import SimpleXMLRPCServer
24
+
25
+ import guidata.dataset as gds
26
+ import numpy as np
27
+ from packaging.version import Version
28
+ from qtpy import QtCore as QC
29
+ from sigima.client import utils
30
+ from sigima.objects import ImageObj, SignalObj, create_image, create_signal
31
+
32
+ import datalab
33
+ from datalab.adapters_plotpy import items_to_json, json_to_items
34
+ from datalab.config import Conf, initialize
35
+ from datalab.control.baseproxy import AbstractDLControl, BaseProxy
36
+ from datalab.env import execenv
37
+
38
+ if TYPE_CHECKING:
39
+ from datalab.gui.main import DLMainWindow
40
+
41
+ # pylint: disable=invalid-name # Allows short reference names like x, y, ...
42
+ # pylint: disable=duplicate-code
43
+
44
+
45
+ def remote_call(func: Callable) -> object:
46
+ """Decorator for method calling DataLab main window remotely"""
47
+
48
+ @functools.wraps(func)
49
+ def method_wrapper(*args, **kwargs):
50
+ """Decorator wrapper function"""
51
+ self = args[0] # extracting 'self' from method arguments
52
+ self.is_ready = False
53
+ output = func(*args, **kwargs)
54
+ while not self.is_ready:
55
+ QC.QCoreApplication.processEvents()
56
+ time.sleep(0.05)
57
+ return output
58
+
59
+ return method_wrapper
60
+
61
+
62
+ # Note: RemoteServer can't inherit from AbstractDLControl because it is a QThread
63
+ # and most of the methods are not returning expected data types
64
+
65
+
66
+ class RemoteServer(QC.QThread):
67
+ """XML-RPC server QThread"""
68
+
69
+ SIG_SERVER_PORT = QC.Signal(int)
70
+ SIG_CLOSE_APP = QC.Signal()
71
+ SIG_RAISE_WINDOW = QC.Signal()
72
+ SIG_ADD_OBJECT = QC.Signal(object, str, bool)
73
+ SIG_ADD_GROUP = QC.Signal(str, str, bool)
74
+ SIG_LOAD_FROM_FILES = QC.Signal(list)
75
+ SIG_LOAD_FROM_DIRECTORY = QC.Signal(str)
76
+ SIG_SELECT_OBJECTS = QC.Signal(list, str)
77
+ SIG_SELECT_GROUPS = QC.Signal(list, str)
78
+ SIG_SELECT_ALL_GROUPS = QC.Signal(str)
79
+ SIG_DELETE_METADATA = QC.Signal(bool, bool)
80
+ SIG_SWITCH_TO_PANEL = QC.Signal(str)
81
+ SIG_TOGGLE_AUTO_REFRESH = QC.Signal(bool)
82
+ SIG_TOGGLE_SHOW_TITLES = QC.Signal(bool)
83
+ SIG_RESET_ALL = QC.Signal()
84
+ SIG_SAVE_TO_H5 = QC.Signal(str)
85
+ SIG_OPEN_H5 = QC.Signal(list, bool, bool)
86
+ SIG_IMPORT_H5 = QC.Signal(str, bool)
87
+ SIG_CALC = QC.Signal(str, object)
88
+ SIG_RUN_MACRO = QC.Signal(str)
89
+ SIG_STOP_MACRO = QC.Signal(str)
90
+ SIG_IMPORT_MACRO_FROM_FILE = QC.Signal(str)
91
+
92
+ def __init__(self, win: DLMainWindow) -> None:
93
+ QC.QThread.__init__(self)
94
+ self.port: int = None
95
+ self.is_ready = True
96
+ self.server: SimpleXMLRPCServer | None = None
97
+ self.win = win
98
+ win.SIG_READY.connect(self.datalab_is_ready)
99
+ win.SIG_CLOSING.connect(self.shutdown_server)
100
+ self.SIG_CLOSE_APP.connect(win.close)
101
+ self.SIG_RAISE_WINDOW.connect(win.raise_window)
102
+ self.SIG_ADD_OBJECT.connect(win.add_object)
103
+ self.SIG_ADD_GROUP.connect(win.add_group)
104
+ self.SIG_LOAD_FROM_FILES.connect(win.load_from_files)
105
+ self.SIG_LOAD_FROM_DIRECTORY.connect(win.load_from_directory)
106
+ self.SIG_SELECT_OBJECTS.connect(win.select_objects)
107
+ self.SIG_SELECT_GROUPS.connect(win.select_groups)
108
+ self.SIG_SELECT_ALL_GROUPS.connect(lambda panel: win.select_groups(None, panel))
109
+ self.SIG_DELETE_METADATA.connect(win.delete_metadata)
110
+ self.SIG_SWITCH_TO_PANEL.connect(win.set_current_panel)
111
+ self.SIG_TOGGLE_AUTO_REFRESH.connect(win.toggle_auto_refresh)
112
+ self.SIG_TOGGLE_SHOW_TITLES.connect(win.toggle_show_titles)
113
+ self.SIG_RESET_ALL.connect(win.reset_all)
114
+ self.SIG_SAVE_TO_H5.connect(win.save_to_h5_file)
115
+ self.SIG_OPEN_H5.connect(win.open_h5_files)
116
+ self.SIG_IMPORT_H5.connect(win.import_h5_file)
117
+ self.SIG_CALC.connect(win.calc)
118
+ self.SIG_RUN_MACRO.connect(win.run_macro)
119
+ self.SIG_STOP_MACRO.connect(win.stop_macro)
120
+ self.SIG_IMPORT_MACRO_FROM_FILE.connect(win.import_macro_from_file)
121
+
122
+ def serve(self) -> None:
123
+ """Start server and serve forever"""
124
+ with SimpleXMLRPCServer(
125
+ ("127.0.0.1", 0), logRequests=False, allow_none=True
126
+ ) as server:
127
+ self.server = server
128
+ server.register_introspection_functions()
129
+ self.register_functions(server)
130
+ self.port = server.server_address[1]
131
+ self.notify_port(self.port)
132
+ with execenv.context(xmlrpcport=self.port):
133
+ server.serve_forever()
134
+
135
+ def shutdown_server(self) -> None:
136
+ """Shutdown server"""
137
+ if self.server is not None:
138
+ self.server.shutdown()
139
+ self.server = None
140
+
141
+ def notify_port(self, port: int) -> None:
142
+ """Notify automatically attributed port.
143
+
144
+ This method is called after the server port has been automatically
145
+ attributed. It notifies the port number to the main window.
146
+
147
+ Args:
148
+ port: Server port number
149
+ """
150
+ self.SIG_SERVER_PORT.emit(port)
151
+
152
+ @classmethod
153
+ def check_remote_functions(cls) -> None:
154
+ """Check if all AbstractDLControl methods are implemented in RemoteServer"""
155
+ mlist = []
156
+ for method in AbstractDLControl.get_public_methods():
157
+ if not hasattr(cls, method):
158
+ mlist.append(method)
159
+ if mlist:
160
+ raise RuntimeError(f"{cls} is missing some methods: {','.join(mlist)}")
161
+
162
+ def register_functions(self, server: SimpleXMLRPCServer) -> None:
163
+ """Register functions"""
164
+ for name in AbstractDLControl.get_public_methods():
165
+ server.register_function(getattr(self, name))
166
+
167
+ def run(self) -> None:
168
+ """Thread execution method"""
169
+ if "coverage" in sys.modules:
170
+ # The following is required to make coverage work with threading
171
+ # pylint: disable=protected-access
172
+ sys.settrace(threading._trace_hook)
173
+ self.serve()
174
+
175
+ def datalab_is_ready(self) -> None:
176
+ """Called when DataLab is ready to process new requests"""
177
+ self.is_ready = True
178
+
179
+ @staticmethod
180
+ def get_version() -> str:
181
+ """Return DataLab public version"""
182
+ return datalab.__version__
183
+
184
+ def close_application(self) -> None:
185
+ """Close DataLab application"""
186
+ self.SIG_CLOSE_APP.emit()
187
+
188
+ def raise_window(self) -> None:
189
+ """Raise DataLab window"""
190
+ self.SIG_RAISE_WINDOW.emit()
191
+
192
+ @remote_call
193
+ def get_current_panel(self) -> str:
194
+ """Return current panel name.
195
+
196
+ Returns:
197
+ Panel name (valid values: 'signal', 'image', 'macro')
198
+ """
199
+ return self.win.get_current_panel()
200
+
201
+ @remote_call
202
+ def set_current_panel(self, panel: str) -> None:
203
+ """Switch to panel.
204
+
205
+ Args:
206
+ panel: Panel name (valid values: 'signal', 'image', 'macro')
207
+ """
208
+ self.SIG_SWITCH_TO_PANEL.emit(panel)
209
+
210
+ @remote_call
211
+ def toggle_auto_refresh(self, state: bool) -> None:
212
+ """Toggle auto refresh state.
213
+
214
+ Args:
215
+ state: True to enable auto refresh, False to disable it
216
+ """
217
+ self.SIG_TOGGLE_AUTO_REFRESH.emit(state)
218
+
219
+ @remote_call
220
+ def toggle_show_titles(self, state: bool) -> None:
221
+ """Toggle show titles state.
222
+
223
+ Args:
224
+ state: True to enable show titles, False to disable it
225
+ """
226
+ self.SIG_TOGGLE_SHOW_TITLES.emit(state)
227
+
228
+ @remote_call
229
+ def reset_all(self) -> None:
230
+ """Reset all application data"""
231
+ self.SIG_RESET_ALL.emit()
232
+
233
+ @remote_call
234
+ def save_to_h5_file(self, filename: str) -> None:
235
+ """Save to a DataLab HDF5 file.
236
+
237
+ Args:
238
+ filename: HDF5 file name (with extension .h5)
239
+ """
240
+ self.SIG_SAVE_TO_H5.emit(filename)
241
+
242
+ @remote_call
243
+ def open_h5_files(
244
+ self,
245
+ h5files: list[str] | None = None,
246
+ import_all: bool | None = None,
247
+ reset_all: bool | None = None,
248
+ ) -> None:
249
+ """Open a DataLab HDF5 file or import from any other HDF5 file.
250
+
251
+ Args:
252
+ h5files: HDF5 file names. Defaults to None.
253
+ import_all: Import all objects from HDF5 file. Defaults to None.
254
+ reset_all: Reset all application data. Defaults to None.
255
+ """
256
+ import_all = True if import_all is None else import_all
257
+ reset_all = False if reset_all is None else reset_all
258
+ self.SIG_OPEN_H5.emit(h5files, import_all, reset_all)
259
+
260
+ @remote_call
261
+ def import_h5_file(self, filename: str, reset_all: bool | None = None) -> None:
262
+ """Open DataLab HDF5 browser to Import HDF5 file.
263
+
264
+ Args:
265
+ filename: HDF5 file name
266
+ reset_all: Reset all application data. Defaults to None.
267
+ """
268
+ reset_all = False if reset_all is None else reset_all
269
+ self.SIG_IMPORT_H5.emit(filename, reset_all)
270
+
271
+ @remote_call
272
+ def load_from_files(self, filenames: list[str]) -> None:
273
+ """Open objects from files in current panel (signals/images).
274
+
275
+ Args:
276
+ filenames: list of file names
277
+ """
278
+ self.SIG_LOAD_FROM_FILES.emit(filenames)
279
+
280
+ @remote_call
281
+ def load_from_directory(self, path: str) -> None:
282
+ """Open objects from directory in current panel (signals/images).
283
+
284
+ Args:
285
+ path: directory path
286
+ """
287
+ self.SIG_LOAD_FROM_DIRECTORY.emit(path)
288
+
289
+ @remote_call
290
+ def add_signal(
291
+ self,
292
+ title: str,
293
+ xbinary: Binary,
294
+ ybinary: Binary,
295
+ xunit: str = "",
296
+ yunit: str = "",
297
+ xlabel: str = "",
298
+ ylabel: str = "",
299
+ group_id: str = "",
300
+ set_current: bool = True,
301
+ ) -> bool: # pylint: disable=too-many-arguments
302
+ """Add signal data to DataLab.
303
+
304
+ Args:
305
+ title: Signal title
306
+ xbinary: X data
307
+ ybinary: Y data
308
+ xunit: X unit. Defaults to ""
309
+ yunit: Y unit. Defaults to ""
310
+ xlabel: X label. Defaults to ""
311
+ ylabel: Y label. Defaults to ""
312
+ group_id: group id in which to add the signal. Defaults to ""
313
+ set_current: if True, set the added signal as current
314
+
315
+ Returns:
316
+ True if successful
317
+ """
318
+ xdata = utils.rpcbinary_to_array(xbinary)
319
+ ydata = utils.rpcbinary_to_array(ybinary)
320
+ signal = create_signal(title, xdata, ydata)
321
+ signal.xunit = xunit or "" # In case xunit is None
322
+ signal.yunit = yunit or "" # In case yunit is None
323
+ signal.xlabel = xlabel or "" # In case xlabel is None
324
+ signal.ylabel = ylabel or "" # In case ylabel is None
325
+ self.SIG_ADD_OBJECT.emit(signal, group_id, set_current)
326
+ return True
327
+
328
+ @remote_call
329
+ def add_image(
330
+ self,
331
+ title: str,
332
+ zbinary: Binary,
333
+ xunit: str = "",
334
+ yunit: str = "",
335
+ zunit: str = "",
336
+ xlabel: str = "",
337
+ ylabel: str = "",
338
+ zlabel: str = "",
339
+ group_id: str = "",
340
+ set_current: bool = True,
341
+ ) -> bool: # pylint: disable=too-many-arguments
342
+ """Add image data to DataLab.
343
+
344
+ Args:
345
+ title: Image title
346
+ zbinary: Z data
347
+ xunit: X unit. Defaults to ""
348
+ yunit: Y unit. Defaults to ""
349
+ zunit: Z unit. Defaults to ""
350
+ xlabel: X label. Defaults to ""
351
+ ylabel: Y label. Defaults to ""
352
+ zlabel: Z label. Defaults to ""
353
+ group_id: group id in which to add the image. Defaults to ""
354
+ set_current: if True, set the added image as current
355
+
356
+ Returns:
357
+ True if successful
358
+ """
359
+ data = utils.rpcbinary_to_array(zbinary)
360
+ image = create_image(title, data)
361
+ image.xunit = xunit or "" # In case xunit is None
362
+ image.yunit = yunit or "" # In case yunit is None
363
+ image.zunit = zunit or "" # In case zunit is None
364
+ image.xlabel = xlabel or "" # In case xlabel is None
365
+ image.ylabel = ylabel or "" # In case ylabel is None
366
+ image.zlabel = zlabel or "" # In case zlabel is None
367
+ self.SIG_ADD_OBJECT.emit(image, group_id, set_current)
368
+ return True
369
+
370
+ @remote_call
371
+ def add_object(
372
+ self, obj_data: list[str], group_id: str = "", set_current: bool = True
373
+ ) -> bool:
374
+ """Add object to DataLab.
375
+
376
+ Args:
377
+ obj_data: Object data
378
+ group_id: Group id in which to add the object. Defaults to ""
379
+ set_current: if True, set the added object as current
380
+
381
+ Returns:
382
+ True if successful
383
+ """
384
+ obj = utils.rpcjson_to_dataset(obj_data)
385
+ self.SIG_ADD_OBJECT.emit(obj, group_id, set_current)
386
+ return True
387
+
388
+ @remote_call
389
+ def get_sel_object_uuids(self, include_groups: bool = False) -> list[str]:
390
+ """Return selected objects uuids.
391
+
392
+ Args:
393
+ include_groups: If True, also return objects from selected groups.
394
+
395
+ Returns:
396
+ List of selected objects uuids.
397
+ """
398
+ return self.win.get_sel_object_uuids(include_groups)
399
+
400
+ @remote_call
401
+ def add_group(
402
+ self, title: str, panel: str | None = None, select: bool = False
403
+ ) -> None:
404
+ """Add group to DataLab.
405
+
406
+ Args:
407
+ title: Group title
408
+ panel: Panel name (valid values: "signal", "image"). Defaults to None.
409
+ select: Select the group after creation. Defaults to False.
410
+ """
411
+ self.SIG_ADD_GROUP.emit(title, panel, select)
412
+
413
+ @remote_call
414
+ def select_objects(
415
+ self,
416
+ selection: list[int | str],
417
+ panel: str | None = None,
418
+ ) -> None:
419
+ """Select objects in current panel.
420
+
421
+ Args:
422
+ selection: List of object numbers (1 to N) or uuids to select
423
+ panel: panel name (valid values: "signal", "image").
424
+ If None, current panel is used. Defaults to None.
425
+ """
426
+ self.SIG_SELECT_OBJECTS.emit(selection, panel)
427
+
428
+ @remote_call
429
+ def select_groups(
430
+ self, selection: list[int | str] | None = None, panel: str | None = None
431
+ ) -> None:
432
+ """Select groups in current panel.
433
+
434
+ Args:
435
+ selection: List of group numbers (1 to N), or list of group uuids,
436
+ or None to select all groups. Defaults to None.
437
+ panel: panel name (valid values: "signal", "image").
438
+ If None, current panel is used. Defaults to None.
439
+ """
440
+ if selection is None:
441
+ self.SIG_SELECT_ALL_GROUPS.emit(panel)
442
+ else:
443
+ self.SIG_SELECT_GROUPS.emit(selection, panel)
444
+
445
+ @remote_call
446
+ def delete_metadata(
447
+ self, refresh_plot: bool = True, keep_roi: bool = False
448
+ ) -> None:
449
+ """Delete metadata of selected objects
450
+
451
+ Args:
452
+ refresh_plot: Refresh plot. Defaults to True.
453
+ keep_roi: Keep ROI. Defaults to False.
454
+ """
455
+ self.SIG_DELETE_METADATA.emit(refresh_plot, keep_roi)
456
+
457
+ @remote_call
458
+ def calc(self, name: str, param_data: list[str] | None = None) -> bool:
459
+ """Call computation feature ``name``
460
+
461
+ .. note::
462
+
463
+ This calls either the processor's ``compute_<name>`` method (if it exists),
464
+ or the processor's ``<name>`` computation feature (if it is registered,
465
+ using the ``run_feature`` method).
466
+ It looks for the function in all panels, starting with the current one.
467
+
468
+ Args:
469
+ name: Compute function name
470
+ param_data: Compute function parameters. Defaults to None.
471
+
472
+ Returns:
473
+ True if successful, False otherwise
474
+ """
475
+ if param_data is None:
476
+ param = None
477
+ else:
478
+ param = utils.rpcjson_to_dataset(param_data)
479
+ self.SIG_CALC.emit(name, param)
480
+ return True
481
+
482
+ @remote_call
483
+ def get_group_titles_with_object_info(
484
+ self,
485
+ ) -> tuple[list[str], list[list[str]], list[list[str]]]:
486
+ """Return groups titles and lists of inner objects uuids and titles.
487
+
488
+ Returns:
489
+ Groups titles, lists of inner objects uuids and titles
490
+ """
491
+ return self.win.get_group_titles_with_object_info()
492
+
493
+ @remote_call
494
+ def get_object_titles(self, panel: str | None = None) -> list[str]:
495
+ """Get object (signal/image) list for current panel.
496
+ Objects are sorted by group number and object index in group.
497
+
498
+ Args:
499
+ panel: panel name (valid values: "signal", "image", "macro").
500
+ If None, current data panel is used (i.e. signal or image panel).
501
+
502
+ Returns:
503
+ List of object titles
504
+ """
505
+ return self.win.get_object_titles(panel)
506
+
507
+ @remote_call
508
+ def get_object(
509
+ self,
510
+ nb_id_title: int | str | None = None,
511
+ panel: str | None = None,
512
+ ) -> list[str]:
513
+ """Get object (signal/image) from index.
514
+
515
+ Args:
516
+ nb_id_title: Object number, or object id, or object title.
517
+ Defaults to None (current object).
518
+ panel: Panel name. Defaults to None (current panel).
519
+
520
+ Returns:
521
+ Object
522
+
523
+ Raises:
524
+ KeyError: if object not found
525
+ """
526
+ obj = self.win.get_object(nb_id_title, panel)
527
+ if obj is None:
528
+ return None
529
+ return utils.dataset_to_rpcjson(obj)
530
+
531
+ @remote_call
532
+ def get_object_uuids(
533
+ self, panel: str | None = None, group: int | str | None = None
534
+ ) -> list[str]:
535
+ """Get object (signal/image) uuid list for current panel.
536
+ Objects are sorted by group number and object index in group.
537
+
538
+ Args:
539
+ panel: panel name (valid values: "signal", "image").
540
+ If None, current panel is used.
541
+ group: Group number, or group id, or group title.
542
+ Defaults to None (all groups).
543
+
544
+ Returns:
545
+ Object uuids
546
+ """
547
+ return self.win.get_object_uuids(panel, group)
548
+
549
+ @remote_call
550
+ def get_object_shapes(
551
+ self,
552
+ nb_id_title: int | str | None = None,
553
+ panel: str | None = None,
554
+ ) -> list:
555
+ """Get plot item shapes associated to object (signal/image).
556
+
557
+ Args:
558
+ nb_id_title: Object number, or object id, or object title.
559
+ Defaults to None (current object).
560
+ panel: Panel name. Defaults to None (current panel).
561
+
562
+ Returns:
563
+ List of plot item shapes
564
+ """
565
+ items = self.win.get_object_shapes(nb_id_title, panel)
566
+ return items_to_json(items)
567
+
568
+ @remote_call
569
+ def add_annotations_from_items(
570
+ self, items_json: str, refresh_plot: bool = True, panel: str | None = None
571
+ ) -> None:
572
+ """Add object annotations (annotation plot items).
573
+
574
+ Args:
575
+ items_json: JSON string of annotation items
576
+ refresh_plot: refresh plot. Defaults to True.
577
+ panel: panel name (valid values: "signal", "image").
578
+ If None, current panel is used.
579
+ """
580
+ items = json_to_items(items_json)
581
+ if items:
582
+ self.win.add_annotations_from_items(items, refresh_plot, panel)
583
+
584
+ @remote_call
585
+ def add_label_with_title(
586
+ self, title: str | None = None, panel: str | None = None
587
+ ) -> None:
588
+ """Add a label with object title on the associated plot
589
+
590
+ Args:
591
+ title: Label title. Defaults to None.
592
+ If None, the title is the object title.
593
+ panel: panel name (valid values: "signal", "image").
594
+ If None, current panel is used.
595
+ """
596
+ self.win.add_label_with_title(title, panel)
597
+
598
+ @remote_call
599
+ def run_macro(self, number_or_title: int | str | None = None) -> None:
600
+ """Run macro.
601
+
602
+ Args:
603
+ number: Number of the macro (starting at 1). Defaults to None (run
604
+ current macro, or does nothing if there is no macro).
605
+ """
606
+ self.SIG_RUN_MACRO.emit(number_or_title)
607
+
608
+ @remote_call
609
+ def stop_macro(self, number_or_title: int | str | None = None) -> None:
610
+ """Stop macro.
611
+
612
+ Args:
613
+ number: Number of the macro (starting at 1). Defaults to None (stop
614
+ current macro, or does nothing if there is no macro).
615
+ """
616
+ self.SIG_STOP_MACRO.emit(number_or_title)
617
+
618
+ @remote_call
619
+ def import_macro_from_file(self, filename: str) -> None:
620
+ """Import macro from file
621
+
622
+ Args:
623
+ filename: Filename.
624
+ """
625
+ self.SIG_IMPORT_MACRO_FROM_FILE.emit(filename)
626
+
627
+
628
+ RemoteServer.check_remote_functions()
629
+
630
+
631
+ # === Python 2.7 client side:
632
+ #
633
+ # # See doc/remotecontrol_py27.py for an almost complete Python 2.7
634
+ # # implementation of RemoteClient class
635
+ #
636
+ # import io
637
+ # from xmlrpclib import ServerProxy, Binary
638
+ # import numpy as np
639
+ # def array_to_binary(data):
640
+ # """Convert NumPy array to XML-RPC Binary object, with shape and dtype"""
641
+ # dbytes = io.BytesIO()
642
+ # np.save(dbytes, data, allow_pickle=False)
643
+ # return Binary(dbytes.getvalue())
644
+ # s = ServerProxy("http://127.0.0.1:8000")
645
+ # data = np.array([[3, 4, 5], [7, 8, 0]], dtype=np.uint16)
646
+ # s.add_image("toto", array_to_binary(data))
647
+
648
+
649
+ def get_datalab_xmlrpc_port() -> str:
650
+ """Return DataLab current XML-RPC port
651
+
652
+ Returns:
653
+ XML-RPC port
654
+
655
+ Raises:
656
+ ConnectionRefusedError: DataLab has not yet been executed
657
+ """
658
+ # The following is valid only when using Python 3.9+ with DataLab
659
+ # installed on the client side. In any other situation, please use the
660
+ # ``get_datalab_xmlrpc_port`` function from doc/remotecontrol_py27.py.
661
+ initialize()
662
+ try:
663
+ return Conf.main.rpc_server_port.get()
664
+ except RuntimeError as exc:
665
+ raise ConnectionRefusedError("DataLab has not yet been executed") from exc
666
+
667
+
668
+ class RemoteClient(BaseProxy):
669
+ """Object representing a proxy/client to DataLab XML-RPC server.
670
+ This object is used to call DataLab functions from a Python script.
671
+
672
+ Examples:
673
+ Here is a simple example of how to use RemoteClient in a Python script
674
+ or in a Jupyter notebook:
675
+
676
+ >>> from datalab.remote import RemoteClient
677
+ >>> proxy = RemoteClient()
678
+ >>> proxy.connect()
679
+ Connecting to DataLab XML-RPC server...OK (port: 28867)
680
+ >>> proxy.get_version()
681
+ '1.0.0'
682
+ >>> proxy.add_signal("toto", np.array([1., 2., 3.]), np.array([4., 5., -1.]))
683
+ True
684
+ >>> proxy.get_object_titles()
685
+ ['toto']
686
+ >>> proxy["toto"]
687
+ <sigima.objects.signal.SignalObj at 0x7f7f1c0b4a90>
688
+ >>> proxy[1]
689
+ <sigima.objects.signal.SignalObj at 0x7f7f1c0b4a90>
690
+ >>> proxy[1].data
691
+ array([1., 2., 3.])
692
+ """
693
+
694
+ def __init__(self) -> None:
695
+ super().__init__()
696
+ self.port: str | None = None
697
+ self._datalab: ServerProxy
698
+
699
+ def set_port(self, port: str | None = None) -> None:
700
+ """Set XML-RPC port to connect to.
701
+
702
+ Args:
703
+ port: XML-RPC port to connect to. If None, the port is automatically
704
+ retrieved from DataLab configuration.
705
+ """
706
+ execenv.print(f"Setting XML-RPC port... [input:{port}] ", end="")
707
+ port_str = ""
708
+ if port is None:
709
+ port = execenv.xmlrpcport
710
+ port_str = f"→[execenv.xmlrpcport:{port}] "
711
+ if port is None:
712
+ port = get_datalab_xmlrpc_port()
713
+ port_str = f"→[Conf.main.rpc_server_port:{port}] "
714
+ execenv.print(port_str, end="")
715
+ self.port = port
716
+ if port is None:
717
+ execenv.print("KO")
718
+ raise ConnectionRefusedError("DataLab XML-RPC port is not set")
719
+ execenv.print("OK")
720
+
721
+ def __connect_to_server(self) -> None:
722
+ """Connect to DataLab XML-RPC server.
723
+
724
+ Args:
725
+ port: XML-RPC port to connect to.
726
+
727
+ Raises:
728
+ ConnectionRefusedError: DataLab is currently not running
729
+ """
730
+ self._datalab = ServerProxy(f"http://127.0.0.1:{self.port}", allow_none=True)
731
+ try:
732
+ version = self.get_version()
733
+ except ConnectionRefusedError as exc:
734
+ raise ConnectionRefusedError("DataLab is currently not running") from exc
735
+ # If DataLab version is not compatible with this client, show a warning
736
+ server_ver = Version(version)
737
+ client_ver = Version(datalab.__version__)
738
+ if server_ver < client_ver:
739
+ warnings.warn(
740
+ f"DataLab server version ({server_ver}) may not be fully compatible "
741
+ f"with this DataLab client version ({client_ver}).\n"
742
+ f"Please upgrade the server to {client_ver} or higher."
743
+ )
744
+
745
+ def connect(
746
+ self,
747
+ port: str | None = None,
748
+ timeout: float | None = None,
749
+ retries: int | None = None,
750
+ ) -> None:
751
+ """Try to connect to DataLab XML-RPC server.
752
+
753
+ Args:
754
+ port: XML-RPC port to connect to. If not specified,
755
+ the port is automatically retrieved from DataLab configuration.
756
+ timeout: Maximum time to wait for connection in seconds. Defaults to 5.0.
757
+ This is the total maximum wait time, not per retry.
758
+ retries: Number of retries. Defaults to 10. This parameter is deprecated
759
+ and will be removed in a future version (kept for backward compatibility).
760
+
761
+ Raises:
762
+ ConnectionRefusedError: Unable to connect to DataLab
763
+ ValueError: Invalid timeout (must be >= 0.0)
764
+ ValueError: Invalid number of retries (must be >= 1)
765
+ """
766
+ timeout = 5.0 if timeout is None else timeout
767
+ retries = 10 if retries is None else retries # Kept for backward compatibility
768
+ if timeout < 0.0:
769
+ raise ValueError("timeout must be >= 0.0")
770
+ if retries < 1:
771
+ raise ValueError("retries must be >= 1")
772
+
773
+ execenv.print(f"Connecting to DataLab XML-RPC server... [port:{port}] ", end="")
774
+
775
+ # Use exponential backoff for more efficient retrying
776
+ start_time = time.time()
777
+ poll_interval = 0.1 # Start with 100ms
778
+ max_poll_interval = 1.0 # Cap at 1 second
779
+
780
+ while True:
781
+ try:
782
+ # Try to set the port - this may fail if DataLab hasn't written its
783
+ # config file yet, so we retry it in the loop
784
+ self.set_port(port)
785
+ self.__connect_to_server()
786
+ elapsed = time.time() - start_time
787
+ execenv.print(f"OK (port: {self.port}, connected in {elapsed:.1f}s)")
788
+ return
789
+ except (ConnectionRefusedError, OSError) as exc:
790
+ # Catch both ConnectionRefusedError and OSError (includes socket errors)
791
+ elapsed = time.time() - start_time
792
+ if elapsed >= timeout:
793
+ execenv.print("KO")
794
+ raise ConnectionRefusedError(
795
+ f"Unable to connect to DataLab after {elapsed:.1f}s"
796
+ ) from exc
797
+ # Wait before next retry with exponential backoff
798
+ time.sleep(poll_interval)
799
+ poll_interval = min(poll_interval * 1.5, max_poll_interval)
800
+
801
+ def disconnect(self) -> None:
802
+ """Disconnect from DataLab XML-RPC server."""
803
+ # This is not mandatory with XML-RPC, but if we change protocol in the
804
+ # future, it may be useful to have a disconnect method.
805
+ self._datalab = None
806
+
807
+ def is_connected(self) -> bool:
808
+ """Return True if connected to DataLab XML-RPC server."""
809
+ if self._datalab is not None:
810
+ try:
811
+ self.get_version()
812
+ return True
813
+ except ConnectionRefusedError:
814
+ self._datalab = None
815
+ return False
816
+
817
+ def get_method_list(self) -> list[str]:
818
+ """Return list of available methods."""
819
+ return self._datalab.system.listMethods()
820
+
821
+ # === Following methods should match the register functions in XML-RPC server
822
+
823
+ def add_signal(
824
+ self,
825
+ title: str,
826
+ xdata: np.ndarray,
827
+ ydata: np.ndarray,
828
+ xunit: str = "",
829
+ yunit: str = "",
830
+ xlabel: str = "",
831
+ ylabel: str = "",
832
+ group_id: str = "",
833
+ set_current: bool = True,
834
+ ) -> bool: # pylint: disable=too-many-arguments
835
+ """Add signal data to DataLab.
836
+
837
+ Args:
838
+ title: Signal title
839
+ xdata: X data
840
+ ydata: Y data
841
+ xunit: X unit. Defaults to ""
842
+ yunit: Y unit. Defaults to ""
843
+ xlabel: X label. Defaults to ""
844
+ ylabel: Y label. Defaults to ""
845
+ group_id: group id in which to add the signal. Defaults to ""
846
+ set_current: if True, set the added signal as current
847
+
848
+ Returns:
849
+ True if signal was added successfully, False otherwise
850
+
851
+ Raises:
852
+ ValueError: Invalid xdata dtype
853
+ ValueError: Invalid ydata dtype
854
+ """
855
+ obj = SignalObj()
856
+ obj.set_xydata(xdata, ydata)
857
+ obj.check_data()
858
+ xbinary = utils.array_to_rpcbinary(xdata)
859
+ ybinary = utils.array_to_rpcbinary(ydata)
860
+ return self._datalab.add_signal(
861
+ title, xbinary, ybinary, xunit, yunit, xlabel, ylabel, group_id, set_current
862
+ )
863
+
864
+ def add_image(
865
+ self,
866
+ title: str,
867
+ data: np.ndarray,
868
+ xunit: str = "",
869
+ yunit: str = "",
870
+ zunit: str = "",
871
+ xlabel: str = "",
872
+ ylabel: str = "",
873
+ zlabel: str = "",
874
+ group_id: str = "",
875
+ set_current: bool = True,
876
+ ) -> bool: # pylint: disable=too-many-arguments
877
+ """Add image data to DataLab.
878
+
879
+ Args:
880
+ title: Image title
881
+ data: Image data
882
+ xunit: X unit. Defaults to ""
883
+ yunit: Y unit. Defaults to ""
884
+ zunit: Z unit. Defaults to ""
885
+ xlabel: X label. Defaults to ""
886
+ ylabel: Y label. Defaults to ""
887
+ zlabel: Z label. Defaults to ""
888
+ group_id: group id in which to add the image. Defaults to ""
889
+ set_current: if True, set the added image as current
890
+
891
+ Returns:
892
+ True if image was added successfully, False otherwise
893
+
894
+ Raises:
895
+ ValueError: Invalid data dtype
896
+ """
897
+ obj = ImageObj()
898
+ obj.data = data
899
+ obj.check_data()
900
+ zbinary = utils.array_to_rpcbinary(data)
901
+ return self._datalab.add_image(
902
+ title,
903
+ zbinary,
904
+ xunit,
905
+ yunit,
906
+ zunit,
907
+ xlabel,
908
+ ylabel,
909
+ zlabel,
910
+ group_id,
911
+ set_current,
912
+ )
913
+
914
+ def add_object(
915
+ self,
916
+ obj: SignalObj | ImageObj,
917
+ group_id: str = "",
918
+ set_current: bool = True,
919
+ ) -> None:
920
+ """Add object to DataLab.
921
+
922
+ Args:
923
+ obj: Signal or image object
924
+ group_id: group id in which to add the object. Defaults to ""
925
+ set_current: if True, set the added object as current
926
+ """
927
+ obj_data = utils.dataset_to_rpcjson(obj)
928
+ self._datalab.add_object(obj_data, group_id, set_current)
929
+
930
+ def calc(self, name: str, param: gds.DataSet | None = None) -> None:
931
+ """Call computation feature ``name``
932
+
933
+ .. note::
934
+
935
+ This calls either the processor's ``compute_<name>`` method (if it exists),
936
+ or the processor's ``<name>`` computation feature (if it is registered,
937
+ using the ``run_feature`` method).
938
+ It looks for the function in all panels, starting with the current one.
939
+
940
+ Args:
941
+ name: Compute function name
942
+ param: Compute function parameter. Defaults to None.
943
+
944
+ Raises:
945
+ ValueError: unknown function
946
+ """
947
+ if param is None:
948
+ return self._datalab.calc(name)
949
+ return self._datalab.calc(name, utils.dataset_to_rpcjson(param))
950
+
951
+ def get_object(
952
+ self,
953
+ nb_id_title: int | str | None = None,
954
+ panel: str | None = None,
955
+ ) -> SignalObj | ImageObj:
956
+ """Get object (signal/image) from index.
957
+
958
+ Args:
959
+ nb_id_title: Object number, or object id, or object title.
960
+ Defaults to None (current object).
961
+ panel: Panel name. Defaults to None (current panel).
962
+
963
+ Returns:
964
+ Object
965
+
966
+ Raises:
967
+ KeyError: if object not found
968
+ """
969
+ param_data = self._datalab.get_object(nb_id_title, panel)
970
+ if param_data is None:
971
+ return None
972
+ return utils.rpcjson_to_dataset(param_data)
973
+
974
+ def get_object_shapes(
975
+ self,
976
+ nb_id_title: int | str | None = None,
977
+ panel: str | None = None,
978
+ ) -> list:
979
+ """Get plot item shapes associated to object (signal/image).
980
+
981
+ Args:
982
+ nb_id_title: Object number, or object id, or object title.
983
+ Defaults to None (current object).
984
+ panel: Panel name. Defaults to None (current panel).
985
+
986
+ Returns:
987
+ List of plot item shapes
988
+ """
989
+ items_json = self._datalab.get_object_shapes(nb_id_title, panel)
990
+ return json_to_items(items_json)
991
+
992
+ def add_annotations_from_items(
993
+ self, items: list, refresh_plot: bool = True, panel: str | None = None
994
+ ) -> None:
995
+ """Add object annotations (annotation plot items).
996
+
997
+ Args:
998
+ items: annotation plot items
999
+ refresh_plot: refresh plot. Defaults to True.
1000
+ panel: panel name (valid values: "signal", "image").
1001
+ If None, current panel is used.
1002
+ """
1003
+ items_json = items_to_json(items)
1004
+ if items_json is not None:
1005
+ self._datalab.add_annotations_from_items(items_json, refresh_plot, panel)