IO4IT 4.0.6__tar.gz → 4.0.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. io4it-4.0.8/PKG-INFO +28 -0
  2. io4it-4.0.8/io4it.egg-info/PKG-INFO +28 -0
  3. {io4it-4.0.6 → io4it-4.0.8}/io4it.egg-info/SOURCES.txt +4 -0
  4. io4it-4.0.8/orangecontrib/IO4IT/utils/environment_collector.py +71 -0
  5. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/utils/mail.py +15 -5
  6. io4it-4.0.8/orangecontrib/IO4IT/utils/pptx2jpg.py +102 -0
  7. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWPPTX2JPG.py +1 -1
  8. io4it-4.0.8/orangecontrib/IO4IT/widgets/OWPipAuditor.py +240 -0
  9. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWXLSX_insert.py +21 -4
  10. io4it-4.0.8/orangecontrib/IO4IT/widgets/designer/owpipauditor.ui +101 -0
  11. io4it-4.0.8/orangecontrib/IO4IT/widgets/icons/pip_auditor.png +0 -0
  12. {io4it-4.0.6 → io4it-4.0.8}/setup.py +1 -1
  13. io4it-4.0.6/PKG-INFO +0 -12
  14. io4it-4.0.6/io4it.egg-info/PKG-INFO +0 -12
  15. io4it-4.0.6/orangecontrib/IO4IT/utils/pptx2jpg.py +0 -64
  16. {io4it-4.0.6 → io4it-4.0.8}/io4it.egg-info/dependency_links.txt +0 -0
  17. {io4it-4.0.6 → io4it-4.0.8}/io4it.egg-info/entry_points.txt +0 -0
  18. {io4it-4.0.6 → io4it-4.0.8}/io4it.egg-info/namespace_packages.txt +0 -0
  19. {io4it-4.0.6 → io4it-4.0.8}/io4it.egg-info/requires.txt +0 -0
  20. {io4it-4.0.6 → io4it-4.0.8}/io4it.egg-info/top_level.txt +0 -0
  21. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/__init__.py +0 -0
  22. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/ocr_function/__init__.py +0 -0
  23. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/ocr_function/word_converter.py +0 -0
  24. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/toolViews/designer/key_manager_ui.ui +0 -0
  25. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/toolViews/designer/link_workflow_manager_ui.ui +0 -0
  26. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/toolViews/key_manager_ui.py +0 -0
  27. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/toolViews/linkHTLMWorkflow_manager_ui.py +0 -0
  28. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/utils/__init__.py +0 -0
  29. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/utils/keys_manager.py +0 -0
  30. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/utils/pool_exec_utils.py +0 -0
  31. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/utils/secret_manager.py +0 -0
  32. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/utils/utils_md.py +0 -0
  33. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWChatGpt.py +0 -0
  34. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWDeep_Search.py +0 -0
  35. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWDoclingToMarkdown.py +0 -0
  36. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWExportMarkdown.py +0 -0
  37. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWExtractTablesDocxToXlsx.py +0 -0
  38. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWInboxMailMonitoring.py +0 -0
  39. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWJsonToDataTable.py +0 -0
  40. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWMD2HTML.py +0 -0
  41. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWMarkdownLoader.py +0 -0
  42. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWMarkdownizer.py +0 -0
  43. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWOfficeNormalizer.py +0 -0
  44. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWParserHTML.py +0 -0
  45. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWPdfType.py +0 -0
  46. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWProcessPoolExecutor.py +0 -0
  47. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWS3Uploader.py +0 -0
  48. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWS3downloader.py +0 -0
  49. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWS3list.py +0 -0
  50. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWWebSearch.py +0 -0
  51. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWmailLoader.py +0 -0
  52. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWmailSender.py +0 -0
  53. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/OWwordpdf2docx.py +0 -0
  54. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/__init__.py +0 -0
  55. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/__init__.py +0 -0
  56. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/nogui.ui +0 -0
  57. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/ow_extract_tables_docx_to_xlsx.ui +0 -0
  58. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/ow_file_ext_selector.ui +0 -0
  59. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/ow_json_to_data_table.ui +0 -0
  60. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owchatgpt.ui +0 -0
  61. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owdeepsearch.ui +0 -0
  62. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owdoclingasr.ui +0 -0
  63. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owdoclingtomarkdown.ui +0 -0
  64. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owexportmarkdown.ui +0 -0
  65. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owinboxmailmonitoring.ui +0 -0
  66. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owinsertdatatoexcel.ui +0 -0
  67. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owmailloader.ui +0 -0
  68. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owmailsender.ui +0 -0
  69. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owmarkdownizer.ui +0 -0
  70. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owmarkdownloader.ui +0 -0
  71. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owmd2html.ui +0 -0
  72. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owofficenormalizer.ui +0 -0
  73. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owparserhtml.ui +0 -0
  74. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owpdftype.ui +0 -0
  75. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owpptx2jpg.ui +0 -0
  76. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owprocesspoolexecutor.ui +0 -0
  77. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owspeechtotext.ui +0 -0
  78. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owvisualizationer.ui +0 -0
  79. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/owwebsearch.ui +0 -0
  80. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/designer/wordpdf2docx.ui +0 -0
  81. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/__init__.py +0 -0
  82. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/chatgpt.png +0 -0
  83. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/check_pdf.png +0 -0
  84. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/deepsearch.svg +0 -0
  85. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/dep_md_old.png +0 -0
  86. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/download.png +0 -0
  87. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/export_md.png +0 -0
  88. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/extract_table.png +0 -0
  89. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/file_extensor.png +0 -0
  90. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/html.png +0 -0
  91. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/json-file.png +0 -0
  92. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/list_aws.png +0 -0
  93. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/load_md.png +0 -0
  94. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/mail_loader.png +0 -0
  95. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/mail_writer.png +0 -0
  96. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/md.png +0 -0
  97. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/monitor-email.svg +0 -0
  98. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/office_normalizer.png +0 -0
  99. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/owmd2html.svg +0 -0
  100. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/pptx2jpg.png +0 -0
  101. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/process_pool_executor.png +0 -0
  102. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/speech_to_text.png +0 -0
  103. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/upload.png +0 -0
  104. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/visualizationer.png +0 -0
  105. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/websearch.png +0 -0
  106. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/wordpdf2docx.png +0 -0
  107. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons/xlsx_insert.png +0 -0
  108. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/IO4IT/widgets/icons_dev/__init__.py +0 -0
  109. {io4it-4.0.6 → io4it-4.0.8}/orangecontrib/__init__.py +0 -0
  110. {io4it-4.0.6 → io4it-4.0.8}/setup.cfg +0 -0
