PaIRS-UniNa 0.2.5__cp313-cp313-win_amd64.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 (323) hide show
  1. PaIRS_UniNa/Calibration_Tab.py +331 -0
  2. PaIRS_UniNa/Changes.txt +110 -0
  3. PaIRS_UniNa/Custom_Top.py +303 -0
  4. PaIRS_UniNa/Explorer.py +3069 -0
  5. PaIRS_UniNa/FolderLoop.py +372 -0
  6. PaIRS_UniNa/Input_Tab.py +719 -0
  7. PaIRS_UniNa/Input_Tab_CalVi.py +788 -0
  8. PaIRS_UniNa/Input_Tab_tools.py +3023 -0
  9. PaIRS_UniNa/Log_Tab.py +110 -0
  10. PaIRS_UniNa/Output_Tab.py +924 -0
  11. PaIRS_UniNa/PaIRS.py +18 -0
  12. PaIRS_UniNa/PaIRS_PIV.py +873 -0
  13. PaIRS_UniNa/PaIRS_pypacks.py +1250 -0
  14. PaIRS_UniNa/Process_Tab.py +1757 -0
  15. PaIRS_UniNa/Process_Tab_CalVi.py +313 -0
  16. PaIRS_UniNa/Process_Tab_Disp.py +163 -0
  17. PaIRS_UniNa/Process_Tab_Min.py +120 -0
  18. PaIRS_UniNa/ResizePopup.py +55 -0
  19. PaIRS_UniNa/Saving_tools.py +296 -0
  20. PaIRS_UniNa/TabTools.py +1251 -0
  21. PaIRS_UniNa/Vis_Tab.py +2100 -0
  22. PaIRS_UniNa/Vis_Tab_CalVi.py +983 -0
  23. PaIRS_UniNa/Whatsnew.py +118 -0
  24. PaIRS_UniNa/_PaIRS_PIV.pyd +0 -0
  25. PaIRS_UniNa/__init__.py +6 -0
  26. PaIRS_UniNa/__main__.py +45 -0
  27. PaIRS_UniNa/addwidgets_ps.py +1125 -0
  28. PaIRS_UniNa/calib.py +1488 -0
  29. PaIRS_UniNa/calibView.py +826 -0
  30. PaIRS_UniNa/gPaIRS.py +3769 -0
  31. PaIRS_UniNa/gPalette.py +189 -0
  32. PaIRS_UniNa/icons/abort.png +0 -0
  33. PaIRS_UniNa/icons/about.png +0 -0
  34. PaIRS_UniNa/icons/align_all.png +0 -0
  35. PaIRS_UniNa/icons/announcement.png +0 -0
  36. PaIRS_UniNa/icons/automatic_levels_off.png +0 -0
  37. PaIRS_UniNa/icons/automatic_levels_on.png +0 -0
  38. PaIRS_UniNa/icons/automatic_off.png +0 -0
  39. PaIRS_UniNa/icons/automatic_on.png +0 -0
  40. PaIRS_UniNa/icons/automatic_size_off.png +0 -0
  41. PaIRS_UniNa/icons/automatic_size_on.png +0 -0
  42. PaIRS_UniNa/icons/axes.png +0 -0
  43. PaIRS_UniNa/icons/background.png +0 -0
  44. PaIRS_UniNa/icons/background_vectors.png +0 -0
  45. PaIRS_UniNa/icons/bin_off.png +0 -0
  46. PaIRS_UniNa/icons/bin_on.png +0 -0
  47. PaIRS_UniNa/icons/browse_file_c.png +0 -0
  48. PaIRS_UniNa/icons/browse_folder_c.png +0 -0
  49. PaIRS_UniNa/icons/brush_cursor.png +0 -0
  50. PaIRS_UniNa/icons/bugfix.png +0 -0
  51. PaIRS_UniNa/icons/cal_proc.png +0 -0
  52. PaIRS_UniNa/icons/cal_proc_off.png +0 -0
  53. PaIRS_UniNa/icons/cal_step.png +0 -0
  54. PaIRS_UniNa/icons/cal_step_off.png +0 -0
  55. PaIRS_UniNa/icons/calibrate.png +0 -0
  56. PaIRS_UniNa/icons/calibration_logo.png +0 -0
  57. PaIRS_UniNa/icons/change_folder.png +0 -0
  58. PaIRS_UniNa/icons/change_folder_off.png +0 -0
  59. PaIRS_UniNa/icons/checklist.png +0 -0
  60. PaIRS_UniNa/icons/clean.png +0 -0
  61. PaIRS_UniNa/icons/clean_run.png +0 -0
  62. PaIRS_UniNa/icons/close.png +0 -0
  63. PaIRS_UniNa/icons/close_all.png +0 -0
  64. PaIRS_UniNa/icons/close_project.png +0 -0
  65. PaIRS_UniNa/icons/close_workspace.png +0 -0
  66. PaIRS_UniNa/icons/colormap.png +0 -0
  67. PaIRS_UniNa/icons/colormaps/Accent.png +0 -0
  68. PaIRS_UniNa/icons/colormaps/BrBG.png +0 -0
  69. PaIRS_UniNa/icons/colormaps/Dark2.png +0 -0
  70. PaIRS_UniNa/icons/colormaps/PRGn.png +0 -0
  71. PaIRS_UniNa/icons/colormaps/Paired.png +0 -0
  72. PaIRS_UniNa/icons/colormaps/Pastel1.png +0 -0
  73. PaIRS_UniNa/icons/colormaps/Pastel2.png +0 -0
  74. PaIRS_UniNa/icons/colormaps/PiYG.png +0 -0
  75. PaIRS_UniNa/icons/colormaps/PuOr.png +0 -0
  76. PaIRS_UniNa/icons/colormaps/RdBu.png +0 -0
  77. PaIRS_UniNa/icons/colormaps/RdGy.png +0 -0
  78. PaIRS_UniNa/icons/colormaps/RdYlBu.png +0 -0
  79. PaIRS_UniNa/icons/colormaps/RdYlGn.png +0 -0
  80. PaIRS_UniNa/icons/colormaps/Set1.png +0 -0
  81. PaIRS_UniNa/icons/colormaps/Set2.png +0 -0
  82. PaIRS_UniNa/icons/colormaps/Set3.png +0 -0
  83. PaIRS_UniNa/icons/colormaps/Spectral.png +0 -0
  84. PaIRS_UniNa/icons/colormaps/Wistia.png +0 -0
  85. PaIRS_UniNa/icons/colormaps/afmhot.png +0 -0
  86. PaIRS_UniNa/icons/colormaps/autumn.png +0 -0
  87. PaIRS_UniNa/icons/colormaps/binary.png +0 -0
  88. PaIRS_UniNa/icons/colormaps/blackVector.png +0 -0
  89. PaIRS_UniNa/icons/colormaps/blueVector.png +0 -0
  90. PaIRS_UniNa/icons/colormaps/bone.png +0 -0
  91. PaIRS_UniNa/icons/colormaps/brg.png +0 -0
  92. PaIRS_UniNa/icons/colormaps/bwr.png +0 -0
  93. PaIRS_UniNa/icons/colormaps/cividis.png +0 -0
  94. PaIRS_UniNa/icons/colormaps/cool.png +0 -0
  95. PaIRS_UniNa/icons/colormaps/coolwarm.png +0 -0
  96. PaIRS_UniNa/icons/colormaps/copper.png +0 -0
  97. PaIRS_UniNa/icons/colormaps/cubehelix.png +0 -0
  98. PaIRS_UniNa/icons/colormaps/cyanVector.png +0 -0
  99. PaIRS_UniNa/icons/colormaps/flag.png +0 -0
  100. PaIRS_UniNa/icons/colormaps/gist_heat.png +0 -0
  101. PaIRS_UniNa/icons/colormaps/gray.png +0 -0
  102. PaIRS_UniNa/icons/colormaps/greenVector.png +0 -0
  103. PaIRS_UniNa/icons/colormaps/hot.png +0 -0
  104. PaIRS_UniNa/icons/colormaps/hsv.png +0 -0
  105. PaIRS_UniNa/icons/colormaps/inferno.png +0 -0
  106. PaIRS_UniNa/icons/colormaps/jet.png +0 -0
  107. PaIRS_UniNa/icons/colormaps/magentaVector.png +0 -0
  108. PaIRS_UniNa/icons/colormaps/magma.png +0 -0
  109. PaIRS_UniNa/icons/colormaps/ocean.png +0 -0
  110. PaIRS_UniNa/icons/colormaps/pink.png +0 -0
  111. PaIRS_UniNa/icons/colormaps/plasma.png +0 -0
  112. PaIRS_UniNa/icons/colormaps/prism.png +0 -0
  113. PaIRS_UniNa/icons/colormaps/rainbow.png +0 -0
  114. PaIRS_UniNa/icons/colormaps/redVector.png +0 -0
  115. PaIRS_UniNa/icons/colormaps/seismic.png +0 -0
  116. PaIRS_UniNa/icons/colormaps/spring.png +0 -0
  117. PaIRS_UniNa/icons/colormaps/summer.png +0 -0
  118. PaIRS_UniNa/icons/colormaps/tab10.png +0 -0
  119. PaIRS_UniNa/icons/colormaps/tab20.png +0 -0
  120. PaIRS_UniNa/icons/colormaps/tab20b.png +0 -0
  121. PaIRS_UniNa/icons/colormaps/tab20c.png +0 -0
  122. PaIRS_UniNa/icons/colormaps/terrain.png +0 -0
  123. PaIRS_UniNa/icons/colormaps/twilight.png +0 -0
  124. PaIRS_UniNa/icons/colormaps/viridis.png +0 -0
  125. PaIRS_UniNa/icons/colormaps/whiteVector.png +0 -0
  126. PaIRS_UniNa/icons/colormaps/winter.png +0 -0
  127. PaIRS_UniNa/icons/colormaps/yellowVector.png +0 -0
  128. PaIRS_UniNa/icons/common_region.png +0 -0
  129. PaIRS_UniNa/icons/common_region_off.png +0 -0
  130. PaIRS_UniNa/icons/completed.png +0 -0
  131. PaIRS_UniNa/icons/contourf_off.png +0 -0
  132. PaIRS_UniNa/icons/contourf_on.png +0 -0
  133. PaIRS_UniNa/icons/copy.png +0 -0
  134. PaIRS_UniNa/icons/copy_process.png +0 -0
  135. PaIRS_UniNa/icons/copy_process_off.png +0 -0
  136. PaIRS_UniNa/icons/copygrid.png +0 -0
  137. PaIRS_UniNa/icons/cursor_lamp.png +0 -0
  138. PaIRS_UniNa/icons/cut.png +0 -0
  139. PaIRS_UniNa/icons/cut_warnings.png +0 -0
  140. PaIRS_UniNa/icons/darkmode.png +0 -0
  141. PaIRS_UniNa/icons/debug_run.png +0 -0
  142. PaIRS_UniNa/icons/delete.png +0 -0
  143. PaIRS_UniNa/icons/deleteErr.png +0 -0
  144. PaIRS_UniNa/icons/disp_step.png +0 -0
  145. PaIRS_UniNa/icons/disp_step_off.png +0 -0
  146. PaIRS_UniNa/icons/down.png +0 -0
  147. PaIRS_UniNa/icons/edit_list.png +0 -0
  148. PaIRS_UniNa/icons/editing.png +0 -0
  149. PaIRS_UniNa/icons/example_list.png +0 -0
  150. PaIRS_UniNa/icons/find_all_planes.png +0 -0
  151. PaIRS_UniNa/icons/find_plane.png +0 -0
  152. PaIRS_UniNa/icons/flaticon_PaIRS.png +0 -0
  153. PaIRS_UniNa/icons/flaticon_PaIRS_beta.png +0 -0
  154. PaIRS_UniNa/icons/flaticon_PaIRS_download.png +0 -0
  155. PaIRS_UniNa/icons/flip_y_off.png +0 -0
  156. PaIRS_UniNa/icons/flip_y_on.png +0 -0
  157. PaIRS_UniNa/icons/focusErrr.png +0 -0
  158. PaIRS_UniNa/icons/gear.gif +0 -0
  159. PaIRS_UniNa/icons/gear.png +0 -0
  160. PaIRS_UniNa/icons/ger.png +0 -0
  161. PaIRS_UniNa/icons/greenv.png +0 -0
  162. PaIRS_UniNa/icons/guide.png +0 -0
  163. PaIRS_UniNa/icons/icon_CalVi.png +0 -0
  164. PaIRS_UniNa/icons/icon_PaIRS.png +0 -0
  165. PaIRS_UniNa/icons/import.png +0 -0
  166. PaIRS_UniNa/icons/import_set.png +0 -0
  167. PaIRS_UniNa/icons/information.png +0 -0
  168. PaIRS_UniNa/icons/input_logo.png +0 -0
  169. PaIRS_UniNa/icons/issue.png +0 -0
  170. PaIRS_UniNa/icons/laser_NTR.png +0 -0
  171. PaIRS_UniNa/icons/laser_TR_double.png +0 -0
  172. PaIRS_UniNa/icons/laser_TR_single.png +0 -0
  173. PaIRS_UniNa/icons/link.png +0 -0
  174. PaIRS_UniNa/icons/linked.png +0 -0
  175. PaIRS_UniNa/icons/loaded.png +0 -0
  176. PaIRS_UniNa/icons/loading_2.gif +0 -0
  177. PaIRS_UniNa/icons/log_logo.png +0 -0
  178. PaIRS_UniNa/icons/logo_CalVi.png +0 -0
  179. PaIRS_UniNa/icons/logo_CalVi_completo.png +0 -0
  180. PaIRS_UniNa/icons/logo_CalVi_party.png +0 -0
  181. PaIRS_UniNa/icons/logo_PaIRS.png +0 -0
  182. PaIRS_UniNa/icons/logo_PaIRS_completo.png +0 -0
  183. PaIRS_UniNa/icons/logo_PaIRS_download.png +0 -0
  184. PaIRS_UniNa/icons/logo_PaIRS_party_rect.png +0 -0
  185. PaIRS_UniNa/icons/logo_PaIRS_rect.png +0 -0
  186. PaIRS_UniNa/icons/logo_opaco.png +0 -0
  187. PaIRS_UniNa/icons/mask.png +0 -0
  188. PaIRS_UniNa/icons/measure.png +0 -0
  189. PaIRS_UniNa/icons/measure_off.png +0 -0
  190. PaIRS_UniNa/icons/min_proc.png +0 -0
  191. PaIRS_UniNa/icons/min_proc_off.png +0 -0
  192. PaIRS_UniNa/icons/min_step.png +0 -0
  193. PaIRS_UniNa/icons/min_step_off.png +0 -0
  194. PaIRS_UniNa/icons/minus.png +0 -0
  195. PaIRS_UniNa/icons/mirror_u.png +0 -0
  196. PaIRS_UniNa/icons/mirror_v.png +0 -0
  197. PaIRS_UniNa/icons/mirror_x.png +0 -0
  198. PaIRS_UniNa/icons/mirror_y.png +0 -0
  199. PaIRS_UniNa/icons/mtplt.png +0 -0
  200. PaIRS_UniNa/icons/new.png +0 -0
  201. PaIRS_UniNa/icons/new_workspace.png +0 -0
  202. PaIRS_UniNa/icons/news.png +0 -0
  203. PaIRS_UniNa/icons/normal_run.png +0 -0
  204. PaIRS_UniNa/icons/open.png +0 -0
  205. PaIRS_UniNa/icons/open_image.png +0 -0
  206. PaIRS_UniNa/icons/open_new_window.png +0 -0
  207. PaIRS_UniNa/icons/open_result.png +0 -0
  208. PaIRS_UniNa/icons/open_workspace.png +0 -0
  209. PaIRS_UniNa/icons/output_logo.png +0 -0
  210. PaIRS_UniNa/icons/paste_above.png +0 -0
  211. PaIRS_UniNa/icons/paste_below.png +0 -0
  212. PaIRS_UniNa/icons/pause.png +0 -0
  213. PaIRS_UniNa/icons/paused.png +0 -0
  214. PaIRS_UniNa/icons/piv_proc.png +0 -0
  215. PaIRS_UniNa/icons/piv_proc_off.png +0 -0
  216. PaIRS_UniNa/icons/piv_step.png +0 -0
  217. PaIRS_UniNa/icons/piv_step_off.png +0 -0
  218. PaIRS_UniNa/icons/plane.png +0 -0
  219. PaIRS_UniNa/icons/play.png +0 -0
  220. PaIRS_UniNa/icons/plus.png +0 -0
  221. PaIRS_UniNa/icons/process_logo.png +0 -0
  222. PaIRS_UniNa/icons/process_loop.png +0 -0
  223. PaIRS_UniNa/icons/project.png +0 -0
  224. PaIRS_UniNa/icons/pylog.png +0 -0
  225. PaIRS_UniNa/icons/python_warning.png +0 -0
  226. PaIRS_UniNa/icons/queue.png +0 -0
  227. PaIRS_UniNa/icons/quit.png +0 -0
  228. PaIRS_UniNa/icons/read.png +0 -0
  229. PaIRS_UniNa/icons/read_list.png +0 -0
  230. PaIRS_UniNa/icons/redo.png +0 -0
  231. PaIRS_UniNa/icons/redx.png +0 -0
  232. PaIRS_UniNa/icons/reset.png +0 -0
  233. PaIRS_UniNa/icons/reset_levels.png +0 -0
  234. PaIRS_UniNa/icons/resize_icon.png +0 -0
  235. PaIRS_UniNa/icons/restore.png +0 -0
  236. PaIRS_UniNa/icons/restore_undo.png +0 -0
  237. PaIRS_UniNa/icons/rotate_clock.png +0 -0
  238. PaIRS_UniNa/icons/rotate_counter.png +0 -0
  239. PaIRS_UniNa/icons/rotate_v_clock.png +0 -0
  240. PaIRS_UniNa/icons/rotate_v_counter.png +0 -0
  241. PaIRS_UniNa/icons/running.gif +0 -0
  242. PaIRS_UniNa/icons/running.png +0 -0
  243. PaIRS_UniNa/icons/running_warn.png +0 -0
  244. PaIRS_UniNa/icons/sandglass.png +0 -0
  245. PaIRS_UniNa/icons/save.png +0 -0
  246. PaIRS_UniNa/icons/save_and_stop.png +0 -0
  247. PaIRS_UniNa/icons/save_cfg.png +0 -0
  248. PaIRS_UniNa/icons/saveas.png +0 -0
  249. PaIRS_UniNa/icons/saveas_workspace.png +0 -0
  250. PaIRS_UniNa/icons/scale_all.png +0 -0
  251. PaIRS_UniNa/icons/scale_down.png +0 -0
  252. PaIRS_UniNa/icons/scale_up.png +0 -0
  253. PaIRS_UniNa/icons/scan_list.png +0 -0
  254. PaIRS_UniNa/icons/scan_path.png +0 -0
  255. PaIRS_UniNa/icons/search.png +0 -0
  256. PaIRS_UniNa/icons/showIW_off.png +0 -0
  257. PaIRS_UniNa/icons/showIW_on.png +0 -0
  258. PaIRS_UniNa/icons/show_all.png +0 -0
  259. PaIRS_UniNa/icons/sort.png +0 -0
  260. PaIRS_UniNa/icons/sort_reversed.png +0 -0
  261. PaIRS_UniNa/icons/spiv_proc.png +0 -0
  262. PaIRS_UniNa/icons/spiv_proc_off.png +0 -0
  263. PaIRS_UniNa/icons/star.png +0 -0
  264. PaIRS_UniNa/icons/step_inheritance.png +0 -0
  265. PaIRS_UniNa/icons/subMIN_off.png +0 -0
  266. PaIRS_UniNa/icons/subMIN_on.png +0 -0
  267. PaIRS_UniNa/icons/tom.png +0 -0
  268. PaIRS_UniNa/icons/trash.png +0 -0
  269. PaIRS_UniNa/icons/undo.png +0 -0
  270. PaIRS_UniNa/icons/unedited.png +0 -0
  271. PaIRS_UniNa/icons/unina_dii.png +0 -0
  272. PaIRS_UniNa/icons/uninitialized.png +0 -0
  273. PaIRS_UniNa/icons/unlink.png +0 -0
  274. PaIRS_UniNa/icons/unwrap_items.png +0 -0
  275. PaIRS_UniNa/icons/up.png +0 -0
  276. PaIRS_UniNa/icons/updating_import.gif +0 -0
  277. PaIRS_UniNa/icons/updating_pairs.gif +0 -0
  278. PaIRS_UniNa/icons/vectorColor.png +0 -0
  279. PaIRS_UniNa/icons/vettore.png +0 -0
  280. PaIRS_UniNa/icons/view.png +0 -0
  281. PaIRS_UniNa/icons/view_off.png +0 -0
  282. PaIRS_UniNa/icons/vis_logo.png +0 -0
  283. PaIRS_UniNa/icons/waiting_circle.png +0 -0
  284. PaIRS_UniNa/icons/warning.png +0 -0
  285. PaIRS_UniNa/icons/warning_circle.png +0 -0
  286. PaIRS_UniNa/icons/window.png +0 -0
  287. PaIRS_UniNa/icons/workspace.png +0 -0
  288. PaIRS_UniNa/icons/wrap_items.png +0 -0
  289. PaIRS_UniNa/icons/write_list.png +0 -0
  290. PaIRS_UniNa/listLib.py +303 -0
  291. PaIRS_UniNa/mtfPIV.py +256 -0
  292. PaIRS_UniNa/parForMulti.py +435 -0
  293. PaIRS_UniNa/parForWorkers.py +593 -0
  294. PaIRS_UniNa/pivParFor.py +235 -0
  295. PaIRS_UniNa/plt_util.py +141 -0
  296. PaIRS_UniNa/preProcParFor.py +155 -0
  297. PaIRS_UniNa/procTools.py +1391 -0
  298. PaIRS_UniNa/readcfg.py +52 -0
  299. PaIRS_UniNa/rqrdpckgs.txt +8 -0
  300. PaIRS_UniNa/stereoPivParFor.py +227 -0
  301. PaIRS_UniNa/tAVarie.py +215 -0
  302. PaIRS_UniNa/tabSplitter.py +612 -0
  303. PaIRS_UniNa/ui_Calibration_Tab.py +545 -0
  304. PaIRS_UniNa/ui_Custom_Top.py +296 -0
  305. PaIRS_UniNa/ui_Input_Tab.py +1101 -0
  306. PaIRS_UniNa/ui_Input_Tab_CalVi.py +1283 -0
  307. PaIRS_UniNa/ui_Log_Tab.py +263 -0
  308. PaIRS_UniNa/ui_Output_Tab.py +2362 -0
  309. PaIRS_UniNa/ui_Process_Tab.py +3810 -0
  310. PaIRS_UniNa/ui_Process_Tab_CalVi.py +1549 -0
  311. PaIRS_UniNa/ui_Process_Tab_Disp.py +1141 -0
  312. PaIRS_UniNa/ui_Process_Tab_Min.py +437 -0
  313. PaIRS_UniNa/ui_ResizePopup.py +204 -0
  314. PaIRS_UniNa/ui_Vis_Tab.py +1628 -0
  315. PaIRS_UniNa/ui_Vis_Tab_CalVi.py +1251 -0
  316. PaIRS_UniNa/ui_Whatsnew.py +132 -0
  317. PaIRS_UniNa/ui_gPairs.py +871 -0
  318. PaIRS_UniNa/ui_infoPaIRS.py +551 -0
  319. PaIRS_UniNa/whatsnew.txt +6 -0
  320. pairs_unina-0.2.5.dist-info/METADATA +151 -0
  321. pairs_unina-0.2.5.dist-info/RECORD +323 -0
  322. pairs_unina-0.2.5.dist-info/WHEEL +5 -0
  323. pairs_unina-0.2.5.dist-info/top_level.txt +2 -0
