xplia 1.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (870) hide show
  1. venv/Lib/site-packages/_distutils_hack/__init__.py +222 -0
  2. venv/Lib/site-packages/_distutils_hack/override.py +1 -0
  3. venv/Lib/site-packages/pip/__init__.py +13 -0
  4. venv/Lib/site-packages/pip/__main__.py +24 -0
  5. venv/Lib/site-packages/pip/__pip-runner__.py +50 -0
  6. venv/Lib/site-packages/pip/_internal/__init__.py +19 -0
  7. venv/Lib/site-packages/pip/_internal/build_env.py +311 -0
  8. venv/Lib/site-packages/pip/_internal/cache.py +292 -0
  9. venv/Lib/site-packages/pip/_internal/cli/__init__.py +4 -0
  10. venv/Lib/site-packages/pip/_internal/cli/autocompletion.py +171 -0
  11. venv/Lib/site-packages/pip/_internal/cli/base_command.py +236 -0
  12. venv/Lib/site-packages/pip/_internal/cli/cmdoptions.py +1074 -0
  13. venv/Lib/site-packages/pip/_internal/cli/command_context.py +27 -0
  14. venv/Lib/site-packages/pip/_internal/cli/main.py +79 -0
  15. venv/Lib/site-packages/pip/_internal/cli/main_parser.py +134 -0
  16. venv/Lib/site-packages/pip/_internal/cli/parser.py +294 -0
  17. venv/Lib/site-packages/pip/_internal/cli/progress_bars.py +68 -0
  18. venv/Lib/site-packages/pip/_internal/cli/req_command.py +508 -0
  19. venv/Lib/site-packages/pip/_internal/cli/spinners.py +159 -0
  20. venv/Lib/site-packages/pip/_internal/cli/status_codes.py +6 -0
  21. venv/Lib/site-packages/pip/_internal/commands/__init__.py +132 -0
  22. venv/Lib/site-packages/pip/_internal/commands/cache.py +222 -0
  23. venv/Lib/site-packages/pip/_internal/commands/check.py +54 -0
  24. venv/Lib/site-packages/pip/_internal/commands/completion.py +121 -0
  25. venv/Lib/site-packages/pip/_internal/commands/configuration.py +282 -0
  26. venv/Lib/site-packages/pip/_internal/commands/debug.py +199 -0
  27. venv/Lib/site-packages/pip/_internal/commands/download.py +147 -0
  28. venv/Lib/site-packages/pip/_internal/commands/freeze.py +108 -0
  29. venv/Lib/site-packages/pip/_internal/commands/hash.py +59 -0
  30. venv/Lib/site-packages/pip/_internal/commands/help.py +41 -0
  31. venv/Lib/site-packages/pip/_internal/commands/index.py +139 -0
  32. venv/Lib/site-packages/pip/_internal/commands/inspect.py +92 -0
  33. venv/Lib/site-packages/pip/_internal/commands/install.py +778 -0
  34. venv/Lib/site-packages/pip/_internal/commands/list.py +368 -0
  35. venv/Lib/site-packages/pip/_internal/commands/search.py +174 -0
  36. venv/Lib/site-packages/pip/_internal/commands/show.py +189 -0
  37. venv/Lib/site-packages/pip/_internal/commands/uninstall.py +113 -0
  38. venv/Lib/site-packages/pip/_internal/commands/wheel.py +183 -0
  39. venv/Lib/site-packages/pip/_internal/configuration.py +381 -0
  40. venv/Lib/site-packages/pip/_internal/distributions/__init__.py +21 -0
  41. venv/Lib/site-packages/pip/_internal/distributions/base.py +39 -0
  42. venv/Lib/site-packages/pip/_internal/distributions/installed.py +23 -0
  43. venv/Lib/site-packages/pip/_internal/distributions/sdist.py +150 -0
  44. venv/Lib/site-packages/pip/_internal/distributions/wheel.py +34 -0
  45. venv/Lib/site-packages/pip/_internal/exceptions.py +733 -0
  46. venv/Lib/site-packages/pip/_internal/index/__init__.py +2 -0
  47. venv/Lib/site-packages/pip/_internal/index/collector.py +505 -0
  48. venv/Lib/site-packages/pip/_internal/index/package_finder.py +1029 -0
  49. venv/Lib/site-packages/pip/_internal/index/sources.py +223 -0
  50. venv/Lib/site-packages/pip/_internal/locations/__init__.py +467 -0
  51. venv/Lib/site-packages/pip/_internal/locations/_distutils.py +173 -0
  52. venv/Lib/site-packages/pip/_internal/locations/_sysconfig.py +213 -0
  53. venv/Lib/site-packages/pip/_internal/locations/base.py +81 -0
  54. venv/Lib/site-packages/pip/_internal/main.py +12 -0
  55. venv/Lib/site-packages/pip/_internal/metadata/__init__.py +127 -0
  56. venv/Lib/site-packages/pip/_internal/metadata/_json.py +84 -0
  57. venv/Lib/site-packages/pip/_internal/metadata/base.py +688 -0
  58. venv/Lib/site-packages/pip/_internal/metadata/importlib/__init__.py +4 -0
  59. venv/Lib/site-packages/pip/_internal/metadata/importlib/_compat.py +55 -0
  60. venv/Lib/site-packages/pip/_internal/metadata/importlib/_dists.py +224 -0
  61. venv/Lib/site-packages/pip/_internal/metadata/importlib/_envs.py +188 -0
  62. venv/Lib/site-packages/pip/_internal/metadata/pkg_resources.py +270 -0
  63. venv/Lib/site-packages/pip/_internal/models/__init__.py +2 -0
  64. venv/Lib/site-packages/pip/_internal/models/candidate.py +34 -0
  65. venv/Lib/site-packages/pip/_internal/models/direct_url.py +237 -0
  66. venv/Lib/site-packages/pip/_internal/models/format_control.py +80 -0
  67. venv/Lib/site-packages/pip/_internal/models/index.py +28 -0
  68. venv/Lib/site-packages/pip/_internal/models/installation_report.py +53 -0
  69. venv/Lib/site-packages/pip/_internal/models/link.py +581 -0
  70. venv/Lib/site-packages/pip/_internal/models/scheme.py +31 -0
  71. venv/Lib/site-packages/pip/_internal/models/search_scope.py +132 -0
  72. venv/Lib/site-packages/pip/_internal/models/selection_prefs.py +51 -0
  73. venv/Lib/site-packages/pip/_internal/models/target_python.py +110 -0
  74. venv/Lib/site-packages/pip/_internal/models/wheel.py +92 -0
  75. venv/Lib/site-packages/pip/_internal/network/__init__.py +2 -0
  76. venv/Lib/site-packages/pip/_internal/network/auth.py +561 -0
  77. venv/Lib/site-packages/pip/_internal/network/cache.py +69 -0
  78. venv/Lib/site-packages/pip/_internal/network/download.py +186 -0
  79. venv/Lib/site-packages/pip/_internal/network/lazy_wheel.py +210 -0
  80. venv/Lib/site-packages/pip/_internal/network/session.py +519 -0
  81. venv/Lib/site-packages/pip/_internal/network/utils.py +96 -0
  82. venv/Lib/site-packages/pip/_internal/network/xmlrpc.py +60 -0
  83. venv/Lib/site-packages/pip/_internal/operations/__init__.py +0 -0
  84. venv/Lib/site-packages/pip/_internal/operations/build/__init__.py +0 -0
  85. venv/Lib/site-packages/pip/_internal/operations/build/build_tracker.py +124 -0
  86. venv/Lib/site-packages/pip/_internal/operations/build/metadata.py +39 -0
  87. venv/Lib/site-packages/pip/_internal/operations/build/metadata_editable.py +41 -0
  88. venv/Lib/site-packages/pip/_internal/operations/build/metadata_legacy.py +74 -0
  89. venv/Lib/site-packages/pip/_internal/operations/build/wheel.py +37 -0
  90. venv/Lib/site-packages/pip/_internal/operations/build/wheel_editable.py +46 -0
  91. venv/Lib/site-packages/pip/_internal/operations/build/wheel_legacy.py +102 -0
  92. venv/Lib/site-packages/pip/_internal/operations/check.py +187 -0
  93. venv/Lib/site-packages/pip/_internal/operations/freeze.py +255 -0
  94. venv/Lib/site-packages/pip/_internal/operations/install/__init__.py +2 -0
  95. venv/Lib/site-packages/pip/_internal/operations/install/editable_legacy.py +46 -0
  96. venv/Lib/site-packages/pip/_internal/operations/install/wheel.py +740 -0
  97. venv/Lib/site-packages/pip/_internal/operations/prepare.py +743 -0
  98. venv/Lib/site-packages/pip/_internal/pyproject.py +179 -0
  99. venv/Lib/site-packages/pip/_internal/req/__init__.py +92 -0
  100. venv/Lib/site-packages/pip/_internal/req/constructors.py +506 -0
  101. venv/Lib/site-packages/pip/_internal/req/req_file.py +552 -0
  102. venv/Lib/site-packages/pip/_internal/req/req_install.py +874 -0
  103. venv/Lib/site-packages/pip/_internal/req/req_set.py +119 -0
  104. venv/Lib/site-packages/pip/_internal/req/req_uninstall.py +650 -0
  105. venv/Lib/site-packages/pip/_internal/resolution/__init__.py +0 -0
  106. venv/Lib/site-packages/pip/_internal/resolution/base.py +20 -0
  107. venv/Lib/site-packages/pip/_internal/resolution/legacy/__init__.py +0 -0
  108. venv/Lib/site-packages/pip/_internal/resolution/legacy/resolver.py +600 -0
  109. venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__init__.py +0 -0
  110. venv/Lib/site-packages/pip/_internal/resolution/resolvelib/base.py +141 -0
  111. venv/Lib/site-packages/pip/_internal/resolution/resolvelib/candidates.py +555 -0
  112. venv/Lib/site-packages/pip/_internal/resolution/resolvelib/factory.py +730 -0
  113. venv/Lib/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py +155 -0
  114. venv/Lib/site-packages/pip/_internal/resolution/resolvelib/provider.py +255 -0
  115. venv/Lib/site-packages/pip/_internal/resolution/resolvelib/reporter.py +80 -0
  116. venv/Lib/site-packages/pip/_internal/resolution/resolvelib/requirements.py +165 -0
  117. venv/Lib/site-packages/pip/_internal/resolution/resolvelib/resolver.py +299 -0
  118. venv/Lib/site-packages/pip/_internal/self_outdated_check.py +242 -0
  119. venv/Lib/site-packages/pip/_internal/utils/__init__.py +0 -0
  120. venv/Lib/site-packages/pip/_internal/utils/_jaraco_text.py +109 -0
  121. venv/Lib/site-packages/pip/_internal/utils/_log.py +38 -0
  122. venv/Lib/site-packages/pip/_internal/utils/appdirs.py +52 -0
  123. venv/Lib/site-packages/pip/_internal/utils/compat.py +63 -0
  124. venv/Lib/site-packages/pip/_internal/utils/compatibility_tags.py +165 -0
  125. venv/Lib/site-packages/pip/_internal/utils/datetime.py +11 -0
  126. venv/Lib/site-packages/pip/_internal/utils/deprecation.py +120 -0
  127. venv/Lib/site-packages/pip/_internal/utils/direct_url_helpers.py +87 -0
  128. venv/Lib/site-packages/pip/_internal/utils/egg_link.py +72 -0
  129. venv/Lib/site-packages/pip/_internal/utils/encoding.py +36 -0
  130. venv/Lib/site-packages/pip/_internal/utils/entrypoints.py +84 -0
  131. venv/Lib/site-packages/pip/_internal/utils/filesystem.py +153 -0
  132. venv/Lib/site-packages/pip/_internal/utils/filetypes.py +27 -0
  133. venv/Lib/site-packages/pip/_internal/utils/glibc.py +88 -0
  134. venv/Lib/site-packages/pip/_internal/utils/hashes.py +151 -0
  135. venv/Lib/site-packages/pip/_internal/utils/inject_securetransport.py +35 -0
  136. venv/Lib/site-packages/pip/_internal/utils/logging.py +348 -0
  137. venv/Lib/site-packages/pip/_internal/utils/misc.py +735 -0
  138. venv/Lib/site-packages/pip/_internal/utils/models.py +39 -0
  139. venv/Lib/site-packages/pip/_internal/utils/packaging.py +57 -0
  140. venv/Lib/site-packages/pip/_internal/utils/setuptools_build.py +146 -0
  141. venv/Lib/site-packages/pip/_internal/utils/subprocess.py +260 -0
  142. venv/Lib/site-packages/pip/_internal/utils/temp_dir.py +246 -0
  143. venv/Lib/site-packages/pip/_internal/utils/unpacking.py +257 -0
  144. venv/Lib/site-packages/pip/_internal/utils/urls.py +62 -0
  145. venv/Lib/site-packages/pip/_internal/utils/virtualenv.py +104 -0
  146. venv/Lib/site-packages/pip/_internal/utils/wheel.py +136 -0
  147. venv/Lib/site-packages/pip/_internal/vcs/__init__.py +15 -0
  148. venv/Lib/site-packages/pip/_internal/vcs/bazaar.py +112 -0
  149. venv/Lib/site-packages/pip/_internal/vcs/git.py +526 -0
  150. venv/Lib/site-packages/pip/_internal/vcs/mercurial.py +163 -0
  151. venv/Lib/site-packages/pip/_internal/vcs/subversion.py +324 -0
  152. venv/Lib/site-packages/pip/_internal/vcs/versioncontrol.py +705 -0
  153. venv/Lib/site-packages/pip/_internal/wheel_builder.py +355 -0
  154. venv/Lib/site-packages/pip/_vendor/__init__.py +120 -0
  155. venv/Lib/site-packages/pip/_vendor/cachecontrol/__init__.py +18 -0
  156. venv/Lib/site-packages/pip/_vendor/cachecontrol/_cmd.py +61 -0
  157. venv/Lib/site-packages/pip/_vendor/cachecontrol/adapter.py +137 -0
  158. venv/Lib/site-packages/pip/_vendor/cachecontrol/cache.py +65 -0
  159. venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__init__.py +9 -0
  160. venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py +188 -0
  161. venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py +39 -0
  162. venv/Lib/site-packages/pip/_vendor/cachecontrol/compat.py +32 -0
  163. venv/Lib/site-packages/pip/_vendor/cachecontrol/controller.py +439 -0
  164. venv/Lib/site-packages/pip/_vendor/cachecontrol/filewrapper.py +111 -0
  165. venv/Lib/site-packages/pip/_vendor/cachecontrol/heuristics.py +139 -0
  166. venv/Lib/site-packages/pip/_vendor/cachecontrol/serialize.py +190 -0
  167. venv/Lib/site-packages/pip/_vendor/cachecontrol/wrapper.py +33 -0
  168. venv/Lib/site-packages/pip/_vendor/certifi/__init__.py +4 -0
  169. venv/Lib/site-packages/pip/_vendor/certifi/__main__.py +12 -0
  170. venv/Lib/site-packages/pip/_vendor/certifi/core.py +108 -0
  171. venv/Lib/site-packages/pip/_vendor/chardet/__init__.py +115 -0
  172. venv/Lib/site-packages/pip/_vendor/chardet/big5freq.py +386 -0
  173. venv/Lib/site-packages/pip/_vendor/chardet/big5prober.py +47 -0
  174. venv/Lib/site-packages/pip/_vendor/chardet/chardistribution.py +261 -0
  175. venv/Lib/site-packages/pip/_vendor/chardet/charsetgroupprober.py +106 -0
  176. venv/Lib/site-packages/pip/_vendor/chardet/charsetprober.py +147 -0
  177. venv/Lib/site-packages/pip/_vendor/chardet/cli/__init__.py +0 -0
  178. venv/Lib/site-packages/pip/_vendor/chardet/cli/chardetect.py +112 -0
  179. venv/Lib/site-packages/pip/_vendor/chardet/codingstatemachine.py +90 -0
  180. venv/Lib/site-packages/pip/_vendor/chardet/codingstatemachinedict.py +19 -0
  181. venv/Lib/site-packages/pip/_vendor/chardet/cp949prober.py +49 -0
  182. venv/Lib/site-packages/pip/_vendor/chardet/enums.py +85 -0
  183. venv/Lib/site-packages/pip/_vendor/chardet/escprober.py +102 -0
  184. venv/Lib/site-packages/pip/_vendor/chardet/escsm.py +261 -0
  185. venv/Lib/site-packages/pip/_vendor/chardet/eucjpprober.py +102 -0
  186. venv/Lib/site-packages/pip/_vendor/chardet/euckrfreq.py +196 -0
  187. venv/Lib/site-packages/pip/_vendor/chardet/euckrprober.py +47 -0
  188. venv/Lib/site-packages/pip/_vendor/chardet/euctwfreq.py +388 -0
  189. venv/Lib/site-packages/pip/_vendor/chardet/euctwprober.py +47 -0
  190. venv/Lib/site-packages/pip/_vendor/chardet/gb2312freq.py +284 -0
  191. venv/Lib/site-packages/pip/_vendor/chardet/gb2312prober.py +47 -0
  192. venv/Lib/site-packages/pip/_vendor/chardet/hebrewprober.py +316 -0
  193. venv/Lib/site-packages/pip/_vendor/chardet/jisfreq.py +325 -0
  194. venv/Lib/site-packages/pip/_vendor/chardet/johabfreq.py +2382 -0
  195. venv/Lib/site-packages/pip/_vendor/chardet/johabprober.py +47 -0
  196. venv/Lib/site-packages/pip/_vendor/chardet/jpcntx.py +238 -0
  197. venv/Lib/site-packages/pip/_vendor/chardet/langbulgarianmodel.py +4649 -0
  198. venv/Lib/site-packages/pip/_vendor/chardet/langgreekmodel.py +4397 -0
  199. venv/Lib/site-packages/pip/_vendor/chardet/langhebrewmodel.py +4380 -0
  200. venv/Lib/site-packages/pip/_vendor/chardet/langhungarianmodel.py +4649 -0
  201. venv/Lib/site-packages/pip/_vendor/chardet/langrussianmodel.py +5725 -0
  202. venv/Lib/site-packages/pip/_vendor/chardet/langthaimodel.py +4380 -0
  203. venv/Lib/site-packages/pip/_vendor/chardet/langturkishmodel.py +4380 -0
  204. venv/Lib/site-packages/pip/_vendor/chardet/latin1prober.py +147 -0
  205. venv/Lib/site-packages/pip/_vendor/chardet/macromanprober.py +162 -0
  206. venv/Lib/site-packages/pip/_vendor/chardet/mbcharsetprober.py +95 -0
  207. venv/Lib/site-packages/pip/_vendor/chardet/mbcsgroupprober.py +57 -0
  208. venv/Lib/site-packages/pip/_vendor/chardet/mbcssm.py +661 -0
  209. venv/Lib/site-packages/pip/_vendor/chardet/metadata/__init__.py +0 -0
  210. venv/Lib/site-packages/pip/_vendor/chardet/metadata/languages.py +352 -0
  211. venv/Lib/site-packages/pip/_vendor/chardet/resultdict.py +16 -0
  212. venv/Lib/site-packages/pip/_vendor/chardet/sbcharsetprober.py +162 -0
  213. venv/Lib/site-packages/pip/_vendor/chardet/sbcsgroupprober.py +88 -0
  214. venv/Lib/site-packages/pip/_vendor/chardet/sjisprober.py +105 -0
  215. venv/Lib/site-packages/pip/_vendor/chardet/universaldetector.py +362 -0
  216. venv/Lib/site-packages/pip/_vendor/chardet/utf1632prober.py +225 -0
  217. venv/Lib/site-packages/pip/_vendor/chardet/utf8prober.py +82 -0
  218. venv/Lib/site-packages/pip/_vendor/chardet/version.py +9 -0
  219. venv/Lib/site-packages/pip/_vendor/colorama/__init__.py +7 -0
  220. venv/Lib/site-packages/pip/_vendor/colorama/ansi.py +102 -0
  221. venv/Lib/site-packages/pip/_vendor/colorama/ansitowin32.py +277 -0
  222. venv/Lib/site-packages/pip/_vendor/colorama/initialise.py +121 -0
  223. venv/Lib/site-packages/pip/_vendor/colorama/tests/__init__.py +1 -0
  224. venv/Lib/site-packages/pip/_vendor/colorama/tests/ansi_test.py +76 -0
  225. venv/Lib/site-packages/pip/_vendor/colorama/tests/ansitowin32_test.py +294 -0
  226. venv/Lib/site-packages/pip/_vendor/colorama/tests/initialise_test.py +189 -0
  227. venv/Lib/site-packages/pip/_vendor/colorama/tests/isatty_test.py +57 -0
  228. venv/Lib/site-packages/pip/_vendor/colorama/tests/utils.py +49 -0
  229. venv/Lib/site-packages/pip/_vendor/colorama/tests/winterm_test.py +131 -0
  230. venv/Lib/site-packages/pip/_vendor/colorama/win32.py +180 -0
  231. venv/Lib/site-packages/pip/_vendor/colorama/winterm.py +195 -0
  232. venv/Lib/site-packages/pip/_vendor/distlib/__init__.py +23 -0
  233. venv/Lib/site-packages/pip/_vendor/distlib/compat.py +1116 -0
  234. venv/Lib/site-packages/pip/_vendor/distlib/database.py +1350 -0
  235. venv/Lib/site-packages/pip/_vendor/distlib/index.py +508 -0
  236. venv/Lib/site-packages/pip/_vendor/distlib/locators.py +1300 -0
  237. venv/Lib/site-packages/pip/_vendor/distlib/manifest.py +393 -0
  238. venv/Lib/site-packages/pip/_vendor/distlib/markers.py +152 -0
  239. venv/Lib/site-packages/pip/_vendor/distlib/metadata.py +1076 -0
  240. venv/Lib/site-packages/pip/_vendor/distlib/resources.py +358 -0
  241. venv/Lib/site-packages/pip/_vendor/distlib/scripts.py +437 -0
  242. venv/Lib/site-packages/pip/_vendor/distlib/util.py +1932 -0
  243. venv/Lib/site-packages/pip/_vendor/distlib/version.py +739 -0
  244. venv/Lib/site-packages/pip/_vendor/distlib/wheel.py +1082 -0
  245. venv/Lib/site-packages/pip/_vendor/distro/__init__.py +54 -0
  246. venv/Lib/site-packages/pip/_vendor/distro/__main__.py +4 -0
  247. venv/Lib/site-packages/pip/_vendor/distro/distro.py +1399 -0
  248. venv/Lib/site-packages/pip/_vendor/idna/__init__.py +44 -0
  249. venv/Lib/site-packages/pip/_vendor/idna/codec.py +112 -0
  250. venv/Lib/site-packages/pip/_vendor/idna/compat.py +13 -0
  251. venv/Lib/site-packages/pip/_vendor/idna/core.py +400 -0
  252. venv/Lib/site-packages/pip/_vendor/idna/idnadata.py +2151 -0
  253. venv/Lib/site-packages/pip/_vendor/idna/intranges.py +54 -0
  254. venv/Lib/site-packages/pip/_vendor/idna/package_data.py +2 -0
  255. venv/Lib/site-packages/pip/_vendor/idna/uts46data.py +8600 -0
  256. venv/Lib/site-packages/pip/_vendor/msgpack/__init__.py +57 -0
  257. venv/Lib/site-packages/pip/_vendor/msgpack/exceptions.py +48 -0
  258. venv/Lib/site-packages/pip/_vendor/msgpack/ext.py +193 -0
  259. venv/Lib/site-packages/pip/_vendor/msgpack/fallback.py +1010 -0
  260. venv/Lib/site-packages/pip/_vendor/packaging/__about__.py +26 -0
  261. venv/Lib/site-packages/pip/_vendor/packaging/__init__.py +25 -0
  262. venv/Lib/site-packages/pip/_vendor/packaging/_manylinux.py +301 -0
  263. venv/Lib/site-packages/pip/_vendor/packaging/_musllinux.py +136 -0
  264. venv/Lib/site-packages/pip/_vendor/packaging/_structures.py +61 -0
  265. venv/Lib/site-packages/pip/_vendor/packaging/markers.py +304 -0
  266. venv/Lib/site-packages/pip/_vendor/packaging/requirements.py +146 -0
  267. venv/Lib/site-packages/pip/_vendor/packaging/specifiers.py +802 -0
  268. venv/Lib/site-packages/pip/_vendor/packaging/tags.py +487 -0
  269. venv/Lib/site-packages/pip/_vendor/packaging/utils.py +136 -0
  270. venv/Lib/site-packages/pip/_vendor/packaging/version.py +504 -0
  271. venv/Lib/site-packages/pip/_vendor/pkg_resources/__init__.py +3361 -0
  272. venv/Lib/site-packages/pip/_vendor/platformdirs/__init__.py +566 -0
  273. venv/Lib/site-packages/pip/_vendor/platformdirs/__main__.py +53 -0
  274. venv/Lib/site-packages/pip/_vendor/platformdirs/android.py +210 -0
  275. venv/Lib/site-packages/pip/_vendor/platformdirs/api.py +223 -0
  276. venv/Lib/site-packages/pip/_vendor/platformdirs/macos.py +91 -0
  277. venv/Lib/site-packages/pip/_vendor/platformdirs/unix.py +223 -0
  278. venv/Lib/site-packages/pip/_vendor/platformdirs/version.py +4 -0
  279. venv/Lib/site-packages/pip/_vendor/platformdirs/windows.py +255 -0
  280. venv/Lib/site-packages/pip/_vendor/pygments/__init__.py +82 -0
  281. venv/Lib/site-packages/pip/_vendor/pygments/__main__.py +17 -0
  282. venv/Lib/site-packages/pip/_vendor/pygments/cmdline.py +668 -0
  283. venv/Lib/site-packages/pip/_vendor/pygments/console.py +70 -0
  284. venv/Lib/site-packages/pip/_vendor/pygments/filter.py +71 -0
  285. venv/Lib/site-packages/pip/_vendor/pygments/filters/__init__.py +940 -0
  286. venv/Lib/site-packages/pip/_vendor/pygments/formatter.py +124 -0
  287. venv/Lib/site-packages/pip/_vendor/pygments/formatters/__init__.py +158 -0
  288. venv/Lib/site-packages/pip/_vendor/pygments/formatters/_mapping.py +23 -0
  289. venv/Lib/site-packages/pip/_vendor/pygments/formatters/bbcode.py +108 -0
  290. venv/Lib/site-packages/pip/_vendor/pygments/formatters/groff.py +170 -0
  291. venv/Lib/site-packages/pip/_vendor/pygments/formatters/html.py +989 -0
  292. venv/Lib/site-packages/pip/_vendor/pygments/formatters/img.py +645 -0
  293. venv/Lib/site-packages/pip/_vendor/pygments/formatters/irc.py +154 -0
  294. venv/Lib/site-packages/pip/_vendor/pygments/formatters/latex.py +521 -0
  295. venv/Lib/site-packages/pip/_vendor/pygments/formatters/other.py +161 -0
  296. venv/Lib/site-packages/pip/_vendor/pygments/formatters/pangomarkup.py +83 -0
  297. venv/Lib/site-packages/pip/_vendor/pygments/formatters/rtf.py +146 -0
  298. venv/Lib/site-packages/pip/_vendor/pygments/formatters/svg.py +188 -0
  299. venv/Lib/site-packages/pip/_vendor/pygments/formatters/terminal.py +127 -0
  300. venv/Lib/site-packages/pip/_vendor/pygments/formatters/terminal256.py +338 -0
  301. venv/Lib/site-packages/pip/_vendor/pygments/lexer.py +943 -0
  302. venv/Lib/site-packages/pip/_vendor/pygments/lexers/__init__.py +362 -0
  303. venv/Lib/site-packages/pip/_vendor/pygments/lexers/_mapping.py +559 -0
  304. venv/Lib/site-packages/pip/_vendor/pygments/lexers/python.py +1198 -0
  305. venv/Lib/site-packages/pip/_vendor/pygments/modeline.py +43 -0
  306. venv/Lib/site-packages/pip/_vendor/pygments/plugin.py +88 -0
  307. venv/Lib/site-packages/pip/_vendor/pygments/regexopt.py +91 -0
  308. venv/Lib/site-packages/pip/_vendor/pygments/scanner.py +104 -0
  309. venv/Lib/site-packages/pip/_vendor/pygments/sphinxext.py +217 -0
  310. venv/Lib/site-packages/pip/_vendor/pygments/style.py +197 -0
  311. venv/Lib/site-packages/pip/_vendor/pygments/styles/__init__.py +103 -0
  312. venv/Lib/site-packages/pip/_vendor/pygments/token.py +213 -0
  313. venv/Lib/site-packages/pip/_vendor/pygments/unistring.py +153 -0
  314. venv/Lib/site-packages/pip/_vendor/pygments/util.py +330 -0
  315. venv/Lib/site-packages/pip/_vendor/pyparsing/__init__.py +322 -0
  316. venv/Lib/site-packages/pip/_vendor/pyparsing/actions.py +217 -0
  317. venv/Lib/site-packages/pip/_vendor/pyparsing/common.py +432 -0
  318. venv/Lib/site-packages/pip/_vendor/pyparsing/core.py +6115 -0
  319. venv/Lib/site-packages/pip/_vendor/pyparsing/diagram/__init__.py +656 -0
  320. venv/Lib/site-packages/pip/_vendor/pyparsing/exceptions.py +299 -0
  321. venv/Lib/site-packages/pip/_vendor/pyparsing/helpers.py +1100 -0
  322. venv/Lib/site-packages/pip/_vendor/pyparsing/results.py +796 -0
  323. venv/Lib/site-packages/pip/_vendor/pyparsing/testing.py +331 -0
  324. venv/Lib/site-packages/pip/_vendor/pyparsing/unicode.py +361 -0
  325. venv/Lib/site-packages/pip/_vendor/pyparsing/util.py +284 -0
  326. venv/Lib/site-packages/pip/_vendor/pyproject_hooks/__init__.py +23 -0
  327. venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_compat.py +8 -0
  328. venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_impl.py +330 -0
  329. venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_in_process/__init__.py +18 -0
  330. venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py +353 -0
  331. venv/Lib/site-packages/pip/_vendor/requests/__init__.py +182 -0
  332. venv/Lib/site-packages/pip/_vendor/requests/__version__.py +14 -0
  333. venv/Lib/site-packages/pip/_vendor/requests/_internal_utils.py +50 -0
  334. venv/Lib/site-packages/pip/_vendor/requests/adapters.py +538 -0
  335. venv/Lib/site-packages/pip/_vendor/requests/api.py +157 -0
  336. venv/Lib/site-packages/pip/_vendor/requests/auth.py +315 -0
  337. venv/Lib/site-packages/pip/_vendor/requests/certs.py +24 -0
  338. venv/Lib/site-packages/pip/_vendor/requests/compat.py +67 -0
  339. venv/Lib/site-packages/pip/_vendor/requests/cookies.py +561 -0
  340. venv/Lib/site-packages/pip/_vendor/requests/exceptions.py +141 -0
  341. venv/Lib/site-packages/pip/_vendor/requests/help.py +131 -0
  342. venv/Lib/site-packages/pip/_vendor/requests/hooks.py +33 -0
  343. venv/Lib/site-packages/pip/_vendor/requests/models.py +1034 -0
  344. venv/Lib/site-packages/pip/_vendor/requests/packages.py +16 -0
  345. venv/Lib/site-packages/pip/_vendor/requests/sessions.py +833 -0
  346. venv/Lib/site-packages/pip/_vendor/requests/status_codes.py +128 -0
  347. venv/Lib/site-packages/pip/_vendor/requests/structures.py +99 -0
  348. venv/Lib/site-packages/pip/_vendor/requests/utils.py +1094 -0
  349. venv/Lib/site-packages/pip/_vendor/resolvelib/__init__.py +26 -0
  350. venv/Lib/site-packages/pip/_vendor/resolvelib/compat/__init__.py +0 -0
  351. venv/Lib/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py +6 -0
  352. venv/Lib/site-packages/pip/_vendor/resolvelib/providers.py +133 -0
  353. venv/Lib/site-packages/pip/_vendor/resolvelib/reporters.py +43 -0
  354. venv/Lib/site-packages/pip/_vendor/resolvelib/resolvers.py +547 -0
  355. venv/Lib/site-packages/pip/_vendor/resolvelib/structs.py +170 -0
  356. venv/Lib/site-packages/pip/_vendor/rich/__init__.py +177 -0
  357. venv/Lib/site-packages/pip/_vendor/rich/__main__.py +274 -0
  358. venv/Lib/site-packages/pip/_vendor/rich/_cell_widths.py +451 -0
  359. venv/Lib/site-packages/pip/_vendor/rich/_emoji_codes.py +3610 -0
  360. venv/Lib/site-packages/pip/_vendor/rich/_emoji_replace.py +32 -0
  361. venv/Lib/site-packages/pip/_vendor/rich/_export_format.py +76 -0
  362. venv/Lib/site-packages/pip/_vendor/rich/_extension.py +10 -0
  363. venv/Lib/site-packages/pip/_vendor/rich/_fileno.py +24 -0
  364. venv/Lib/site-packages/pip/_vendor/rich/_inspect.py +270 -0
  365. venv/Lib/site-packages/pip/_vendor/rich/_log_render.py +94 -0
  366. venv/Lib/site-packages/pip/_vendor/rich/_loop.py +43 -0
  367. venv/Lib/site-packages/pip/_vendor/rich/_null_file.py +69 -0
  368. venv/Lib/site-packages/pip/_vendor/rich/_palettes.py +309 -0
  369. venv/Lib/site-packages/pip/_vendor/rich/_pick.py +17 -0
  370. venv/Lib/site-packages/pip/_vendor/rich/_ratio.py +160 -0
  371. venv/Lib/site-packages/pip/_vendor/rich/_spinners.py +482 -0
  372. venv/Lib/site-packages/pip/_vendor/rich/_stack.py +16 -0
  373. venv/Lib/site-packages/pip/_vendor/rich/_timer.py +19 -0
  374. venv/Lib/site-packages/pip/_vendor/rich/_win32_console.py +662 -0
  375. venv/Lib/site-packages/pip/_vendor/rich/_windows.py +72 -0
  376. venv/Lib/site-packages/pip/_vendor/rich/_windows_renderer.py +56 -0
  377. venv/Lib/site-packages/pip/_vendor/rich/_wrap.py +56 -0
  378. venv/Lib/site-packages/pip/_vendor/rich/abc.py +33 -0
  379. venv/Lib/site-packages/pip/_vendor/rich/align.py +311 -0
  380. venv/Lib/site-packages/pip/_vendor/rich/ansi.py +240 -0
  381. venv/Lib/site-packages/pip/_vendor/rich/bar.py +94 -0
  382. venv/Lib/site-packages/pip/_vendor/rich/box.py +517 -0
  383. venv/Lib/site-packages/pip/_vendor/rich/cells.py +154 -0
  384. venv/Lib/site-packages/pip/_vendor/rich/color.py +622 -0
  385. venv/Lib/site-packages/pip/_vendor/rich/color_triplet.py +38 -0
  386. venv/Lib/site-packages/pip/_vendor/rich/columns.py +187 -0
  387. venv/Lib/site-packages/pip/_vendor/rich/console.py +2633 -0
  388. venv/Lib/site-packages/pip/_vendor/rich/constrain.py +37 -0
  389. venv/Lib/site-packages/pip/_vendor/rich/containers.py +167 -0
  390. venv/Lib/site-packages/pip/_vendor/rich/control.py +225 -0
  391. venv/Lib/site-packages/pip/_vendor/rich/default_styles.py +190 -0
  392. venv/Lib/site-packages/pip/_vendor/rich/diagnose.py +37 -0
  393. venv/Lib/site-packages/pip/_vendor/rich/emoji.py +96 -0
  394. venv/Lib/site-packages/pip/_vendor/rich/errors.py +34 -0
  395. venv/Lib/site-packages/pip/_vendor/rich/file_proxy.py +57 -0
  396. venv/Lib/site-packages/pip/_vendor/rich/filesize.py +89 -0
  397. venv/Lib/site-packages/pip/_vendor/rich/highlighter.py +232 -0
  398. venv/Lib/site-packages/pip/_vendor/rich/json.py +140 -0
  399. venv/Lib/site-packages/pip/_vendor/rich/jupyter.py +101 -0
  400. venv/Lib/site-packages/pip/_vendor/rich/layout.py +443 -0
  401. venv/Lib/site-packages/pip/_vendor/rich/live.py +375 -0
  402. venv/Lib/site-packages/pip/_vendor/rich/live_render.py +113 -0
  403. venv/Lib/site-packages/pip/_vendor/rich/logging.py +289 -0
  404. venv/Lib/site-packages/pip/_vendor/rich/markup.py +246 -0
  405. venv/Lib/site-packages/pip/_vendor/rich/measure.py +151 -0
  406. venv/Lib/site-packages/pip/_vendor/rich/padding.py +141 -0
  407. venv/Lib/site-packages/pip/_vendor/rich/pager.py +34 -0
  408. venv/Lib/site-packages/pip/_vendor/rich/palette.py +100 -0
  409. venv/Lib/site-packages/pip/_vendor/rich/panel.py +308 -0
  410. venv/Lib/site-packages/pip/_vendor/rich/pretty.py +994 -0
  411. venv/Lib/site-packages/pip/_vendor/rich/progress.py +1702 -0
  412. venv/Lib/site-packages/pip/_vendor/rich/progress_bar.py +224 -0
  413. venv/Lib/site-packages/pip/_vendor/rich/prompt.py +376 -0
  414. venv/Lib/site-packages/pip/_vendor/rich/protocol.py +42 -0
  415. venv/Lib/site-packages/pip/_vendor/rich/region.py +10 -0
  416. venv/Lib/site-packages/pip/_vendor/rich/repr.py +149 -0
  417. venv/Lib/site-packages/pip/_vendor/rich/rule.py +130 -0
  418. venv/Lib/site-packages/pip/_vendor/rich/scope.py +86 -0
  419. venv/Lib/site-packages/pip/_vendor/rich/screen.py +54 -0
  420. venv/Lib/site-packages/pip/_vendor/rich/segment.py +739 -0
  421. venv/Lib/site-packages/pip/_vendor/rich/spinner.py +137 -0
  422. venv/Lib/site-packages/pip/_vendor/rich/status.py +132 -0
  423. venv/Lib/site-packages/pip/_vendor/rich/style.py +796 -0
  424. venv/Lib/site-packages/pip/_vendor/rich/styled.py +42 -0
  425. venv/Lib/site-packages/pip/_vendor/rich/syntax.py +948 -0
  426. venv/Lib/site-packages/pip/_vendor/rich/table.py +1002 -0
  427. venv/Lib/site-packages/pip/_vendor/rich/terminal_theme.py +153 -0
  428. venv/Lib/site-packages/pip/_vendor/rich/text.py +1307 -0
  429. venv/Lib/site-packages/pip/_vendor/rich/theme.py +115 -0
  430. venv/Lib/site-packages/pip/_vendor/rich/themes.py +5 -0
  431. venv/Lib/site-packages/pip/_vendor/rich/traceback.py +756 -0
  432. venv/Lib/site-packages/pip/_vendor/rich/tree.py +251 -0
  433. venv/Lib/site-packages/pip/_vendor/six.py +998 -0
  434. venv/Lib/site-packages/pip/_vendor/tenacity/__init__.py +608 -0
  435. venv/Lib/site-packages/pip/_vendor/tenacity/_asyncio.py +94 -0
  436. venv/Lib/site-packages/pip/_vendor/tenacity/_utils.py +76 -0
  437. venv/Lib/site-packages/pip/_vendor/tenacity/after.py +51 -0
  438. venv/Lib/site-packages/pip/_vendor/tenacity/before.py +46 -0
  439. venv/Lib/site-packages/pip/_vendor/tenacity/before_sleep.py +71 -0
  440. venv/Lib/site-packages/pip/_vendor/tenacity/nap.py +43 -0
  441. venv/Lib/site-packages/pip/_vendor/tenacity/retry.py +272 -0
  442. venv/Lib/site-packages/pip/_vendor/tenacity/stop.py +103 -0
  443. venv/Lib/site-packages/pip/_vendor/tenacity/tornadoweb.py +59 -0
  444. venv/Lib/site-packages/pip/_vendor/tenacity/wait.py +228 -0
  445. venv/Lib/site-packages/pip/_vendor/tomli/__init__.py +11 -0
  446. venv/Lib/site-packages/pip/_vendor/tomli/_parser.py +691 -0
  447. venv/Lib/site-packages/pip/_vendor/tomli/_re.py +107 -0
  448. venv/Lib/site-packages/pip/_vendor/tomli/_types.py +10 -0
  449. venv/Lib/site-packages/pip/_vendor/typing_extensions.py +3072 -0
  450. venv/Lib/site-packages/pip/_vendor/urllib3/__init__.py +102 -0
  451. venv/Lib/site-packages/pip/_vendor/urllib3/_collections.py +337 -0
  452. venv/Lib/site-packages/pip/_vendor/urllib3/_version.py +2 -0
  453. venv/Lib/site-packages/pip/_vendor/urllib3/connection.py +572 -0
  454. venv/Lib/site-packages/pip/_vendor/urllib3/connectionpool.py +1132 -0
  455. venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__init__.py +0 -0
  456. venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py +36 -0
  457. venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py +0 -0
  458. venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py +519 -0
  459. venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py +397 -0
  460. venv/Lib/site-packages/pip/_vendor/urllib3/contrib/appengine.py +314 -0
  461. venv/Lib/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py +130 -0
  462. venv/Lib/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py +518 -0
  463. venv/Lib/site-packages/pip/_vendor/urllib3/contrib/securetransport.py +921 -0
  464. venv/Lib/site-packages/pip/_vendor/urllib3/contrib/socks.py +216 -0
  465. venv/Lib/site-packages/pip/_vendor/urllib3/exceptions.py +323 -0
  466. venv/Lib/site-packages/pip/_vendor/urllib3/fields.py +274 -0
  467. venv/Lib/site-packages/pip/_vendor/urllib3/filepost.py +98 -0
  468. venv/Lib/site-packages/pip/_vendor/urllib3/packages/__init__.py +0 -0
  469. venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py +0 -0
  470. venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py +51 -0
  471. venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/weakref_finalize.py +155 -0
  472. venv/Lib/site-packages/pip/_vendor/urllib3/packages/six.py +1076 -0
  473. venv/Lib/site-packages/pip/_vendor/urllib3/poolmanager.py +537 -0
  474. venv/Lib/site-packages/pip/_vendor/urllib3/request.py +170 -0
  475. venv/Lib/site-packages/pip/_vendor/urllib3/response.py +879 -0
  476. venv/Lib/site-packages/pip/_vendor/urllib3/util/__init__.py +49 -0
  477. venv/Lib/site-packages/pip/_vendor/urllib3/util/connection.py +149 -0
  478. venv/Lib/site-packages/pip/_vendor/urllib3/util/proxy.py +57 -0
  479. venv/Lib/site-packages/pip/_vendor/urllib3/util/queue.py +22 -0
  480. venv/Lib/site-packages/pip/_vendor/urllib3/util/request.py +137 -0
  481. venv/Lib/site-packages/pip/_vendor/urllib3/util/response.py +107 -0
  482. venv/Lib/site-packages/pip/_vendor/urllib3/util/retry.py +620 -0
  483. venv/Lib/site-packages/pip/_vendor/urllib3/util/ssl_.py +495 -0
  484. venv/Lib/site-packages/pip/_vendor/urllib3/util/ssl_match_hostname.py +159 -0
  485. venv/Lib/site-packages/pip/_vendor/urllib3/util/ssltransport.py +221 -0
  486. venv/Lib/site-packages/pip/_vendor/urllib3/util/timeout.py +271 -0
  487. venv/Lib/site-packages/pip/_vendor/urllib3/util/url.py +435 -0
  488. venv/Lib/site-packages/pip/_vendor/urllib3/util/wait.py +152 -0
  489. venv/Lib/site-packages/pip/_vendor/webencodings/__init__.py +342 -0
  490. venv/Lib/site-packages/pip/_vendor/webencodings/labels.py +231 -0
  491. venv/Lib/site-packages/pip/_vendor/webencodings/mklabels.py +59 -0
  492. venv/Lib/site-packages/pip/_vendor/webencodings/tests.py +153 -0
  493. venv/Lib/site-packages/pip/_vendor/webencodings/x_user_defined.py +325 -0
  494. venv/Lib/site-packages/pip/py.typed +4 -0
  495. venv/Lib/site-packages/pkg_resources/__init__.py +3296 -0
  496. venv/Lib/site-packages/pkg_resources/_vendor/__init__.py +0 -0
  497. venv/Lib/site-packages/pkg_resources/_vendor/appdirs.py +608 -0
  498. venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/__init__.py +36 -0
  499. venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/_adapters.py +170 -0
  500. venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/_common.py +104 -0
  501. venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/_compat.py +98 -0
  502. venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/_itertools.py +35 -0
  503. venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/_legacy.py +121 -0
  504. venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/abc.py +137 -0
  505. venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/readers.py +122 -0
  506. venv/Lib/site-packages/pkg_resources/_vendor/importlib_resources/simple.py +116 -0
  507. venv/Lib/site-packages/pkg_resources/_vendor/jaraco/__init__.py +0 -0
  508. venv/Lib/site-packages/pkg_resources/_vendor/jaraco/context.py +213 -0
  509. venv/Lib/site-packages/pkg_resources/_vendor/jaraco/functools.py +525 -0
  510. venv/Lib/site-packages/pkg_resources/_vendor/jaraco/text/__init__.py +599 -0
  511. venv/Lib/site-packages/pkg_resources/_vendor/more_itertools/__init__.py +4 -0
  512. venv/Lib/site-packages/pkg_resources/_vendor/more_itertools/more.py +4316 -0
  513. venv/Lib/site-packages/pkg_resources/_vendor/more_itertools/recipes.py +698 -0
  514. venv/Lib/site-packages/pkg_resources/_vendor/packaging/__about__.py +26 -0
  515. venv/Lib/site-packages/pkg_resources/_vendor/packaging/__init__.py +25 -0
  516. venv/Lib/site-packages/pkg_resources/_vendor/packaging/_manylinux.py +301 -0
  517. venv/Lib/site-packages/pkg_resources/_vendor/packaging/_musllinux.py +136 -0
  518. venv/Lib/site-packages/pkg_resources/_vendor/packaging/_structures.py +61 -0
  519. venv/Lib/site-packages/pkg_resources/_vendor/packaging/markers.py +304 -0
  520. venv/Lib/site-packages/pkg_resources/_vendor/packaging/requirements.py +146 -0
  521. venv/Lib/site-packages/pkg_resources/_vendor/packaging/specifiers.py +802 -0
  522. venv/Lib/site-packages/pkg_resources/_vendor/packaging/tags.py +487 -0
  523. venv/Lib/site-packages/pkg_resources/_vendor/packaging/utils.py +136 -0
  524. venv/Lib/site-packages/pkg_resources/_vendor/packaging/version.py +504 -0
  525. venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/__init__.py +331 -0
  526. venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/actions.py +207 -0
  527. venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/common.py +424 -0
  528. venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/core.py +5814 -0
  529. venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/diagram/__init__.py +642 -0
  530. venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/exceptions.py +267 -0
  531. venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/helpers.py +1088 -0
  532. venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/results.py +760 -0
  533. venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/testing.py +331 -0
  534. venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/unicode.py +352 -0
  535. venv/Lib/site-packages/pkg_resources/_vendor/pyparsing/util.py +235 -0
  536. venv/Lib/site-packages/pkg_resources/_vendor/zipp.py +329 -0
  537. venv/Lib/site-packages/pkg_resources/extern/__init__.py +76 -0
  538. venv/Lib/site-packages/setuptools/__init__.py +247 -0
  539. venv/Lib/site-packages/setuptools/_deprecation_warning.py +7 -0
  540. venv/Lib/site-packages/setuptools/_distutils/__init__.py +24 -0
  541. venv/Lib/site-packages/setuptools/_distutils/_collections.py +56 -0
  542. venv/Lib/site-packages/setuptools/_distutils/_functools.py +20 -0
  543. venv/Lib/site-packages/setuptools/_distutils/_macos_compat.py +12 -0
  544. venv/Lib/site-packages/setuptools/_distutils/_msvccompiler.py +572 -0
  545. venv/Lib/site-packages/setuptools/_distutils/archive_util.py +280 -0
  546. venv/Lib/site-packages/setuptools/_distutils/bcppcompiler.py +408 -0
  547. venv/Lib/site-packages/setuptools/_distutils/ccompiler.py +1220 -0
  548. venv/Lib/site-packages/setuptools/_distutils/cmd.py +436 -0
  549. venv/Lib/site-packages/setuptools/_distutils/command/__init__.py +25 -0
  550. venv/Lib/site-packages/setuptools/_distutils/command/_framework_compat.py +55 -0
  551. venv/Lib/site-packages/setuptools/_distutils/command/bdist.py +157 -0
  552. venv/Lib/site-packages/setuptools/_distutils/command/bdist_dumb.py +144 -0
  553. venv/Lib/site-packages/setuptools/_distutils/command/bdist_rpm.py +615 -0
  554. venv/Lib/site-packages/setuptools/_distutils/command/build.py +153 -0
  555. venv/Lib/site-packages/setuptools/_distutils/command/build_clib.py +208 -0
  556. venv/Lib/site-packages/setuptools/_distutils/command/build_ext.py +787 -0
  557. venv/Lib/site-packages/setuptools/_distutils/command/build_py.py +407 -0
  558. venv/Lib/site-packages/setuptools/_distutils/command/build_scripts.py +173 -0
  559. venv/Lib/site-packages/setuptools/_distutils/command/check.py +151 -0
  560. venv/Lib/site-packages/setuptools/_distutils/command/clean.py +76 -0
  561. venv/Lib/site-packages/setuptools/_distutils/command/config.py +377 -0
  562. venv/Lib/site-packages/setuptools/_distutils/command/install.py +814 -0
  563. venv/Lib/site-packages/setuptools/_distutils/command/install_data.py +84 -0
  564. venv/Lib/site-packages/setuptools/_distutils/command/install_egg_info.py +91 -0
  565. venv/Lib/site-packages/setuptools/_distutils/command/install_headers.py +45 -0
  566. venv/Lib/site-packages/setuptools/_distutils/command/install_lib.py +238 -0
  567. venv/Lib/site-packages/setuptools/_distutils/command/install_scripts.py +61 -0
  568. venv/Lib/site-packages/setuptools/_distutils/command/py37compat.py +31 -0
  569. venv/Lib/site-packages/setuptools/_distutils/command/register.py +319 -0
  570. venv/Lib/site-packages/setuptools/_distutils/command/sdist.py +531 -0
  571. venv/Lib/site-packages/setuptools/_distutils/command/upload.py +205 -0
  572. venv/Lib/site-packages/setuptools/_distutils/config.py +139 -0
  573. venv/Lib/site-packages/setuptools/_distutils/core.py +291 -0
  574. venv/Lib/site-packages/setuptools/_distutils/cygwinccompiler.py +364 -0
  575. venv/Lib/site-packages/setuptools/_distutils/debug.py +5 -0
  576. venv/Lib/site-packages/setuptools/_distutils/dep_util.py +96 -0
  577. venv/Lib/site-packages/setuptools/_distutils/dir_util.py +243 -0
  578. venv/Lib/site-packages/setuptools/_distutils/dist.py +1286 -0
  579. venv/Lib/site-packages/setuptools/_distutils/errors.py +127 -0
  580. venv/Lib/site-packages/setuptools/_distutils/extension.py +248 -0
  581. venv/Lib/site-packages/setuptools/_distutils/fancy_getopt.py +470 -0
  582. venv/Lib/site-packages/setuptools/_distutils/file_util.py +249 -0
  583. venv/Lib/site-packages/setuptools/_distutils/filelist.py +371 -0
  584. venv/Lib/site-packages/setuptools/_distutils/log.py +80 -0
  585. venv/Lib/site-packages/setuptools/_distutils/msvc9compiler.py +832 -0
  586. venv/Lib/site-packages/setuptools/_distutils/msvccompiler.py +695 -0
  587. venv/Lib/site-packages/setuptools/_distutils/py38compat.py +8 -0
  588. venv/Lib/site-packages/setuptools/_distutils/py39compat.py +22 -0
  589. venv/Lib/site-packages/setuptools/_distutils/spawn.py +109 -0
  590. venv/Lib/site-packages/setuptools/_distutils/sysconfig.py +558 -0
  591. venv/Lib/site-packages/setuptools/_distutils/text_file.py +287 -0
  592. venv/Lib/site-packages/setuptools/_distutils/unixccompiler.py +401 -0
  593. venv/Lib/site-packages/setuptools/_distutils/util.py +513 -0
  594. venv/Lib/site-packages/setuptools/_distutils/version.py +358 -0
  595. venv/Lib/site-packages/setuptools/_distutils/versionpredicate.py +175 -0
  596. venv/Lib/site-packages/setuptools/_entry_points.py +86 -0
  597. venv/Lib/site-packages/setuptools/_imp.py +82 -0
  598. venv/Lib/site-packages/setuptools/_importlib.py +47 -0
  599. venv/Lib/site-packages/setuptools/_itertools.py +23 -0
  600. venv/Lib/site-packages/setuptools/_path.py +29 -0
  601. venv/Lib/site-packages/setuptools/_reqs.py +19 -0
  602. venv/Lib/site-packages/setuptools/_vendor/__init__.py +0 -0
  603. venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/__init__.py +1047 -0
  604. venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/_adapters.py +68 -0
  605. venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/_collections.py +30 -0
  606. venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/_compat.py +71 -0
  607. venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/_functools.py +104 -0
  608. venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/_itertools.py +73 -0
  609. venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/_meta.py +48 -0
  610. venv/Lib/site-packages/setuptools/_vendor/importlib_metadata/_text.py +99 -0
  611. venv/Lib/site-packages/setuptools/_vendor/importlib_resources/__init__.py +36 -0
  612. venv/Lib/site-packages/setuptools/_vendor/importlib_resources/_adapters.py +170 -0
  613. venv/Lib/site-packages/setuptools/_vendor/importlib_resources/_common.py +104 -0
  614. venv/Lib/site-packages/setuptools/_vendor/importlib_resources/_compat.py +98 -0
  615. venv/Lib/site-packages/setuptools/_vendor/importlib_resources/_itertools.py +35 -0
  616. venv/Lib/site-packages/setuptools/_vendor/importlib_resources/_legacy.py +121 -0
  617. venv/Lib/site-packages/setuptools/_vendor/importlib_resources/abc.py +137 -0
  618. venv/Lib/site-packages/setuptools/_vendor/importlib_resources/readers.py +122 -0
  619. venv/Lib/site-packages/setuptools/_vendor/importlib_resources/simple.py +116 -0
  620. venv/Lib/site-packages/setuptools/_vendor/jaraco/__init__.py +0 -0
  621. venv/Lib/site-packages/setuptools/_vendor/jaraco/context.py +213 -0
  622. venv/Lib/site-packages/setuptools/_vendor/jaraco/functools.py +525 -0
  623. venv/Lib/site-packages/setuptools/_vendor/jaraco/text/__init__.py +599 -0
  624. venv/Lib/site-packages/setuptools/_vendor/more_itertools/__init__.py +4 -0
  625. venv/Lib/site-packages/setuptools/_vendor/more_itertools/more.py +3824 -0
  626. venv/Lib/site-packages/setuptools/_vendor/more_itertools/recipes.py +620 -0
  627. venv/Lib/site-packages/setuptools/_vendor/ordered_set.py +488 -0
  628. venv/Lib/site-packages/setuptools/_vendor/packaging/__about__.py +26 -0
  629. venv/Lib/site-packages/setuptools/_vendor/packaging/__init__.py +25 -0
  630. venv/Lib/site-packages/setuptools/_vendor/packaging/_manylinux.py +301 -0
  631. venv/Lib/site-packages/setuptools/_vendor/packaging/_musllinux.py +136 -0
  632. venv/Lib/site-packages/setuptools/_vendor/packaging/_structures.py +61 -0
  633. venv/Lib/site-packages/setuptools/_vendor/packaging/markers.py +304 -0
  634. venv/Lib/site-packages/setuptools/_vendor/packaging/requirements.py +146 -0
  635. venv/Lib/site-packages/setuptools/_vendor/packaging/specifiers.py +802 -0
  636. venv/Lib/site-packages/setuptools/_vendor/packaging/tags.py +487 -0
  637. venv/Lib/site-packages/setuptools/_vendor/packaging/utils.py +136 -0
  638. venv/Lib/site-packages/setuptools/_vendor/packaging/version.py +504 -0
  639. venv/Lib/site-packages/setuptools/_vendor/pyparsing/__init__.py +331 -0
  640. venv/Lib/site-packages/setuptools/_vendor/pyparsing/actions.py +207 -0
  641. venv/Lib/site-packages/setuptools/_vendor/pyparsing/common.py +424 -0
  642. venv/Lib/site-packages/setuptools/_vendor/pyparsing/core.py +5814 -0
  643. venv/Lib/site-packages/setuptools/_vendor/pyparsing/diagram/__init__.py +642 -0
  644. venv/Lib/site-packages/setuptools/_vendor/pyparsing/exceptions.py +267 -0
  645. venv/Lib/site-packages/setuptools/_vendor/pyparsing/helpers.py +1088 -0
  646. venv/Lib/site-packages/setuptools/_vendor/pyparsing/results.py +760 -0
  647. venv/Lib/site-packages/setuptools/_vendor/pyparsing/testing.py +331 -0
  648. venv/Lib/site-packages/setuptools/_vendor/pyparsing/unicode.py +352 -0
  649. venv/Lib/site-packages/setuptools/_vendor/pyparsing/util.py +235 -0
  650. venv/Lib/site-packages/setuptools/_vendor/tomli/__init__.py +11 -0
  651. venv/Lib/site-packages/setuptools/_vendor/tomli/_parser.py +691 -0
  652. venv/Lib/site-packages/setuptools/_vendor/tomli/_re.py +107 -0
  653. venv/Lib/site-packages/setuptools/_vendor/tomli/_types.py +10 -0
  654. venv/Lib/site-packages/setuptools/_vendor/typing_extensions.py +2296 -0
  655. venv/Lib/site-packages/setuptools/_vendor/zipp.py +329 -0
  656. venv/Lib/site-packages/setuptools/archive_util.py +213 -0
  657. venv/Lib/site-packages/setuptools/build_meta.py +511 -0
  658. venv/Lib/site-packages/setuptools/command/__init__.py +12 -0
  659. venv/Lib/site-packages/setuptools/command/alias.py +78 -0
  660. venv/Lib/site-packages/setuptools/command/bdist_egg.py +457 -0
  661. venv/Lib/site-packages/setuptools/command/bdist_rpm.py +40 -0
  662. venv/Lib/site-packages/setuptools/command/build.py +146 -0
  663. venv/Lib/site-packages/setuptools/command/build_clib.py +101 -0
  664. venv/Lib/site-packages/setuptools/command/build_ext.py +383 -0
  665. venv/Lib/site-packages/setuptools/command/build_py.py +368 -0
  666. venv/Lib/site-packages/setuptools/command/develop.py +193 -0
  667. venv/Lib/site-packages/setuptools/command/dist_info.py +142 -0
  668. venv/Lib/site-packages/setuptools/command/easy_install.py +2312 -0
  669. venv/Lib/site-packages/setuptools/command/editable_wheel.py +844 -0
  670. venv/Lib/site-packages/setuptools/command/egg_info.py +763 -0
  671. venv/Lib/site-packages/setuptools/command/install.py +139 -0
  672. venv/Lib/site-packages/setuptools/command/install_egg_info.py +63 -0
  673. venv/Lib/site-packages/setuptools/command/install_lib.py +122 -0
  674. venv/Lib/site-packages/setuptools/command/install_scripts.py +70 -0
  675. venv/Lib/site-packages/setuptools/command/py36compat.py +134 -0
  676. venv/Lib/site-packages/setuptools/command/register.py +18 -0
  677. venv/Lib/site-packages/setuptools/command/rotate.py +64 -0
  678. venv/Lib/site-packages/setuptools/command/saveopts.py +22 -0
  679. venv/Lib/site-packages/setuptools/command/sdist.py +210 -0
  680. venv/Lib/site-packages/setuptools/command/setopt.py +149 -0
  681. venv/Lib/site-packages/setuptools/command/test.py +251 -0
  682. venv/Lib/site-packages/setuptools/command/upload.py +17 -0
  683. venv/Lib/site-packages/setuptools/command/upload_docs.py +213 -0
  684. venv/Lib/site-packages/setuptools/config/__init__.py +35 -0
  685. venv/Lib/site-packages/setuptools/config/_apply_pyprojecttoml.py +377 -0
  686. venv/Lib/site-packages/setuptools/config/_validate_pyproject/__init__.py +34 -0
  687. venv/Lib/site-packages/setuptools/config/_validate_pyproject/error_reporting.py +318 -0
  688. venv/Lib/site-packages/setuptools/config/_validate_pyproject/extra_validations.py +36 -0
  689. venv/Lib/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_exceptions.py +51 -0
  690. venv/Lib/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_validations.py +1035 -0
  691. venv/Lib/site-packages/setuptools/config/_validate_pyproject/formats.py +259 -0
  692. venv/Lib/site-packages/setuptools/config/expand.py +462 -0
  693. venv/Lib/site-packages/setuptools/config/pyprojecttoml.py +493 -0
  694. venv/Lib/site-packages/setuptools/config/setupcfg.py +762 -0
  695. venv/Lib/site-packages/setuptools/dep_util.py +25 -0
  696. venv/Lib/site-packages/setuptools/depends.py +176 -0
  697. venv/Lib/site-packages/setuptools/discovery.py +600 -0
  698. venv/Lib/site-packages/setuptools/dist.py +1222 -0
  699. venv/Lib/site-packages/setuptools/errors.py +58 -0
  700. venv/Lib/site-packages/setuptools/extension.py +148 -0
  701. venv/Lib/site-packages/setuptools/extern/__init__.py +76 -0
  702. venv/Lib/site-packages/setuptools/glob.py +167 -0
  703. venv/Lib/site-packages/setuptools/installer.py +104 -0
  704. venv/Lib/site-packages/setuptools/launch.py +36 -0
  705. venv/Lib/site-packages/setuptools/logging.py +36 -0
  706. venv/Lib/site-packages/setuptools/monkey.py +165 -0
  707. venv/Lib/site-packages/setuptools/msvc.py +1703 -0
  708. venv/Lib/site-packages/setuptools/namespaces.py +107 -0
  709. venv/Lib/site-packages/setuptools/package_index.py +1126 -0
  710. venv/Lib/site-packages/setuptools/py34compat.py +13 -0
  711. venv/Lib/site-packages/setuptools/sandbox.py +530 -0
  712. venv/Lib/site-packages/setuptools/unicode_utils.py +42 -0
  713. venv/Lib/site-packages/setuptools/version.py +6 -0
  714. venv/Lib/site-packages/setuptools/wheel.py +222 -0
  715. venv/Lib/site-packages/setuptools/windows_support.py +29 -0
  716. xplia/__init__.py +72 -0
  717. xplia/api/__init__.py +432 -0
  718. xplia/api/fastapi_app.py +453 -0
  719. xplia/cli.py +321 -0
  720. xplia/compliance/__init__.py +39 -0
  721. xplia/compliance/ai_act.py +538 -0
  722. xplia/compliance/compliance_checker.py +511 -0
  723. xplia/compliance/compliance_report.py +236 -0
  724. xplia/compliance/expert_review/__init__.py +18 -0
  725. xplia/compliance/expert_review/evaluation_criteria.py +209 -0
  726. xplia/compliance/expert_review/integration.py +270 -0
  727. xplia/compliance/expert_review/trust_expert_evaluator.py +379 -0
  728. xplia/compliance/explanation_rights.py +45 -0
  729. xplia/compliance/formatters/__init__.py +35 -0
  730. xplia/compliance/formatters/csv_formatter.py +179 -0
  731. xplia/compliance/formatters/html_formatter.py +689 -0
  732. xplia/compliance/formatters/html_trust_formatter.py +147 -0
  733. xplia/compliance/formatters/json_formatter.py +107 -0
  734. xplia/compliance/formatters/pdf_formatter.py +641 -0
  735. xplia/compliance/formatters/pdf_trust_formatter.py +309 -0
  736. xplia/compliance/formatters/trust_formatter_mixin.py +267 -0
  737. xplia/compliance/formatters/xml_formatter.py +173 -0
  738. xplia/compliance/gdpr.py +803 -0
  739. xplia/compliance/hipaa.py +134 -0
  740. xplia/compliance/report_base.py +205 -0
  741. xplia/compliance/report_generator.py +820 -0
  742. xplia/compliance/translations.py +299 -0
  743. xplia/core/__init__.py +98 -0
  744. xplia/core/base.py +391 -0
  745. xplia/core/config.py +297 -0
  746. xplia/core/factory.py +416 -0
  747. xplia/core/model_adapters/__init__.py +47 -0
  748. xplia/core/model_adapters/base.py +160 -0
  749. xplia/core/model_adapters/pytorch_adapter.py +339 -0
  750. xplia/core/model_adapters/sklearn_adapter.py +215 -0
  751. xplia/core/model_adapters/tensorflow_adapter.py +280 -0
  752. xplia/core/model_adapters/xgboost_adapter.py +295 -0
  753. xplia/core/optimizations.py +322 -0
  754. xplia/core/performance/__init__.py +57 -0
  755. xplia/core/performance/cache_manager.py +502 -0
  756. xplia/core/performance/memory_optimizer.py +465 -0
  757. xplia/core/performance/parallel_executor.py +327 -0
  758. xplia/core/registry.py +1234 -0
  759. xplia/explainers/__init__.py +70 -0
  760. xplia/explainers/__init__updated.py +62 -0
  761. xplia/explainers/adaptive/__init__.py +24 -0
  762. xplia/explainers/adaptive/explainer_selector.py +405 -0
  763. xplia/explainers/adaptive/explanation_quality.py +395 -0
  764. xplia/explainers/adaptive/fusion_strategies.py +297 -0
  765. xplia/explainers/adaptive/meta_explainer.py +320 -0
  766. xplia/explainers/adversarial/__init__.py +21 -0
  767. xplia/explainers/adversarial/adversarial_xai.py +678 -0
  768. xplia/explainers/anchor_explainer.py +1769 -0
  769. xplia/explainers/attention_explainer.py +996 -0
  770. xplia/explainers/bayesian/__init__.py +8 -0
  771. xplia/explainers/bayesian/bayesian_explainer.py +127 -0
  772. xplia/explainers/bias/__init__.py +17 -0
  773. xplia/explainers/bias/advanced_bias_detection.py +934 -0
  774. xplia/explainers/calibration/__init__.py +26 -0
  775. xplia/explainers/calibration/audience_adapter.py +376 -0
  776. xplia/explainers/calibration/audience_profiles.py +372 -0
  777. xplia/explainers/calibration/calibration_metrics.py +299 -0
  778. xplia/explainers/calibration/explanation_calibrator.py +460 -0
  779. xplia/explainers/causal/__init__.py +19 -0
  780. xplia/explainers/causal/causal_inference.py +669 -0
  781. xplia/explainers/certified/__init__.py +21 -0
  782. xplia/explainers/certified/certified_explanations.py +619 -0
  783. xplia/explainers/continual/__init__.py +8 -0
  784. xplia/explainers/continual/continual_explainer.py +102 -0
  785. xplia/explainers/counterfactual_explainer.py +804 -0
  786. xplia/explainers/counterfactuals/__init__.py +17 -0
  787. xplia/explainers/counterfactuals/advanced_counterfactuals.py +259 -0
  788. xplia/explainers/expert_evaluator.py +538 -0
  789. xplia/explainers/feature_importance_explainer.py +376 -0
  790. xplia/explainers/federated/__init__.py +17 -0
  791. xplia/explainers/federated/federated_xai.py +664 -0
  792. xplia/explainers/generative/__init__.py +15 -0
  793. xplia/explainers/generative/generative_explainer.py +243 -0
  794. xplia/explainers/gradient_explainer.py +3590 -0
  795. xplia/explainers/graph/__init__.py +26 -0
  796. xplia/explainers/graph/gnn_explainer.py +638 -0
  797. xplia/explainers/graph/molecular_explainer.py +438 -0
  798. xplia/explainers/lime_explainer.py +1580 -0
  799. xplia/explainers/llm/__init__.py +23 -0
  800. xplia/explainers/llm/llm_explainability.py +737 -0
  801. xplia/explainers/metalearning/__init__.py +15 -0
  802. xplia/explainers/metalearning/metalearning_explainer.py +276 -0
  803. xplia/explainers/moe/__init__.py +8 -0
  804. xplia/explainers/moe/moe_explainer.py +108 -0
  805. xplia/explainers/multimodal/__init__.py +30 -0
  806. xplia/explainers/multimodal/base.py +262 -0
  807. xplia/explainers/multimodal/diffusion_explainer.py +608 -0
  808. xplia/explainers/multimodal/foundation_model_explainer.py +323 -0
  809. xplia/explainers/multimodal/registry.py +139 -0
  810. xplia/explainers/multimodal/text_image_explainer.py +381 -0
  811. xplia/explainers/multimodal/vision_language_explainer.py +608 -0
  812. xplia/explainers/nas/__init__.py +5 -0
  813. xplia/explainers/nas/nas_explainer.py +65 -0
  814. xplia/explainers/neuralodes/__init__.py +5 -0
  815. xplia/explainers/neuralodes/neuralode_explainer.py +64 -0
  816. xplia/explainers/neurosymbolic/__init__.py +8 -0
  817. xplia/explainers/neurosymbolic/neurosymbolic_explainer.py +97 -0
  818. xplia/explainers/partial_dependence_explainer.py +509 -0
  819. xplia/explainers/privacy/__init__.py +21 -0
  820. xplia/explainers/privacy/differential_privacy_xai.py +624 -0
  821. xplia/explainers/quantum/__init__.py +5 -0
  822. xplia/explainers/quantum/quantum_explainer.py +79 -0
  823. xplia/explainers/recommender/__init__.py +8 -0
  824. xplia/explainers/recommender/recsys_explainer.py +124 -0
  825. xplia/explainers/reinforcement/__init__.py +15 -0
  826. xplia/explainers/reinforcement/rl_explainer.py +173 -0
  827. xplia/explainers/shap_explainer.py +2238 -0
  828. xplia/explainers/streaming/__init__.py +19 -0
  829. xplia/explainers/streaming/streaming_xai.py +703 -0
  830. xplia/explainers/timeseries/__init__.py +15 -0
  831. xplia/explainers/timeseries/timeseries_explainer.py +252 -0
  832. xplia/explainers/trust/__init__.py +24 -0
  833. xplia/explainers/trust/confidence_report.py +368 -0
  834. xplia/explainers/trust/fairwashing.py +489 -0
  835. xplia/explainers/trust/uncertainty.py +453 -0
  836. xplia/explainers/unified_explainer.py +566 -0
  837. xplia/explainers/unified_explainer_utils.py +309 -0
  838. xplia/integrations/__init__.py +3 -0
  839. xplia/integrations/mlflow_integration.py +331 -0
  840. xplia/integrations/wandb_integration.py +375 -0
  841. xplia/plugins/__init__.py +36 -0
  842. xplia/plugins/example_visualizer.py +11 -0
  843. xplia/utils/__init__.py +18 -0
  844. xplia/utils/performance.py +119 -0
  845. xplia/utils/validation.py +109 -0
  846. xplia/visualizations/__init__.py +31 -0
  847. xplia/visualizations/base.py +256 -0
  848. xplia/visualizations/boxplot_chart.py +224 -0
  849. xplia/visualizations/charts_impl.py +65 -0
  850. xplia/visualizations/gauge_chart.py +211 -0
  851. xplia/visualizations/gradient_viz.py +117 -0
  852. xplia/visualizations/heatmap_chart.py +173 -0
  853. xplia/visualizations/histogram_chart.py +176 -0
  854. xplia/visualizations/line_chart.py +100 -0
  855. xplia/visualizations/pie_chart.py +134 -0
  856. xplia/visualizations/radar_chart.py +154 -0
  857. xplia/visualizations/registry.py +76 -0
  858. xplia/visualizations/sankey_chart.py +190 -0
  859. xplia/visualizations/scatter_chart.py +252 -0
  860. xplia/visualizations/table_chart.py +263 -0
  861. xplia/visualizations/treemap_chart.py +216 -0
  862. xplia/visualizations.py +535 -0
  863. xplia/visualizers/__init__.py +87 -0
  864. xplia/visualizers/base_visualizer.py +294 -0
  865. xplia-1.0.1.dist-info/METADATA +685 -0
  866. xplia-1.0.1.dist-info/RECORD +870 -0
  867. xplia-1.0.1.dist-info/WHEEL +5 -0
  868. xplia-1.0.1.dist-info/entry_points.txt +2 -0
  869. xplia-1.0.1.dist-info/licenses/LICENSE +21 -0
  870. xplia-1.0.1.dist-info/top_level.txt +2 -0