io4it-4.0.8/PKG-INFO ADDED
@@ -0,0 +1,28 @@
1
+ Metadata-Version: 2.1
2
+ Name: io4it
3
+ Version: 4.0.8
4
+ Home-page:
5
+ Author:
6
+ Author-email:
7
+ Keywords: orange3 add-on
8
+ Requires-Dist: torchvision
9
+ Requires-Dist: torch
10
+ Requires-Dist: pylatexenc
11
+ Requires-Dist: docopt
12
+ Requires-Dist: boto3
13
+ Requires-Dist: opencv-python-headless
14
+ Requires-Dist: docling
15
+ Requires-Dist: docling-core
16
+ Requires-Dist: whisper
17
+ Requires-Dist: whisper-openai
18
+ Requires-Dist: pypandoc
19
+ Requires-Dist: pypandoc-binary
20
+ Requires-Dist: scikit-learn
21
+ Requires-Dist: openai
22
+ Requires-Dist: pip-system-certs
23
+ Requires-Dist: docx2pdf
24
+ Requires-Dist: msal
25
+ Requires-Dist: exchangelib
26
+ Requires-Dist: html2text
27
+ Requires-Dist: ddgs
28
+ Requires-Dist: CATEGORIT
@@ -0,0 +1,28 @@
1
+ Metadata-Version: 2.1
2
+ Name: io4it
3
+ Version: 4.0.8
4
+ Home-page:
5
+ Author:
6
+ Author-email:
7
+ Keywords: orange3 add-on
8
+ Requires-Dist: torchvision
9
+ Requires-Dist: torch
10
+ Requires-Dist: pylatexenc
11
+ Requires-Dist: docopt
12
+ Requires-Dist: boto3
13
+ Requires-Dist: opencv-python-headless
14
+ Requires-Dist: docling
15
+ Requires-Dist: docling-core
16
+ Requires-Dist: whisper
17
+ Requires-Dist: whisper-openai
18
+ Requires-Dist: pypandoc
19
+ Requires-Dist: pypandoc-binary
20
+ Requires-Dist: scikit-learn
21
+ Requires-Dist: openai
22
+ Requires-Dist: pip-system-certs
23
+ Requires-Dist: docx2pdf
24
+ Requires-Dist: msal
25
+ Requires-Dist: exchangelib
26
+ Requires-Dist: html2text
27
+ Requires-Dist: ddgs
28
+ Requires-Dist: CATEGORIT
@@ -11,6 +11,7 @@ orangecontrib/IO4IT/__init__.py
11
11
  orangecontrib/IO4IT/ocr_function/__init__.py
12
12
  orangecontrib/IO4IT/ocr_function/word_converter.py
13
13
  orangecontrib/IO4IT/utils/__init__.py
14
+ orangecontrib/IO4IT/utils/environment_collector.py
14
15
  orangecontrib/IO4IT/utils/keys_manager.py
15
16
  orangecontrib/IO4IT/utils/mail.py
16
17
  orangecontrib/IO4IT/utils/pool_exec_utils.py
@@ -31,6 +32,7 @@ orangecontrib/IO4IT/widgets/OWOfficeNormalizer.py
31
32
  orangecontrib/IO4IT/widgets/OWPPTX2JPG.py
32
33
  orangecontrib/IO4IT/widgets/OWParserHTML.py
33
34
  orangecontrib/IO4IT/widgets/OWPdfType.py
35
+ orangecontrib/IO4IT/widgets/OWPipAuditor.py
34
36
  orangecontrib/IO4IT/widgets/OWProcessPoolExecutor.py
35
37
  orangecontrib/IO4IT/widgets/OWS3Uploader.py