@@ -0,0 +1,1250 @@
1
+ from math import ceil, floor
2
+ #PrintTA.flagPriority=PrintTAPriority.always
3
+ Flag_DEBUG=False
4
+ Flag_DEBUG_PARPOOL=False
5
+ FlagPrintTime=False
6
+ FlagPrintCoding=False
7
+
8
+ pwddbg='Buss4Co1Pied1'
9
+ time_warnings_debug=-1 #10000 #milliseconds #5000
10
+
11
+ import uuid
12
+ basefold='./'
13
+ basefold_DEBUGOptions=[]
14
+ basefold_DEBUG='./'
15
+ basefold_DEBUG_VIS=''
16
+ #basefold='B:/dl/apairs/jetcross'
17
+
18
+ developerIDs={
19
+ 'GP_Win_Office': '231128824800632', #'0x7824af430781',
20
+ 'GP_Win_Office_New': '140626882900161', #'0x7824af430781',
21
+ 'GP_Mac_Laptop': 'V94LRP93FV', #'0xa275dd445ab0',
22
+ 'TA_Win_Office': '160983906000941', #'0xccb0da8c896e'
23
+ 'TA_Win_Office_New': '231128824801036', #??
24
+ }
25
+
26
+ import psutil,subprocess
27
+ def getCurrentID():
28
+ #return hex(uuid.getnode())
29
+ serial_number=None
30
+ try:
31
+ if psutil.LINUX:
32
+ # On Linux, the motherboard serial number can be obtained from the /sys/class/dmi/id/board_serial file
33
+ with open('/sys/class/dmi/id/board_serial', 'r') as f:
34
+ serial_number = f.read().strip()
35
+ elif psutil.WINDOWS:
36
+ # On Windows, the motherboard serial number can be obtained using WMI
37
+ output = subprocess.check_output(["wmic", "baseboard", "get", "SerialNumber"]).decode('utf-8')
38
+ serial_number = output.strip().split('\n')[1].strip()
39
+ elif psutil.MACOS:
40
+ # On macOS, the motherboard serial number can be obtained using the system_profiler command
41
+ output = subprocess.check_output(["system_profiler", "SPHardwareDataType"])
42
+ for line in output.splitlines():
43
+ if b'Serial Number (system)' in line:
44
+ serial_number = line.split(b':')[1].strip().decode('utf-8')
45
+ except Exception as e:
46
+ print(f"Error while retrieving motherboard serial number: {e}")
47
+ return serial_number
48
+
49
+ currentID=getCurrentID()
50
+ FlagAddMotherBoard=False
51
+ if currentID in (developerIDs['GP_Win_Office'],developerIDs['GP_Win_Office_New']): #gerardo windows
52
+ basefold_DEBUG='C:/desk/PIV_Img/_data/PIV_data/virtual_case/'
53
+ basefold_DEBUGOptions=[
54
+ 'C:/desk/PIV_Img/img1/',
55
+ 'C:/desk/PIV_Img/_data/PIV_data/virtual_case/',
56
+ 'C:/desk/PIV_Img/_data/PIV_data/real_case/',
57
+ 'C:/desk/PIV_Img/_data/Calibration_data/pinhole/',
58
+ 'C:/desk/PIV_Img/_data/Calibration_data/cylinder/',
59
+ ]
60
+ basefold_DEBUG_VIS='C:/desk/PIV_Img/_data/PIV_data/real_case/'
61
+ elif currentID==developerIDs['GP_Mac_Laptop']: #gerardo mac
62
+ basefold_DEBUG='/Users/gerardo/Desktop/PIV_Img/swirler_png/' #'/Users/gerardo/Desktop/PIV_Img/img1/'
63
+ basefold_DEBUGOptions=[
64
+ '/Users/gerardo/Desktop/PIV_Img/img1/',
65
+ '/Users/gerardo/Desktop/PaIRS_examples/PIV_data/virtual_case/',
66
+ #'/Users/gerardo/Desktop/PaIRS_examples/PIV_data/virtual_case_2/',
67
+ '/Users/gerardo/Desktop/PaIRS_examples/PIV_data/real_case/',
68
+ '/Users/gerardo/Desktop/PaIRS_examples/SPIV_data/real_case/img/',
69
+ '/Users/gerardo/Desktop/PaIRS_examples/Calibration_data/pinhole/',
70
+ '/Users/gerardo/Desktop/PaIRS_examples/Calibration_data/cylinder/'
71
+ ]
72
+ basefold_DEBUG_VIS='/Users/gerardo/Desktop/PaIRS_examples/PIV_data/real_case/'
73
+ basefold_DEBUG_VIS='/Users/gerardo/Desktop/PIV_Img/img1/'
74
+ elif currentID in (developerIDs['TA_Win_Office'],developerIDs['TA_Win_Office_New']): #TA windows
75
+ basefold_DEBUG='C:\desk\Attuali\PythonLibC\PIV\img'
76
+ basefold_DEBUGOptions=[
77
+ 'C:/desk/PIV_Img/img1/',
78
+ 'C:/desk/PIV_Img/swirler_png/',
79
+ '../../img/calib/',
80
+ 'C:\desk\Attuali\PythonLibC\PIV\img',
81
+ ]
82
+ basefold_DEBUG_VIS=''
83
+ else:
84
+ FlagAddMotherBoard=True
85
+
86
+ #fontName='Inter'
87
+ #fontName='Cambria'
88
+ fontName='Arial'
89
+ fontPixelSize=14
90
+ dfontLog=2
91
+ fontPixelSize_lim=[8,20]
92
+ import platform
93
+ if (platform.system() == "Linux"):
94
+ fontName='sans-serif'
95
+
96
+ Flag_SHOWSPLASH=False
97
+ Flag_GRAPHICS=True #if True PaIRS plots while processing
98
+ Flag_NATIVEDIALOGS=True
99
+ Flag_DISABLE_onUpdate=False
100
+ Flag_RESIZEONRUN=False
101
+ Flag_GROUPSEPARATOR=True
102
+
103
+ imin_im_pair=1 #minimum index value for image pair
104
+
105
+ f_empty_width=250 #blank space in scrollable area within the main window
106
+ time_ScrollBar=250 #time of animation of scroll area
107
+ time_callback2_async=0 #time to test async callbacks
108
+ time_showSplashOnTop=250
109
+
110
+ fileChanges='Changes.txt'
111
+ fileWhatsNew=['whatsnew.txt','whatwasnew.txt']
112
+ icons_path="icons/"
113
+
114
+ from psutil import cpu_count
115
+ NUMTHREADS_MAX=cpu_count(logical=True)#-1
116
+ if NUMTHREADS_MAX<1: NUMTHREADS_MAX=1
117
+ ParFor_sleepTime=0.1
118
+ #multithreading
119
+ FlagStopWorkers=[0]#messo qui ma utilizzato solo da min e PIV
120
+ NUMTHREADS_gPaIRS=0
121
+ SleepTime_Workers=0.5 #for multithreading and other stuff
122
+ timeOutWorker=0 # used in parfor when the proces is stuck
123
+
124
+ from .__init__ import __version__,__subversion__,__year__,__mail__
125
+ from PySide6 import QtCore, QtGui, QtWidgets
126
+ from PySide6.QtCore import*
127
+ from PySide6.QtGui import *
128
+ from PySide6.QtWidgets import*
129
+ from typing import cast
130
+ if Flag_DEBUG_PARPOOL: import debugpy
131
+
132
+ import numpy as np
133
+ import scipy.io, pickle
134
+ from PIL import Image
135
+ from PIL.ImageQt import ImageQt
136
+ import sys, os, glob, copy, re, traceback, datetime
137
+ from time import sleep as timesleep
138
+ from collections import namedtuple
139
+ from .plt_util import writePlt, readPlt
140
+ #from multiprocessing import cpu_count
141
+
142
+ from .tAVarie import *
143
+ deltaTimePlot=0.75
144
+ import concurrent.futures
145
+ import gc#garbage collection si può eliminare
146
+ from .mtfPIV import *
147
+
148
+ import sys
149
+ import concurrent.futures
150
+ import asyncio
151
+
152
+
153
+ class ColorPrint:
154
+ def __init__(self,flagTime=False,prio=PrintTAPriority.medium,faceStd=PrintTA.faceStd,flagFullDebug=False):
155
+ self.flagTime=flagTime
156
+ self.prio=prio
157
+ self.faceStd=faceStd
158
+ self.flagFullDebug=flagFullDebug
159
+ self.setPrints()
160
+
161
+ def setPrints(self):
162
+ if self.flagTime:
163
+ self.white = lambda flagReset=0, *args, **kwargs: PrintTA(PrintTA.white, self.faceStd, self.prio).prTime(flagReset,*args,**kwargs)
164
+ self.red = lambda flagReset=0, *args, **kwargs: PrintTA(PrintTA.red, self.faceStd, self.prio).prTime(flagReset,*args,**kwargs)
165
+ self.green = lambda flagReset=0, *args, **kwargs: PrintTA(PrintTA.green, self.faceStd, self.prio).prTime(flagReset,*args,**kwargs)
166
+ self.blue = lambda flagReset=0, *args, **kwargs: PrintTA(PrintTA.blue, self.faceStd, self.prio).prTime(flagReset,*args,**kwargs)
167
+ self.cyan = lambda flagReset=0, *args, **kwargs: PrintTA(PrintTA.cyan, self.faceStd, self.prio).prTime(flagReset,*args,**kwargs)
168
+ self.magenta = lambda flagReset=0, *args, **kwargs: PrintTA(PrintTA.magenta, self.faceStd, self.prio).prTime(flagReset,*args,**kwargs)
169
+ self.yellow = lambda flagReset=0, *args, **kwargs: PrintTA(PrintTA.yellow, self.faceStd, self.prio).prTime(flagReset,*args,**kwargs)
170
+ else:
171
+ self.white = PrintTA(PrintTA.white, self.faceStd, self.prio).pr
172
+ self.red = PrintTA(PrintTA.red, self.faceStd, self.prio).pr
173
+ self.green = PrintTA(PrintTA.green, self.faceStd, self.prio).pr
174
+ self.blue = PrintTA(PrintTA.blue, self.faceStd, self.prio).pr
175
+ self.cyan = PrintTA(PrintTA.cyan, self.faceStd, self.prio).pr
176
+ self.magenta = PrintTA(PrintTA.magenta, self.faceStd, self.prio).pr
177
+ self.yellow = PrintTA(PrintTA.yellow, self.faceStd, self.prio).pr
178
+
179
+ #if prio is assigned to never, in the gPaIRS initializiation the printing is deactivated, otherwise activated
180
+ #if prio is > veryLow, then by default the printing is activated after gPaIRS initialization
181
+ #flagFullDebug=True means that the printing is available only if fullDebug mode is active
182
+ class GPaIRSPrint:
183
+ def __init__(self):
184
+ self.Info=ColorPrint(prio=PrintTAPriority.medium)
185
+ self.Time=ColorPrint(prio=PrintTAPriority.medium if FlagPrintTime else PrintTAPriority.veryLow,flagTime=True,faceStd=PrintTA.faceUnderline)
186
+ self.Error=ColorPrint(prio=PrintTAPriority.medium,faceStd=PrintTA.faceBold)
187
+ self.Process=ColorPrint(prio=PrintTAPriority.veryLow)
188
+ self.Callback=ColorPrint(prio=PrintTAPriority.veryLow)
189
+ self.TABparDiff=ColorPrint(prio=PrintTAPriority.veryLow)
190
+ self.PlotTime=ColorPrint(prio=PrintTAPriority.veryLow,flagTime=True,faceStd=PrintTA.faceUnderline,flagFullDebug=True)
191
+ self.Coding=ColorPrint(prio=PrintTAPriority.medium if FlagPrintCoding else PrintTAPriority.never,flagFullDebug=True)
192
+
193
+ pri=GPaIRSPrint()
194
+ printTypes={}
195
+ for npt,pt in pri.__dict__.items():
196
+ printTypes[npt]=pt.prio in (PrintTAPriority.medium,PrintTAPriority.mediumHigh,PrintTAPriority.high,PrintTAPriority.always)
197
+
198
+ def activateFlagDebug(Flag=True):
199
+ ''' used to activate the debug mode; when called with false disables'''
200
+ Flag_DEBUG=Flag
201
+ PrintTA.flagPriority=PrintTAPriority.veryLow if Flag_DEBUG else PrintTAPriority.always
202
+ global basefold
203
+ from .gPaIRS import Flag_fullDEBUG
204
+ if not Flag_fullDEBUG:
205
+ basefold='./'
206
+ else:
207
+ basefold=basefold_DEBUG
208
+
209
+ PaIRS_Header=f'PaIRS - version {__version__}\n'+\
210
+ 'Particle Image Reconstruction Software\n'+\
211
+ f'(C) {__year__} Gerardo Paolillo & Tommaso Astarita.\nAll rights reserved.\n'+\
212
+ f'email: {__mail__}\n'+\
213
+ '****************************************\n'
214
+
215
+ from .parForMulti import *
216
+ #from pkg_resources import resource_filename
217
+ from .parForMulti import ParForMul
218
+
219
+ import faulthandler # per capire da dove vengono gli errori c
220
+ faulthandler.enable()
221
+
222
+ if __package__ or "." in __name__:
223
+ import PaIRS_UniNa.PaIRS_PIV as PaIRS_lib
224
+ else:
225
+ import sys
226
+ if (platform.system() == "Darwin"):
227
+ sys.path.append('../lib/mac')
228
+ else:
229
+ #sys.path.append('PaIRS_PIV')
230
+ sys.path.append('../lib')
231
+ import PaIRS_PIV as PaIRS_lib
232
+
233
+ if __package__ or "." in __name__:
234
+ import importlib.resources as resources
235
+ resources_path = resources.files(__package__)
236
+ foldPaIRS = str(resources_path)+"\\"
237
+ foldPaIRS = foldPaIRS.replace('\\', '/')
238
+ else:
239
+ foldPaIRS='./'
240
+
241
+ class ProcessTypes:
242
+ null=None
243
+ min=0
244
+ piv=1
245
+ spiv=2
246
+ tpiv=3
247
+ cal=10
248
+
249
+ singleCamera=[piv]
250
+ threeCameras=[tpiv]
251
+
252
+ class StepTypes:
253
+ null=None
254
+ min=0
255
+ piv=1
256
+ spiv=2
257
+ cal=10
258
+ disp=11
259
+
260
+ process={
261
+ ProcessTypes.null: '-',
262
+ ProcessTypes.min: 'minimum',
263
+ ProcessTypes.piv: 'PIV',
264
+ ProcessTypes.spiv: 'SPIV',
265
+ ProcessTypes.tpiv: 'TPIV',
266
+ ProcessTypes.cal: 'calibration',
267
+ }
268
+ process_items=[v for v in process.values()]
269
+ process_ord=range(len(process_items))
270
+ class outExt:
271
+ #legacy
272
+ cfg='.pairs_cfg'
273
+ dum='.pairs_dum'
274
+
275
+ #Workspaces and projects
276
+ wksp='.pairs_wksp'
277
+ proj='.pairs_proj'
278
+
279
+ #StepTypes
280
+ min='.pairs_min'
281
+ piv='.pairs_piv'
282
+ spiv='.pairs_spiv'
283
+ cal='.pairs_cal'
284
+ calvi='.calvi'
285
+ disp='.pairs_disp'
286
+
287
+ #Further types of variable
288
+ #PIV process
289
+ pro='.pairs_pro'
290
+ #CalVi
291
+ cfg_calvi='.calvi_cfg'
292
+ pla='.pairs_pla'
293
+
294
+
295
+
296
+ lastcfgname='lastWorkSpace'+outExt.wksp
297
+
298
+ fileChanges=foldPaIRS+'Changes.txt'
299
+ fileWhatsNew=[foldPaIRS+f for f in fileWhatsNew]
300
+ icons_path=foldPaIRS+icons_path
301
+ lastcfgname=foldPaIRS+lastcfgname
302
+ pro_path=foldPaIRS+"pro/"
303
+ if not os.path.exists(pro_path):
304
+ try:
305
+ os.mkdir(pro_path)
306
+ except Exception as inst:
307
+ pri.Error.red(f'It was not possible to make the directory {pro_path}:\n{traceback.format_exc()}\n\n{inst}')
308
+ custom_list_file="pro_list.txt"
309
+
310
+ exts = Image.registered_extensions()
311
+ supported_exts = sorted({ex for ex, f in exts.items() if f in Image.OPEN})
312
+ text_filter = "Common image files (*.bmp *.gif *.ico *.jpeg *.jpg *.png *.tif *.tiff *.webp"\
313
+ + ");;"+" ;;".join(["{} ".format(fo[1:]) +"(*{})".format(fo) for fo in supported_exts])
314
+ #text_filter = "All files (*"\
315
+ # + ");;"+" ;;".join(["{} ".format(fo[1:]) +"(*{})".format(fo) for fo in supported_exts])
316
+ #text_filter = "All files ("+ " ".join(["*{}".format(fo) for fo in supported_exts])\
317
+ # + ");;"+" ;;".join(["{} ".format(fo[1:]) +"(*{})".format(fo) for fo in supported_exts])
318
+
319
+ if Flag_NATIVEDIALOGS:
320
+ optionNativeDialog=QFileDialog.Options()
321
+ else:
322
+ optionNativeDialog=QFileDialog.Option.DontUseNativeDialog
323
+
324
+ def warningDialog(self:QWidget,Message,time_milliseconds=0,flagScreenCenter=False,icon:QIcon=QIcon(),palette=None,pixmap=None,title='Warning!',flagRichText=False,flagNoButtons=False,addButton:dict=None,FlagStayOnTop=False,pixmapSize=64): #addButton=['Print Message',lambda: print(Message)]
325
+ dlg=None
326
+ if Message:
327
+ if isinstance(self,QMainWindow) and hasattr(self,'w_Input'):
328
+ dlg = QMessageBox(self.w_Input)
329
+ else:
330
+ dlg = QMessageBox(self)
331
+ dlg.setWindowTitle(title)
332
+ dlg.setText(str(Message))
333
+
334
+ if flagRichText: dlg.setTextFormat(Qt.TextFormat.RichText)
335
+ if flagNoButtons:
336
+ dlg.setStandardButtons(QMessageBox.StandardButton.NoButton)
337
+ else:
338
+ dlg.setStandardButtons(QMessageBox.StandardButton.Ok)
339
+ if addButton:
340
+ for addB, addAction in addButton.items():
341
+ abutt = dlg.addButton(addB, QtWidgets.QMessageBox.YesRole)
342
+ abutt.clicked.disconnect()
343
+ def aFun(fun):
344
+ fun()
345
+ dlg.done(0)
346
+ abutt.clicked.connect(lambda flag=None,fun=addAction: aFun(fun))
347
+ dlg.setIcon(QMessageBox.Warning)
348
+ if icon:
349
+ if type(icon)==QIcon: dlg.setWindowIcon(icon)
350
+ else:
351
+ try:
352
+ iconW=QIcon()
353
+ iconW.addFile(icon)
354
+ dlg.setWindowIcon(iconW)
355
+ except Exception as e:
356
+ pri.Error.red(f'Error while reading the window icon from the file {icon}:\n{e}')
357
+ else:
358
+ if not hasattr(self,'windowIcon') or not self.windowIcon():
359
+ iconW=QIcon()
360
+ iconW.addFile(icons_path+'icon_PaIRS.png')
361
+ dlg.setWindowIcon(iconW)
362
+ else:
363
+ dlg.setWindowIcon(self.windowIcon())
364
+ if palette:
365
+ dlg.setPalette(palette)
366
+ if pixmap:
367
+ dlg.setIconPixmap(QPixmap(pixmap).scaled(pixmapSize, pixmapSize, Qt.AspectRatioMode.KeepAspectRatio,Qt.SmoothTransformation))
368
+ if self:
369
+ dlg.setFont(self.font())
370
+ c=dlg.findChildren(QObject)
371
+ for w in c:
372
+ if hasattr(w,'setFont'):
373
+ font=w.font()
374
+ font.setFamily(fontName)
375
+ w.setFont(font)
376
+ #dlg.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
377
+ dlg.show()
378
+ if flagScreenCenter and hasattr(self,'maximumGeometry'):
379
+ geom=dlg.geometry()
380
+ geom.moveCenter(self.maximumGeometry.center())
381
+ dlg.setGeometry(geom)
382
+ if time_milliseconds:
383
+ QTimer.singleShot(time_milliseconds, lambda : dlg.done(0))
384
+ else:
385
+ if Flag_DEBUG and time_warnings_debug>=0:
386
+ QTimer.singleShot(time_warnings_debug, lambda : dlg.done(0))
387
+ if FlagStayOnTop: dlg.setWindowFlag(Qt.WindowStaysOnTopHint, True)
388
+ if not flagNoButtons: dlg.exec()
389
+ return dlg
390
+
391
+ def questionDialog(self,Message,icon=QMessageBox.Warning):
392
+ if isinstance(self,QMainWindow) and hasattr(self,'w_Input'):
393
+ dlg = QMessageBox(self.w_Input)
394
+ else:
395
+ dlg = QMessageBox(self)
396
+ dlg.setWindowTitle("Warning!")
397
+ dlg.setText(str(Message))
398
+ if not self.windowIcon():
399
+ icons_path+'icon_PaIRS.png'
400
+ iconW=QIcon()
401
+ iconW.addFile(icon)
402
+ dlg.setWindowIcon(iconW)
403
+ else:
404
+ dlg.setWindowIcon(self.windowIcon())
405
+
406
+ dlg.setStandardButtons(QMessageBox.Yes|QMessageBox.No)
407
+ dlg.setDefaultButton(QMessageBox.Yes)
408
+ dlg.setIcon(icon)
409
+ if self:
410
+ dlg.setFont(self.font())
411
+ c=dlg.findChildren(QObject)
412
+ for w in c:
413
+ if hasattr(w,'setFont'):
414
+ font=w.font()
415
+ font.setFamily(fontName)
416
+ w.setFont(font)
417
+ button = dlg.exec()
418
+ return button==QMessageBox.Yes
419
+
420
+ def inputDialog(self,title,label,icon=None,palette=None,completer_list=[],width=0,flagMouseCenter=False,flagScreenCenter=False):
421
+ dlg = QtWidgets.QInputDialog(self)
422
+ dlg.setWindowTitle(title)
423
+ dlg.setLabelText(label)
424
+ dlg.setTextValue("")
425
+ if icon:
426
+ dlg.setWindowIcon(icon)
427
+ if palette:
428
+ dlg.setPalette(palette)
429
+ le = dlg.findChild(QtWidgets.QLineEdit)
430
+ if self:
431
+ dlg.setFont(self.font())
432
+ c=dlg.findChildren(QObject)
433
+ for w in c:
434
+ if hasattr(w,'setFont'):
435
+ font=w.font()
436
+ font.setFamily(fontName)
437
+ w.setFont(font)
438
+
439
+ if len(completer_list):
440
+ completer = QtWidgets.QCompleter(completer_list, le)
441
+ completer.setCompletionMode(QCompleter.CompletionMode(1))
442
+ le.setCompleter(completer)
443
+
444
+ if not width: width=int(0.5*self.width())
445
+ dlg.resize(width,dlg.height())
446
+ dlg.updateGeometry()
447
+
448
+ if flagMouseCenter:
449
+ dlg.show()
450
+ geom = dlg.geometry()
451
+ geom.moveCenter(QtGui.QCursor.pos())
452
+ dlg.setGeometry(geom)
453
+
454
+ if flagScreenCenter and hasattr(self,'maximumGeometry'):
455
+ dlg.show()
456
+ geom=dlg.geometry()
457
+ geom.moveCenter(self.maximumGeometry.center())
458
+ dlg.setGeometry(geom)
459
+
460
+ c=dlg.findChildren(QObject)
461
+ for w in c:
462
+ if hasattr(w,'setFont'):
463
+ font=w.font()
464
+ font.setFamily(fontName)
465
+ w.setFont(font)
466
+
467
+ ok, text = (
468
+ dlg.exec() == QtWidgets.QDialog.Accepted,
469
+ dlg.textValue(),
470
+ )
471
+ return ok, text
472
+
473
+ def errorDialog(self,Message,*args):
474
+ if len(args): time_milliseconds = args[0]
475
+ else: time_milliseconds=0
476
+ if Message:
477
+ dlg = QMessageBox(self)
478
+ dlg.setWindowTitle("Warning!")
479
+ dlg.setText(str(Message))
480
+ copy_butt = dlg.addButton('Copy error to clipboard', QtWidgets.QMessageBox.YesRole)
481
+ copy_butt.clicked.disconnect()
482
+ def copy_fun():
483
+ QApplication.clipboard().setText(Message)
484
+ dlg.done(0)
485
+ copy_butt.clicked.connect(copy_fun)
486
+ ok_butt = dlg.addButton('Ok', QtWidgets.QMessageBox.YesRole)
487
+ dlg.setIcon(QMessageBox.Critical)
488
+ if self:
489
+ dlg.setFont(self.font())
490
+ c=dlg.findChildren(QObject)
491
+ for w in c:
492
+ if hasattr(w,'setFont'):
493
+ font=w.font()
494
+ font.setFamily(fontName)
495
+ w.setFont(font)
496
+ #dlg.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
497
+ if time_milliseconds>=0:
498
+ QTimer.singleShot(time_milliseconds, lambda : dlg.done(0))
499
+ else:
500
+ if Flag_DEBUG and time_warnings_debug>=0:
501
+ QTimer.singleShot(time_warnings_debug, lambda : dlg.done(0))
502
+ dlg.exec()
503
+
504
+ def printException(stringa='',flagMessage=Flag_DEBUG,flagDispDialog=False,exception=None): #timemilliseconds=-1 ***
505
+ ''' used to print when an exception is raised TA has decided that the printing function is a simple
506
+ print in this way we cannot have any problems when printing in non-compatible terminals
507
+ use with something like
508
+
509
+ try:
510
+ a=1/0
511
+ except :#non need to put a variable al the info are in traceback
512
+ printException()
513
+ * stringa is an additional string (to specify the point where the error comes from)
514
+ * flagMessage is a flag, if true the error message is generated; default value is Flag_DEBUG
515
+ * flagDispDialog is a flag, if true a critical dialog appears after the exception
516
+ * exception is the exception, normally you don't need it but for parForMul is required
517
+ '''
518
+ #print(f'***** ParForMul Exception ***** Deltat={time()-PrintTA.startTime}\n{traceback.format_exc()}',*args,**kwargs)
519
+ #print(sys.exc_info()[2])
520
+ Message=""
521
+ if flagMessage or flagDispDialog:
522
+ Message+=f'Please, mail to: {__mail__}\n\n'
523
+ Message+=f'***** PaIRS Exception ***** time={time()-PrintTA.startTime}\n'+stringa
524
+ Message+=f'***** traceback.print_exc() ***** \n'
525
+ if exception is None:
526
+ Message+=traceback.format_exc()
527
+ else:
528
+ Message+=''.join(traceback.format_exception(exception))
529
+ Message+=f'***** traceback.extract_stack() ***** \n'
530
+ # to print all the queue comment if not needed
531
+ for st in traceback.format_list( traceback.extract_stack()):
532
+ if 'PAIRS_GUI' in st and 'printException'not in st:# limits to files that have PAIRS_GUI in the path
533
+ Message+=st
534
+ Message+=f'***** PaIRS Exception -> End *****\n'
535
+ if Flag_DEBUG: print(Message)
536
+ #errorDialog(None,Message,timemilliseconds) ***
537
+ if flagDispDialog:
538
+ WarningMessage=f'PaIRS Exception!\n\n'+f'Do you want to copy the error message to the clipboard so that you can send it to: {__mail__}?'
539
+ flagYes=questionDialog(None,WarningMessage,QMessageBox.Critical)
540
+ if flagYes:
541
+ QApplication.clipboard().setText(Message)
542
+ return Message
543
+
544
+ def noPrint(*args,**kwargs):
545
+ pass
546
+
547
+ #import unidecode
548
+ def myStandardPath(path):
549
+ currpath = path.rstrip() # Remove trailing white spaces from the path
550
+ currpath = currpath.replace('\\', '/') # Replace all backslashes with forward slashes
551
+ currpath = currpath.rstrip('/') + '/' if currpath else './' # Add a trailing slash to the path if not present
552
+ currpath = re.sub('/+', '/', currpath) # Reduce consecutive slashes to a single slash
553
+ return currpath
554
+
555
+ def myStandardRoot(root):
556
+ currroot = root.rstrip() # Remove trailing white spaces from the root
557
+ currroot = currroot.replace('\\', '/') # Replace all backslashes with forward slashes
558
+ currroot = re.sub('/+', '/', currroot) # Reduce consecutive slashes to a single slash
559
+ return currroot
560
+
561
+ def findFiles_sorted(pattern):
562
+ list_files=glob.glob(pattern)
563
+ files=sorted([re.sub(r'\\+',r'/',f) for f in list_files],key=str.lower)
564
+ return files
565
+
566
+ def transfIm(OUT,flagTransf:int=2,Images:list=[],flagRot=1):
567
+ ''' the output is a copy (not deep) of the input list)
568
+ flagTransf==0 solo img
569
+ flagTransf==1 solo piv
570
+ flagTransf==2 solo entrambi (default)
571
+ '''
572
+ if len(Images)==0: return
573
+ if OUT.FlagNone: return Images
574
+
575
+ if flagTransf==1: #solo PIV
576
+ ops=OUT.aimop
577
+ else:
578
+ if OUT.h>0 and OUT.w>0:
579
+ for i,_ in enumerate(Images):
580
+ Images[i]=Images[i][OUT.y:OUT.y+OUT.h,OUT.x:OUT.x+OUT.w]#limita l'img
581
+ ops=OUT.bimop if flagTransf==0 else OUT.vecop
582
+
583
+
584
+ if len(ops):
585
+ for i,_ in enumerate(Images):# non funziona se si fa il normale ciclo for img in Images
586
+ for op in ops:
587
+ if op==1: #rot 90 counter
588
+ Images[i]=np.rot90(Images[i],-1*flagRot)
589
+ elif op==-1: #rot 90 clock
590
+ Images[i]=np.rot90(Images[i],1*flagRot)
591
+ elif op==3: #flip
592
+ Images[i]=np.flipud(Images[i])
593
+ elif op==2:
594
+ Images[i]=np.fliplr(Images[i])
595
+ Images[i]=np.ascontiguousarray(Images[i])
596
+ return Images # the input list is also changed accordingly but it may come in handy in some situation in order to avoid explicitly make a copy
597
+
598
+ def transfVect(OUT,PIV):
599
+ x,y,u,v=transfIm(OUT,flagTransf=1,Images=[PIV.x,PIV.y,PIV.u,PIV.v],flagRot=1)# l'output non sarebbe necessario ma così mi fa anche la copia (per ora virtuale)
600
+ for op in OUT.aimop:
601
+ if op==-1: #rot 90 counter
602
+ # PIV.u,PIV.v=PIV.v,-PIV.u #questa da errore penso perchè non riesce a fare la copia
603
+ u,v=v,-u
604
+ x,y=y,OUT.w-x
605
+ elif op==1: #rot 90 clock
606
+ u,v=-v,u
607
+ x,y=OUT.h-y,x
608
+ elif op==2:#flip
609
+ u=-u
610
+ x=OUT.w-x
611
+ elif op==3: #flip
612
+ v=-v
613
+ y=OUT.h-y
614
+ return x,y,u,v
615
+
616
+ def readCustomListFile():
617
+ custom_list=[]
618
+ filename=pro_path+custom_list_file
619
+ if os.path.exists(filename):
620
+ try:
621
+ with open(filename,'r') as file:
622
+ while True:
623
+ line = file.readline()
624
+ if not line:
625
+ break
626
+ else:
627
+ l=line.strip()
628
+ if l: custom_list.append(l)
629
+ file.close()
630
+ except:
631
+ pri.Error.red(f'Error while opening the custom process list file: {filename}.\n{traceback.format_exc()}\n')
632
+ return custom_list
633
+
634
+ def setCustomList(task):
635
+ custom_list=readCustomListFile()
636
+ for k,name in enumerate(custom_list):
637
+ filename=pro_path+name+outExt.pro
638
+ try:
639
+ with open(filename,'rb') as file:
640
+ var=pickle.load(file)
641
+ task(var,name)
642
+ except Exception as inst:
643
+ pri.Error.red(f'Error while loading custom process file {filename}\t[from list]:\n{traceback.format_exc()}\n\n{inst}')
644
+ custom_list.pop(k)
645
+ if os.path.exists(filename):
646
+ os.remove(filename)
647
+ profiles=glob.glob(pro_path+f"*{outExt.pro}")
648
+ for f in profiles:
649
+ name=os.path.basename(f)[:-10]
650
+ if not name in custom_list:
651
+ filename=myStandardRoot(f)
652
+ try:
653
+ with open(filename,'rb') as file:
654
+ var=pickle.load(file)
655
+ task(var,name)
656
+ custom_list.append(name)
657
+ except Exception as inst:
658
+ pri.Error.red(f'Error while loading the custom process file {filename}\t[from disk]:\n{traceback.format_exc()}\n\n{inst}')
659
+ if os.path.exists(filename):
660
+ os.remove(filename)
661
+ rewriteCustomList(custom_list)
662
+ return custom_list
663
+
664
+ def rewriteCustomList(custom_list):
665
+ filename=pro_path+custom_list_file
666
+ try:
667
+ with open(filename,'w') as file:
668
+ for c in custom_list:
669
+ file.write(c+'\n')
670
+ file.close()
671
+ except:
672
+ pri.Error.red(f'Error while rewriting the custom process file {filename}\t[from disk]:\n{traceback.format_exc()}\n')
673
+
674
+ def identifierName(typeObject:str='proc'):
675
+ username=platform.system()+'-'+os.environ.get('USER', os.environ.get('USERNAME'))
676
+ date_time=QDate.currentDate().toString('yyyy/MM/dd')+'-'+\
677
+ QTime().currentTime().toString()
678
+ ppid=str(os.getppid())+'-'+str(os.getpid())
679
+ version='PaIRS-v'+__version__
680
+ version_user_info=version+'_'+username+'_'+date_time
681
+ id=ppid+'_'+str(uuid.uuid4())
682
+ name=version_user_info+'_'+typeObject+'_'+id
683
+ return name, username, __version__
684
+
685
+ PlainTextConverter=QtGui.QTextDocument()
686
+ def toPlainText(text):
687
+ PlainTextConverter.setHtml(text) #for safety
688
+ return PlainTextConverter.toPlainText()
689
+
690
+ def showTip(obj,message):
691
+ toolTipDuration=obj.toolTipDuration()
692
+ obj.setToolTipDuration(3000)
693
+ QToolTip.showText(QCursor.pos(),message)
694
+ obj.setToolTipDuration(toolTipDuration)
695
+
696
+ def clean_tree(tree:QTreeWidget):
697
+ def remove_children(item:QTreeWidgetItem):
698
+ while item.childCount() > 0:
699
+ child = item.takeChild(0)
700
+ remove_children(child)
701
+ del item
702
+
703
+ while tree.topLevelItemCount() > 0:
704
+ item = tree.takeTopLevelItem(0)
705
+ # Elimina ricorsivamente tutti i figli dell'elemento
706
+ remove_children(item)
707
+
708
+ def html_image(icon_path,size=16):
709
+ text=f"""
710
+ <img src="{icon_path}" width="{size}" height="{size}" style="margin-right: 0px;">
711
+ """
712
+ return text
713
+
714
+ def procOutName(self):
715
+ for attr_name, attr_value in vars(ProcessTypes).items():
716
+ if attr_value == self.Process:
717
+ procExt=getattr(outExt,attr_name)
718
+ break
719
+ return f'{self.outPathRoot}{procExt}'
720
+
721
+ def stepOutName(self):
722
+ for attr_name, attr_value in vars(StepTypes).items():
723
+ if attr_value == self.Step:
724
+ procExt=getattr(outExt,attr_name)
725
+ break
726
+ return f'{self.outPathRoot}{procExt}'
727
+
728
+ def findIDFromLog(file_path):
729
+ nMaximumLines=50
730
+ try:
731
+ with open(file_path, 'r') as file:
732
+ # Legge fino a 50 righe (o meno, se il file ha meno righe)
733
+ for _ in range(nMaximumLines):
734
+ line = file.readline()
735
+ if not line: # Fine del file
736
+ break
737
+ if line.startswith("PaIRS-v"):
738
+ return line.strip() # Ritorna la riga trovata senza spazi extra
739
+ return None # Nessuna riga trovata
740
+ except FileNotFoundError:
741
+ pri.Error.red(f"File not found: {file_path}")
742
+ return None
743
+
744
+ def resultCheck(tab,par,ind=None):
745
+ if ind is None: ind=par.ind
746
+ ITE=tab.gui.ui.Explorer.ITEfromInd(ind)
747
+ filename=stepOutName(ITE.procdata)+'.log'
748
+ if os.path.exists(filename):
749
+ id=findIDFromLog(filename)
750
+ FlagResult=id==ITE.procdata.name_proc
751
+ else:
752
+ FlagResult=False
753
+ return FlagResult
754
+
755
+ def runPaIRS(self,command='',flagQuestion=True):
756
+ Flag=__package__ or "." in __name__
757
+ pyCommands={
758
+ '' : 'import PaIRS; PaIRS.run()',
759
+ '-c': 'import PaIRS; PaIRS.cleanRun()',
760
+ '-d': 'import PaIRS; PaIRS.debugRun()',
761
+ '-calvi' : 'import CalVi; CalVi.run()',
762
+ '-calvi -c': 'import CalVi; CalVi.cleanRun()',
763
+ '-calvi -d': 'import CalVi; CalVi.debugRun()',
764
+ }
765
+ nameIstance={
766
+ '' : 'PaIRS',
767
+ '-c': 'PaIRS (clean mode)',
768
+ '-d': 'PaIRS (debug mode)',
769
+ '-calvi' : 'CalVi',
770
+ '-calvi -c': 'CalVi (clean mode)',
771
+ '-calvi -d': 'CalVi (debug mode)',
772
+ }
773
+
774
+ class SignalsinstPaIRS(QObject):
775
+ errorSignal=Signal()
776
+ class instPaIRS(QRunnable):
777
+ def __init__(self):
778
+ super(instPaIRS,self).__init__()
779
+ self.isRunning=True
780
+ self.signals=SignalsinstPaIRS()
781
+
782
+ def run(self):
783
+ try:
784
+ import subprocess
785
+ if Flag: #launched from package
786
+ pri.Info.white(sys.executable+' -m PaIRS_UniNa '+command)
787
+ subprocess.call(sys.executable+' -m PaIRS_UniNa '+command,shell=True)
788
+ else:
789
+ pri.Info.white(sys.executable+' -c '+'"'+f"import os; os.chdir('{os.getcwd()}'); {pyCommands[command]}"+'"')
790
+ subprocess.call(sys.executable+' -c '+'"'+f"import os; os.chdir('{os.getcwd()}'); {pyCommands[command]}"+'"',shell=True)
791
+ self.isRunning=False
792
+ except Exception as inst:
793
+ pri.Error.red(inst)
794
+ self.signals.errorSignal.emit()
795
+
796
+ if flagQuestion:
797
+ Message='Are you sure to launch a new istance of '+nameIstance[command]+'?'
798
+ yes=questionDialog(self,Message)
799
+ if not yes: return
800
+ runnable = instPaIRS()
801
+ runnable.signals.errorSignal.connect(lambda: self.warningDialog('It was not possible to launch the module from the present application!\nPlease, retry in another Python environment.'))
802
+ QThreadPool.globalInstance().start(runnable)
803
+ if not hasattr(self,'SecondaryThreads'):
804
+ self.SecondaryThreads=[]
805
+ self.SecondaryThreads.append(runnable)
806
+
807
+ def showSplash(filename=''+ icons_path +'logo_PaIRS_completo.png'):
808
+ splash=QLabel()
809
+ splash_pix = QPixmap(filename)
810
+ splash.setPixmap(splash_pix)
811
+ splash.setScaledContents(True)
812
+ splash.setMaximumSize(360,360)
813
+ splash.setWindowFlags(Qt.Window|Qt.FramelessWindowHint)
814
+ splash.setAttribute(Qt.WA_NoSystemBackground)
815
+ splash.setAttribute(Qt.WA_TranslucentBackground)
816
+ splash.show()
817
+ return splash
818
+
819
+ def checkLatestVersion(self,version,app:QApplication=None,splash:QLabel=None):
820
+ flagStopAndDownload=False
821
+ var=self.TABpar
822
+ #var.FlagOutDated=0 if currentVersion==var.latestVersion else var.FlagOutDated
823
+ if abs(var.FlagOutDated)==1:
824
+ warningLatestVersion(self,app,flagExit=0,flagWarning=1,FlagStayOnTop=True)
825
+ var.FlagOutDated=2 if var.FlagOutDated==1 else -2
826
+ """
827
+ flagStopAndDownload=questionDialog(self,f'A new version of the PaIRS_UniNa package is available. Do you want to download it before starting the current istance of {self.name}?')
828
+ if flagStopAndDownload:
829
+ if splash: splash.hide()
830
+ downloadLatestVersion(self,app)
831
+ return flagStopAndDownload
832
+ else:
833
+ var.FlagOutDated=2
834
+ """
835
+
836
+ packageName='PaIRS_UniNa'
837
+ def printOutDated(flagOutDated,currentVersion,latestVersion):
838
+ """"
839
+ if not flagOutDated:
840
+ flagOutDated2=any([c<l for (c,l) in zip(version.split('.'),latestVersion.split('.'))])
841
+ if flagOutDated2:
842
+ currentVersion=version
843
+ flagOutDated=1
844
+ """
845
+ var.currentVersion=currentVersion
846
+ var.latestVersion=latestVersion
847
+ if flagOutDated==1:
848
+ sOut=f'{packageName} the current version ({currentVersion}) of {packageName} is obsolete! Please, install the latest version: {latestVersion} by using:\npython -m pip install --upgrade {packageName}'
849
+ var.FlagOutDated=2 if var.FlagOutDated==2 else 1
850
+ elif flagOutDated==-1:
851
+ sOut=f'The version of the current instance of {packageName} ({currentVersion}) is newer than the latest official releas ({latestVersion})!\nYou should contact Tommaso and Gerardo if you are a developer and some relevant change is made by yourself!\nIf you are a user, enjoy this beta version and please report any issue!'
852
+ var.FlagOutDated=-2 if var.FlagOutDated==-2 else -1
853
+ elif flagOutDated==-1000:
854
+ sOut=f'Error from pip: it was not possible to check for a new version of the {packageName} package!'
855
+ var.FlagOutDated=0
856
+ else:
857
+ sOut=f'{packageName} The current version ({currentVersion}) of {packageName} is up-to-date! Enjoy it!'
858
+ var.FlagOutDated=0
859
+ pri.Info.cyan(f'[{var.FlagOutDated}] '+sOut)
860
+ self.signals.printOutDated.emit()
861
+ #self.ui.button_PaIRS_download.setVisible(flagOutDated>0)
862
+ pass
863
+
864
+ checkOutDated(packageName,printOutDated)
865
+ return flagStopAndDownload
866
+
867
+ def warningLatestVersion(self,app,flagExit=0,flagWarning=0,time_milliseconds=0,FlagStayOnTop=False):
868
+ if not flagExit:
869
+ exitSuggestion=f'exit the current instance of {self.name} and '
870
+ else:
871
+ exitSuggestion=''
872
+ py=myStandardRoot(sys.executable).split('/')[-1].split('.')[0]
873
+ command=f'{py} -m pip install --upgrade PaIRS_UniNa'
874
+ if self.TABpar.FlagOutDated>0:
875
+ Message=f'A new version of the PaIRS_UniNa package is available (current: {self.TABpar.currentVersion}, latest: {self.TABpar.latestVersion}).\nPlease, {exitSuggestion}install it with the following command:\n{command}'
876
+ else:
877
+ Message=f'The version of the current instance of PaIRS_UniNa ({self.TABpar.currentVersion}) is newer than the latest official releas ({self.TABpar.latestVersion})!\nYou should contact Tommaso and Gerardo if you are a developer and some relevant change is made by yourself!\nIf you are a user, enjoy this beta version and please report any issue!'
878
+ if flagExit:
879
+ print(f"\n{'*'*100}\n"+Message+f"\n{'*'*100}\n")
880
+ if flagWarning:
881
+ warningDialog(self,Message,time_milliseconds=time_milliseconds,flagScreenCenter=True,pixmap=''+ icons_path +'flaticon_PaIRS_download.png' if self.TABpar.FlagOutDated>0 else ''+ icons_path +'flaticon_PaIRS_beta.png',FlagStayOnTop=FlagStayOnTop,addButton={"See what's new!": lambda: QDesktopServices.openUrl(QUrl("https://pypi.org/project/PaIRS-UniNa/"))} if self.TABpar.FlagOutDated>0 else {})
882
+
883
+ def downloadLatestVersion(self,app):
884
+ try:
885
+ print(f'{"*"*20} Upgrading PaIRS_UniNa {"*"*20}')
886
+ splash=showSplash(filename=''+ icons_path +'logo_PaIRS_download.png')
887
+ app.processEvents()
888
+ reqs=subprocess.run([sys.executable, '-m', 'pip', 'install','--upgrade','PaIRS_UniNa'],capture_output=True)
889
+ print(reqs.stderr.decode("utf-8"))
890
+ print(reqs.stdout.decode("utf-8"))
891
+ print(f'{"*"*20} PaIRS_UniNa upgraded {"*"*20}')
892
+ #reqs=subprocess.run([sys.executable, '-m', 'pip', 'install','PaIRS_UniNa'],capture_output=True)
893
+ #print(reqs.stderr.decode("utf-8"))
894
+ #print(reqs.stdout.decode("utf-8"))
895
+ splash.hide()
896
+ except Exception as inst:
897
+ print(inst)
898
+ try:
899
+ warningDialog(self,f'The following error occured while downloading the latest version of the PaIRS_UniNa package from https://pypi.org:\n{inst}.\n\nPlease, try by yourself with the following command:\nnpython -m pip install --upgrade PaIRS_UniNa')
900
+ except Exception as inst:
901
+ print(inst)
902
+
903
+ def button_download_PaIRS_action(self,app):
904
+ warningLatestVersion(self,app,flagExit=0,flagWarning=1)
905
+ return
906
+ flagStopAndDownload=questionDialog(self,f'A new version of the PaIRS_UniNa package is available. Do you want to close the current instance of {self.name} and download it?')
907
+ if not flagStopAndDownload: return
908
+ self.TABpar.FlagOutDated=0
909
+ self.close()
910
+ downloadLatestVersion(self,app)
911
+ print(f'{"*"*20} Relaunching PaIRS {"*"*20}')
912
+ if self.name=='CalVi': command='-calvi'
913
+ else: command=''
914
+ subprocess.call(sys.executable+' -m PaIRS_UniNa '+command,shell=True)
915
+ #runPaIRS(self,flagQuestion=False)
916
+
917
+ def checkOutDated(packageName:str,printOutDated):
918
+ '''
919
+ Check if a package is out dated works asynchronously.
920
+ call with
921
+ checkOutDated('PaIRS_UniNa',printOutDated)
922
+ Input
923
+ packageName the name of the package
924
+ fun a function that is called when ready and in input will receive a bool (True if outdated and a string that explain to the user what to do)
925
+ def printOutDated(flagOutDated,sOut):
926
+ if flagOutDated==1:
927
+ print (sOut)
928
+ elseif flagOutDated=-1:
929
+ print ('Error from pip ')
930
+ else:
931
+ pass #in this case the last version of the package is installed
932
+ '''
933
+ async def checkOutDatedInternal(packageName):
934
+ #reqs = subprocess.check_output([sys.executable, '-m', 'pip', 'list','--outdated'])
935
+ #reqs = subprocess.run([sys.executable, '-m', 'pip', 'list','--outdated'],capture_output=True)
936
+ #reqs = subprocess.check_output([sys.executable, '-m', 'pip', 'index','versions','PaIRS_UniNa'])
937
+ #reqs = subprocess.check_output([sys.executable, '-m', 'pip', 'install','PaIRS_UniNa=='])
938
+
939
+ """"
940
+ reqs = subprocess.run([sys.executable, '-m', 'pip', 'list','--outdated'],capture_output=True)
941
+ outDated = [r.decode().split('==')[0] for r in reqs.stdout.split()]
942
+ """
943
+ flagOutDated=-1000
944
+ currentVersion='none'
945
+ latestVersion=''
946
+ try:
947
+ if Flag_DEBUG:
948
+ currentVersion=__version__+'.'+__subversion__ if int(__subversion__) else __version__
949
+ else:
950
+ command=[sys.executable, '-m', 'pip', 'show', packageName]
951
+ reqs = subprocess.run(command,capture_output=True)
952
+ if reqs.returncode:
953
+ pri.Error.red('Error in command:\n'+' '.join(command)+'\n'+reqs.stderr.decode("utf-8") )
954
+ return flagOutDated,currentVersion,latestVersion
955
+ printing=reqs.stdout.decode("utf-8")
956
+ pri.Info.cyan( printing )
957
+ r=reqs.stdout.decode("utf-8").replace('\r','').split('\n')
958
+ currentVersion='none'
959
+ for s in r:
960
+ if 'Version: ' in s:
961
+ currentVersion=s.replace('Version: ','')
962
+ break
963
+ if currentVersion!=__version__:
964
+ message=f'Greetings, developer!\nThe version of the current instance of PaIRS_UniNa ({__version__}) is different from that installed in the present Python environment ({currentVersion})!\nYou should contact Tommaso and Gerardo if some relevant change is made by yourself!'
965
+ pri.Info.yellow(f'{"-"*50}\n{message}\n{"-"*50}\n')
966
+ command=[sys.executable, '-m', 'pip', 'index','versions',packageName]
967
+ reqs = subprocess.run(command,capture_output=True)
968
+ if not reqs.returncode:
969
+ printing=reqs.stdout.decode("utf-8")
970
+ pri.Info.cyan( printing )
971
+ r=reqs.stdout.decode("utf-8").replace('\r','').split('\n')
972
+ #currentVersion=r[0].replace(packageName,'').replace('(','').replace(')','').replace(' ','')
973
+ latestVersion=r[1].replace('Available versions: ','').split(',')[0]
974
+ else:
975
+ pri.Error.red('Error in command:\n'+' '.join(command)+'\n'+reqs.stderr.decode("utf-8") )
976
+
977
+ command=[sys.executable, '-m', 'pip', 'list','--outdated']
978
+ reqs = subprocess.run(command,capture_output=True)
979
+ if reqs.returncode:
980
+ pri.Error.red('Error in command:\n'+' '.join(command)+'\n'+reqs.stderr.decode("utf-8") )
981
+ return flagOutDated,currentVersion,latestVersion
982
+ outDated = [r.decode().split('==')[0] for r in reqs.stdout.split()]
983
+ if packageName in outDated:
984
+ i=outDated.index(packageName)
985
+ latestVersion=outDated[i+2]
986
+ else:
987
+ latestVersion=currentVersion
988
+ pri.Info.cyan(f'{packageName} ({currentVersion}). Latest version available: {latestVersion}')
989
+ #flagOutDated=1 if currentVersion!=latestVersion else 0
990
+ cV_parts=[int(c) for c in currentVersion.split('.')]
991
+ lV_parts=[int(c) for c in latestVersion.split('.')]
992
+ flagOutDated=1 if (cV_parts[0] < lV_parts[0] or
993
+ cV_parts[1] < lV_parts[1] or
994
+ cV_parts[2] < lV_parts[2]) \
995
+ else -1 if (cV_parts[0] > lV_parts[0] or
996
+ cV_parts[1] > lV_parts[1] or
997
+ cV_parts[2] > lV_parts[2] ) \
998
+ or (cV_parts[0] == lV_parts[0] and
999
+ cV_parts[1] == lV_parts[1] and
1000
+ cV_parts[2] == lV_parts[2] and len(cV_parts)>len(lV_parts)) \
1001
+ else 0
1002
+ except Exception as inst:
1003
+ pri.Error.red(inst)
1004
+ return flagOutDated,currentVersion,latestVersion
1005
+ def checkOutDatedComplete(_f3):
1006
+ flagOutDated,currentVersion,latestVersion=_f3.result()
1007
+ printOutDated (flagOutDated,currentVersion,latestVersion)
1008
+ executor = concurrent.futures.ThreadPoolExecutor(max_workers=2)
1009
+ f3=executor.submit(asyncio.run,checkOutDatedInternal(packageName))
1010
+ f3.add_done_callback(checkOutDatedComplete)
1011
+
1012
+ def changes(self,TabType,filename,title=" Changes"):
1013
+ FlagShow=False
1014
+ if self.logChanges:
1015
+ if self.logChanges.isVisible():
1016
+ FlagShow=True
1017
+ if FlagShow:
1018
+ self.logChanges.hide()
1019
+ self.logChanges.show()
1020
+ else:
1021
+ self.logChanges=TabType(self,True)
1022
+ self.logChanges.resize(720,720)
1023
+ self.logChanges.show()
1024
+ self.logChanges.ui.progress_Proc.hide()
1025
+ self.logChanges.ui.button_close_tab.hide()
1026
+ icon=QPixmap(''+ icons_path +'news.png')
1027
+ self.logChanges.ui.icon.setPixmap(icon)
1028
+ self.logChanges.setWindowIcon(self.windowIcon())
1029
+ self.logChanges.setWindowTitle(title)
1030
+ self.logChanges.ui.name_tab.setText(title)
1031
+
1032
+ self.logChanges.ui.log.setLineWrapColumnOrWidth(self.logChanges.ui.log.width()-20)
1033
+ self.logChanges.ui.log.setStyleSheet("")
1034
+
1035
+ def setFontPixelSize(logChanges:type(self.logChanges),fPixSize):
1036
+ logfont=self.font()
1037
+ logfont.setFamily(fontName)
1038
+ logfont.setPixelSize(fPixSize+2)
1039
+ logChanges.ui.log.setFont(logfont)
1040
+ fPixSize_TabNames=min([fPixSize*2,30])
1041
+ lab=logChanges.ui.name_tab
1042
+ font=lab.font()
1043
+ font.setPixelSize(fPixSize_TabNames)
1044
+ lab.setFont(font)
1045
+ self.logChanges.setFontPixelSize=lambda fS: setFontPixelSize(self.logChanges,fS)
1046
+ self.logChanges.setFontPixelSize(self.TABpar.fontPixelSize)
1047
+ def logResizeEvent(logChanges:type(self.logChanges),e):
1048
+ super(type(logChanges),logChanges).resizeEvent(e)
1049
+ logChanges.ui.log.setLineWrapColumnOrWidth(logChanges.ui.log.width()-20)
1050
+ self.logChanges.ui.log.resizeEvent=lambda e: logResizeEvent(self.logChanges,e)
1051
+
1052
+ self.logChanges.ui.icon.addfuncclick['whatsnew']=self.whatsNew
1053
+ self.logChanges.ui.icon.setCustomCursor()
1054
+
1055
+ try:
1056
+ file = open(filename, "rb")
1057
+ content = file.read().decode("utf-8")
1058
+ self.logChanges.ui.log.setText(content)
1059
+ file.close()
1060
+ except Exception as inst:
1061
+ pri.Error.red(f'There was a problem while reading the file {filename}:\n{inst}')
1062
+ self.logChanges.ui.log.setText(f'No information about PaIRS-UniNa updates available!\n\nSorry for this, try to reinstall PaIRS-UniNa or alternatively contact the authors at {__mail__}.')
1063
+ return
1064
+
1065
+ import webbrowser
1066
+ def downloadExampleData(self,url):
1067
+ Message=f'Test data are available at the following link:\n{url}'
1068
+ warningDialog(self,Message,pixmap=''+ icons_path +'flaticon_PaIRS_download.png',title='Download test data',addButton={'Download data!':lambda:webbrowser.open(url)})
1069
+
1070
+ def optimalPivCores(totCore,nImgs,penCore=1):
1071
+ ''' Used to determine the optimal number of pivCores as a function of the total number of cores and the number of imag to be processed
1072
+ totCore is the total number of cores that can be used
1073
+ nImgs is the number of images
1074
+ penCore is a penalization for the internal parallelization of the PIV process if = to 1 the parallelization it is assumed to be perfect
1075
+ Most probably a value of 0.95-1 should work correctly
1076
+ with 0.95 adding the xth pivCore is counted as: x=10->0.63 20->0.38 40->0.14 80->0.017
1077
+ with 0.98 adding the xth pivCore is counted as: x=10->0.83 20->0.68 40->0.45 80->0.20
1078
+ Output
1079
+ nPivMax the number of pivCores to be used
1080
+ nCoreMax the number of multiProces to be used
1081
+ '''
1082
+ pen=1 #initially the penalization is zero
1083
+ procPower=1 # the processing power of piv is not directly proportional to the numbers of cores
1084
+ nCorePerImgMax=0
1085
+ nPivMax=0
1086
+ for nPiv in range(1,totCore+1):
1087
+ nProc=floor(totCore/nPiv)
1088
+ nCicli=ceil(nImgs/nProc)
1089
+ nCorePerImg=procPower/nCicli
1090
+ #♥print(nPiv,nProc,pen,procPower,nCorePerImg,nCicli)
1091
+ if nCorePerImg>nCorePerImgMax:
1092
+ nCorePerImgMax=nCorePerImg
1093
+ nPivMax=nPiv
1094
+ pen*=penCore
1095
+ procPower+=pen
1096
+ nCoreMax=floor(totCore/nPivMax)
1097
+ #nPivMax=floor(totCore/nCoreMax)
1098
+ return nPivMax,nCoreMax
1099
+
1100
+ from PySide6.QtCore import qInstallMessageHandler, QtMsgType
1101
+ def custom_qt_message_handler(mode, context, message):
1102
+ if ("QPainter" in message or "paintEngine" in message):
1103
+ return #Silenzia questi messaggi
1104
+ print(message) #Altrimenti stampali normalmente (oppure loggali)
1105
+ qInstallMessageHandler(custom_qt_message_handler)
1106
+
1107
+ """
1108
+ def custom_qt_message_handler(mode, context, message):
1109
+ if "QPainter" in message or "paintEngine" in message:
1110
+ print("\n!!! Intercepted Qt message:")
1111
+ print(message)
1112
+ print("\n*** Current Python stacktrace:")
1113
+ traceback.print_stack() # Questo stampa lo stack in cui è stato generato il messaggio
1114
+ else:
1115
+ print(message)
1116
+ qInstallMessageHandler(custom_qt_message_handler)
1117
+ import functools
1118
+ import traceback
1119
+ def log_qpainter_usage(func):
1120
+ @functools.wraps(func)
1121
+ def wrapper(*args, **kwargs):
1122
+ print(f"\n°°° Execution of {func.__name__} in {func.__module__}")
1123
+ traceback.print_stack(limit=4) # Mostra solo lo stack alto
1124
+ return func(*args, **kwargs)
1125
+ return wrapper
1126
+ """
1127
+
1128
+ class PaIRSApp(QApplication):
1129
+ def __init__(self,*args):
1130
+ super().__init__(*args)
1131
+ self.installMessageHandler()
1132
+ self.setStyle('Fusion')
1133
+
1134
+ def applicationSupportsSecureRestorableState(self):
1135
+ return True
1136
+
1137
+ def message_handler(self, mode, context, message):
1138
+ if "QBasicTimer::start" not in message and "QObject::startTimer" not in message:
1139
+ print(message)
1140
+
1141
+ def installMessageHandler(self):
1142
+ qInstallMessageHandler(self.message_handler)
1143
+
1144
+ rqrdpckgs_filename=foldPaIRS+"rqrdpckgs.txt"
1145
+ from packaging.version import Version
1146
+ import importlib.metadata
1147
+
1148
+ def resetRequiredPackagesFile(filename=rqrdpckgs_filename):
1149
+ # Leggi il contenuto esistente
1150
+ try:
1151
+ with open(filename, "r") as f:
1152
+ lines = f.readlines()
1153
+ except FileNotFoundError:
1154
+ pri.Error.red(f"resetRequiredPackagesFile: File {filename} not found.")
1155
+ return
1156
+
1157
+ with open(filename, "w") as f:
1158
+ for line in lines:
1159
+ parts = line.strip().split()
1160
+ if len(parts) >= 3:
1161
+ pkg = parts[0]
1162
+ vmin = parts[1]
1163
+ vmax = parts[2]
1164
+ f.write(f"{pkg}\t{vmin}\t{vmax}\t0\n")
1165
+ else:
1166
+ pri.Error.red(f"resetRequiredPackagesFile: Skipping malformed line: {line}")
1167
+
1168
+ def checkRequiredPackages(self, filename=rqrdpckgs_filename, FlagDisplay=False, FlagForcePrint=False):
1169
+ required_packages = []
1170
+ vmin_list = []
1171
+ vmax_list = []
1172
+ vcurr_list = []
1173
+
1174
+ # Read file
1175
+ with open(filename, "r") as f:
1176
+ for line in f:
1177
+ #pri.Info.white(line)
1178
+ parts = line.strip().split()
1179
+ if len(parts) >= 4:
1180
+ required_packages.append(parts[0])
1181
+ vmin_list.append(Version(parts[1]))
1182
+ vmax_list.append(Version(parts[2]))
1183
+ vcurr_list.append(Version(parts[3]) if parts[3] != "0" else None)
1184
+ else:
1185
+ pri.Error.red(f"Malformed line: {line}")
1186
+
1187
+ Flag = False
1188
+ warnings = []
1189
+
1190
+ for i, pkg in enumerate(required_packages):
1191
+ try:
1192
+ installed_version = Version(importlib.metadata.version(pkg))
1193
+ except importlib.metadata.PackageNotFoundError:
1194
+ installed_version = None
1195
+
1196
+ # Update current installed version
1197
+ if installed_version is not None and (installed_version != vcurr_list[i] or FlagDisplay):
1198
+ vcurr_list[i] = installed_version
1199
+ Flag = True
1200
+
1201
+ # Check if within [vmin, vmax]
1202
+ if not (vmin_list[i] <= installed_version <= vmax_list[i]):
1203
+ """
1204
+ warnings.append(
1205
+ f"- {pkg}: installed = {installed_version}, target range = [{vmin_list[i]}, {vmax_list[i]}]"
1206
+ )
1207
+ """
1208
+ warnings.append(
1209
+ f"- {pkg} {installed_version} not in [{vmin_list[i]}, {vmax_list[i]}]"
1210
+ )
1211
+
1212
+ # Show warning
1213
+ if len(warnings)>0: self.FlagPackIssue=True
1214
+ if len(warnings)>0 or FlagForcePrint:
1215
+ message = (
1216
+ "Some installed packages have a version outside the target range used to develop "
1217
+ "the current release of the PaIRS_UniNa package.\n\n"
1218
+ "This may lead to compatibility issues. If you experience unexpected behavior, "
1219
+ "it is recommended to either reinstall the last tested compatible versions."
1220
+ f" If any issue occurs, please contact the authors at {__mail__}.\n\n"
1221
+ #"or use the standalone executable available at:\n"
1222
+ #"https://pairs.unina.it/#download\n\n"
1223
+ "Incompatible packages:\n"
1224
+ + "\n".join(warnings) +
1225
+ "\n\nYou may reinstall the last compatible versions using the following commands:\n\n"
1226
+ )
1227
+ for i, pkg in enumerate(required_packages):
1228
+ if vcurr_list[i] is not None and (not (vmin_list[i] <= vcurr_list[i] <= vmax_list[i]) or FlagForcePrint):
1229
+ message += (
1230
+ f"python -m pip uninstall {pkg}\n"
1231
+ f"python -m pip install {pkg}=={vmax_list[i]}\n"
1232
+ )
1233
+
1234
+ warningDialog(
1235
+ self,
1236
+ Message=message,
1237
+ flagScreenCenter=True,
1238
+ pixmap=icons_path + 'python_warning.png',
1239
+ pixmapSize=96
1240
+ )
1241
+ elif FlagDisplay:
1242
+ warningDialog(self, Message="All installed packages are within the expected version range.", flagScreenCenter=True,pixmap=icons_path+'greenv.png')
1243
+
1244
+ # Update file if needed
1245
+ if Flag:
1246
+ with open(filename, "w") as f:
1247
+ for pkg, vmin, vmax, vcurr in zip(required_packages, vmin_list, vmax_list, vcurr_list):
1248
+ f.write(f"{pkg}\t{vmin}\t{vmax}\t{vcurr if vcurr else 0}\n")
1249
+
1250
+ return required_packages, vmin_list, vmax_list, vcurr_list