@@ -0,0 +1,1769 @@
1
+ """
2
+ Explainer basé sur Anchor pour XPLIA
3
+ ====================================
4
+
5
+ Ce module implémente l'explainer Anchor qui génère des règles d'ancrage
6
+ pour expliquer les prédictions d'un modèle.
7
+
8
+ Les règles d'ancrage sont des règles SI-ALORS qui suffisent à "ancrer" une prédiction,
9
+ c'est-à-dire que si les conditions de la règle sont satisfaites, la prédiction
10
+ reste presque certainement la même, indépendamment des autres caractéristiques.
11
+ """
12
+
13
+ import logging
14
+ import numpy as np
15
+ import pandas as pd
16
+ import os
17
+ import hashlib
18
+ import json
19
+ import time
20
+ import traceback
21
+ import datetime
22
+ from functools import lru_cache
23
+ from contextlib import contextmanager
24
+ from typing import List, Dict, Any, Union, Optional, Tuple, Callable
25
+ from dataclasses import dataclass, field
26
+
27
+ from ..core.base import ExplainerBase, register_explainer
28
+ from ..core.explanation import (
29
+ ExplanationResult,
30
+ FeatureImportance,
31
+ ModelMetadata,
32
+ ExplainabilityMethod,
33
+ AudienceLevel
34
+ )
35
+
36
+ @dataclass
37
+ class AnchorExplainerConfig:
38
+ """Configuration pour l'AnchorExplainer permettant un paramétrage complet."""
39
+ # Paramètres généraux
40
+ feature_names: Optional[List[str]] = None
41
+ categorical_features: Optional[List[int]] = None
42
+ class_names: Optional[List[str]] = None
43
+ discretize_continuous: bool = True
44
+
45
+ # Paramètres d'optimisation
46
+ use_cache: bool = True
47
+ cache_size: int = 128
48
+ use_gpu: bool = True
49
+ compute_quality_metrics: bool = True
50
+
51
+ # Paramètres d'ancrage
52
+ threshold: float = 0.95
53
+ tau: float = 0.15
54
+ batch_size: int = 100
55
+ coverage_samples: int = 10000
56
+ beam_size: int = 5
57
+ max_anchor_size: Optional[int] = None
58
+ stop_on_first: bool = False
59
+ binary_cache_size: int = 10000
60
+ cache_margin: int = 1000
61
+
62
+ # Paramètres de narrative
63
+ narrative_audiences: List[str] = field(default_factory=lambda: ["technical"])
64
+ supported_languages: List[str] = field(default_factory=lambda: ["en", "fr"])
65
+
66
+ # Paramètres de conformité
67
+ verify_compliance: bool = True
68
+ compliance_rules: Dict[str, Any] = field(default_factory=dict)
69
+
70
+ # Paramètres d'échantillonnage pour les explications de groupes
71
+ sampling_method: str = "random" # 'random', 'kmeans', 'stratified'
72
+ max_instances: int = 10
73
+
74
+ @register_explainer
75
+ class AnchorExplainer(ExplainerBase):
76
+ """
77
+ Explainer qui génère des règles d'ancrage pour expliquer les prédictions d'un modèle.
78
+
79
+ Les règles d'ancrage sont des règles SI-ALORS qui suffisent à "ancrer" une prédiction,
80
+ c'est-à-dire que si les conditions de la règle sont satisfaites, la prédiction
81
+ reste presque certainement la même, indépendamment des autres caractéristiques.
82
+
83
+ Cette implémentation utilise la bibliothèque Anchor originale.
84
+
85
+ Attributes:
86
+ _model: Modèle à expliquer
87
+ _feature_names: Noms des caractéristiques
88
+ _categorical_features: Indices des caractéristiques catégorielles
89
+ _class_names: Noms des classes (pour les modèles de classification)
90
+ _explainer: Instance de l'explainer Anchor
91
+ _metadata: Métadonnées du modèle
92
+ _discretizer: Discrétiseur pour les caractéristiques continues
93
+ _logger: Logger pour les messages de débogage
94
+ """
95
+
96
+ def __init__(self, model, config=None, **kwargs):
97
+ """
98
+ Initialise l'explainer Anchor avec des fonctionnalités avancées.
99
+
100
+ Args:
101
+ model: Modèle à expliquer
102
+ config: Configuration via AnchorExplainerConfig
103
+ **kwargs: Arguments additionnels pour configuration
104
+ feature_names: Liste des noms des caractéristiques
105
+ categorical_features: Liste des indices des caractéristiques catégorielles
106
+ class_names: Liste des noms des classes
107
+ discretize_continuous: Si True, discrétise les caractéristiques continues
108
+ use_cache: Utiliser le cache pour les explications répétées
109
+ cache_size: Taille du cache LRU
110
+ use_gpu: Utiliser le GPU si disponible
111
+ compute_quality_metrics: Calculer les métriques de qualité
112
+ verify_compliance: Vérifier la conformité réglementaire
113
+ narrative_audiences: Audiences pour les narratives
114
+ supported_languages: Langues supportées
115
+ """
116
+ super().__init__(model=model, **kwargs)
117
+
118
+ # Initialiser la configuration
119
+ if config is None:
120
+ self._config = AnchorExplainerConfig()
121
+ elif isinstance(config, dict):
122
+ self._config = AnchorExplainerConfig(**config)
123
+ else:
124
+ self._config = config
125
+
126
+ # Surcharger la configuration avec les paramètres spécifiques
127
+ for key, value in kwargs.items():
128
+ if hasattr(self._config, key):
129
+ setattr(self._config, key, value)
130
+
131
+ # Initialiser les attributs de base
132
+ self._feature_names = self._config.feature_names
133
+ self._categorical_features = self._config.categorical_features or []
134
+ self._class_names = self._config.class_names
135
+ self._discretize_continuous = self._config.discretize_continuous
136
+
137
+ # Explainer Anchor
138
+ self._explainer = None
139
+
140
+ # Discrétiseur pour les caractéristiques continues
141
+ self._discretizer = None
142
+
143
+ # Métadonnées du modèle
144
+ self._metadata = None
145
+
146
+ # Logger
147
+ self._logger = logging.getLogger(__name__)
148
+
149
+ # Détecter le type de framework (TensorFlow, PyTorch, etc.)
150
+ self._framework = self._extract_model_type()
151
+
152
+ # Initialiser la gestion du GPU si demandée
153
+ if self._config.use_gpu:
154
+ self._initialize_gpu()
155
+
156
+ # Initialiser le vérificateur de conformité réglementaire
157
+ if self._config.verify_compliance:
158
+ self._initialize_compliance_checker()
159
+ else:
160
+ self._compliance_checker = None
161
+
162
+ # Tracer l'initialisation
163
+ self._logger.info(f"AnchorExplainer initialisé avec le framework '{self._framework}'")
164
+ if self._compliance_checker:
165
+ self._logger.info("Vérificateur de conformité initialisé")
166
+ if self._config.use_gpu:
167
+ self._logger.info("Support GPU activé")
168
+
169
+ def _initialize_gpu(self):
170
+ """
171
+ Initialise la configuration GPU pour le framework détecté.
172
+ Cette méthode configure le GPU pour TensorFlow/PyTorch si disponible.
173
+ """
174
+ try:
175
+ if self._framework == 'tensorflow':
176
+ # Configuration GPU pour TensorFlow
177
+ try:
178
+ import tensorflow as tf
179
+ gpus = tf.config.list_physical_devices('GPU')
180
+ if gpus:
181
+ # Configuration de la croissance dynamique de la mémoire
182
+ self._set_gpu_memory_growth(gpus)
183
+ self._logger.info(f"GPU TensorFlow configuré: {len(gpus)} GPU(s) disponible(s)")
184
+ else:
185
+ self._logger.info("Aucun GPU TensorFlow détecté, utilisation du CPU")
186
+ except ImportError:
187
+ self._logger.warning("TensorFlow non disponible pour la configuration GPU")
188
+
189
+ elif self._framework == 'pytorch':
190
+ # Configuration GPU pour PyTorch
191
+ try:
192
+ import torch
193
+ if torch.cuda.is_available():
194
+ # Réserver la mémoire au fur et à mesure
195
+ torch.cuda.set_per_process_memory_fraction(0.9) # Réserver 90% de la mémoire GPU
196
+ torch.cuda.empty_cache()
197
+ self._logger.info(f"GPU PyTorch configuré: {torch.cuda.device_count()} GPU(s) disponible(s)")
198
+ else:
199
+ self._logger.info("Aucun GPU PyTorch détecté, utilisation du CPU")
200
+ except ImportError:
201
+ self._logger.warning("PyTorch non disponible pour la configuration GPU")
202
+ except Exception as e:
203
+ self._logger.warning(f"Erreur lors de l'initialisation GPU: {str(e)}")
204
+
205
+ def _set_gpu_memory_growth(self, gpus):
206
+ """
207
+ Configure la croissance dynamique de la mémoire GPU pour TensorFlow
208
+ afin d'éviter les erreurs OOM (Out of Memory).
209
+
210
+ Args:
211
+ gpus: Liste des GPU physiques disponibles (tf.config.list_physical_devices)
212
+ """
213
+ try:
214
+ import tensorflow as tf
215
+ for gpu in gpus:
216
+ tf.config.experimental.set_memory_growth(gpu, True)
217
+ except Exception as e:
218
+ self._logger.warning(f"Erreur lors de la configuration de la croissance mémoire GPU: {str(e)}")
219
+
220
+ @contextmanager
221
+ def _maybe_use_gpu_context(self, use_gpu=None):
222
+ """
223
+ Context manager pour gérer l'utilisation du GPU selon le framework.
224
+
225
+ Args:
226
+ use_gpu: Si True, utilise le GPU si disponible. Si None, utilise la valeur de configuration.
227
+
228
+ Yields:
229
+ Contexte GPU approprié pour le framework
230
+ """
231
+ # Déterminer si on utilise le GPU
232
+ if use_gpu is None:
233
+ use_gpu = self._config.use_gpu
234
+
235
+ if not use_gpu:
236
+ # Si GPU non demandé, simplement passer
237
+ yield
238
+ return
239
+
240
+ # Sauvegarder le device/contexte actuel
241
+ original_device = None
242
+ device_changed = False
243
+
244
+ try:
245
+ # Utiliser le GPU selon le framework
246
+ if self._framework == 'tensorflow':
247
+ try:
248
+ import tensorflow as tf
249
+ # Vérifier si GPU est disponible
250
+ gpus = tf.config.list_physical_devices('GPU')
251
+ if gpus:
252
+ # Utiliser le premier GPU
253
+ with tf.device('/GPU:0'):
254
+ yield
255
+ else:
256
+ # Pas de GPU disponible
257
+ yield
258
+ except ImportError:
259
+ # TensorFlow non disponible
260
+ yield
261
+
262
+ elif self._framework == 'pytorch':
263
+ try:
264
+ import torch
265
+ if torch.cuda.is_available():
266
+ # Sauvegarder le device actuel
267
+ original_device = torch.cuda.current_device()
268
+ # Utiliser le premier GPU
269
+ torch.cuda.set_device(0)
270
+ device_changed = True
271
+ yield
272
+ else:
273
+ # Pas de GPU disponible
274
+ yield
275
+ except ImportError:
276
+ # PyTorch non disponible
277
+ yield
278
+ else:
279
+ # Autre framework non supporté pour GPU
280
+ yield
281
+ finally:
282
+ # Restaurer le device original si nécessaire
283
+ if device_changed and original_device is not None:
284
+ try:
285
+ import torch
286
+ torch.cuda.set_device(original_device)
287
+ torch.cuda.empty_cache() # Libérer la mémoire GPU
288
+ except:
289
+ pass
290
+
291
+ def _initialize_compliance_checker(self):
292
+ """
293
+ Initialise le vérificateur de conformité réglementaire.
294
+ """
295
+ try:
296
+ from ..compliance.compliance_checker import ComplianceChecker
297
+ self._compliance_checker = ComplianceChecker(
298
+ rules=self._config.compliance_rules,
299
+ explainer_type="AnchorExplainer"
300
+ )
301
+ self._logger.info("Vérificateur de conformité initialisé avec succès")
302
+ except ImportError:
303
+ self._logger.warning("Module de conformité non disponible")
304
+ self._compliance_checker = None
305
+ except Exception as e:
306
+ self._logger.warning(f"Impossible d'initialiser le vérificateur de conformité: {str(e)}")
307
+ self._compliance_checker = None
308
+
309
+ def explain_instance(self, instance, **kwargs) -> ExplanationResult:
310
+ """
311
+ Génère une explication basée sur des règles d'ancrage pour une instance spécifique.
312
+ Cette version améliorée inclut le cache, la gestion GPU, les métriques de qualité,
313
+ les narratives multilingues et la vérification de conformité réglementaire.
314
+
315
+ Args:
316
+ instance: Instance à expliquer (array, liste, dict ou pandas.Series)
317
+ **kwargs: Paramètres additionnels
318
+ data_type: Type de données ('tabular', 'text', 'image')
319
+ threshold: Seuil de précision pour l'ancrage (défaut: selon config)
320
+ tau: Paramètre de relaxation (défaut: selon config)
321
+ beam_size: Taille du faisceau pour la recherche (défaut: selon config)
322
+ max_anchor_size: Taille maximum de l'ancrage (défaut: selon config)
323
+ stop_on_first: Arrêter à la première explication valide (défaut: selon config)
324
+ binary_cache_size: Taille du cache binaire (défaut: selon config)
325
+ cache_margin: Marge du cache (défaut: selon config)
326
+ feature_names: Noms des caractéristiques (défaut: ceux de l'initialisation)
327
+ audience_level: Niveau d'audience (TECHNICAL, BUSINESS, PUBLIC, ALL)
328
+ language: Code de langue ('en', 'fr', etc.) (défaut: 'en')
329
+ use_gpu: Utiliser le GPU si disponible (défaut: selon config)
330
+ use_cache: Utiliser le cache pour les explications répétées (défaut: selon config)
331
+ compute_quality_metrics: Calculer les métriques de qualité (défaut: selon config)
332
+ verify_compliance: Vérifier la conformité réglementaire (défaut: selon config)
333
+
334
+ Returns:
335
+ ExplanationResult: Résultat standardisé de l'explication
336
+ """
337
+ # Paramètres de base
338
+ audience_level = kwargs.get('audience_level', AudienceLevel.TECHNICAL)
339
+ data_type = kwargs.get('data_type', 'tabular')
340
+ language = kwargs.get('language', 'en')
341
+ use_cache = kwargs.get('use_cache', self._config.use_cache)
342
+
343
+ # Initialiser la mesure du temps d'exécution
344
+ start_time = time.time()
345
+ execution_metadata = {
346
+ 'start_time': datetime.datetime.now().isoformat(),
347
+ 'data_type': data_type,
348
+ 'audience_level': str(audience_level),
349
+ 'language': language,
350
+ 'from_cache': False,
351
+ 'framework': getattr(self, '_framework', 'unknown')
352
+ }
353
+
354
+ try:
355
+ # Audit de l'action
356
+ self.add_audit_record("explain_instance", {
357
+ "data_type": data_type,
358
+ "audience_level": audience_level.value if isinstance(audience_level, AudienceLevel) else audience_level,
359
+ "language": language,
360
+ "use_cache": use_cache,
361
+ "use_gpu": kwargs.get('use_gpu', self._config.use_gpu)
362
+ })
363
+
364
+ # 1. Vérifier si une explication en cache est disponible
365
+ explanation_data = None
366
+ if use_cache:
367
+ cache_key = self._get_cache_key(instance, **kwargs)
368
+ if cache_key:
369
+ self._logger.debug(f"Recherche dans le cache avec la clé: {cache_key[:10]}...")
370
+ # Récupérer du cache ou calculer si nécessaire
371
+ explanation_data = self._get_cached_explanation(cache_key, instance, **kwargs)
372
+ if explanation_data and explanation_data.get('metadata', {}).get('from_cache', False):
373
+ self._logger.info(f"Explication trouvée dans le cache: {cache_key[:10]}...")
374
+ execution_metadata['from_cache'] = True
375
+
376
+ # 2. Si pas de cache ou non trouvée, calculer l'explication
377
+ if not use_cache or not explanation_data or 'error' in explanation_data:
378
+ explanation_data = self._compute_explanation_cached(instance, **kwargs)
379
+
380
+ # 3. Convertir le résultat au format ExplanationResult
381
+ if not explanation_data:
382
+ raise ValueError("Échec du calcul de l'explication, résultat vide")
383
+
384
+ if 'error' in explanation_data:
385
+ # Gérer les erreurs
386
+ error_msg = explanation_data.get('error', "Erreur inconnue lors de l'explication")
387
+ self._logger.error(f"Erreur lors de l'explication: {error_msg}")
388
+ raise ValueError(error_msg)
389
+
390
+ # 4. Extraire les informations pour créer l'ExplanationResult
391
+ # Recréer les objets FeatureImportance à partir des dictionnaires si nécessaire
392
+ feature_importances_data = explanation_data.get('feature_importances', [])
393
+ feature_importances = []
394
+
395
+ for fi_data in feature_importances_data:
396
+ if isinstance(fi_data, dict):
397
+ feature_importances.append(FeatureImportance(
398
+ feature_name=fi_data.get('feature_name', ""),
399
+ importance=fi_data.get('importance', 0.0),
400
+ local_value=fi_data.get('local_value')
401
+ ))
402
+ else:
403
+ feature_importances.append(fi_data) # Déjà un objet FeatureImportance
404
+
405
+ # Récupérer les règles d'ancrage et autres informations
406
+ anchor_rules = explanation_data.get('anchor_rules', [])
407
+ prediction = explanation_data.get('prediction')
408
+ narratives = explanation_data.get('narratives', {})
409
+
410
+ # Extraire la narrative appropriée selon le niveau d'audience et la langue
411
+ explanation_narrative = None
412
+ if language in narratives:
413
+ lang_narratives = narratives[language]
414
+ audience_key = audience_level.lower() if isinstance(audience_level, AudienceLevel) else str(audience_level).lower()
415
+
416
+ if audience_key in lang_narratives:
417
+ explanation_narrative = lang_narratives[audience_key]
418
+ elif 'technical' in lang_narratives: # Fallback sur technical
419
+ explanation_narrative = lang_narratives['technical']
420
+
421
+ # Préparer les métadonnées enrichies
422
+ metadata = {
423
+ 'data_type': data_type,
424
+ 'audience_level': str(audience_level),
425
+ 'language': language,
426
+ 'execution_time_ms': int((time.time() - start_time) * 1000)
427
+ }
428
+
429
+ # Ajouter les métriques d'ancrage aux métadonnées
430
+ if 'anchor_metrics' in explanation_data:
431
+ metadata.update(explanation_data['anchor_metrics'])
432
+
433
+ # Ajouter les métriques de qualité si disponibles
434
+ if 'quality_metrics' in explanation_data:
435
+ metadata['quality'] = explanation_data['quality_metrics']
436
+
437
+ # Ajouter les résultats de conformité si disponibles
438
+ if 'compliance' in explanation_data:
439
+ metadata['compliance'] = explanation_data['compliance']
440
+
441
+ # Ajouter les métadonnées d'exécution
442
+ metadata.update(execution_metadata)
443
+
444
+ # 5. Créer et retourner l'ExplanationResult final
445
+ result = ExplanationResult(
446
+ method=ExplainabilityMethod.ANCHOR,
447
+ feature_importances=feature_importances,
448
+ anchor_rules=anchor_rules,
449
+ metadata=metadata,
450
+ audience_level=audience_level,
451
+ explanation_narrative=explanation_narrative
452
+ )
453
+
454
+ return result
455
+
456
+ except Exception as e:
457
+ # Enregistrer l'erreur
458
+ self._logger.error(f"Erreur lors de l'explication Anchor: {str(e)}")
459
+ self._logger.debug(traceback.format_exc())
460
+
461
+ # Mettre à jour les métadonnées d'exécution avec l'erreur
462
+ execution_metadata['error'] = str(e)
463
+ execution_metadata['traceback'] = traceback.format_exc()
464
+ execution_metadata['execution_time_ms'] = int((time.time() - start_time) * 1000)
465
+
466
+ # Retourner un résultat d'erreur
467
+ return ExplanationResult(
468
+ method=ExplainabilityMethod.ANCHOR,
469
+ feature_importances=[],
470
+ metadata=execution_metadata,
471
+ audience_level=audience_level
472
+ )
473
+
474
+ def explain(self, X, y=None, **kwargs) -> ExplanationResult:
475
+ """
476
+ Génère des explications basées sur des règles d'ancrage pour un ensemble de données.
477
+ Pour les explications par ancrage, cette méthode sélectionne un échantillon
478
+ représentatif et génère des règles d'ancrage pour chaque instance.
479
+
480
+ Args:
481
+ X: Données d'entrée à expliquer
482
+ y: Valeurs cibles réelles (optionnel)
483
+ **kwargs: Paramètres additionnels
484
+ max_instances: Nombre maximum d'instances à expliquer
485
+ sampling_strategy: Stratégie d'échantillonnage ('random', 'stratified', 'kmeans')
486
+ data_type: Type de données ('tabular', 'text', 'image')
487
+
488
+ Returns:
489
+ ExplanationResult: Résultat standardisé de l'explication
490
+ """
491
+ # Paramètres
492
+ audience_level = kwargs.get('audience_level', AudienceLevel.TECHNICAL)
493
+ max_instances = kwargs.get('max_instances', 5)
494
+ sampling_strategy = kwargs.get('sampling_strategy', 'random')
495
+ data_type = kwargs.get('data_type', 'tabular')
496
+
497
+ # Conversion des données en format approprié
498
+ if isinstance(X, pd.DataFrame):
499
+ feature_names = X.columns.tolist()
500
+ X_values = X.values
501
+ else:
502
+ X_values = np.array(X)
503
+ feature_names = kwargs.get('feature_names', self._feature_names) or \
504
+ [f"feature_{i}" for i in range(X_values.shape[1])]
505
+
506
+ # Échantillonner des instances représentatives
507
+ sampled_indices = self._sample_instances(X_values, y, max_instances, sampling_strategy)
508
+ sampled_instances = X_values[sampled_indices]
509
+
510
+ # Tracer l'action
511
+ self.add_audit_record("explain", {
512
+ "n_samples": X_values.shape[0],
513
+ "n_features": X_values.shape[1],
514
+ "audience_level": audience_level.value if isinstance(audience_level, AudienceLevel) else audience_level,
515
+ "max_instances": max_instances,
516
+ "sampling_strategy": sampling_strategy,
517
+ "data_type": data_type
518
+ })
519
+
520
+ try:
521
+ # Générer des règles d'ancrage pour chaque instance échantillonnée
522
+ all_anchor_rules = []
523
+ all_anchor_metrics = []
524
+ all_feature_importances = []
525
+
526
+ for instance in sampled_instances:
527
+ # Utiliser explain_instance pour chaque instance
528
+ instance_result = self.explain_instance(
529
+ instance,
530
+ feature_names=feature_names,
531
+ audience_level=audience_level,
532
+ data_type=data_type,
533
+ **kwargs
534
+ )
535
+
536
+ # Collecter les résultats
537
+ all_anchor_rules.append(instance_result.raw_explanation["anchor_rules"])
538
+ all_anchor_metrics.append(instance_result.raw_explanation["anchor_metrics"])
539
+ all_feature_importances.append(instance_result.feature_importances)
540
+
541
+ # Agréger les importances de caractéristiques
542
+ aggregated_importances = self._aggregate_feature_importances(all_feature_importances, feature_names)
543
+
544
+ # Extraire les métadonnées du modèle
545
+ if not self._metadata:
546
+ self._extract_metadata()
547
+
548
+ # Créer le résultat d'explication
549
+ result = ExplanationResult(
550
+ method=ExplainabilityMethod.ANCHOR,
551
+ model_metadata=self._metadata,
552
+ feature_importances=aggregated_importances,
553
+ raw_explanation={
554
+ "sampled_instances": sampled_instances.tolist(),
555
+ "sampled_indices": sampled_indices.tolist(),
556
+ "all_anchor_rules": all_anchor_rules,
557
+ "all_anchor_metrics": all_anchor_metrics,
558
+ "feature_names": feature_names,
559
+ "data_type": data_type
560
+ },
561
+ audience_level=audience_level
562
+ )
563
+
564
+ return result
565
+
566
+ except Exception as e:
567
+ self._logger.error(f"Erreur lors de la génération des règles d'ancrage: {str(e)}")
568
+ raise RuntimeError(f"Échec de l'explication par ancrage: {str(e)}")
569
+
570
+ def _initialize_explainer(self, X, data_type='tabular'):
571
+ """
572
+ Initialise l'explainer Anchor selon le type de données.
573
+
574
+ Args:
575
+ X: Données d'entrée
576
+ data_type: Type de données ('tabular', 'text', 'image')
577
+ """
578
+ try:
579
+ import anchor
580
+ from anchor import anchor_tabular, anchor_text, anchor_image
581
+ except ImportError:
582
+ raise ImportError("Le package Anchor est requis pour cette méthode. "
583
+ "Installez-le avec 'pip install anchor-exp'.")
584
+
585
+ if data_type == 'tabular':
586
+ # Initialiser le discrétiseur si nécessaire
587
+ if self._discretize_continuous and self._discretizer is None:
588
+ self._discretizer = anchor_tabular.AnchorTabularExplainer.discretizer(
589
+ X,
590
+ self._categorical_features,
591
+ self._feature_names
592
+ )
593
+
594
+ # Créer l'explainer pour données tabulaires
595
+ self._explainer = anchor_tabular.AnchorTabularExplainer(
596
+ class_names=self._class_names,
597
+ feature_names=self._feature_names,
598
+ train_data=X,
599
+ categorical_names={i: [] for i in self._categorical_features},
600
+ discretizer=self._discretizer
601
+ )
602
+
603
+ elif data_type == 'text':
604
+ # Créer l'explainer pour données textuelles
605
+ self._explainer = anchor_text.AnchorText(
606
+ nlp=None, # Utiliser spaCy par défaut
607
+ class_names=self._class_names
608
+ )
609
+
610
+ elif data_type == 'image':
611
+ # Créer l'explainer pour images
612
+ self._explainer = anchor_image.AnchorImage(
613
+ class_names=self._class_names
614
+ )
615
+
616
+ else:
617
+ raise ValueError(f"Type de données non supporté: {data_type}")
618
+
619
+ # Définir la fonction de prédiction
620
+ self._explainer.predictor = self._get_prediction_function()
621
+
622
+ def _get_prediction_function(self):
623
+ """
624
+ Crée une fonction de prédiction pour l'explainer Anchor.
625
+
626
+ Returns:
627
+ function: Fonction de prédiction
628
+ """
629
+ # Déterminer le type de modèle
630
+ model_type = self._get_model_type()
631
+
632
+ # Créer une fonction de prédiction appropriée
633
+ def predict_fn(instances):
634
+ # Pour les modèles scikit-learn et similaires
635
+ if model_type in ['sklearn', 'xgboost', 'lightgbm', 'catboost']:
636
+ if hasattr(self._model, 'predict'):
637
+ return self._model.predict(instances)
638
+ else:
639
+ raise ValueError("Le modèle ne possède pas de méthode 'predict'.")
640
+
641
+ # Pour TensorFlow/Keras
642
+ elif model_type == 'tensorflow':
643
+ import tensorflow as tf
644
+ # Convertir en tensor si nécessaire
645
+ if not isinstance(instances, tf.Tensor):
646
+ instances = tf.convert_to_tensor(instances, dtype=tf.float32)
647
+ # Faire la prédiction
648
+ preds = self._model(instances)
649
+ # Convertir en classes si nécessaire
650
+ if len(preds.shape) > 1 and preds.shape[1] > 1:
651
+ return tf.argmax(preds, axis=1).numpy()
652
+ else:
653
+ return tf.round(preds).numpy()
654
+
655
+ # Pour PyTorch
656
+ elif model_type == 'pytorch':
657
+ import torch
658
+ # Mettre le modèle en mode évaluation
659
+ self._model.eval()
660
+ # Convertir en tensor si nécessaire
661
+ if not isinstance(instances, torch.Tensor):
662
+ instances = torch.tensor(instances, dtype=torch.float32)
663
+ # Désactiver le calcul de gradient
664
+ with torch.no_grad():
665
+ # Faire la prédiction
666
+ preds = self._model(instances)
667
+ # Convertir en classes
668
+ if preds.shape[1] > 1:
669
+ return torch.argmax(preds, dim=1).numpy()
670
+ else:
671
+ return torch.round(preds).numpy()
672
+
673
+ # Pour les autres types de modèles
674
+ else:
675
+ # Essayer d'appeler predict
676
+ if hasattr(self._model, 'predict'):
677
+ return self._model.predict(instances)
678
+ else:
679
+ # Essayer d'appeler le modèle directement
680
+ try:
681
+ return self._model(instances)
682
+ except:
683
+ raise ValueError("Impossible de faire des prédictions avec le modèle fourni.")
684
+
685
+ return predict_fn
686
+
687
+ def _explain_tabular_instance(self, instance, **kwargs):
688
+ """
689
+ Génère une explication pour une instance tabulaire.
690
+
691
+ Args:
692
+ instance: Instance à expliquer
693
+ **kwargs: Paramètres pour l'explainer Anchor
694
+
695
+ Returns:
696
+ object: Explication générée par Anchor
697
+ """
698
+ return self._explainer.explain_instance(
699
+ instance,
700
+ threshold=kwargs.get('threshold', 0.95),
701
+ tau=kwargs.get('tau', 0.15),
702
+ batch_size=kwargs.get('batch_size', 100),
703
+ coverage_samples=kwargs.get('coverage_samples', 10000),
704
+ beam_size=kwargs.get('beam_size', 5),
705
+ max_anchor_size=kwargs.get('max_anchor_size'),
706
+ stop_on_first=kwargs.get('stop_on_first', False),
707
+ binary_cache_size=kwargs.get('binary_cache_size', 10000),
708
+ cache_margin=kwargs.get('cache_margin', 1000),
709
+ verbose=kwargs.get('verbose', False),
710
+ verbose_every=kwargs.get('verbose_every', 1)
711
+ )
712
+
713
+ def _explain_text_instance(self, text, **kwargs):
714
+ """
715
+ Génère une explication pour une instance textuelle.
716
+
717
+ Args:
718
+ text: Texte à expliquer
719
+ **kwargs: Paramètres pour l'explainer Anchor
720
+
721
+ Returns:
722
+ object: Explication générée par Anchor
723
+ """
724
+ return self._explainer.explain_instance(
725
+ text,
726
+ threshold=kwargs.get('threshold', 0.95),
727
+ use_unk=kwargs.get('use_unk', True),
728
+ use_proba=kwargs.get('use_proba', False),
729
+ sample_proba=kwargs.get('sample_proba', 0.5),
730
+ top_n=kwargs.get('top_n', 100),
731
+ temperature=kwargs.get('temperature', 1.0),
732
+ beam_size=kwargs.get('beam_size', 5)
733
+ )
734
+
735
+ def _explain_image_instance(self, image, **kwargs):
736
+ """
737
+ Génère une explication pour une image.
738
+
739
+ Args:
740
+ image: Image à expliquer
741
+ **kwargs: Paramètres pour l'explainer Anchor
742
+
743
+ Returns:
744
+ object: Explication générée par Anchor
745
+ """
746
+ segmentation_fn = kwargs.get('segmentation_fn')
747
+ if segmentation_fn is None:
748
+ # Utiliser une segmentation par défaut si non fournie
749
+ try:
750
+ from skimage.segmentation import felzenszwalb
751
+ segmentation_fn = lambda x: felzenszwalb(x, scale=100, sigma=0.5, min_size=50)
752
+ except ImportError:
753
+ raise ImportError("scikit-image est requis pour la segmentation d'image. "
754
+ "Installez-le avec 'pip install scikit-image'.")
755
+
756
+ return self._explainer.explain_instance(
757
+ image,
758
+ segmentation_fn,
759
+ threshold=kwargs.get('threshold', 0.95),
760
+ p_sample=kwargs.get('p_sample', 0.5),
761
+ **{k: v for k, v in kwargs.items() if k not in ['threshold', 'p_sample', 'segmentation_fn']}
762
+ )
763
+
764
+ def _extract_anchor_rules(self, explanation, feature_names):
765
+ """
766
+ Extrait les règles d'ancrage à partir de l'explication.
767
+
768
+ Args:
769
+ explanation: Explication générée par Anchor
770
+ feature_names: Noms des caractéristiques
771
+
772
+ Returns:
773
+ list: Liste des règles d'ancrage
774
+ """
775
+ rules = []
776
+
777
+ # Pour les explications tabulaires
778
+ if hasattr(explanation, 'names'):
779
+ for rule in explanation.names():
780
+ rules.append(rule)
781
+ # Pour les explications textuelles
782
+ elif hasattr(explanation, 'exp_map'):
783
+ for pos in explanation.exp_map['names']:
784
+ rules.append(pos)
785
+ # Pour les explications d'images
786
+ elif hasattr(explanation, 'segments'):
787
+ rules = [f"segment_{i}" for i in explanation.segments()]
788
+ # Fallback
789
+ else:
790
+ try:
791
+ # Essayer d'extraire les règles directement
792
+ rules = explanation.names()
793
+ except:
794
+ self._logger.warning("Impossible d'extraire les règles d'ancrage. Format d'explication non reconnu.")
795
+ rules = []
796
+
797
+ return rules
798
+
799
+ def _extract_anchor_metrics(self, explanation):
800
+ """
801
+ Extrait les métriques de l'explication.
802
+
803
+ Args:
804
+ explanation: Explication générée par Anchor
805
+
806
+ Returns:
807
+ dict: Métriques de l'explication
808
+ """
809
+ metrics = {}
810
+
811
+ # Métriques communes
812
+ if hasattr(explanation, 'precision'):
813
+ metrics['precision'] = float(explanation.precision)
814
+ if hasattr(explanation, 'coverage'):
815
+ metrics['coverage'] = float(explanation.coverage)
816
+
817
+ # Métriques spécifiques aux données tabulaires
818
+ if hasattr(explanation, 'anchor'):
819
+ metrics['anchor_size'] = len(explanation.anchor)
820
+
821
+ # Métriques spécifiques aux textes
822
+ if hasattr(explanation, 'exp_map'):
823
+ if 'precision' in explanation.exp_map:
824
+ metrics['precision'] = float(explanation.exp_map['precision'])
825
+ if 'coverage' in explanation.exp_map:
826
+ metrics['coverage'] = float(explanation.exp_map['coverage'])
827
+
828
+ # Métriques spécifiques aux images
829
+ if hasattr(explanation, 'segments'):
830
+ metrics['num_segments'] = len(explanation.segments())
831
+
832
+ return metrics
833
+
834
+ def _convert_rules_to_importances(self, anchor_rules, feature_names):
835
+ """
836
+ Convertit les règles d'ancrage en importances de caractéristiques.
837
+
838
+ Args:
839
+ anchor_rules: Règles d'ancrage
840
+ feature_names: Noms des caractéristiques
841
+
842
+ Returns:
843
+ list: Liste d'objets FeatureImportance
844
+ """
845
+ importances = []
846
+ feature_counts = {}
847
+
848
+ # Compter les occurrences des caractéristiques dans les règles
849
+ for rule in anchor_rules:
850
+ # Extraire les noms des caractéristiques de la règle
851
+ for feature in feature_names:
852
+ if feature in rule:
853
+ feature_counts[feature] = feature_counts.get(feature, 0) + 1
854
+
855
+ # Convertir les comptages en importances
856
+ total_counts = sum(feature_counts.values()) if feature_counts else 1
857
+ for feature, count in feature_counts.items():
858
+ importances.append(FeatureImportance(
859
+ feature_name=feature,
860
+ importance=count / total_counts,
861
+ std=0.0, # Pas d'écart-type pour les règles d'ancrage
862
+ additional_info={
863
+ 'occurrence_count': count,
864
+ 'total_rules': len(anchor_rules)
865
+ }
866
+ ))
867
+
868
+ # Ajouter les caractéristiques non utilisées avec importance nulle
869
+ for feature in feature_names:
870
+ if feature not in feature_counts:
871
+ importances.append(FeatureImportance(
872
+ feature_name=feature,
873
+ importance=0.0,
874
+ std=0.0,
875
+ additional_info={
876
+ 'occurrence_count': 0,
877
+ 'total_rules': len(anchor_rules)
878
+ }
879
+ ))
880
+
881
+ # Trier par importance décroissante
882
+ importances.sort(key=lambda x: x.importance, reverse=True)
883
+
884
+ return importances
885
+
886
+ def _aggregate_feature_importances(self, all_importances, feature_names):
887
+ """
888
+ Agrège les importances de caractéristiques de plusieurs instances.
889
+
890
+ Args:
891
+ all_importances: Liste de listes d'objets FeatureImportance
892
+ feature_names: Noms des caractéristiques
893
+
894
+ Returns:
895
+ list: Liste agrégée d'objets FeatureImportance
896
+ """
897
+ # Initialiser un dictionnaire pour stocker les importances agrégées
898
+ aggregated = {feature: {'sum': 0.0, 'count': 0, 'values': []} for feature in feature_names}
899
+
900
+ # Collecter toutes les importances par caractéristique
901
+ for importances in all_importances:
902
+ for imp in importances:
903
+ feature = imp.feature_name
904
+ if feature in aggregated:
905
+ aggregated[feature]['sum'] += imp.importance
906
+ aggregated[feature]['count'] += 1
907
+ aggregated[feature]['values'].append(imp.importance)
908
+
909
+ # Calculer les importances moyennes et les écarts-types
910
+ result = []
911
+ for feature, data in aggregated.items():
912
+ if data['count'] > 0:
913
+ mean_importance = data['sum'] / data['count']
914
+ std_importance = np.std(data['values']) if len(data['values']) > 1 else 0.0
915
+
916
+ result.append(FeatureImportance(
917
+ feature_name=feature,
918
+ importance=mean_importance,
919
+ std=float(std_importance),
920
+ additional_info={
921
+ 'count': data['count'],
922
+ 'min': float(min(data['values'])) if data['values'] else 0.0,
923
+ 'max': float(max(data['values'])) if data['values'] else 0.0
924
+ }
925
+ ))
926
+ else:
927
+ # Caractéristique non utilisée
928
+ result.append(FeatureImportance(
929
+ feature_name=feature,
930
+ importance=0.0,
931
+ std=0.0,
932
+ additional_info={
933
+ 'count': 0,
934
+ 'min': 0.0,
935
+ 'max': 0.0
936
+ }
937
+ ))
938
+
939
+ # Trier par importance décroissante
940
+ result.sort(key=lambda x: x.importance, reverse=True)
941
+
942
+ return result
943
+
944
+ def _sample_instances(self, X, y=None, max_instances=5, strategy='random'):
945
+ """
946
+ Échantillonne des instances représentatives à partir des données.
947
+
948
+ Args:
949
+ X: Données d'entrée
950
+ y: Valeurs cibles réelles (optionnel)
951
+ max_instances: Nombre maximum d'instances à sélectionner
952
+ strategy: Stratégie d'échantillonnage ('random', 'stratified', 'kmeans')
953
+
954
+ Returns:
955
+ numpy.ndarray: Indices des instances sélectionnées
956
+ """
957
+ n_samples = X.shape[0]
958
+ max_instances = min(max_instances, n_samples)
959
+
960
+ if strategy == 'random':
961
+ # Échantillonnage aléatoire
962
+ indices = np.random.choice(n_samples, max_instances, replace=False)
963
+
964
+ elif strategy == 'stratified' and y is not None:
965
+ # Échantillonnage stratifié par classe
966
+ try:
967
+ from sklearn.model_selection import StratifiedShuffleSplit
968
+ except ImportError:
969
+ self._logger.warning("scikit-learn est requis pour l'échantillonnage stratifié. "
970
+ "Utilisation de l'échantillonnage aléatoire.")
971
+ return np.random.choice(n_samples, max_instances, replace=False)
972
+
973
+ sss = StratifiedShuffleSplit(n_splits=1, test_size=max_instances/n_samples, random_state=42)
974
+ for _, test_idx in sss.split(X, y):
975
+ indices = test_idx
976
+ if len(indices) > max_instances:
977
+ indices = indices[:max_instances]
978
+ break
979
+
980
+ elif strategy == 'kmeans':
981
+ # Échantillonnage basé sur le clustering k-means
982
+ try:
983
+ from sklearn.cluster import KMeans
984
+ from sklearn.preprocessing import StandardScaler
985
+ except ImportError:
986
+ self._logger.warning("scikit-learn est requis pour l'échantillonnage k-means. "
987
+ "Utilisation de l'échantillonnage aléatoire.")
988
+ return np.random.choice(n_samples, max_instances, replace=False)
989
+
990
+ # Normaliser les données
991
+ scaler = StandardScaler()
992
+ X_scaled = scaler.fit_transform(X)
993
+
994
+ # Appliquer k-means
995
+ kmeans = KMeans(n_clusters=max_instances, random_state=42, n_init=10)
996
+ clusters = kmeans.fit_predict(X_scaled)
997
+
998
+ # Sélectionner l'instance la plus proche de chaque centroide
999
+ indices = []
1000
+ for i in range(max_instances):
1001
+ cluster_points = np.where(clusters == i)[0]
1002
+ if len(cluster_points) > 0:
1003
+ # Trouver le point le plus proche du centroide
1004
+ centroid = kmeans.cluster_centers_[i]
1005
+ distances = np.linalg.norm(X_scaled[cluster_points] - centroid, axis=1)
1006
+ closest_idx = cluster_points[np.argmin(distances)]
1007
+ indices.append(closest_idx)
1008
+
1009
+ # Compléter si nécessaire
1010
+ if len(indices) < max_instances:
1011
+ remaining = np.setdiff1d(np.arange(n_samples), indices)
1012
+ additional = np.random.choice(remaining, max_instances - len(indices), replace=False)
1013
+ indices = np.concatenate([indices, additional])
1014
+ else:
1015
+ # Par défaut, échantillonnage aléatoire
1016
+ indices = np.random.choice(n_samples, max_instances, replace=False)
1017
+
1018
+ return indices
1019
+
1020
+ def _extract_metadata(self):
1021
+ """
1022
+ Extrait les métadonnées du modèle.
1023
+ """
1024
+ # Déterminer le type de modèle
1025
+ model_type = self._get_model_type()
1026
+
1027
+ # Déterminer le type de tâche (classification ou régression)
1028
+ task_type = self._get_task_type()
1029
+
1030
+ # Créer les métadonnées du modèle
1031
+ self._metadata = ModelMetadata(
1032
+ model_type=model_type,
1033
+ framework=model_type, # Utiliser le type comme framework pour simplifier
1034
+ task_type=task_type,
1035
+ feature_names=self._feature_names,
1036
+ target_names=self._class_names,
1037
+ model_parameters={
1038
+ 'categorical_features': self._categorical_features,
1039
+ 'discretize_continuous': self._discretize_continuous
1040
+ }
1041
+ )
1042
+
1043
+ def _get_model_type(self):
1044
+ """
1045
+ Détermine le type de modèle (framework).
1046
+
1047
+ Returns:
1048
+ str: Type de modèle (sklearn, tensorflow, pytorch, etc.)
1049
+ """
1050
+ model_module = self._model.__module__.split('.')[0].lower()
1051
+
1052
+ if model_module in ['sklearn', 'scikit']:
1053
+ return 'sklearn'
1054
+ elif model_module in ['tensorflow', 'tf', 'keras']:
1055
+ return 'tensorflow'
1056
+ elif model_module in ['torch', 'pytorch']:
1057
+ return 'pytorch'
1058
+ elif model_module in ['xgboost']:
1059
+ return 'xgboost'
1060
+ elif model_module in ['lightgbm']:
1061
+ return 'lightgbm'
1062
+ elif model_module in ['catboost']:
1063
+ return 'catboost'
1064
+ else:
1065
+ return 'unknown'
1066
+
1067
+ def _get_task_type(self):
1068
+ """
1069
+ Détermine le type de tâche (classification ou régression).
1070
+
1071
+ Returns:
1072
+ str: Type de tâche ('classification' ou 'regression')
1073
+ """
1074
+ # Vérifier les méthodes disponibles sur le modèle
1075
+ if hasattr(self._model, 'predict_proba'):
1076
+ return 'classification'
1077
+ elif hasattr(self._model, '_estimator_type'):
1078
+ return self._model._estimator_type
1079
+ else:
1080
+ # Par défaut, supposer que c'est une classification
1081
+ return 'classification'
1082
+
1083
+ def _get_cache_key(self, instance, **kwargs):
1084
+ """
1085
+ Génère une clé de cache unique pour une instance et des paramètres d'explication.
1086
+
1087
+ Args:
1088
+ instance: Instance à expliquer
1089
+ **kwargs: Paramètres d'explication
1090
+
1091
+ Returns:
1092
+ str: Clé de cache unique ou None si impossible de générer
1093
+ """
1094
+ try:
1095
+ # Convertir l'instance en structure serializable
1096
+ if isinstance(instance, pd.DataFrame):
1097
+ instance_data = instance.to_dict('records')
1098
+ elif isinstance(instance, pd.Series):
1099
+ instance_data = instance.to_dict()
1100
+ elif isinstance(instance, dict):
1101
+ instance_data = instance
1102
+ elif isinstance(instance, (list, np.ndarray)):
1103
+ instance_data = instance
1104
+ # Convertir les ndarray en listes
1105
+ if isinstance(instance_data, np.ndarray):
1106
+ instance_data = instance_data.tolist()
1107
+ else:
1108
+ self._logger.warning(f"Type d'instance non supporté pour le cache: {type(instance)}")
1109
+ return None
1110
+
1111
+ # Extraire les paramètres pertinents pour la clé de cache
1112
+ cache_params = {
1113
+ 'data_type': kwargs.get('data_type', 'tabular'),
1114
+ 'threshold': kwargs.get('threshold', self._config.threshold),
1115
+ 'tau': kwargs.get('tau', self._config.tau),
1116
+ 'max_anchor_size': kwargs.get('max_anchor_size', self._config.max_anchor_size),
1117
+ 'beam_size': kwargs.get('beam_size', self._config.beam_size),
1118
+ }
1119
+
1120
+ # Créer une chaîne unique pour l'instance et les paramètres
1121
+ cache_data = {
1122
+ 'instance': instance_data,
1123
+ 'params': cache_params
1124
+ }
1125
+
1126
+ # Générer un hash SHA-256 comme clé de cache
1127
+ cache_key = hashlib.sha256(json.dumps(cache_data, sort_keys=True).encode()).hexdigest()
1128
+
1129
+ return cache_key
1130
+
1131
+ except Exception as e:
1132
+ self._logger.warning(f"Erreur lors de la génération de la clé de cache: {str(e)}")
1133
+ return None
1134
+
1135
+ @lru_cache(maxsize=128)
1136
+ def _compute_explanation(self, instance_hash, instance_serialized, **kwargs):
1137
+ """
1138
+ Calcule l'explication pour une instance avec gestion du cache LRU.
1139
+ Cette méthode est décorée avec lru_cache pour mémoriser les résultats.
1140
+
1141
+ Args:
1142
+ instance_hash: Hash de l'instance (pour le cache)
1143
+ instance_serialized: Représentation sérialisée de l'instance
1144
+ **kwargs: Paramètres d'explication
1145
+
1146
+ Returns:
1147
+ dict: Résultat d'explication
1148
+ """
1149
+ # Désérialiser l'instance
1150
+ instance = json.loads(instance_serialized)
1151
+
1152
+ # Convertir en format approprié selon le type de données
1153
+ data_type = kwargs.get('data_type', 'tabular')
1154
+
1155
+ if data_type == 'tabular':
1156
+ # Reconvertir en array numpy
1157
+ instance_array = np.array(instance)
1158
+ elif data_type == 'text':
1159
+ # String pour texte
1160
+ instance_array = instance
1161
+ elif data_type == 'image':
1162
+ # Reconvertir en array numpy pour image
1163
+ instance_array = np.array(instance)
1164
+ else:
1165
+ raise ValueError(f"Type de données non supporté: {data_type}")
1166
+
1167
+ # Calculer l'explication via la méthode adéquate selon le type de données
1168
+ # Déléguer à la méthode complète
1169
+ return self._compute_explanation_cached(instance_array, **kwargs)
1170
+
1171
+ def _get_cached_explanation(self, cache_key, instance, **kwargs):
1172
+ """
1173
+ Récupère une explication du cache ou la calcule si nécessaire.
1174
+
1175
+ Args:
1176
+ cache_key: Clé de cache
1177
+ instance: Instance à expliquer
1178
+ **kwargs: Paramètres d'explication
1179
+
1180
+ Returns:
1181
+ dict: Résultat d'explication
1182
+ """
1183
+ try:
1184
+ # Sérialiser l'instance pour le cache
1185
+ if isinstance(instance, pd.DataFrame):
1186
+ serialized_instance = json.dumps(instance.to_dict('records')[0])
1187
+ elif isinstance(instance, pd.Series):
1188
+ serialized_instance = json.dumps(instance.to_dict())
1189
+ elif isinstance(instance, dict):
1190
+ serialized_instance = json.dumps(instance)
1191
+ elif isinstance(instance, (list, np.ndarray)):
1192
+ if isinstance(instance, np.ndarray):
1193
+ serialized_instance = json.dumps(instance.tolist())
1194
+ else:
1195
+ serialized_instance = json.dumps(instance)
1196
+ else:
1197
+ raise ValueError(f"Type d'instance non supporté pour le cache: {type(instance)}")
1198
+
1199
+ # Appeler la méthode cachée
1200
+ explanation = self._compute_explanation(cache_key, serialized_instance, **kwargs)
1201
+
1202
+ # Marquer comme provenant du cache
1203
+ if explanation and 'metadata' in explanation:
1204
+ explanation['metadata']['from_cache'] = True
1205
+
1206
+ return explanation
1207
+
1208
+ except Exception as e:
1209
+ self._logger.warning(f"Erreur lors de la récupération du cache: {str(e)}")
1210
+ # En cas d'erreur, calculer directement
1211
+ return self._compute_explanation_cached(instance, **kwargs)
1212
+
1213
+ def _compute_explanation_quality_metrics(self, anchor_rules, explanation=None, instance=None, prediction=None):
1214
+ """
1215
+ Calcule les métriques de qualité de l'explication par ancrage.
1216
+
1217
+ Args:
1218
+ anchor_rules: Règles d'ancrage générées
1219
+ explanation: Objet d'explication original (optionnel)
1220
+ instance: Instance expliquée (optionnel)
1221
+ prediction: Prédiction du modèle (optionnel)
1222
+
1223
+ Returns:
1224
+ dict: Métriques de qualité de l'explication
1225
+ """
1226
+ metrics = {}
1227
+
1228
+ try:
1229
+ # 1. Précision de l'ancrage (directement depuis l'objet explanation)
1230
+ if explanation and hasattr(explanation, 'precision'):
1231
+ metrics['precision'] = float(explanation.precision)
1232
+ else:
1233
+ metrics['precision'] = None
1234
+
1235
+ # 2. Couverture de l'ancrage (directement depuis l'objet explanation)
1236
+ if explanation and hasattr(explanation, 'coverage'):
1237
+ metrics['coverage'] = float(explanation.coverage)
1238
+ else:
1239
+ metrics['coverage'] = None
1240
+
1241
+ # 3. Nombre de conditions dans la règle d'ancrage
1242
+ metrics['rule_length'] = len(anchor_rules) if anchor_rules else 0
1243
+
1244
+ # 4. Score de complexité de la règle (bas = simple, haut = complexe)
1245
+ # Normalisé par le nombre de caractéristiques disponibles
1246
+ n_features = len(self._feature_names) if self._feature_names else 1
1247
+ metrics['complexity_score'] = metrics['rule_length'] / n_features if n_features > 0 else 0
1248
+
1249
+ # 5. Stabilité de l'explication (indice de Jaccard moyen pour des petites perturbations)
1250
+ # Pour Anchor, nous utilisons la métrique de stabilité approximative basée sur la précision
1251
+ metrics['stability_score'] = float(metrics['precision']) if metrics['precision'] is not None else None
1252
+
1253
+ # 6. Score global de qualité (moyenne pondérée des scores individuels)
1254
+ # Combiner précision, couverture et inverse de la complexité
1255
+ quality_components = []
1256
+ weights = [0.5, 0.3, 0.2] # Pondération: précision, couverture, simplicité
1257
+
1258
+ if metrics['precision'] is not None:
1259
+ quality_components.append(metrics['precision'] * weights[0])
1260
+ if metrics['coverage'] is not None:
1261
+ quality_components.append(metrics['coverage'] * weights[1])
1262
+ if metrics['complexity_score'] is not None:
1263
+ # Inverser la complexité (plus simple = meilleur score)
1264
+ simplicity = 1.0 - min(1.0, metrics['complexity_score'])
1265
+ quality_components.append(simplicity * weights[2])
1266
+
1267
+ if quality_components:
1268
+ # Normaliser par la somme des poids utilisés
1269
+ used_weights = weights[:len(quality_components)]
1270
+ metrics['quality_score'] = sum(quality_components) / sum(used_weights)
1271
+ else:
1272
+ metrics['quality_score'] = None
1273
+
1274
+ except Exception as e:
1275
+ self._logger.warning(f"Erreur lors du calcul des métriques de qualité: {str(e)}")
1276
+ self._logger.debug(traceback.format_exc())
1277
+
1278
+ return metrics
1279
+
1280
+ def _get_cache_key(self, instance, **kwargs):
1281
+ """
1282
+ Génère une clé de cache unique pour l'instance et les paramètres.
1283
+
1284
+ Args:
1285
+ instance: Instance à expliquer
1286
+ **kwargs: Paramètres d'explication
1287
+
1288
+ Returns:
1289
+ str: Clé de cache unique (hash MD5)
1290
+ """
1291
+ try:
1292
+ # Extraire les paramètres qui affectent le résultat de l'explication
1293
+ cache_key_params = {
1294
+ 'data_type': kwargs.get('data_type', 'tabular'),
1295
+ 'threshold': kwargs.get('threshold', self._config.threshold),
1296
+ 'tau': kwargs.get('tau', self._config.tau),
1297
+ 'beam_size': kwargs.get('beam_size', self._config.beam_size),
1298
+ 'max_anchor_size': kwargs.get('max_anchor_size', self._config.max_anchor_size),
1299
+ 'stop_on_first': kwargs.get('stop_on_first', self._config.stop_on_first),
1300
+ 'audience_level': str(kwargs.get('audience_level', AudienceLevel.TECHNICAL)),
1301
+ 'language': kwargs.get('language', 'en'),
1302
+ }
1303
+
1304
+ # Sérialiser l'instance selon son type
1305
+ instance_str = self._serialize_instance(instance)
1306
+
1307
+ # Créer un dictionnaire complet pour le hachage
1308
+ hash_dict = {
1309
+ 'instance': instance_str,
1310
+ 'params': cache_key_params,
1311
+ 'model_id': id(self._model), # Ajouter l'ID du modèle pour éviter les collisions entre différents modèles
1312
+ }
1313
+
1314
+ # Générer la clé de cache (hash MD5)
1315
+ hash_str = json.dumps(hash_dict, sort_keys=True)
1316
+ return hashlib.md5(hash_str.encode('utf-8')).hexdigest()
1317
+
1318
+ except Exception as e:
1319
+ self._logger.warning(f"Erreur lors de la génération de la clé de cache: {str(e)}")
1320
+ return None
1321
+
1322
+ def _serialize_instance(self, instance):
1323
+ """
1324
+ Sérialise une instance pour le hachage du cache.
1325
+
1326
+ Args:
1327
+ instance: Instance à sérialiser
1328
+
1329
+ Returns:
1330
+ str: Représentation sérialisée de l'instance
1331
+ """
1332
+ try:
1333
+ if isinstance(instance, np.ndarray):
1334
+ return instance.tolist()
1335
+ elif isinstance(instance, pd.DataFrame) or isinstance(instance, pd.Series):
1336
+ return instance.to_dict()
1337
+ elif isinstance(instance, (list, dict, str, int, float, bool)):
1338
+ return instance
1339
+ else:
1340
+ return str(instance)
1341
+ except Exception as e:
1342
+ self._logger.warning(f"Erreur lors de la sérialisation de l'instance: {str(e)}")
1343
+ return str(instance)
1344
+
1345
+ def reset_cache(self):
1346
+ """
1347
+ Réinitialise le cache des explications.
1348
+ Utile lorsque le modèle est mis à jour ou lorsqu'on veut forcer
1349
+ le recalcul des explications.
1350
+ """
1351
+ try:
1352
+ self._logger.info("Réinitialisation du cache des explications")
1353
+ self._get_cached_explanation.cache_clear()
1354
+ return {"status": "success", "message": "Cache réinitialisé avec succès"}
1355
+ except Exception as e:
1356
+ self._logger.error(f"Erreur lors de la réinitialisation du cache: {str(e)}")
1357
+ return {"status": "error", "message": f"Erreur lors de la réinitialisation du cache: {str(e)}"}
1358
+
1359
+ @lru_cache(maxsize=128)
1360
+ def _get_cached_explanation(self, cache_key, instance, **kwargs):
1361
+ """
1362
+ Récupère ou calcule une explication avec cache LRU.
1363
+ Cette méthode est décorée avec lru_cache pour mémoriser les explications précédemment calculées.
1364
+
1365
+ Args:
1366
+ cache_key: Clé unique pour l'instance et les paramètres
1367
+ instance: Instance à expliquer
1368
+ **kwargs: Paramètres d'explication
1369
+
1370
+ Returns:
1371
+ dict: Résultat d'explication
1372
+ """
1373
+ try:
1374
+ # Décorer cette méthode avec lru_cache permet de mettre automatiquement en cache
1375
+ # les résultats selon la clé fournie. Si la même clé est utilisée à nouveau,
1376
+ # le résultat en cache est retourné sans recalcul.
1377
+
1378
+ # Calculer l'explication
1379
+ explanation = self._compute_explanation_cached(instance, **kwargs)
1380
+
1381
+ # Marquer comme provenant du cache
1382
+ if explanation and 'metadata' in explanation:
1383
+ explanation['metadata']['from_cache'] = True
1384
+
1385
+ return explanation
1386
+
1387
+ except Exception as e:
1388
+ self._logger.error(f"Erreur lors de la récupération du cache: {str(e)}")
1389
+ return {"error": f"Erreur de cache: {str(e)}"}
1390
+
1391
+ def _extract_model_type(self):
1392
+ """
1393
+ Extrait le type de modèle/framework utilisé (scikit-learn, TensorFlow, PyTorch, etc.)
1394
+
1395
+ Returns:
1396
+ str: Type de framework détecté
1397
+ """
1398
+ module_name = self._model.__class__.__module__.split('.')[0].lower()
1399
+
1400
+ if module_name in ('sklearn', 'lightgbm', 'xgboost'):
1401
+ return module_name
1402
+ elif module_name == 'keras' or 'tensorflow' in module_name:
1403
+ return 'tensorflow'
1404
+ elif 'torch' in module_name:
1405
+ return 'pytorch'
1406
+ else:
1407
+ return 'unknown'
1408
+
1409
+ def _generate_explanation_narrative(self, anchor_rules, feature_importances, prediction=None, audience_level=AudienceLevel.TECHNICAL, language='en'):
1410
+ """
1411
+ Génère une narrative d'explication adaptée à l'audience et à la langue.
1412
+
1413
+ Args:
1414
+ anchor_rules: Règles d'ancrage générées
1415
+ feature_importances: Importances des caractéristiques
1416
+ prediction: Prédiction du modèle (optionnel)
1417
+ audience_level: Niveau d'audience (technique, business, public)
1418
+ language: Code de langue ('en', 'fr', etc.)
1419
+
1420
+ Returns:
1421
+ dict: Narratives d'explication par niveau d'audience et langue
1422
+ """
1423
+ narratives = {}
1424
+
1425
+ try:
1426
+ # Définir les templates par niveau d'audience et langue
1427
+ templates = {
1428
+ 'en': {
1429
+ 'technical': {
1430
+ 'intro': "The model's prediction is explained by the following anchor rule conditions:",
1431
+ 'rule': "The model predicts '{prediction}' when {conditions}.",
1432
+ 'precision': "This rule has {precision:.0%} precision, meaning the prediction is consistent {precision:.0%} of the time when these conditions are met.",
1433
+ 'coverage': "The rule covers {coverage:.0%} of instances similar to this one.",
1434
+ 'outro': "The model relies primarily on {top_features_str} for this prediction."
1435
+ },
1436
+ 'business': {
1437
+ 'intro': "The prediction for this case is based on the following key factors:",
1438
+ 'rule': "When {conditions_simple}, our model predicts '{prediction}'.",
1439
+ 'reliability': "This explanation is reliable in {precision:.0%} of similar cases.",
1440
+ 'outro': "The most influential factors were: {top_features_simple}."
1441
+ },
1442
+ 'public': {
1443
+ 'intro': "Here's why this decision was made:",
1444
+ 'rule': "The system predicted '{prediction}' because {conditions_very_simple}.",
1445
+ 'outro': "The main factors affecting this decision were: {top_features_very_simple}."
1446
+ }
1447
+ },
1448
+ 'fr': {
1449
+ 'technical': {
1450
+ 'intro': "La prédiction du modèle est expliquée par les conditions d'ancrage suivantes :",
1451
+ 'rule': "Le modèle prédit '{prediction}' lorsque {conditions}.",
1452
+ 'precision': "Cette règle a une précision de {precision:.0%}, ce qui signifie que la prédiction est cohérente dans {precision:.0%} des cas où ces conditions sont respectées.",
1453
+ 'coverage': "La règle couvre {coverage:.0%} des instances similaires à celle-ci.",
1454
+ 'outro': "Le modèle s'appuie principalement sur {top_features_str} pour cette prédiction."
1455
+ },
1456
+ 'business': {
1457
+ 'intro': "La prédiction pour ce cas est basée sur les facteurs clés suivants :",
1458
+ 'rule': "Lorsque {conditions_simple}, notre modèle prédit '{prediction}'.",
1459
+ 'reliability': "Cette explication est fiable dans {precision:.0%} des cas similaires.",
1460
+ 'outro': "Les facteurs les plus influents étaient : {top_features_simple}."
1461
+ },
1462
+ 'public': {
1463
+ 'intro': "Voici pourquoi cette décision a été prise :",
1464
+ 'rule': "Le système a prédit '{prediction}' parce que {conditions_very_simple}.",
1465
+ 'outro': "Les principaux facteurs affectant cette décision étaient : {top_features_very_simple}."
1466
+ }
1467
+ }
1468
+ }
1469
+
1470
+ # S'assurer que la langue est supportée, sinon utiliser l'anglais
1471
+ if language not in templates:
1472
+ language = 'en'
1473
+
1474
+ # Préparer les éléments pour les narratives
1475
+ precision = 0.0
1476
+ coverage = 0.0
1477
+ prediction_str = str(prediction) if prediction is not None else "unknown"
1478
+
1479
+ # Extraire métriques de l'ancrage si disponibles
1480
+ if hasattr(anchor_rules, 'precision'):
1481
+ precision = float(anchor_rules.precision)
1482
+ if hasattr(anchor_rules, 'coverage'):
1483
+ coverage = float(anchor_rules.coverage)
1484
+
1485
+ # Extraire les règles d'ancrage en texte
1486
+ conditions_text = "no specific conditions found"
1487
+ if isinstance(anchor_rules, list) and anchor_rules:
1488
+ conditions_text = " AND ".join(anchor_rules)
1489
+ elif hasattr(anchor_rules, 'names') and anchor_rules.names:
1490
+ conditions_text = " AND ".join(anchor_rules.names)
1491
+
1492
+ # Simplifier les conditions pour les audiences non techniques
1493
+ conditions_simple = conditions_text.replace(' AND ', ' et ') # Version plus simple
1494
+ conditions_very_simple = conditions_text.replace(' AND ', ' et ')
1495
+ if len(conditions_very_simple.split(' et ')) > 2:
1496
+ # Limiter à 2 conditions max pour le public
1497
+ parts = conditions_very_simple.split(' et ')
1498
+ conditions_very_simple = ' et '.join(parts[:2]) + f" et {len(parts)-2} autres facteurs"
1499
+
1500
+ # Extraire les principales caractéristiques
1501
+ top_features = []
1502
+ if feature_importances:
1503
+ # Trier par importance décroissante et prendre les 3 premières
1504
+ sorted_features = sorted(feature_importances, key=lambda x: abs(x.importance), reverse=True)
1505
+ top_features = sorted_features[:3]
1506
+
1507
+ # Formater les noms des caractéristiques principales
1508
+ top_features_str = ", ".join([f"{feature.feature_name} ({feature.importance:.2f})" for feature in top_features]) if top_features else "aucune caractéristique identifiée"
1509
+ top_features_simple = ", ".join([feature.feature_name for feature in top_features]) if top_features else "aucun facteur identifié"
1510
+ top_features_very_simple = top_features_simple
1511
+
1512
+ # Construire la narrative pour chaque niveau d'audience
1513
+ for audience in ['technical', 'business', 'public']:
1514
+ if audience == audience_level.lower() or audience_level == AudienceLevel.ALL:
1515
+ template = templates[language][audience]
1516
+ narrative_parts = []
1517
+
1518
+ # Construction de la narrative selon le niveau d'audience
1519
+ if audience == 'technical':
1520
+ narrative_parts.append(template['intro'])
1521
+ narrative_parts.append(template['rule'].format(
1522
+ prediction=prediction_str,
1523
+ conditions=conditions_text
1524
+ ))
1525
+ narrative_parts.append(template['precision'].format(precision=precision))
1526
+ narrative_parts.append(template['coverage'].format(coverage=coverage))
1527
+ narrative_parts.append(template['outro'].format(top_features_str=top_features_str))
1528
+ elif audience == 'business':
1529
+ narrative_parts.append(template['intro'])
1530
+ narrative_parts.append(template['rule'].format(
1531
+ prediction=prediction_str,
1532
+ conditions_simple=conditions_simple
1533
+ ))
1534
+ narrative_parts.append(template['reliability'].format(precision=precision))
1535
+ narrative_parts.append(template['outro'].format(top_features_simple=top_features_simple))
1536
+ else: # public
1537
+ narrative_parts.append(template['intro'])
1538
+ narrative_parts.append(template['rule'].format(
1539
+ prediction=prediction_str,
1540
+ conditions_very_simple=conditions_very_simple
1541
+ ))
1542
+ narrative_parts.append(template['outro'].format(top_features_very_simple=top_features_very_simple))
1543
+
1544
+ narratives[audience] = " ".join(narrative_parts)
1545
+
1546
+ except Exception as e:
1547
+ self._logger.warning(f"Erreur lors de la génération de narratives d'explication: {str(e)}")
1548
+ narratives['error'] = f"Unable to generate explanation narrative: {str(e)}"
1549
+
1550
+ return narratives
1551
+
1552
+ def _compute_explanation_cached(self, instance, **kwargs):
1553
+ """
1554
+ Méthode centrale pour calculer l'explication avec toutes les fonctionnalités avancées.
1555
+ Cette méthode intègre la gestion du GPU, le calcul des métriques de qualité,
1556
+ la génération de narratives multilingues et la vérification de conformité.
1557
+
1558
+ Args:
1559
+ instance: Instance à expliquer
1560
+ **kwargs: Paramètres d'explication
1561
+ data_type: Type de données ('tabular', 'text', 'image')
1562
+ threshold: Seuil de précision pour l'ancrage
1563
+
1564
+ # Créer un résultat d'erreur
1565
+ result = ExplanationResult(
1566
+ method=ExplainabilityMethod.ANCHOR,
1567
+ feature_importances=[],
1568
+ metadata={
1569
+ 'error': error_msg,
1570
+ 'execution_time_ms': int((time.time() - start_time) * 1000)
1571
+ },
1572
+ audience_level=audience_level
1573
+ )
1574
+ else:
1575
+ # Extraire les informations importantes du résultat calculé
1576
+ feature_importances_data = explanation_data.get('feature_importances', [])
1577
+ feature_importances = []
1578
+ use_unk=kwargs.get('use_unk', True),
1579
+ use_uppercase_unk=kwargs.get('use_uppercase_unk', True),
1580
+ sample_proba=kwargs.get('sample_proba', 0.5),
1581
+ top_n=kwargs.get('top_n', 100),
1582
+ temperature=kwargs.get('temperature', 1.0))
1583
+
1584
+ elif data_type == 'image':
1585
+ # Pour les images
1586
+ anchor_explanation = self._explain_image_instance(instance_array,
1587
+ threshold=threshold,
1588
+ segmentation_fn=kwargs.get('segmentation_fn', None),
1589
+ p_sample=kwargs.get('p_sample', 0.5),
1590
+ n_segments=kwargs.get('n_segments', 10))
1591
+
1592
+ # 3. Vérifier que l'explication a été générée avec succès
1593
+ if anchor_explanation is None:
1594
+ raise ValueError("L'explication Anchor n'a pas pu être générée")
1595
+
1596
+ # 4. Obtenir une prédiction du modèle pour l'instance
1597
+ try:
1598
+ if hasattr(self._model, 'predict_proba') and self._get_task_type() == 'classification':
1599
+ prediction = self._model.predict_proba(instance_array)[0]
1600
+ predicted_class = np.argmax(prediction)
1601
+ if self._class_names and predicted_class < len(self._class_names):
1602
+ prediction_label = self._class_names[predicted_class]
1603
+ else:
1604
+ prediction_label = str(predicted_class)
1605
+ else:
1606
+ prediction = self._model.predict(instance_array)[0]
1607
+ prediction_label = str(prediction)
1608
+ except Exception as pred_err:
1609
+ self._logger.warning(f"Erreur lors de la prédiction: {str(pred_err)}")
1610
+ prediction = None
1611
+ prediction_label = "unknown"
1612
+
1613
+ # 5. Extraire les règles d'ancrage
1614
+ feature_names = kwargs.get('feature_names', self._feature_names)
1615
+ anchor_rules = self._extract_anchor_rules(anchor_explanation, feature_names)
1616
+
1617
+ # 6. Convertir les règles en importances de caractéristiques
1618
+ feature_importances = self._convert_rules_to_importances(anchor_rules, feature_names)
1619
+
1620
+ # 7. Calculer les métriques de qualité de l'explication
1621
+ quality_metrics = {}
1622
+ if self._config.compute_quality_metrics:
1623
+ quality_metrics = self._compute_explanation_quality_metrics(
1624
+ anchor_rules=anchor_rules,
1625
+ explanation=anchor_explanation,
1626
+ instance=instance,
1627
+ prediction=prediction
1628
+ )
1629
+
1630
+ # 8. Générer les narratives d'explication
1631
+ narratives = {}
1632
+ narratives[language] = self._generate_explanation_narrative(
1633
+ anchor_rules=anchor_explanation,
1634
+ feature_importances=feature_importances,
1635
+ prediction=prediction_label,
1636
+ audience_level=audience_level,
1637
+ language=language
1638
+ )
1639
+
1640
+ # 9. Construire le résultat d'explication
1641
+ result = {
1642
+ "method": "anchor",
1643
+ "feature_importances": [fi.__dict__ for fi in feature_importances],
1644
+ "anchor_rules": anchor_rules,
1645
+ "anchor_metrics": {
1646
+ "precision": float(anchor_explanation.precision) if hasattr(anchor_explanation, 'precision') else None,
1647
+ "coverage": float(anchor_explanation.coverage) if hasattr(anchor_explanation, 'coverage') else None,
1648
+ },
1649
+ "prediction": prediction_label,
1650
+ "quality_metrics": quality_metrics,
1651
+ "narratives": narratives,
1652
+ "metadata": execution_metadata
1653
+ }
1654
+
1655
+ # 10. Vérifier la conformité réglementaire si demandé
1656
+ if self._config.verify_compliance:
1657
+ compliance_result = self._verify_compliance_requirements(result, instance)
1658
+ result["compliance"] = compliance_result
1659
+
1660
+ # Marquer comme réussi
1661
+ execution_metadata['success'] = True
1662
+
1663
+ except Exception as e:
1664
+ # En cas d'erreur, enregistrer les détails
1665
+ self._logger.error(f"Erreur lors du calcul de l'explication: {str(e)}")
1666
+ self._logger.debug(traceback.format_exc())
1667
+
1668
+ # Retourner un résultat minimal avec l'erreur
1669
+ result = {
1670
+ "method": "anchor",
1671
+ "error": str(e),
1672
+ "traceback": traceback.format_exc(),
1673
+ "metadata": execution_metadata
1674
+ }
1675
+
1676
+ finally:
1677
+ # Calculer le temps d'exécution
1678
+ execution_time_ms = int((time.time() - start_time) * 1000)
1679
+ execution_metadata['execution_time_ms'] = execution_time_ms
1680
+ result["metadata"] = execution_metadata
1681
+
1682
+ # Tracer les métriques d'exécution
1683
+ self._logger.info(f"Explication Anchor calculée en {execution_time_ms}ms (succès: {execution_metadata['success']})")
1684
+
1685
+ # Collecter des statistiques d'utilisation de mémoire/GPU si disponible
1686
+ try:
1687
+ import psutil
1688
+ memory_info = psutil.Process().memory_info()
1689
+ execution_metadata['memory_rss_bytes'] = memory_info.rss
1690
+ execution_metadata['memory_vms_bytes'] = memory_info.vms
1691
+
1692
+ # Statistiques GPU si disponible
1693
+ if use_gpu:
1694
+ if self._framework == 'tensorflow':
1695
+ try:
1696
+ import tensorflow as tf
1697
+ if tf.config.list_physical_devices('GPU'):
1698
+ gpu_stats = tf.config.experimental.get_memory_info('GPU:0')
1699
+ execution_metadata['gpu_memory_bytes'] = gpu_stats['current']
1700
+ except:
1701
+ pass
1702
+ elif self._framework == 'pytorch':
1703
+ try:
1704
+ import torch
1705
+ if torch.cuda.is_available():
1706
+ execution_metadata['gpu_memory_bytes'] = torch.cuda.memory_allocated()
1707
+ execution_metadata['gpu_max_memory_bytes'] = torch.cuda.max_memory_allocated()
1708
+ except:
1709
+ pass
1710
+ except ImportError:
1711
+ pass # psutil non disponible
1712
+ except Exception as mem_err:
1713
+ self._logger.debug(f"Erreur lors de la collecte des métriques de mémoire: {str(mem_err)}")
1714
+
1715
+ return result
1716
+
1717
+ def _verify_compliance_requirements(self, explanation_data, instance):
1718
+ """
1719
+ Vérifie la conformité réglementaire de l'explication générée.
1720
+
1721
+ Args:
1722
+ explanation_data: Données d'explication générées
1723
+ instance: Instance expliquée
1724
+
1725
+ Returns:
1726
+ dict: Résultat de la vérification de conformité
1727
+ """
1728
+ if not self._compliance_checker:
1729
+ return {"status": "skip", "reason": "Aucun vérificateur de conformité disponible"}
1730
+
1731
+ try:
1732
+ # Extraire les éléments pertinents pour la vérification
1733
+ check_data = {
1734
+ "explainer_type": "AnchorExplainer",
1735
+ "feature_importances": explanation_data.get("feature_importances", []),
1736
+ "anchor_rules": explanation_data.get("anchor_rules", []),
1737
+ "anchor_metrics": explanation_data.get("anchor_metrics", {}),
1738
+ "instance": instance,
1739
+ "metadata": explanation_data.get("metadata", {})
1740
+ }
1741
+
1742
+ # Vérifier la conformité
1743
+ compliance_result = self._compliance_checker.check_explanation(check_data)
1744
+
1745
+ # Enregistrer un audit de conformité
1746
+ try:
1747
+ from ..audit import AuditLogger
1748
+ audit_logger = AuditLogger()
1749
+ audit_logger.log_compliance_check(
1750
+ explainer_type="AnchorExplainer",
1751
+ status=compliance_result.get("status", "unknown"),
1752
+ requirements=compliance_result.get("requirements", {}),
1753
+ details=compliance_result
1754
+ )
1755
+ except ImportError:
1756
+ self._logger.debug("Module d'audit non disponible")
1757
+ except Exception as audit_err:
1758
+ self._logger.debug(f"Erreur lors de l'audit de conformité: {str(audit_err)}")
1759
+
1760
+ return compliance_result
1761
+
1762
+ except Exception as e:
1763
+ error_result = {
1764
+ "status": "error",
1765
+ "reason": f"Erreur lors de la vérification de conformité: {str(e)}",
1766
+ "details": traceback.format_exc()
1767
+ }
1768
+ self._logger.warning(f"Erreur lors de la vérification de conformité: {str(e)}")
1769
+ return error_result