36
38
  orangecontrib/IO4IT/widgets/OWS3downloader.py
@@ -65,6 +67,7 @@ orangecontrib/IO4IT/widgets/designer/owmd2html.ui
65
67
  orangecontrib/IO4IT/widgets/designer/owofficenormalizer.ui
66
68
  orangecontrib/IO4IT/widgets/designer/owparserhtml.ui
67
69
  orangecontrib/IO4IT/widgets/designer/owpdftype.ui
70
+ orangecontrib/IO4IT/widgets/designer/owpipauditor.ui
68
71
  orangecontrib/IO4IT/widgets/designer/owpptx2jpg.ui
69
72
  orangecontrib/IO4IT/widgets/designer/owprocesspoolexecutor.ui
70
73
  orangecontrib/IO4IT/widgets/designer/owspeechtotext.ui
@@ -90,6 +93,7 @@ orangecontrib/IO4IT/widgets/icons/md.png
90
93
  orangecontrib/IO4IT/widgets/icons/monitor-email.svg
91
94
  orangecontrib/IO4IT/widgets/icons/office_normalizer.png
92
95
  orangecontrib/IO4IT/widgets/icons/owmd2html.svg
96
+ orangecontrib/IO4IT/widgets/icons/pip_auditor.png
93
97
  orangecontrib/IO4IT/widgets/icons/pptx2jpg.png
94
98
  orangecontrib/IO4IT/widgets/icons/process_pool_executor.png
95
99
  orangecontrib/IO4IT/widgets/icons/speech_to_text.png
@@ -0,0 +1,71 @@
1
+ import sys
2
+ import platform
3
+ import datetime
4
+
5
+ try:
6
+ import importlib.metadata as importlib_metadata
7
+ except ImportError:
8
+ import importlib_metadata # fallback for Python < 3.8
9
+
10
+
11
+ class EnvironmentCollector:
12
+ """
13
+ Utilitaire pour collecter les informations d'environnement système
14
+ (OS, Python, dépendances pip) sans recourir à subprocess.
15
+ """
16
+
17
+ @staticmethod
18
+ def _dependencies_freeze_space() -> str:
19
+ """
20
+ Retourne l'équivalent d'un `pip freeze` (Package==Version ...)
21
+ séparé par des retours à la ligne.
22
+ Utilise importlib.metadata (pas de subprocess).
23
+ """
24
+ try:
25
+ dists = sorted(
26
+ importlib_metadata.distributions(),
27
+ key=lambda d: (d.metadata.get("Name", "") or "").lower()
28
+ )
29
+ parts = []
30
+ for dist in dists:
31
+ name = (dist.metadata.get("Name") or "").strip()
32
+ version = getattr(dist, "version", None)
33
+ if name and version:
34
+ parts.append(f"{name}=={version}")
35
+ return "\n\r".join(parts)
36
+ except Exception as e:
37
+ return f"Error collecting dependencies: {e}"
38
+
39
+ def _collect(self):
40
+ """
41
+ Collecte les informations clés de l'environnement courant.
42
+
43
+ Returns:
44
+ tuple: (keys: list[str], vals: list[str|None])
45
+ - keys : noms des colonnes
46
+ - vals : valeurs correspondantes
47
+ (None pour "Row number", géré en aval avec np.arange)
48
+ """
49
+ keys = [
50
+ "Row number",
51
+ "Current Time",
52
+ "OS",
53
+ "Machine",
54
+ "Processor",
55
+ "Python Version",
56
+ "Python Executable",
57
+ "Dependencies",
58
+ ]
59
+
60
+ vals = [
61
+ None, # Row number (géré dans _apply avec np.arange)
62
+ datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
63
+ platform.platform(),
64
+ platform.machine(),
65
+ platform.processor() or platform.machine(),
66
+ sys.version.replace("\n", " "),
67
+ sys.executable,
68
+ self._dependencies_freeze_space(),
69
+ ]
70
+
71
+ return keys, vals
@@ -677,9 +677,18 @@ def extraire_emails(champ):
677
677
  """
678
678
  if not champ:
679
679
  return []
680
+ # Nettoie les guillemets littéraux et valeurs placeholder
681
+ champ = champ.strip().strip('"').strip("'")
682
+
683
+ if champ in ("", "?", "-", "none", "null"):
684
+ return []
680
685
 
681
686
  emails = champ.replace(";", ",").split(",")
682
- return [email.strip() for email in emails if email.strip()]
687
+ return [
688
+ email.strip().strip('"').strip("'")
689
+ for email in emails
690
+ if email.strip().strip('"').strip("'") and "@" in email
691
+ ]
683
692
 
684
693
  def to_graph_recipients(champ):
685
694
  """
@@ -722,7 +731,7 @@ def check_send_new_emails(offusc_conf_agent, type_co):
722
731
  destinataires,
723
732
  infos["tit"],
724
733
  infos["txt"],
725
- cc=copies,
734
+ #cc=copies,
726
735
  piece_jointe_paths=chemin_dossier_out + "/" + contenu + "/pj"
727
736
  )
728
737
  MetManagement.reset_folder(chemin_dossier_in + contenu, recreate=False)
