PaIRS-UniNa 0.1.13__cp310-cp310-win_amd64.whl → 0.2.8__cp310-cp310-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.
- PaIRS_UniNa/Calibration_Tab.py +331 -0
- PaIRS_UniNa/Changes.txt +134 -2
- PaIRS_UniNa/Custom_Top.py +299 -299
- PaIRS_UniNa/Explorer.py +3136 -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 +3025 -0
- PaIRS_UniNa/Log_Tab.py +57 -14
- PaIRS_UniNa/Output_Tab.py +922 -0
- PaIRS_UniNa/PaIRS_PIV.py +111 -18
- PaIRS_UniNa/PaIRS_pypacks.py +698 -140
- PaIRS_UniNa/Process_Tab.py +1221 -1402
- PaIRS_UniNa/Process_Tab_CalVi.py +137 -262
- PaIRS_UniNa/Process_Tab_Disp.py +163 -0
- PaIRS_UniNa/Process_Tab_Min.py +120 -0
- PaIRS_UniNa/Saving_tools.py +296 -0
- PaIRS_UniNa/TabTools.py +863 -543
- PaIRS_UniNa/Vis_Tab.py +1898 -1315
- PaIRS_UniNa/Vis_Tab_CalVi.py +484 -356
- PaIRS_UniNa/Whatsnew.py +59 -10
- PaIRS_UniNa/_PaIRS_PIV.pyd +0 -0
- PaIRS_UniNa/__init__.py +4 -3
- PaIRS_UniNa/addwidgets_ps.py +326 -56
- PaIRS_UniNa/calib.py +19 -12
- PaIRS_UniNa/calibView.py +48 -25
- PaIRS_UniNa/gPaIRS.py +3902 -3461
- PaIRS_UniNa/gPalette.py +189 -170
- 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/bin_off.png +0 -0
- PaIRS_UniNa/icons/bin_on.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/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/close_all.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/cut.png +0 -0
- PaIRS_UniNa/icons/cut_warnings.png +0 -0
- PaIRS_UniNa/icons/darkmode.png +0 -0
- PaIRS_UniNa/icons/disp_step.png +0 -0
- PaIRS_UniNa/icons/disp_step_off.png +0 -0
- PaIRS_UniNa/icons/edit_list.png +0 -0
- PaIRS_UniNa/icons/example_list.png +0 -0
- PaIRS_UniNa/icons/flaticon_PaIRS_beta.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/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/import_set.png +0 -0
- PaIRS_UniNa/icons/information.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/log_logo.png +0 -0
- PaIRS_UniNa/icons/logo_opaco.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/new_workspace.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/paused.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/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/read.png +0 -0
- PaIRS_UniNa/icons/read_list.png +0 -0
- PaIRS_UniNa/icons/reset.png +0 -0
- PaIRS_UniNa/icons/reset_levels.png +0 -0
- PaIRS_UniNa/icons/restore_undo.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/save_and_stop.png +0 -0
- PaIRS_UniNa/icons/save_cfg.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/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/unedited.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/vectorColor.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/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 +8 -8
- PaIRS_UniNa/parForMulti.py +7 -5
- PaIRS_UniNa/parForWorkers.py +370 -31
- PaIRS_UniNa/pivParFor.py +233 -229
- PaIRS_UniNa/plt_util.py +141 -141
- PaIRS_UniNa/preProcParFor.py +153 -148
- PaIRS_UniNa/procTools.py +631 -178
- PaIRS_UniNa/readcfg.py +31 -1
- PaIRS_UniNa/rqrdpckgs.txt +9 -0
- PaIRS_UniNa/stereoPivParFor.py +227 -0
- PaIRS_UniNa/tAVarie.py +215 -215
- PaIRS_UniNa/tabSplitter.py +612 -0
- PaIRS_UniNa/ui_Calibration_Tab.py +545 -0
- PaIRS_UniNa/ui_Custom_Top.py +5 -5
- PaIRS_UniNa/ui_Input_Tab.py +1101 -0
- PaIRS_UniNa/{ui_Import_Tab_CalVi.py → ui_Input_Tab_CalVi.py} +1282 -1275
- PaIRS_UniNa/ui_Log_Tab.py +262 -257
- PaIRS_UniNa/{ui_Export_Tab.py → ui_Output_Tab.py} +2361 -1778
- PaIRS_UniNa/ui_Process_Tab.py +3809 -3758
- PaIRS_UniNa/ui_Process_Tab_CalVi.py +1547 -1546
- PaIRS_UniNa/ui_Process_Tab_Disp.py +1141 -0
- PaIRS_UniNa/ui_Process_Tab_Min.py +437 -0
- PaIRS_UniNa/ui_Vis_Tab.py +1626 -1208
- PaIRS_UniNa/ui_Vis_Tab_CalVi.py +1249 -1249
- PaIRS_UniNa/ui_Whatsnew.py +131 -131
- PaIRS_UniNa/ui_gPairs.py +876 -950
- PaIRS_UniNa/ui_infoPaIRS.py +550 -425
- PaIRS_UniNa/whatsnew.txt +6 -4
- {PaIRS_UniNa-0.1.13.dist-info → pairs_unina-0.2.8.dist-info}/METADATA +69 -51
- pairs_unina-0.2.8.dist-info/RECORD +329 -0
- {PaIRS_UniNa-0.1.13.dist-info → pairs_unina-0.2.8.dist-info}/WHEEL +1 -1
- PaIRS_UniNa/CalVi.py +0 -18
- PaIRS_UniNa/Export_Tab.py +0 -574
- PaIRS_UniNa/Import_Tab.py +0 -657
- PaIRS_UniNa/Import_Tab_CalVi.py +0 -861
- PaIRS_UniNa/Import_Tab_tools.py +0 -598
- PaIRS_UniNa/Tree_Tab.py +0 -543
- PaIRS_UniNa/gCalVi.py +0 -2024
- PaIRS_UniNa/icons/add.png +0 -0
- PaIRS_UniNa/icons/cancelled.png +0 -0
- PaIRS_UniNa/icons/chain.png +0 -0
- PaIRS_UniNa/icons/chain_broken.png +0 -0
- PaIRS_UniNa/icons/default_sizes.png +0 -0
- PaIRS_UniNa/icons/dock_tabs.png +0 -0
- PaIRS_UniNa/icons/done.png +0 -0
- PaIRS_UniNa/icons/down_arrow.png +0 -0
- PaIRS_UniNa/icons/export_logo.png +0 -0
- PaIRS_UniNa/icons/fast_delete.png +0 -0
- PaIRS_UniNa/icons/flip_y.png +0 -0
- PaIRS_UniNa/icons/ganci.png +0 -0
- PaIRS_UniNa/icons/import_blue.png +0 -0
- PaIRS_UniNa/icons/import_logo.png +0 -0
- PaIRS_UniNa/icons/missing.png +0 -0
- PaIRS_UniNa/icons/process_icon.png +0 -0
- PaIRS_UniNa/icons/processing.png +0 -0
- PaIRS_UniNa/icons/restart.png +0 -0
- PaIRS_UniNa/icons/right_arrow.png +0 -0
- PaIRS_UniNa/icons/run_piv.png +0 -0
- PaIRS_UniNa/icons/terminal.png +0 -0
- PaIRS_UniNa/icons/undock_tabs.png +0 -0
- PaIRS_UniNa/icons/vect_field.png +0 -0
- PaIRS_UniNa/icons/w0.png +0 -0
- PaIRS_UniNa/icons/w1.png +0 -0
- PaIRS_UniNa/icons/w2.png +0 -0
- PaIRS_UniNa/icons/w3.png +0 -0
- PaIRS_UniNa/icons/w4.png +0 -0
- PaIRS_UniNa/icons/w5.png +0 -0
- PaIRS_UniNa/run_CalVi.py +0 -14
- PaIRS_UniNa/run_gcalvi.py +0 -5
- PaIRS_UniNa/ui_Import_Tab.py +0 -1077
- PaIRS_UniNa/ui_Tree_Tab.py +0 -684
- PaIRS_UniNa/ui_gCalVi.py +0 -640
- PaIRS_UniNa/ui_infoCalVi.py +0 -428
- PaIRS_UniNa-0.1.13.dist-info/LICENSE +0 -19
- PaIRS_UniNa-0.1.13.dist-info/RECORD +0 -174
- /PaIRS_UniNa/icons/{clean_queue.png → clean.png} +0 -0
- /PaIRS_UniNa/icons/{waiting_c.png → sandglass.png} +0 -0
- {PaIRS_UniNa-0.1.13.dist-info → pairs_unina-0.2.8.dist-info}/top_level.txt +0 -0
PaIRS_UniNa/PaIRS_pypacks.py
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
from math import ceil, floor
|
|
1
2
|
#PrintTA.flagPriority=PrintTAPriority.always
|
|
2
|
-
Flag_DEBUG=
|
|
3
|
+
Flag_DEBUG=False
|
|
3
4
|
Flag_DEBUG_PARPOOL=False
|
|
5
|
+
FlagPrintTime=False
|
|
6
|
+
FlagPrintCoding=False
|
|
7
|
+
|
|
4
8
|
pwddbg='Buss4Co1Pied1'
|
|
5
9
|
time_warnings_debug=-1 #10000 #milliseconds #5000
|
|
6
10
|
|
|
@@ -8,34 +12,112 @@ import uuid
|
|
|
8
12
|
basefold='./'
|
|
9
13
|
basefold_DEBUGOptions=[]
|
|
10
14
|
basefold_DEBUG='./'
|
|
15
|
+
basefold_DEBUG_VIS=''
|
|
11
16
|
#basefold='B:/dl/apairs/jetcross'
|
|
12
|
-
|
|
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
|
|
13
78
|
basefold_DEBUG='C:/desk/PIV_Img/_data/PIV_data/virtual_case/'
|
|
14
79
|
basefold_DEBUGOptions=[
|
|
15
80
|
'C:/desk/PIV_Img/img1/',
|
|
16
|
-
'C:/desk/PIV_Img/_data/PIV_data/virtual_case/',
|
|
81
|
+
'C:/desk/PIV_Img/_data/PIV_data/virtual_case/',
|
|
17
82
|
'C:/desk/PIV_Img/_data/PIV_data/real_case/',
|
|
18
83
|
'C:/desk/PIV_Img/_data/Calibration_data/pinhole/',
|
|
19
|
-
'C:/desk/PIV_Img/_data/Calibration_data/cylinder/'
|
|
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/',
|
|
20
95
|
]
|
|
21
|
-
|
|
22
|
-
|
|
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/'
|
|
23
99
|
basefold_DEBUGOptions=[
|
|
24
100
|
'/Users/gerardo/Desktop/PIV_Img/img1/',
|
|
25
|
-
'/Users/gerardo/Desktop/PaIRS_examples/PIV_data/virtual_case/',
|
|
101
|
+
'/Users/gerardo/Desktop/PaIRS_examples/PIV_data/virtual_case/',
|
|
102
|
+
#'/Users/gerardo/Desktop/PaIRS_examples/PIV_data/virtual_case_2/',
|
|
26
103
|
'/Users/gerardo/Desktop/PaIRS_examples/PIV_data/real_case/',
|
|
104
|
+
'/Users/gerardo/Desktop/PaIRS_examples/SPIV_data/real_case/img/',
|
|
27
105
|
'/Users/gerardo/Desktop/PaIRS_examples/Calibration_data/pinhole/',
|
|
28
106
|
'/Users/gerardo/Desktop/PaIRS_examples/Calibration_data/cylinder/'
|
|
29
107
|
]
|
|
30
|
-
|
|
31
|
-
|
|
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'
|
|
32
112
|
basefold_DEBUGOptions=[
|
|
33
113
|
'C:/desk/PIV_Img/img1/',
|
|
34
114
|
'C:/desk/PIV_Img/swirler_png/',
|
|
35
115
|
'../../img/calib/',
|
|
36
|
-
'C:\desk\Attuali\PythonLibC\PIV\img',
|
|
116
|
+
r'C:\desk\Attuali\PythonLibC\PIV\img',
|
|
37
117
|
]
|
|
38
|
-
|
|
118
|
+
basefold_DEBUG_VIS=''
|
|
119
|
+
else:
|
|
120
|
+
FlagAddMotherBoard=True
|
|
39
121
|
|
|
40
122
|
#fontName='Inter'
|
|
41
123
|
#fontName='Cambria'
|
|
@@ -58,17 +140,17 @@ imin_im_pair=1 #minimum index value for image pair
|
|
|
58
140
|
|
|
59
141
|
f_empty_width=250 #blank space in scrollable area within the main window
|
|
60
142
|
time_ScrollBar=250 #time of animation of scroll area
|
|
61
|
-
|
|
143
|
+
time_callback2_async=0 #time to test async callbacks
|
|
62
144
|
time_showSplashOnTop=250
|
|
145
|
+
pathCompleterLength=10
|
|
63
146
|
|
|
64
147
|
fileChanges='Changes.txt'
|
|
65
148
|
fileWhatsNew=['whatsnew.txt','whatwasnew.txt']
|
|
66
149
|
icons_path="icons/"
|
|
67
150
|
|
|
68
151
|
from psutil import cpu_count
|
|
69
|
-
|
|
70
|
-
if
|
|
71
|
-
NUMTHREADS_PIV_MAX=NUMTHREADS_PIV
|
|
152
|
+
NUMTHREADS_MAX=cpu_count(logical=True)#-1
|
|
153
|
+
if NUMTHREADS_MAX<1: NUMTHREADS_MAX=1
|
|
72
154
|
ParFor_sleepTime=0.1
|
|
73
155
|
#multithreading
|
|
74
156
|
FlagStopWorkers=[0]#messo qui ma utilizzato solo da min e PIV
|
|
@@ -76,7 +158,7 @@ NUMTHREADS_gPaIRS=0
|
|
|
76
158
|
SleepTime_Workers=0.5 #for multithreading and other stuff
|
|
77
159
|
timeOutWorker=0 # used in parfor when the proces is stuck
|
|
78
160
|
|
|
79
|
-
from .__init__ import __version__,__year__,__mail__
|
|
161
|
+
from .__init__ import __version__,__subversion__,__year__,__mail__
|
|
80
162
|
from PySide6 import QtCore, QtGui, QtWidgets
|
|
81
163
|
from PySide6.QtCore import*
|
|
82
164
|
from PySide6.QtGui import *
|
|
@@ -98,14 +180,43 @@ from .tAVarie import *
|
|
|
98
180
|
deltaTimePlot=0.75
|
|
99
181
|
import concurrent.futures
|
|
100
182
|
import gc#garbage collection si può eliminare
|
|
101
|
-
import psutil
|
|
102
183
|
from .mtfPIV import *
|
|
103
184
|
|
|
104
|
-
import subprocess
|
|
105
185
|
import sys
|
|
106
186
|
import concurrent.futures
|
|
107
187
|
import asyncio
|
|
108
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'
|
|
109
220
|
|
|
110
221
|
class ColorPrint:
|
|
111
222
|
def __init__(self,flagTime=False,prio=PrintTAPriority.medium,faceStd=PrintTA.faceStd,flagFullDebug=False):
|
|
@@ -138,14 +249,15 @@ class ColorPrint:
|
|
|
138
249
|
#flagFullDebug=True means that the printing is available only if fullDebug mode is active
|
|
139
250
|
class GPaIRSPrint:
|
|
140
251
|
def __init__(self):
|
|
141
|
-
self.General=ColorPrint(prio=PrintTAPriority.medium)
|
|
142
252
|
self.Info=ColorPrint(prio=PrintTAPriority.medium)
|
|
143
|
-
self.Time=ColorPrint(prio=PrintTAPriority.veryLow,flagTime=True,faceStd=PrintTA.faceUnderline)
|
|
253
|
+
self.Time=ColorPrint(prio=PrintTAPriority.medium if FlagPrintTime else PrintTAPriority.veryLow,flagTime=True,faceStd=PrintTA.faceUnderline)
|
|
144
254
|
self.Error=ColorPrint(prio=PrintTAPriority.medium,faceStd=PrintTA.faceBold)
|
|
255
|
+
self.IOError=ColorPrint(prio=PrintTAPriority.veryLow,faceStd=PrintTA.faceBold)
|
|
145
256
|
self.Process=ColorPrint(prio=PrintTAPriority.veryLow)
|
|
146
257
|
self.Callback=ColorPrint(prio=PrintTAPriority.veryLow)
|
|
147
|
-
self.
|
|
258
|
+
self.TABparDiff=ColorPrint(prio=PrintTAPriority.veryLow)
|
|
148
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)
|
|
149
261
|
|
|
150
262
|
pri=GPaIRSPrint()
|
|
151
263
|
printTypes={}
|
|
@@ -169,12 +281,6 @@ PaIRS_Header=f'PaIRS - version {__version__}\n'+\
|
|
|
169
281
|
f'email: {__mail__}\n'+\
|
|
170
282
|
'****************************************\n'
|
|
171
283
|
|
|
172
|
-
CalVi_Header=f'CalVi - version {__version__}\n'+\
|
|
173
|
-
'Calibration Visualizer\n'+\
|
|
174
|
-
f'(C) {__year__} Gerardo Paolillo & Tommaso Astarita.\nAll rights reserved.\n'+\
|
|
175
|
-
f'email: {__mail__}\n'+\
|
|
176
|
-
'****************************************\n'
|
|
177
|
-
|
|
178
284
|
from .parForMulti import *
|
|
179
285
|
#from pkg_resources import resource_filename
|
|
180
286
|
from .parForMulti import ParForMul
|
|
@@ -194,35 +300,90 @@ else:
|
|
|
194
300
|
import PaIRS_PIV as PaIRS_lib
|
|
195
301
|
|
|
196
302
|
if __package__ or "." in __name__:
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
foldPaIRS=
|
|
303
|
+
import importlib.resources as resources
|
|
304
|
+
resources_path = resources.files(__package__)
|
|
305
|
+
foldPaIRS = str(resources_path)+"\\"
|
|
306
|
+
foldPaIRS = foldPaIRS.replace('\\', '/')
|
|
200
307
|
else:
|
|
201
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]
|
|
202
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))
|
|
203
338
|
class outExt:
|
|
339
|
+
#legacy
|
|
204
340
|
cfg='.pairs_cfg'
|
|
205
341
|
dum='.pairs_dum'
|
|
342
|
+
|
|
343
|
+
#Workspaces and projects
|
|
344
|
+
wksp='.pairs_wksp'
|
|
345
|
+
proj='.pairs_proj'
|
|
346
|
+
|
|
347
|
+
#StepTypes
|
|
206
348
|
min='.pairs_min'
|
|
207
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
|
|
208
357
|
pro='.pairs_pro'
|
|
358
|
+
#CalVi
|
|
209
359
|
cfg_calvi='.calvi_cfg'
|
|
210
|
-
cal='.pairs_cal'
|
|
211
360
|
pla='.pairs_pla'
|
|
212
361
|
|
|
213
|
-
lastcfgname='lastuicfg'+outExt.cfg
|
|
214
|
-
lastcfgname_CalVi='lastuicfg'+outExt.cfg_calvi
|
|
215
362
|
|
|
363
|
+
lastcfgname='lastWorkSpace'+outExt.wksp
|
|
216
364
|
fileChanges=foldPaIRS+'Changes.txt'
|
|
217
|
-
fileWhatsNew=[foldPaIRS+f for f in fileWhatsNew]
|
|
218
365
|
icons_path=foldPaIRS+icons_path
|
|
219
|
-
|
|
220
|
-
|
|
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
|
+
|
|
221
380
|
if not os.path.exists(pro_path):
|
|
222
|
-
|
|
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}')
|
|
223
385
|
custom_list_file="pro_list.txt"
|
|
224
386
|
|
|
225
|
-
|
|
226
387
|
exts = Image.registered_extensions()
|
|
227
388
|
supported_exts = sorted({ex for ex, f in exts.items() if f in Image.OPEN})
|
|
228
389
|
text_filter = "Common image files (*.bmp *.gif *.ico *.jpeg *.jpg *.png *.tif *.tiff *.webp"\
|
|
@@ -237,31 +398,50 @@ if Flag_NATIVEDIALOGS:
|
|
|
237
398
|
else:
|
|
238
399
|
optionNativeDialog=QFileDialog.Option.DontUseNativeDialog
|
|
239
400
|
|
|
240
|
-
def warningDialog(self,Message,time_milliseconds=0,flagScreenCenter=False,icon=QIcon(),palette=None,pixmap=None,title='Warning!',flagRichText=False,flagNoButtons=False,addButton=None): #addButton=['Print Message',lambda: print(Message)]
|
|
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)]
|
|
241
402
|
dlg=None
|
|
242
403
|
if Message:
|
|
243
|
-
|
|
404
|
+
if isinstance(self,QMainWindow) and hasattr(self,'w_Input'):
|
|
405
|
+
dlg = QMessageBox(self.w_Input)
|
|
406
|
+
else:
|
|
407
|
+
dlg = QMessageBox(self)
|
|
244
408
|
dlg.setWindowTitle(title)
|
|
245
409
|
dlg.setText(str(Message))
|
|
410
|
+
|
|
246
411
|
if flagRichText: dlg.setTextFormat(Qt.TextFormat.RichText)
|
|
247
412
|
if flagNoButtons:
|
|
248
413
|
dlg.setStandardButtons(QMessageBox.StandardButton.NoButton)
|
|
249
414
|
else:
|
|
250
415
|
dlg.setStandardButtons(QMessageBox.StandardButton.Ok)
|
|
251
|
-
if addButton:
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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))
|
|
258
424
|
dlg.setIcon(QMessageBox.Warning)
|
|
259
425
|
if icon:
|
|
260
|
-
dlg.setWindowIcon(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())
|
|
261
441
|
if palette:
|
|
262
442
|
dlg.setPalette(palette)
|
|
263
443
|
if pixmap:
|
|
264
|
-
dlg.setIconPixmap(QPixmap(pixmap).scaled(
|
|
444
|
+
dlg.setIconPixmap(QPixmap(pixmap).scaled(pixmapSize, pixmapSize, Qt.AspectRatioMode.KeepAspectRatio,Qt.SmoothTransformation))
|
|
265
445
|
if self:
|
|
266
446
|
dlg.setFont(self.font())
|
|
267
447
|
c=dlg.findChildren(QObject)
|
|
@@ -272,22 +452,33 @@ def warningDialog(self,Message,time_milliseconds=0,flagScreenCenter=False,icon=Q
|
|
|
272
452
|
w.setFont(font)
|
|
273
453
|
#dlg.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
|
|
274
454
|
dlg.show()
|
|
275
|
-
if flagScreenCenter and hasattr(self,'
|
|
455
|
+
if flagScreenCenter and hasattr(self,'maximumGeometry'):
|
|
276
456
|
geom=dlg.geometry()
|
|
277
|
-
geom.moveCenter(self.
|
|
457
|
+
geom.moveCenter(self.maximumGeometry.center())
|
|
278
458
|
dlg.setGeometry(geom)
|
|
279
459
|
if time_milliseconds:
|
|
280
460
|
QTimer.singleShot(time_milliseconds, lambda : dlg.done(0))
|
|
281
461
|
else:
|
|
282
462
|
if Flag_DEBUG and time_warnings_debug>=0:
|
|
283
463
|
QTimer.singleShot(time_warnings_debug, lambda : dlg.done(0))
|
|
464
|
+
if FlagStayOnTop: dlg.setWindowFlag(Qt.WindowStaysOnTopHint, True)
|
|
284
465
|
if not flagNoButtons: dlg.exec()
|
|
285
466
|
return dlg
|
|
286
|
-
|
|
467
|
+
|
|
287
468
|
def questionDialog(self,Message,icon=QMessageBox.Warning):
|
|
288
|
-
|
|
469
|
+
if isinstance(self,QMainWindow) and hasattr(self,'w_Input'):
|
|
470
|
+
dlg = QMessageBox(self.w_Input)
|
|
471
|
+
else:
|
|
472
|
+
dlg = QMessageBox(self)
|
|
289
473
|
dlg.setWindowTitle("Warning!")
|
|
290
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())
|
|
291
482
|
|
|
292
483
|
dlg.setStandardButtons(QMessageBox.Yes|QMessageBox.No)
|
|
293
484
|
dlg.setDefaultButton(QMessageBox.Yes)
|
|
@@ -337,10 +528,10 @@ def inputDialog(self,title,label,icon=None,palette=None,completer_list=[],width=
|
|
|
337
528
|
geom.moveCenter(QtGui.QCursor.pos())
|
|
338
529
|
dlg.setGeometry(geom)
|
|
339
530
|
|
|
340
|
-
if flagScreenCenter and hasattr(self,'
|
|
531
|
+
if flagScreenCenter and hasattr(self,'maximumGeometry'):
|
|
341
532
|
dlg.show()
|
|
342
533
|
geom=dlg.geometry()
|
|
343
|
-
geom.moveCenter(self.
|
|
534
|
+
geom.moveCenter(self.maximumGeometry.center())
|
|
344
535
|
dlg.setGeometry(geom)
|
|
345
536
|
|
|
346
537
|
c=dlg.findChildren(QObject)
|
|
@@ -432,24 +623,25 @@ def noPrint(*args,**kwargs):
|
|
|
432
623
|
|
|
433
624
|
#import unidecode
|
|
434
625
|
def myStandardPath(path):
|
|
435
|
-
|
|
436
|
-
currpath=
|
|
437
|
-
if currpath
|
|
438
|
-
|
|
439
|
-
currpath=re.sub(r'\\+',r'/',currpath)
|
|
440
|
-
currpath=currpath+'/'
|
|
441
|
-
currpath=re.sub('/+', '/',currpath)
|
|
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
|
|
442
630
|
return currpath
|
|
443
631
|
|
|
444
632
|
def myStandardRoot(root):
|
|
445
|
-
|
|
446
|
-
currroot=
|
|
447
|
-
|
|
448
|
-
while currroot[-1]==" ": currroot=currroot[:-1]
|
|
449
|
-
currroot=re.sub(r'\\+',r'/',currroot)
|
|
450
|
-
currroot=re.sub('/+', '/',currroot)
|
|
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
|
|
451
636
|
return currroot
|
|
452
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
|
+
|
|
453
645
|
def findFiles_sorted(pattern):
|
|
454
646
|
list_files=glob.glob(pattern)
|
|
455
647
|
files=sorted([re.sub(r'\\+',r'/',f) for f in list_files],key=str.lower)
|
|
@@ -462,6 +654,7 @@ def transfIm(OUT,flagTransf:int=2,Images:list=[],flagRot=1):
|
|
|
462
654
|
flagTransf==2 solo entrambi (default)
|
|
463
655
|
'''
|
|
464
656
|
if len(Images)==0: return
|
|
657
|
+
if OUT.FlagNone: return Images
|
|
465
658
|
|
|
466
659
|
if flagTransf==1: #solo PIV
|
|
467
660
|
ops=OUT.aimop
|
|
@@ -508,15 +701,18 @@ def readCustomListFile():
|
|
|
508
701
|
custom_list=[]
|
|
509
702
|
filename=pro_path+custom_list_file
|
|
510
703
|
if os.path.exists(filename):
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
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')
|
|
520
716
|
return custom_list
|
|
521
717
|
|
|
522
718
|
def setCustomList(task):
|
|
@@ -528,7 +724,7 @@ def setCustomList(task):
|
|
|
528
724
|
var=pickle.load(file)
|
|
529
725
|
task(var,name)
|
|
530
726
|
except Exception as inst:
|
|
531
|
-
pri.Error.red(f'Error while loading custom process file {filename}\t[from list]:\n{traceback.
|
|
727
|
+
pri.Error.red(f'Error while loading custom process file {filename}\t[from list]:\n{traceback.format_exc()}\n\n{inst}')
|
|
532
728
|
custom_list.pop(k)
|
|
533
729
|
if os.path.exists(filename):
|
|
534
730
|
os.remove(filename)
|
|
@@ -543,7 +739,7 @@ def setCustomList(task):
|
|
|
543
739
|
task(var,name)
|
|
544
740
|
custom_list.append(name)
|
|
545
741
|
except Exception as inst:
|
|
546
|
-
pri.Error.red(f'Error while loading custom process file {filename}\t[from disk]:\n{traceback.
|
|
742
|
+
pri.Error.red(f'Error while loading the custom process file {filename}\t[from disk]:\n{traceback.format_exc()}\n\n{inst}')
|
|
547
743
|
if os.path.exists(filename):
|
|
548
744
|
os.remove(filename)
|
|
549
745
|
rewriteCustomList(custom_list)
|
|
@@ -551,10 +747,61 @@ def setCustomList(task):
|
|
|
551
747
|
|
|
552
748
|
def rewriteCustomList(custom_list):
|
|
553
749
|
filename=pro_path+custom_list_file
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
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
|
|
558
805
|
|
|
559
806
|
PlainTextConverter=QtGui.QTextDocument()
|
|
560
807
|
def toPlainText(text):
|
|
@@ -562,12 +809,70 @@ def toPlainText(text):
|
|
|
562
809
|
return PlainTextConverter.toPlainText()
|
|
563
810
|
|
|
564
811
|
def showTip(obj,message):
|
|
565
|
-
tip=QToolTip(obj)
|
|
566
812
|
toolTipDuration=obj.toolTipDuration()
|
|
567
813
|
obj.setToolTipDuration(3000)
|
|
568
|
-
|
|
814
|
+
QToolTip.showText(QCursor.pos(),message)
|
|
569
815
|
obj.setToolTipDuration(toolTipDuration)
|
|
570
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
|
+
|
|
571
876
|
def runPaIRS(self,command='',flagQuestion=True):
|
|
572
877
|
Flag=__package__ or "." in __name__
|
|
573
878
|
pyCommands={
|
|
@@ -598,12 +903,16 @@ def runPaIRS(self,command='',flagQuestion=True):
|
|
|
598
903
|
def run(self):
|
|
599
904
|
try:
|
|
600
905
|
import subprocess
|
|
601
|
-
if
|
|
602
|
-
pri.Info.white(sys.executable+'
|
|
603
|
-
subprocess.call(sys.executable+'
|
|
906
|
+
if Flag_ISEXE:
|
|
907
|
+
pri.Info.white(sys.executable+' '+command)
|
|
908
|
+
subprocess.call(sys.executable+' '+command,shell=True)
|
|
604
909
|
else:
|
|
605
|
-
|
|
606
|
-
|
|
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)
|
|
607
916
|
self.isRunning=False
|
|
608
917
|
except Exception as inst:
|
|
609
918
|
pri.Error.red(inst)
|
|
@@ -632,13 +941,13 @@ def showSplash(filename=''+ icons_path +'logo_PaIRS_completo.png'):
|
|
|
632
941
|
splash.show()
|
|
633
942
|
return splash
|
|
634
943
|
|
|
635
|
-
def checkLatestVersion(self,version,app:QApplication=None,splash:QLabel=None):
|
|
944
|
+
def checkLatestVersion(self,version,app:QApplication=None,splash:QLabel=None,flagWarning=1):
|
|
636
945
|
flagStopAndDownload=False
|
|
637
946
|
var=self.TABpar
|
|
638
947
|
#var.FlagOutDated=0 if currentVersion==var.latestVersion else var.FlagOutDated
|
|
639
|
-
if var.FlagOutDated==1:
|
|
640
|
-
warningLatestVersion(self,app,flagExit=0,flagWarning=
|
|
641
|
-
var.FlagOutDated=2
|
|
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
|
|
642
951
|
"""
|
|
643
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}?')
|
|
644
953
|
if flagStopAndDownload:
|
|
@@ -664,31 +973,42 @@ def checkLatestVersion(self,version,app:QApplication=None,splash:QLabel=None):
|
|
|
664
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}'
|
|
665
974
|
var.FlagOutDated=2 if var.FlagOutDated==2 else 1
|
|
666
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:
|
|
667
979
|
sOut=f'Error from pip: it was not possible to check for a new version of the {packageName} package!'
|
|
668
|
-
var.FlagOutDated
|
|
980
|
+
var.FlagOutDated=-1000
|
|
669
981
|
else:
|
|
670
982
|
sOut=f'{packageName} The current version ({currentVersion}) of {packageName} is up-to-date! Enjoy it!'
|
|
671
983
|
var.FlagOutDated=0
|
|
672
|
-
pri.
|
|
673
|
-
self.signals.printOutDated.emit(
|
|
984
|
+
pri.Info.cyan(f'[{var.FlagOutDated}] '+sOut)
|
|
985
|
+
self.signals.printOutDated.emit()
|
|
674
986
|
#self.ui.button_PaIRS_download.setVisible(flagOutDated>0)
|
|
675
987
|
pass
|
|
676
988
|
|
|
677
989
|
checkOutDated(packageName,printOutDated)
|
|
678
990
|
return flagStopAndDownload
|
|
679
991
|
|
|
680
|
-
def warningLatestVersion(self,app,flagExit=0,flagWarning=0):
|
|
992
|
+
def warningLatestVersion(self,app,flagExit=0,flagWarning=0,time_milliseconds=0,FlagStayOnTop=False):
|
|
681
993
|
if not flagExit:
|
|
682
994
|
exitSuggestion=f'exit the current instance of {self.name} and '
|
|
683
995
|
else:
|
|
684
996
|
exitSuggestion=''
|
|
685
997
|
py=myStandardRoot(sys.executable).split('/')[-1].split('.')[0]
|
|
686
998
|
command=f'{py} -m pip install --upgrade PaIRS_UniNa'
|
|
687
|
-
|
|
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!'
|
|
688
1008
|
if flagExit:
|
|
689
1009
|
print(f"\n{'*'*100}\n"+Message+f"\n{'*'*100}\n")
|
|
690
1010
|
if flagWarning:
|
|
691
|
-
warningDialog(self,Message,flagScreenCenter=True,pixmap=''+ icons_path +'flaticon_PaIRS_download.png')
|
|
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 {})
|
|
692
1012
|
|
|
693
1013
|
def downloadLatestVersion(self,app):
|
|
694
1014
|
try:
|
|
@@ -710,8 +1030,9 @@ def downloadLatestVersion(self,app):
|
|
|
710
1030
|
except Exception as inst:
|
|
711
1031
|
print(inst)
|
|
712
1032
|
|
|
713
|
-
def
|
|
1033
|
+
def button_download_PaIRS_action(self,app):
|
|
714
1034
|
warningLatestVersion(self,app,flagExit=0,flagWarning=1)
|
|
1035
|
+
checkLatestVersion(self,__version__,self.app,splash=None,flagWarning=0)
|
|
715
1036
|
return
|
|
716
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?')
|
|
717
1038
|
if not flagStopAndDownload: return
|
|
@@ -723,6 +1044,20 @@ def button_download_PaIRS_callback(self,app):
|
|
|
723
1044
|
else: command=''
|
|
724
1045
|
subprocess.call(sys.executable+' -m PaIRS_UniNa '+command,shell=True)
|
|
725
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}"
|
|
726
1061
|
|
|
727
1062
|
def checkOutDated(packageName:str,printOutDated):
|
|
728
1063
|
'''
|
|
@@ -741,7 +1076,6 @@ def checkOutDated(packageName:str,printOutDated):
|
|
|
741
1076
|
pass #in this case the last version of the package is installed
|
|
742
1077
|
'''
|
|
743
1078
|
async def checkOutDatedInternal(packageName):
|
|
744
|
-
flagOutDated=0
|
|
745
1079
|
#reqs = subprocess.check_output([sys.executable, '-m', 'pip', 'list','--outdated'])
|
|
746
1080
|
#reqs = subprocess.run([sys.executable, '-m', 'pip', 'list','--outdated'],capture_output=True)
|
|
747
1081
|
#reqs = subprocess.check_output([sys.executable, '-m', 'pip', 'index','versions','PaIRS_UniNa'])
|
|
@@ -751,50 +1085,77 @@ def checkOutDated(packageName:str,printOutDated):
|
|
|
751
1085
|
reqs = subprocess.run([sys.executable, '-m', 'pip', 'list','--outdated'],capture_output=True)
|
|
752
1086
|
outDated = [r.decode().split('==')[0] for r in reqs.stdout.split()]
|
|
753
1087
|
"""
|
|
754
|
-
flagOutDated=-
|
|
1088
|
+
flagOutDated=-1000
|
|
755
1089
|
currentVersion='none'
|
|
756
1090
|
latestVersion=''
|
|
757
1091
|
try:
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
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
|
|
771
1111
|
if currentVersion!=__version__:
|
|
772
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!'
|
|
773
1113
|
pri.Info.yellow(f'{"-"*50}\n{message}\n{"-"*50}\n')
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
if not reqs.returncode:
|
|
777
|
-
printing=reqs.stdout.decode("utf-8")
|
|
778
|
-
pri.Info.cyan( printing )
|
|
779
|
-
r=reqs.stdout.decode("utf-8").replace('\r','').split('\n')
|
|
780
|
-
#currentVersion=r[0].replace(packageName,'').replace('(','').replace(')','').replace(' ','')
|
|
781
|
-
latestVersion=r[1].replace('Available versions: ','').split(',')[0]
|
|
1114
|
+
if Flag_ISEXE:
|
|
1115
|
+
_, latestVersion = get_package_version_urllib("PaIRS_UniNa")
|
|
782
1116
|
else:
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
command=[sys.executable, '-m', 'pip', 'list','--outdated']
|
|
1117
|
+
command=[sys.executable, '-m', 'pip', 'index', 'versions', packageName]
|
|
786
1118
|
reqs = subprocess.run(command,capture_output=True)
|
|
787
|
-
if reqs.returncode:
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
latestVersion=outDated[i+2]
|
|
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]
|
|
794
1125
|
else:
|
|
795
|
-
latestVersion=
|
|
796
|
-
|
|
797
|
-
|
|
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
|
|
798
1159
|
except Exception as inst:
|
|
799
1160
|
pri.Error.red(inst)
|
|
800
1161
|
return flagOutDated,currentVersion,latestVersion
|
|
@@ -805,7 +1166,6 @@ def checkOutDated(packageName:str,printOutDated):
|
|
|
805
1166
|
f3=executor.submit(asyncio.run,checkOutDatedInternal(packageName))
|
|
806
1167
|
f3.add_done_callback(checkOutDatedComplete)
|
|
807
1168
|
|
|
808
|
-
|
|
809
1169
|
def changes(self,TabType,filename,title=" Changes"):
|
|
810
1170
|
FlagShow=False
|
|
811
1171
|
if self.logChanges:
|
|
@@ -846,6 +1206,9 @@ def changes(self,TabType,filename,title=" Changes"):
|
|
|
846
1206
|
logChanges.ui.log.setLineWrapColumnOrWidth(logChanges.ui.log.width()-20)
|
|
847
1207
|
self.logChanges.ui.log.resizeEvent=lambda e: logResizeEvent(self.logChanges,e)
|
|
848
1208
|
|
|
1209
|
+
self.logChanges.ui.icon.addfuncclick['whatsnew']=self.whatsNew
|
|
1210
|
+
self.logChanges.ui.icon.setCustomCursor()
|
|
1211
|
+
|
|
849
1212
|
try:
|
|
850
1213
|
file = open(filename, "rb")
|
|
851
1214
|
content = file.read().decode("utf-8")
|
|
@@ -856,8 +1219,203 @@ def changes(self,TabType,filename,title=" Changes"):
|
|
|
856
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__}.')
|
|
857
1220
|
return
|
|
858
1221
|
|
|
859
|
-
|
|
860
1222
|
import webbrowser
|
|
861
1223
|
def downloadExampleData(self,url):
|
|
862
1224
|
Message=f'Test data are available at the following link:\n{url}'
|
|
863
|
-
warningDialog(self,Message,pixmap=''+ icons_path +'flaticon_PaIRS_download.png',title='Download test data',addButton=
|
|
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
|