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