@@ -906,7 +915,7 @@ def check_send_new_emails(offusc_conf_agent, type_co):
906
915
  client_id, client_secret, tenant_id, user_email = keys_manager.lire_config_oauth2(
907
916
  offusc_conf_agent, type_co
908
917
  )
909
-
918
+ print(client_id, client_secret, tenant_id, user_email)
910
919
  agent = user_email
911
920
  chemin_dossier_in, chemin_dossier_out = mail_in_folder(agent, "out")
912
921
  authority = f"https://login.microsoftonline.com/{tenant_id}"
@@ -993,6 +1002,7 @@ def check_send_new_emails(offusc_conf_agent, type_co):
993
1002
  response = requests.post(send_url, headers=headers, json=message_data)
994
1003
  response.raise_for_status()
995
1004
  except requests.exceptions.HTTPError as e:
1005
+ print(f"Graph error body: {response.json()}") # ← ajoute cette ligne
996
1006
  if response.status_code == 403:
997
1007
  raise Exception("❌ Permission Mail.Send manquante.")
998
1008
  else:
@@ -1035,7 +1045,7 @@ if __name__ == "__main__":
1035
1045
  while True:
1036
1046
  for offusc_conf_agent in offusc_conf_agents:
1037
1047
  print("offusc conf agent : ", offusc_conf_agent)
1038
- check_new_emails(offusc_conf_agent,type_co, list_agent_email)
1039
- time.sleep(1)
1048
+ #check_new_emails(offusc_conf_agent,type_co, list_agent_email)
1049
+ #time.sleep(1)
1040
1050
  check_send_new_emails(offusc_conf_agent,type_co)
1041
1051
  time.sleep(1)
@@ -0,0 +1,102 @@
1
+ import sys
2
+ import time
3
+ import subprocess
4
+ import shutil
5
+ from pathlib import Path
6
+
7
+ def get_conversion_method():
8
+ """Determines the best available conversion method."""
9
+ # 1. Check for MS Office
10
+ if sys.platform.startswith("win"):
11
+ try:
12
+ import win32com.client
13
+ # Try to see if the COM object is registered
14
+ win32com.client.GetActiveObject("PowerPoint.Application")
15
+ return "office"
16
+ except:
17
+ try:
18
+ # If not running, try to see if it's dispatchable
19
+ win32com.client.Dispatch("PowerPoint.Application")
20
+ return "office"
21
+ except: pass
22
+ elif sys.platform == "darwin":
23
+ # Check if PowerPoint app exists on Mac
24
+ if Path("/Applications/Microsoft PowerPoint.app").exists():
25
+ return "office"
26
+
27
+ # 2. Check for LibreOffice (soffice)
28
+ if shutil.which("soffice"):
29
+ return "libreoffice"
30
+
31
+ # 3. Fallback to Aspose
32
+ return "aspose"
33
+
34
+ def convert_via_office(src: Path, pdf_path: Path):
35
+ if sys.platform.startswith("win"):
36
+ import win32com.client
37
+ powerpoint = win32com.client.Dispatch("PowerPoint.Application")
38
+ try:
39
+ presentation = powerpoint.Presentations.Open(str(src), WithWindow=False)
40
+ presentation.SaveAs(str(pdf_path), 32) # 32 = ppSaveAsPDF
41
+ presentation.Close()
42
+ finally:
43
+ # Note: We don't quit() powerpoint here to avoid killing other open docs
44
+ pass
45
+ elif sys.platform == "darwin":
46
+ script = f'tell application "Microsoft PowerPoint" to save (open POSIX file "{src}") in POSIX file "{pdf_path}" as PDF'
47
+ subprocess.run(["osascript", "-e", script], check=True)
48
+
49
+ def convert_via_libreoffice(src: Path, out_dir: Path):
50
+ subprocess.run([
51
+ "soffice", "--headless", "--convert-to", "pdf",
52
+ "--outdir", str(out_dir), str(src)
53
+ ], check=True, capture_output=True)
54
+ return src.with_suffix(".pdf")
55
+
56
+ def process_one_pptx(file_path_str: str, unique_folder: bool = True):
57
+ try:
58
+ import fitz # PyMuPDF
59
+ except ImportError:
60
+ return [file_path_str, "", "nok", "0.0", "Erreur: PyMuPDF non installé"]
61
+
62
+ t0 = time.time()
63
+ src = Path(file_path_str).resolve()
64
+ out_dir = src.parent / (f"images_{src.stem}" if unique_folder else "images")
65
+ out_dir.mkdir(parents=True, exist_ok=True)
66
+
67
+ method = get_conversion_method()
68
+ img_list = []
69
+
70
+ try:
71
+ # --- PHASE 1: GENERATE IMAGES ---
72
+ if method == "aspose":
73
+ # import aspose.slides as slides
74
+ # with slides.Presentation(str(src)) as pres:
75
+ # for i, slide in enumerate(pres.slides, start=1):
76
+ # img_path = out_dir / f"{src.stem}_slide_{i:03d}.jpg"
77
+ # slide.get_thumbnail(1.5, 1.5).save(str(img_path), slides.export.ImageFormat.JPEG)
78
+ # img_list.append(str(img_path))
79
+ print("converting slides without having libre office or office isn't possible for the moment")
80
+ else:
81
+ # Office or LibreOffice both generate a PDF first
82
+ pdf_path = out_dir / f"{src.stem}.pdf"
83
+ if method == "office":
84
+ convert_via_office(src, pdf_path)
85
+ else: # libreoffice
86
+ convert_via_libreoffice(src, out_dir)
87
+
88
+ # Convert PDF pages to JPG using PyMuPDF
89
+ doc = fitz.open(str(pdf_path))
90
+ for i, page in enumerate(doc, start=1):
91
+ pix = page.get_pixmap(dpi=150)
92
+ img_path = out_dir / f"{src.stem}_slide_{i:03d}.jpg"
93
+ pix.save(str(img_path))
94
+ img_list.append(str(img_path))
95
+ doc.close()
96
+ if pdf_path.exists(): pdf_path.unlink()
97
+
98
+ duration = time.time() - t0
99
+ return [str(src), "|".join(img_list), "ok", f"{duration:.2f}", f"{len(img_list)} slides ({method})"]
100
+
101
+ except Exception as e:
102
+ return [str(src), "", "nok", f"{time.time()-t0:.2f}", f"Method {method} failed: {str(e)}"]
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  import sys
3
3
  from AnyQt.QtWidgets import QApplication
4
- from AnyQt.QtCore import pyqtSignal, QTimer
4
+ from AnyQt.QtCore import pyqtSignal
5
5
  from Orange.widgets.utils.signals import Input, Output
6
6
  from Orange.data import Domain, StringVariable, Table, DiscreteVariable
7
7
  from Orange.widgets.settings import Setting
@@ -0,0 +1,240 @@
1
+ import os
2
+ import sys
3
+ import Orange.data
4
+ from Orange.widgets import widget
5
+ from Orange.data import Domain, StringVariable, Table
6
+ from AnyQt.QtWidgets import QApplication
7
+ from Orange.widgets.settings import Setting
8
+ from Orange.widgets.utils.signals import Output
9
+ from AnyQt.QtCore import QTimer
10
+
11
+
12
+ # Importations conditionnelles selon l'architecture du projet
13
+ if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
14
+ from Orange.widgets.orangecontrib.AAIT.utils import thread_management, help_management
15
+ from Orange.widgets.orangecontrib.AAIT.utils.initialize_from_ini import apply_modification_from_python_file
16
+ from Orange.widgets.orangecontrib.IO4IT.utils.environment_collector import EnvironmentCollector
17
+ from Orange.widgets.orangecontrib.AAIT.utils.import_uic import uic
18
+ else:
19
+ from orangecontrib.AAIT.utils import thread_management, help_management
20
+ from orangecontrib.AAIT.utils.initialize_from_ini import apply_modification_from_python_file
21
+ from orangecontrib.IO4IT.utils.environment_collector import EnvironmentCollector
22
+ from orangecontrib.AAIT.utils.import_uic import uic
23
+
24
+
25
+ # ---------------------------------------------------------------------------
26
+ # Helpers (module-level, utilisables hors widget et dans les threads)
27
+ # ---------------------------------------------------------------------------
28
+
29
+ def get_pip_freeze_dict() -> dict:
30
+ """
31
+ Retourne un dict {package_name_lower: version} via importlib.metadata.
32
+ N'utilise pas de subprocess.
33
+ """
34
+ collector = EnvironmentCollector()
35
+ freeze_str = collector._dependencies_freeze_space()
36
+ packages = {}
37
+ for line in freeze_str.splitlines():
38
+ line = line.strip().strip("\r")
39
+ if "==" in line:
40
+ name, version = line.split("==", 1)
41
+ packages[name.lower()] = version
42
+ return packages
43
+
44
+
45
+ def _make_table(rows: list, columns: list) -> Table:
46
+ """Construit une Orange Table avec les colonnes (StringVariable) spécifiées."""
47
+ metas = [StringVariable(col) for col in columns]
48
+ domain = Domain([], metas=metas)
49
+ return Table.from_list(domain, rows)
50
+
51
+
52
+ def run_audit(saved_packages: dict) -> tuple:
53
+ current_packages = get_pip_freeze_dict()
54
+ all_keys = set(saved_packages.keys()) | set(current_packages.keys())
55
+
56
+ diff_rows = []
57
+ current_rows = []
58
+ previous_rows = []
59
+
60
+ for pkg in sorted(all_keys):
61
+ saved_v = saved_packages.get(pkg, "(Absent)")
62
+ current_v = current_packages.get(pkg, "(Nouveau)")
63
+
64
+ if saved_v == "(Absent)":
65
+ status = "➕ Nouveau"
66
+ elif current_v == "(Nouveau)":
67
+ status = "❌ Manquant"
68
+ elif saved_v != current_v:
69
+ status = "⚠️ Différent"
70
+ else:
71
+ status = "✅ OK"
72
+
73
+ # Table différences : 4 colonnes complètes
74
+ #if status != "✅ OK":
75
+ diff_rows.append([pkg, saved_v, current_v, status])
76
+
77
+ # Table courante : uniquement Package + Version courante
78
+ if current_v != "(Nouveau)":
79
+ current_rows.append([pkg, current_v])
80
+
81
+ # Table précédente : uniquement Package + Version sauvegardée
82
+ if saved_v != "(Absent)":
83
+ previous_rows.append([pkg, saved_v])
84
+
85
+ diff_cols = ["Package", "Saved Version", "Current Version", "Status"]
86
+ current_cols = ["Package", "Current Version"]
87
+ previous_cols = ["Package", "Saved Version"]
88
+
89
+ diff_table = _make_table(diff_rows, diff_cols) if diff_rows else None
90
+ current_table = _make_table(current_rows, current_cols) if current_rows else None
91
+ previous_table = _make_table(previous_rows, previous_cols) if previous_rows else None
92
+
93
+ return diff_table, current_table, previous_table
94
+
95
+
96
+ # ---------------------------------------------------------------------------
97
+ # Widget
98
+ # ---------------------------------------------------------------------------
99
+
100
+ @apply_modification_from_python_file(filepath_original_widget=__file__)
101
+ class OWPipAuditor(widget.OWWidget):
102
+ name = "Pip Auditor"
103
+ description = "Snapshot and compare pip freeze environment"
104
+ category = "AAIT - TOOLBOX"
105
+ icon = "icons/pip_auditor.png"
106
+ if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
107
+ icon = "icons_dev/pip_auditor.png"
108
+
109
+ gui = os.path.join(os.path.dirname(os.path.abspath(__file__)), "designer/owpipauditor.ui")
110
+
111
+ want_control_area = False
112
+ priority = 1100
113
+
114
+
115
+ # ------------------------------------------------------------------
116
+ # Settings persistants
117
+ # ------------------------------------------------------------------
118
+ saved_freeze: dict = Setting({}) # Snapshot sauvegardé (dict pkg→version)
119
+ autorun: bool = Setting(False) # Checkbox "Lancer automatiquement au démarrage"
120
+
121
+ # ------------------------------------------------------------------
122
+ # Sorties
123
+ # ------------------------------------------------------------------
124
+ class Outputs:
125
+ diff_table = Output("Différences", Orange.data.Table) # Packages avec écart
126
+ current_table = Output("Actuels", Orange.data.Table) # Snapshot courant
127
+ previous_table = Output("Précédents", Orange.data.Table) # Snapshot sauvegardé
128
+
129
+ # ------------------------------------------------------------------
130
+ # Initialisation
131
+ # ------------------------------------------------------------------
132
+ def __init__(self):
133
+ super().__init__()
134
+ self.setFixedWidth(470)
135
+ self.setFixedHeight(351)
136
+ uic.loadUi(self.gui, self)
137
+
138
+ self.thread = None
139
+ self._last_results = (None, None, None) # (diff, current, previous)
140
+
141
+ # Connexion des boutons définis dans le .ui
142
+ self.pushButton_snapshot.clicked.connect(self.take_snapshot)
143
+ self.pushButton_run.clicked.connect(self.run)
144
+
145
+ # Checkbox autorun (doit être définie dans owpipauditor.ui avec le nom checkBox_autorun)
146
+ self.checkBox_autorun.setChecked(self.autorun)
147
+ self.checkBox_autorun.stateChanged.connect(self._on_autorun_changed)
148
+
149
+ self.post_initialized()
150
+ QTimer.singleShot(0, lambda: help_management.override_help_action(self))
151
+
152
+ # Démarrage automatique si l'option est activée et qu'un snapshot existe
153
+ if self.autorun and self.saved_freeze:
154
+ QTimer.singleShot(100, self.run)
155
+
156
+ # ------------------------------------------------------------------
157
+ # Slots
158
+ # ------------------------------------------------------------------
159
+ def _on_autorun_changed(self, state: int):
160
+ """Persistance de la checkbox autorun."""
161
+ self.autorun = bool(state)
162
+
163
+ def take_snapshot(self):
164
+ """Sauvegarde l'état pip courant dans le Setting."""
165
+ try:
166
+ self.saved_freeze = get_pip_freeze_dict()
167
+ self.information(
168
+ f"Snapshot réussi : {len(self.saved_freeze)} packages sauvegardés."
169
+ )
170
+ except Exception as e:
171
+ self.error(f"Erreur Snapshot: {str(e)}")
172
+
173
+ def run(self):
174
+ """Compare le snapshot sauvegardé avec l'environnement courant et émet les 3 sorties."""
175
+ self.error("")
176
+ self.warning("")
177
+
178
+ if not self.saved_freeze:
179
+ self.error("Aucun snapshot sauvegardé. Cliquez d'abord sur Snapshot.")
180
+ return
181
+
182
+ if self.thread is not None:
183
+ self.thread.safe_quit()
184
+
185
+ self.progressBarInit()
186
+
187
+ self.thread = thread_management.Thread(run_audit, self.saved_freeze)
188
+ self.thread.progress.connect(self.handle_progress)
189
+ self.thread.result.connect(self.handle_result)
190
+ self.thread.finish.connect(self.handle_finish)
191
+ self.thread.start()
192
+
193
+ # ------------------------------------------------------------------
194
+ # Handlers thread
195
+ # ------------------------------------------------------------------
196
+ def handle_progress(self, value: float):
197
+ self.progressBarSet(value)
198
+
199
+ def handle_result(self, result):
200
+ """
201
+ result est un tuple (diff_table, current_table, previous_table).
202
+ """
203
+ try:
204
+ diff_table, current_table, previous_table = result
205
+ self._last_results = result
206
+
207
+ self.Outputs.diff_table.send(diff_table)
208
+ self.Outputs.current_table.send(current_table)
209
+ self.Outputs.previous_table.send(previous_table)
210
+
211
+ n_diff = sum(1 for row in diff_table if str(row["Status"]) != "✅ OK")
212
+ self.information(f"Audit terminé : {n_diff} différence(s) détectée(s) sur {len(diff_table)} package(s).")
213
+ except Exception as e:
214
+ self.error(f"Erreur lors de l'envoi des tables: {e}")
215
+ self.Outputs.diff_table.send(None)
216
+ self.Outputs.current_table.send(None)
217
+ self.Outputs.previous_table.send(None)
218
+
219
+ def handle_finish(self):
220
+ self.progressBarFinished()
221
+
222
+ # ------------------------------------------------------------------
223
+ # Hook post-init (override si besoin dans une sous-classe)
224
+ # ------------------------------------------------------------------
225
+ def post_initialized(self):
226
+ pass
227
+
228
+
229
+ # ---------------------------------------------------------------------------
230
+ # Lancement standalone
231
+ # ---------------------------------------------------------------------------
232
+ if __name__ == "__main__":
233
+ app = QApplication(sys.argv)
234
+ my_widget = OWPipAuditor()
235
+ my_widget.show()
236
+ if hasattr(app, "exec"):
237
+ app.exec()
238
+ else:
239
+ app.exec_()
240
+
@@ -207,12 +207,29 @@ class OWInsertDataToExcel(base_widget.BaseListWidget):
207
207
  self.Outputs.status_data.send(Table.from_list(domain, [[status, details]]))
208
208
 
209
209
  def _orange_table_to_dataframe(self, table: Table) -> pd.DataFrame:
210
- col_names = [var.name for var in table.domain.attributes + table.domain.metas]
210
+ # Preserve original column order: attributes first, then metas, then class
211
+ # but respect the domain's actual declaration order
212
+ all_vars = list(table.domain.attributes) + list(table.domain.metas)
211
213
  if table.domain.class_var:
212
- col_names.append(table.domain.class_var.name)
213
-
214
- data = {name: list(table.get_column(name)) for name in col_names}
214
+ all_vars.append(table.domain.class_var)
215
+
216
+ data = {}
217
+ for var in all_vars:
218
+ raw = list(table.get_column(var.name))
219
+ if isinstance(var, DiscreteVariable):
220
+ data[var.name] = [
221
+ var.values[int(v)] if not (isinstance(v, float) and pd.isna(v)) and int(v) >= 0 else ""
222
+ for v in raw
223
+ ]
224
+ else:
225
+ data[var.name] = raw
226
+
215
227
  df = pd.DataFrame(data).astype(str).replace("nan", "")
228
+
229
+ # Re-order columns to match the original Table column order
230
+ original_order = [var.name for var in table.domain.variables + table.domain.metas]
231
+ df = df[[col for col in original_order if col in df.columns]]
232
+
216
233
  return df
217
234
 
218
235
  if __name__ == "__main__":
@@ -0,0 +1,101 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <ui version="4.0">
3
+ <class>Form</class>
4
+ <widget class="QWidget" name="Form">
5
+ <property name="geometry">
6
+ <rect>
7
+ <x>0</x>
8
+ <y>0</y>
9
+ <width>470</width>
10
+ <height>351</height>
11
+ </rect>
12
+ </property>
13
+ <property name="windowTitle">
14
+ <string>Pip Auditor</string>
15
+ </property>
16
+ <widget class="QGroupBox" name="groupBox">
17
+ <property name="geometry">
18
+ <rect>
19
+ <x>20</x>
20
+ <y>20</y>
21
+ <width>431</width>
22
+ <height>100</height>
23
+ </rect>
24
+ </property>
25
+ <property name="title">
26
+ <string>1. Environment Reference</string>
27
+ </property>
28
+ <widget class="QPushButton" name="pushButton_snapshot">
29
+ <property name="geometry">
30
+ <rect>
31
+ <x>10</x>
32
+ <y>40</y>
33
+ <width>411</width>
34
+ <height>41</height>
35
+ </rect>
36
+ </property>
37
+ <property name="text">
38
+ <string>Take Snapshot (pip freeze)</string>
39
+ </property>
40
+ </widget>
41
+ </widget>
42
+ <widget class="QGroupBox" name="groupBox_2">
43
+ <property name="geometry">
44
+ <rect>
45
+ <x>20</x>
46
+ <y>140</y>
47
+ <width>431</width>
48
+ <height>171</height>
49
+ </rect>
50
+ </property>
51
+ <property name="title">
52
+ <string>2. Audit &amp; Comparison</string>
53
+ </property>
54
+ <widget class="QLabel" name="label">
55
+ <property name="geometry">
56
+ <rect>
57
+ <x>10</x>
58
+ <y>30</y>
59
+ <width>411</width>
60
+ <height>41</height>
61
+ </rect>
62
+ </property>
63
+ <property name="text">
64
+ <string>Compare the current environment with the snapshot.
65
+ This will output a table of differences (mismatches, missing or new packages).</string>
66
+ </property>
67
+ <property name="wordWrap">
68
+ <bool>true</bool>
69
+ </property>
70
+ </widget>
71
+ <widget class="QCheckBox" name="checkBox_autorun">
72
+ <property name="geometry">
73
+ <rect>
74
+ <x>10</x>
75
+ <y>80</y>
76
+ <width>411</width>
77
+ <height>21</height>
78
+ </rect>
79
+ </property>
80
+ <property name="text">
81
+ <string>Auto-run comparison on startup</string>
82
+ </property>
83
+ </widget>
84
+ <widget class="QPushButton" name="pushButton_run">
85
+ <property name="geometry">
86
+ <rect>
87
+ <x>10</x>
88
+ <y>111</y>
89
+ <width>411</width>
90
+ <height>41</height>
91
+ </rect>
92
+ </property>
93
+ <property name="text">
94
+ <string>Run Comparison</string>
95
+ </property>
96
+ </widget>
97
+ </widget>
98
+ </widget>
99
+ <resources/>
100
+ <connections/>
101
+ </ui>
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  # Configuration
4
4
  NAME = "io4it"
5
- VERSION = "4.0.6"
5
+ VERSION = "4.0.8"
6
6
 
7
7
  INSTALL_REQUIRES = [
8
8
  "torchvision",
io4it-4.0.6/PKG-INFO DELETED
@@ -1,12 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: io4it
3
- Version: 4.0.6
4
- Summary: UNKNOWN
5
- Home-page:
6
- Author:
7
- Author-email:
8
- License: UNKNOWN
9
- Keywords: orange3 add-on
10
- Platform: UNKNOWN
11
-
12
- UNKNOWN
@@ -1,12 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: io4it
3
- Version: 4.0.6
4
- Summary: UNKNOWN
5
- Home-page:
6
- Author:
7
- Author-email:
8
- License: UNKNOWN
9
- Keywords: orange3 add-on
10
- Platform: UNKNOWN
11
-
12
- UNKNOWN
@@ -1,64 +0,0 @@
1
- import sys
2
- import time
3
- import subprocess
4
- from pathlib import Path
5
-
6
- def pptx_to_pdf(pptx_path: Path) -> Path:
7
- pdf_path = pptx_path.with_suffix(".pdf")
8
- if sys.platform.startswith("win"):
9
- import win32com.client
10
- powerpoint = win32com.client.Dispatch("PowerPoint.Application")
11
- try:
12
- presentation = powerpoint.Presentations.Open(str(pptx_path), WithWindow=False)
13
- presentation.SaveAs(str(pdf_path), 32)
14
- presentation.Close()
15
- except Exception as e:
16
- raise RuntimeError(f"Erreur PowerPoint : {e}")
17
- elif sys.platform == "darwin":
18
- script = f'tell application "Microsoft PowerPoint" to save (open POSIX file "{pptx_path}") in POSIX file "{pdf_path}" as PDF'
19
- subprocess.run(["osascript", "-e", script], check=True)
20
- else:
21
- raise RuntimeError("Système d'exploitation non supporté.")
22
- return pdf_path
23
-
24
- def process_one_pptx(file_path_str: str, unique_folder: bool = True):
25
- try:
26
- import fitz
27
- except ImportError:
28
- return [file_path_str, "", "nok", "0.0", "Erreur: PyMuPDF (fitz) non installé"]
29
-
30
- t0 = time.time()
31
- src = Path(file_path_str).resolve()
32
-
33
- # ✅ unique_folder=True → un dossier par pptx : images_monFichier/
34
- # ✅ unique_folder=False → tout dans un dossier commun : images/ (à côté des pptx)
35
- if unique_folder:
36
- out_dir = src.parent / f"images_{src.stem}"
37
- else:
38
- out_dir = src.parent / "images"
39
-
40
- try:
41
- out_dir.mkdir(parents=True, exist_ok=True)
42
-
43
- pdf_path = pptx_to_pdf(src)
44
-
45
- doc = fitz.open(str(pdf_path))
46
- img_list = []
47
- for i, page in enumerate(doc, start=1):
48
- pix = page.get_pixmap(dpi=150)
49
- # ✅ Préfixe avec le nom du pptx pour éviter les collisions en mode commun
50
- img_path = out_dir / f"{src.stem}_slide_{i:03d}.jpg"
51
- pix.save(str(img_path))
52
- img_list.append(str(img_path))
53
- doc.close()
54
-
55
- if pdf_path.exists():
56
- pdf_path.unlink()
57
-
58
- duration = time.time() - t0
59
- return [str(src), "|".join(img_list), "ok", f"{duration:.2f}", f"{len(img_list)} slides"]
60
-
61
- except Exception as e:
62
- duration = time.time() - t0
63
- import traceback
64
- return [str(src), "", "nok", f"{duration:.2f}", f"{str(e)}\n{traceback.format_exc()}"]
File without changes
File without changes
File without changes