ansible-core 2.18.5rc1__py3-none-any.whl → 2.19.0b2__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 (710) hide show
  1. ansible/_internal/__init__.py +53 -0
  2. ansible/_internal/_ansiballz.py +265 -0
  3. ansible/_internal/_collection_proxy.py +47 -0
  4. ansible/_internal/_datatag/__init__.py +0 -0
  5. ansible/_internal/_datatag/_tags.py +130 -0
  6. ansible/_internal/_datatag/_utils.py +19 -0
  7. ansible/_internal/_datatag/_wrappers.py +33 -0
  8. ansible/_internal/_errors/__init__.py +0 -0
  9. ansible/_internal/_errors/_captured.py +128 -0
  10. ansible/_internal/_errors/_handler.py +91 -0
  11. ansible/_internal/_errors/_utils.py +310 -0
  12. ansible/_internal/_json/__init__.py +203 -0
  13. ansible/_internal/_json/_legacy_encoder.py +34 -0
  14. ansible/_internal/_json/_profiles/__init__.py +0 -0
  15. ansible/_internal/_json/_profiles/_cache_persistence.py +55 -0
  16. ansible/_internal/_json/_profiles/_inventory_legacy.py +40 -0
  17. ansible/_internal/_json/_profiles/_legacy.py +197 -0
  18. ansible/_internal/_locking.py +21 -0
  19. ansible/_internal/_plugins/__init__.py +0 -0
  20. ansible/_internal/_plugins/_cache.py +57 -0
  21. ansible/_internal/_task.py +78 -0
  22. ansible/_internal/_templating/__init__.py +10 -0
  23. ansible/_internal/_templating/_access.py +86 -0
  24. ansible/_internal/_templating/_chain_templar.py +63 -0
  25. ansible/_internal/_templating/_datatag.py +95 -0
  26. ansible/_internal/_templating/_engine.py +588 -0
  27. ansible/_internal/_templating/_errors.py +28 -0
  28. ansible/_internal/_templating/_jinja_bits.py +1066 -0
  29. ansible/_internal/_templating/_jinja_common.py +332 -0
  30. ansible/_internal/_templating/_jinja_patches.py +44 -0
  31. ansible/_internal/_templating/_jinja_plugins.py +345 -0
  32. ansible/_internal/_templating/_lazy_containers.py +633 -0
  33. ansible/_internal/_templating/_marker_behaviors.py +103 -0
  34. ansible/_internal/_templating/_transform.py +63 -0
  35. ansible/_internal/_templating/_utils.py +107 -0
  36. ansible/_internal/_wrapt.py +1052 -0
  37. ansible/_internal/_yaml/__init__.py +0 -0
  38. ansible/_internal/_yaml/_constructor.py +240 -0
  39. ansible/_internal/_yaml/_dumper.py +62 -0
  40. ansible/_internal/_yaml/_errors.py +166 -0
  41. ansible/_internal/_yaml/_loader.py +66 -0
  42. ansible/_internal/ansible_collections/ansible/_protomatter/README.md +11 -0
  43. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/debug.py +36 -0
  44. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/apply_trust.py +19 -0
  45. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/dump_object.py +18 -0
  46. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/finalize.py +16 -0
  47. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/origin.py +18 -0
  48. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.py +24 -0
  49. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.yml +33 -0
  50. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/tag_names.py +16 -0
  51. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +17 -0
  52. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +49 -0
  53. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.py +21 -0
  54. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.yml +2 -0
  55. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.py +15 -0
  56. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.yml +19 -0
  57. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.py +18 -0
  58. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.yml +19 -0
  59. ansible/cli/__init__.py +159 -89
  60. ansible/cli/_ssh_askpass.py +47 -0
  61. ansible/cli/adhoc.py +14 -7
  62. ansible/cli/arguments/option_helpers.py +154 -7
  63. ansible/cli/config.py +43 -68
  64. ansible/cli/console.py +10 -8
  65. ansible/cli/doc.py +62 -53
  66. ansible/cli/galaxy.py +27 -20
  67. ansible/cli/inventory.py +28 -26
  68. ansible/cli/playbook.py +4 -12
  69. ansible/cli/pull.py +51 -11
  70. ansible/cli/scripts/ansible_connection_cli_stub.py +7 -7
  71. ansible/cli/vault.py +12 -11
  72. ansible/compat/__init__.py +2 -2
  73. ansible/config/base.yml +166 -112
  74. ansible/config/manager.py +52 -49
  75. ansible/constants.py +3 -4
  76. ansible/errors/__init__.py +277 -235
  77. ansible/executor/interpreter_discovery.py +28 -149
  78. ansible/executor/module_common.py +426 -493
  79. ansible/executor/play_iterator.py +22 -27
  80. ansible/executor/playbook_executor.py +11 -11
  81. ansible/executor/powershell/async_watchdog.ps1 +97 -102
  82. ansible/executor/powershell/async_wrapper.ps1 +202 -151
  83. ansible/executor/powershell/become_wrapper.ps1 +89 -144
  84. ansible/executor/powershell/bootstrap_wrapper.ps1 +24 -9
  85. ansible/executor/powershell/coverage_wrapper.ps1 +82 -135
  86. ansible/executor/powershell/exec_wrapper.ps1 +462 -196
  87. ansible/executor/powershell/module_manifest.py +417 -265
  88. ansible/executor/powershell/module_wrapper.ps1 +169 -186
  89. ansible/executor/powershell/psrp_fetch_file.ps1 +41 -0
  90. ansible/executor/powershell/psrp_put_file.ps1 +122 -0
  91. ansible/executor/powershell/winrm_fetch_file.ps1 +46 -0
  92. ansible/executor/powershell/winrm_put_file.ps1 +36 -0
  93. ansible/executor/process/worker.py +161 -96
  94. ansible/executor/stats.py +5 -5
  95. ansible/executor/task_executor.py +268 -258
  96. ansible/executor/task_queue_manager.py +124 -90
  97. ansible/executor/task_result.py +183 -78
  98. ansible/galaxy/__init__.py +2 -2
  99. ansible/galaxy/api.py +22 -18
  100. ansible/galaxy/collection/__init__.py +1 -1
  101. ansible/galaxy/collection/concrete_artifact_manager.py +8 -11
  102. ansible/galaxy/dependency_resolution/dataclasses.py +14 -4
  103. ansible/galaxy/dependency_resolution/providers.py +1 -1
  104. ansible/galaxy/dependency_resolution/reporters.py +81 -0
  105. ansible/galaxy/role.py +4 -8
  106. ansible/galaxy/token.py +28 -21
  107. ansible/inventory/data.py +47 -57
  108. ansible/inventory/group.py +44 -72
  109. ansible/inventory/helpers.py +9 -0
  110. ansible/inventory/host.py +32 -54
  111. ansible/inventory/manager.py +78 -34
  112. ansible/keyword_desc.yml +1 -1
  113. ansible/module_utils/_internal/__init__.py +55 -0
  114. ansible/module_utils/_internal/_ambient_context.py +58 -0
  115. ansible/module_utils/_internal/_ansiballz.py +133 -0
  116. ansible/module_utils/_internal/_concurrent/_daemon_threading.py +1 -0
  117. ansible/module_utils/_internal/_dataclass_annotation_patch.py +64 -0
  118. ansible/module_utils/_internal/_dataclass_validation.py +217 -0
  119. ansible/module_utils/_internal/_datatag/__init__.py +928 -0
  120. ansible/module_utils/_internal/_datatag/_tags.py +38 -0
  121. ansible/module_utils/_internal/_debugging.py +31 -0
  122. ansible/module_utils/_internal/_errors.py +30 -0
  123. ansible/module_utils/_internal/_json/__init__.py +63 -0
  124. ansible/module_utils/_internal/_json/_legacy_encoder.py +26 -0
  125. ansible/module_utils/_internal/_json/_profiles/__init__.py +410 -0
  126. ansible/module_utils/_internal/_json/_profiles/_fallback_to_str.py +73 -0
  127. ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +31 -0
  128. ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +35 -0
  129. ansible/module_utils/_internal/_json/_profiles/_module_modern_c2m.py +35 -0
  130. ansible/module_utils/_internal/_json/_profiles/_module_modern_m2c.py +33 -0
  131. ansible/module_utils/_internal/_json/_profiles/_tagless.py +50 -0
  132. ansible/module_utils/_internal/_patches/__init__.py +66 -0
  133. ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +55 -0
  134. ansible/module_utils/_internal/_patches/_socket_patch.py +34 -0
  135. ansible/module_utils/_internal/_patches/_sys_intern_patch.py +34 -0
  136. ansible/module_utils/_internal/_plugin_exec_context.py +49 -0
  137. ansible/module_utils/_internal/_testing.py +0 -0
  138. ansible/module_utils/_internal/_traceback.py +89 -0
  139. ansible/module_utils/ansible_release.py +2 -2
  140. ansible/module_utils/api.py +1 -2
  141. ansible/module_utils/basic.py +152 -120
  142. ansible/module_utils/common/_utils.py +24 -28
  143. ansible/module_utils/common/collections.py +1 -2
  144. ansible/module_utils/common/dict_transformations.py +2 -2
  145. ansible/module_utils/common/file.py +2 -2
  146. ansible/module_utils/common/json.py +90 -84
  147. ansible/module_utils/common/locale.py +2 -2
  148. ansible/module_utils/common/messages.py +108 -0
  149. ansible/module_utils/common/parameters.py +27 -24
  150. ansible/module_utils/common/process.py +2 -2
  151. ansible/module_utils/common/respawn.py +41 -19
  152. ansible/module_utils/common/sentinel.py +66 -0
  153. ansible/module_utils/common/sys_info.py +8 -8
  154. ansible/module_utils/common/text/converters.py +16 -37
  155. ansible/module_utils/common/validation.py +35 -24
  156. ansible/module_utils/common/warnings.py +86 -25
  157. ansible/module_utils/common/yaml.py +29 -3
  158. ansible/module_utils/compat/datetime.py +33 -21
  159. ansible/module_utils/compat/paramiko.py +21 -10
  160. ansible/module_utils/compat/typing.py +6 -5
  161. ansible/module_utils/connection.py +2 -2
  162. ansible/module_utils/csharp/Ansible.Basic.cs +14 -11
  163. ansible/module_utils/csharp/Ansible.Become.cs +1 -0
  164. ansible/module_utils/csharp/Ansible._Async.cs +517 -0
  165. ansible/module_utils/datatag.py +46 -0
  166. ansible/module_utils/distro/__init__.py +2 -2
  167. ansible/module_utils/facts/ansible_collector.py +4 -5
  168. ansible/module_utils/facts/collector.py +13 -14
  169. ansible/module_utils/facts/compat.py +4 -4
  170. ansible/module_utils/facts/default_collectors.py +1 -1
  171. ansible/module_utils/facts/hardware/aix.py +34 -0
  172. ansible/module_utils/facts/hardware/base.py +1 -1
  173. ansible/module_utils/facts/hardware/darwin.py +1 -3
  174. ansible/module_utils/facts/hardware/freebsd.py +2 -2
  175. ansible/module_utils/facts/hardware/linux.py +4 -4
  176. ansible/module_utils/facts/namespace.py +1 -1
  177. ansible/module_utils/facts/network/base.py +1 -1
  178. ansible/module_utils/facts/network/fc_wwn.py +1 -2
  179. ansible/module_utils/facts/network/iscsi.py +1 -2
  180. ansible/module_utils/facts/network/nvme.py +1 -2
  181. ansible/module_utils/facts/other/facter.py +1 -2
  182. ansible/module_utils/facts/other/ohai.py +2 -3
  183. ansible/module_utils/facts/system/apparmor.py +1 -2
  184. ansible/module_utils/facts/system/caps.py +1 -1
  185. ansible/module_utils/facts/system/chroot.py +1 -2
  186. ansible/module_utils/facts/system/cmdline.py +1 -2
  187. ansible/module_utils/facts/system/date_time.py +5 -3
  188. ansible/module_utils/facts/system/distribution.py +9 -8
  189. ansible/module_utils/facts/system/dns.py +1 -1
  190. ansible/module_utils/facts/system/env.py +1 -2
  191. ansible/module_utils/facts/system/fips.py +7 -20
  192. ansible/module_utils/facts/system/loadavg.py +1 -2
  193. ansible/module_utils/facts/system/local.py +1 -2
  194. ansible/module_utils/facts/system/lsb.py +1 -2
  195. ansible/module_utils/facts/system/pkg_mgr.py +1 -2
  196. ansible/module_utils/facts/system/platform.py +1 -2
  197. ansible/module_utils/facts/system/python.py +1 -2
  198. ansible/module_utils/facts/system/selinux.py +1 -1
  199. ansible/module_utils/facts/system/service_mgr.py +1 -2
  200. ansible/module_utils/facts/system/ssh_pub_keys.py +1 -1
  201. ansible/module_utils/facts/system/systemd.py +1 -1
  202. ansible/module_utils/facts/system/user.py +1 -2
  203. ansible/module_utils/facts/utils.py +3 -3
  204. ansible/module_utils/facts/virtual/base.py +1 -1
  205. ansible/module_utils/facts/virtual/sunos.py +3 -15
  206. ansible/module_utils/facts/virtual/sysctl.py +3 -16
  207. ansible/module_utils/json_utils.py +2 -2
  208. ansible/module_utils/parsing/convert_bool.py +1 -1
  209. ansible/module_utils/service.py +18 -21
  210. ansible/module_utils/splitter.py +7 -7
  211. ansible/module_utils/testing.py +31 -0
  212. ansible/module_utils/urls.py +60 -31
  213. ansible/modules/add_host.py +4 -4
  214. ansible/modules/apt.py +60 -46
  215. ansible/modules/apt_key.py +19 -12
  216. ansible/modules/apt_repository.py +19 -16
  217. ansible/modules/assemble.py +6 -6
  218. ansible/modules/assert.py +4 -4
  219. ansible/modules/async_status.py +10 -12
  220. ansible/modules/async_wrapper.py +8 -3
  221. ansible/modules/blockinfile.py +6 -7
  222. ansible/modules/command.py +10 -17
  223. ansible/modules/copy.py +57 -144
  224. ansible/modules/cron.py +20 -15
  225. ansible/modules/deb822_repository.py +8 -9
  226. ansible/modules/debconf.py +5 -5
  227. ansible/modules/debug.py +4 -4
  228. ansible/modules/dnf.py +8 -8
  229. ansible/modules/dnf5.py +39 -13
  230. ansible/modules/dpkg_selections.py +4 -4
  231. ansible/modules/expect.py +8 -10
  232. ansible/modules/fail.py +4 -4
  233. ansible/modules/fetch.py +4 -4
  234. ansible/modules/file.py +174 -133
  235. ansible/modules/find.py +19 -17
  236. ansible/modules/gather_facts.py +3 -3
  237. ansible/modules/get_url.py +59 -53
  238. ansible/modules/getent.py +7 -9
  239. ansible/modules/git.py +28 -25
  240. ansible/modules/group.py +6 -6
  241. ansible/modules/group_by.py +4 -4
  242. ansible/modules/hostname.py +13 -29
  243. ansible/modules/import_playbook.py +6 -6
  244. ansible/modules/import_role.py +6 -6
  245. ansible/modules/import_tasks.py +6 -6
  246. ansible/modules/include_role.py +6 -6
  247. ansible/modules/include_tasks.py +6 -6
  248. ansible/modules/include_vars.py +6 -6
  249. ansible/modules/iptables.py +86 -73
  250. ansible/modules/known_hosts.py +10 -10
  251. ansible/modules/lineinfile.py +5 -5
  252. ansible/modules/meta.py +4 -4
  253. ansible/modules/mount_facts.py +2 -2
  254. ansible/modules/package.py +4 -4
  255. ansible/modules/package_facts.py +22 -10
  256. ansible/modules/pause.py +6 -6
  257. ansible/modules/ping.py +6 -6
  258. ansible/modules/pip.py +10 -11
  259. ansible/modules/raw.py +4 -4
  260. ansible/modules/reboot.py +6 -6
  261. ansible/modules/replace.py +9 -13
  262. ansible/modules/rpm_key.py +7 -8
  263. ansible/modules/script.py +4 -4
  264. ansible/modules/service.py +7 -8
  265. ansible/modules/service_facts.py +87 -10
  266. ansible/modules/set_fact.py +5 -5
  267. ansible/modules/set_stats.py +4 -4
  268. ansible/modules/setup.py +2 -2
  269. ansible/modules/shell.py +6 -6
  270. ansible/modules/slurp.py +6 -6
  271. ansible/modules/stat.py +9 -23
  272. ansible/modules/subversion.py +15 -15
  273. ansible/modules/systemd.py +6 -6
  274. ansible/modules/systemd_service.py +6 -6
  275. ansible/modules/sysvinit.py +6 -6
  276. ansible/modules/tempfile.py +5 -6
  277. ansible/modules/template.py +6 -6
  278. ansible/modules/unarchive.py +32 -11
  279. ansible/modules/uri.py +33 -26
  280. ansible/modules/user.py +53 -34
  281. ansible/modules/validate_argument_spec.py +10 -7
  282. ansible/modules/wait_for.py +32 -27
  283. ansible/modules/wait_for_connection.py +6 -6
  284. ansible/modules/yum_repository.py +6 -6
  285. ansible/parsing/ajson.py +14 -32
  286. ansible/parsing/dataloader.py +99 -54
  287. ansible/parsing/mod_args.py +28 -44
  288. ansible/parsing/plugin_docs.py +21 -86
  289. ansible/parsing/quoting.py +1 -1
  290. ansible/parsing/splitter.py +27 -12
  291. ansible/parsing/utils/addresses.py +24 -24
  292. ansible/parsing/utils/jsonify.py +5 -1
  293. ansible/parsing/utils/yaml.py +32 -61
  294. ansible/parsing/vault/__init__.py +319 -87
  295. ansible/parsing/yaml/__init__.py +0 -18
  296. ansible/parsing/yaml/dumper.py +6 -120
  297. ansible/parsing/yaml/loader.py +6 -39
  298. ansible/parsing/yaml/objects.py +43 -335
  299. ansible/playbook/__init__.py +1 -1
  300. ansible/playbook/attribute.py +8 -3
  301. ansible/playbook/base.py +182 -132
  302. ansible/playbook/block.py +26 -24
  303. ansible/playbook/collectionsearch.py +1 -15
  304. ansible/playbook/conditional.py +3 -77
  305. ansible/playbook/handler.py +8 -2
  306. ansible/playbook/helpers.py +41 -53
  307. ansible/playbook/included_file.py +31 -27
  308. ansible/playbook/loop_control.py +2 -2
  309. ansible/playbook/play.py +85 -44
  310. ansible/playbook/play_context.py +12 -17
  311. ansible/playbook/playbook_include.py +14 -15
  312. ansible/playbook/role/__init__.py +24 -26
  313. ansible/playbook/role/definition.py +15 -17
  314. ansible/playbook/role/include.py +2 -4
  315. ansible/playbook/role/metadata.py +10 -11
  316. ansible/playbook/role_include.py +3 -3
  317. ansible/playbook/taggable.py +13 -8
  318. ansible/playbook/task.py +188 -118
  319. ansible/playbook/task_include.py +5 -5
  320. ansible/plugins/__init__.py +68 -21
  321. ansible/plugins/action/__init__.py +209 -176
  322. ansible/plugins/action/add_host.py +1 -1
  323. ansible/plugins/action/assemble.py +1 -1
  324. ansible/plugins/action/assert.py +54 -66
  325. ansible/plugins/action/copy.py +7 -11
  326. ansible/plugins/action/debug.py +37 -31
  327. ansible/plugins/action/dnf.py +3 -4
  328. ansible/plugins/action/fail.py +1 -1
  329. ansible/plugins/action/fetch.py +4 -5
  330. ansible/plugins/action/gather_facts.py +7 -6
  331. ansible/plugins/action/group_by.py +1 -1
  332. ansible/plugins/action/include_vars.py +10 -11
  333. ansible/plugins/action/package.py +3 -6
  334. ansible/plugins/action/pause.py +2 -2
  335. ansible/plugins/action/script.py +15 -8
  336. ansible/plugins/action/service.py +6 -11
  337. ansible/plugins/action/set_fact.py +3 -12
  338. ansible/plugins/action/set_stats.py +3 -8
  339. ansible/plugins/action/template.py +35 -59
  340. ansible/plugins/action/unarchive.py +1 -1
  341. ansible/plugins/action/validate_argument_spec.py +5 -5
  342. ansible/plugins/action/wait_for_connection.py +1 -1
  343. ansible/plugins/become/__init__.py +31 -8
  344. ansible/plugins/become/runas.py +71 -0
  345. ansible/plugins/become/su.py +13 -8
  346. ansible/plugins/become/sudo.py +19 -0
  347. ansible/plugins/cache/__init__.py +35 -44
  348. ansible/plugins/cache/base.py +8 -0
  349. ansible/plugins/cache/jsonfile.py +10 -16
  350. ansible/plugins/cache/memory.py +6 -12
  351. ansible/plugins/callback/__init__.py +284 -179
  352. ansible/plugins/callback/default.py +99 -92
  353. ansible/plugins/callback/junit.py +44 -39
  354. ansible/plugins/callback/minimal.py +28 -25
  355. ansible/plugins/callback/oneline.py +28 -21
  356. ansible/plugins/callback/tree.py +16 -11
  357. ansible/plugins/connection/__init__.py +47 -34
  358. ansible/plugins/connection/local.py +150 -54
  359. ansible/plugins/connection/paramiko_ssh.py +21 -18
  360. ansible/plugins/connection/psrp.py +76 -165
  361. ansible/plugins/connection/ssh.py +301 -78
  362. ansible/plugins/connection/winrm.py +58 -140
  363. ansible/plugins/doc_fragments/action_common_attributes.py +14 -14
  364. ansible/plugins/doc_fragments/action_core.py +6 -6
  365. ansible/plugins/doc_fragments/backup.py +2 -2
  366. ansible/plugins/doc_fragments/checksum_common.py +27 -0
  367. ansible/plugins/doc_fragments/constructed.py +6 -2
  368. ansible/plugins/doc_fragments/decrypt.py +2 -2
  369. ansible/plugins/doc_fragments/default_callback.py +2 -2
  370. ansible/plugins/doc_fragments/files.py +2 -2
  371. ansible/plugins/doc_fragments/inventory_cache.py +2 -2
  372. ansible/plugins/doc_fragments/result_format_callback.py +2 -2
  373. ansible/plugins/doc_fragments/return_common.py +2 -2
  374. ansible/plugins/doc_fragments/template_common.py +4 -4
  375. ansible/plugins/doc_fragments/url.py +17 -1
  376. ansible/plugins/doc_fragments/url_windows.py +2 -2
  377. ansible/plugins/doc_fragments/validate.py +2 -2
  378. ansible/plugins/doc_fragments/vars_plugin_staging.py +2 -2
  379. ansible/plugins/filter/__init__.py +6 -2
  380. ansible/plugins/filter/b64decode.yml +22 -0
  381. ansible/plugins/filter/b64encode.yml +22 -0
  382. ansible/plugins/filter/bool.yml +11 -4
  383. ansible/plugins/filter/core.py +225 -108
  384. ansible/plugins/filter/encryption.py +32 -32
  385. ansible/plugins/filter/flatten.yml +3 -2
  386. ansible/plugins/filter/human_to_bytes.yml +1 -1
  387. ansible/plugins/filter/mathstuff.py +30 -37
  388. ansible/plugins/filter/password_hash.yml +8 -0
  389. ansible/plugins/filter/regex_search.yml +1 -4
  390. ansible/plugins/filter/split.yml +1 -1
  391. ansible/plugins/filter/to_nice_yaml.yml +0 -4
  392. ansible/plugins/filter/to_yaml.yml +0 -4
  393. ansible/plugins/filter/unvault.yml +1 -1
  394. ansible/plugins/filter/urls.py +1 -1
  395. ansible/plugins/filter/urlsplit.py +8 -9
  396. ansible/plugins/filter/vault.yml +14 -9
  397. ansible/plugins/filter/win_basename.yml +6 -1
  398. ansible/plugins/filter/win_dirname.yml +5 -0
  399. ansible/plugins/inventory/__init__.py +97 -77
  400. ansible/plugins/inventory/advanced_host_list.py +7 -5
  401. ansible/plugins/inventory/auto.py +11 -4
  402. ansible/plugins/inventory/constructed.py +21 -24
  403. ansible/plugins/inventory/generator.py +16 -11
  404. ansible/plugins/inventory/host_list.py +7 -5
  405. ansible/plugins/inventory/ini.py +78 -44
  406. ansible/plugins/inventory/script.py +189 -119
  407. ansible/plugins/inventory/toml.py +16 -126
  408. ansible/plugins/inventory/yaml.py +10 -8
  409. ansible/plugins/list.py +3 -3
  410. ansible/plugins/loader.py +197 -82
  411. ansible/plugins/lookup/__init__.py +21 -4
  412. ansible/plugins/lookup/config.py +21 -35
  413. ansible/plugins/lookup/csvfile.py +3 -2
  414. ansible/plugins/lookup/dict.py +1 -6
  415. ansible/plugins/lookup/env.py +12 -9
  416. ansible/plugins/lookup/file.py +5 -8
  417. ansible/plugins/lookup/first_found.py +86 -55
  418. ansible/plugins/lookup/indexed_items.py +1 -10
  419. ansible/plugins/lookup/ini.py +14 -13
  420. ansible/plugins/lookup/items.py +1 -1
  421. ansible/plugins/lookup/lines.py +8 -1
  422. ansible/plugins/lookup/list.py +1 -1
  423. ansible/plugins/lookup/nested.py +2 -18
  424. ansible/plugins/lookup/password.py +5 -5
  425. ansible/plugins/lookup/pipe.py +5 -7
  426. ansible/plugins/lookup/sequence.py +18 -8
  427. ansible/plugins/lookup/subelements.py +1 -4
  428. ansible/plugins/lookup/template.py +42 -36
  429. ansible/plugins/lookup/together.py +0 -12
  430. ansible/plugins/lookup/unvault.py +1 -5
  431. ansible/plugins/lookup/url.py +2 -8
  432. ansible/plugins/lookup/vars.py +16 -24
  433. ansible/plugins/shell/__init__.py +2 -2
  434. ansible/plugins/shell/cmd.py +2 -2
  435. ansible/plugins/shell/powershell.py +39 -22
  436. ansible/plugins/shell/sh.py +3 -2
  437. ansible/plugins/strategy/__init__.py +159 -184
  438. ansible/plugins/strategy/debug.py +2 -2
  439. ansible/plugins/strategy/free.py +16 -31
  440. ansible/plugins/strategy/host_pinned.py +2 -2
  441. ansible/plugins/strategy/linear.py +41 -41
  442. ansible/plugins/terminal/__init__.py +4 -4
  443. ansible/plugins/test/__init__.py +7 -2
  444. ansible/plugins/test/core.py +55 -21
  445. ansible/plugins/test/files.py +1 -1
  446. ansible/plugins/test/mathstuff.py +3 -3
  447. ansible/plugins/test/uri.py +3 -3
  448. ansible/plugins/vars/host_group_vars.py +7 -14
  449. ansible/release.py +2 -2
  450. ansible/template/__init__.py +370 -944
  451. ansible/utils/__init__.py +0 -18
  452. ansible/utils/_ssh_agent.py +657 -0
  453. ansible/utils/collection_loader/__init__.py +52 -5
  454. ansible/utils/collection_loader/_collection_config.py +5 -6
  455. ansible/utils/collection_loader/_collection_finder.py +79 -93
  456. ansible/utils/collection_loader/_collection_meta.py +13 -8
  457. ansible/utils/display.py +433 -63
  458. ansible/utils/encrypt.py +27 -19
  459. ansible/utils/fqcn.py +2 -2
  460. ansible/utils/hashing.py +2 -2
  461. ansible/utils/helpers.py +2 -2
  462. ansible/utils/listify.py +8 -8
  463. ansible/utils/lock.py +2 -2
  464. ansible/utils/path.py +4 -4
  465. ansible/utils/plugin_docs.py +14 -13
  466. ansible/utils/sentinel.py +4 -62
  467. ansible/utils/singleton.py +2 -0
  468. ansible/utils/ssh_functions.py +1 -1
  469. ansible/utils/unsafe_proxy.py +23 -332
  470. ansible/utils/vars.py +51 -8
  471. ansible/utils/version.py +2 -2
  472. ansible/vars/clean.py +5 -5
  473. ansible/vars/hostvars.py +60 -90
  474. ansible/vars/manager.py +206 -282
  475. ansible/vars/reserved.py +8 -9
  476. ansible_core-2.19.0b2.dist-info/BSD-3-Clause.txt +28 -0
  477. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/METADATA +5 -4
  478. ansible_core-2.19.0b2.dist-info/RECORD +1072 -0
  479. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/WHEEL +1 -1
  480. ansible_test/_data/completion/docker.txt +7 -7
  481. ansible_test/_data/completion/remote.txt +6 -6
  482. ansible_test/_data/completion/windows.txt +1 -0
  483. ansible_test/_data/requirements/ansible.txt +2 -2
  484. ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
  485. ansible_test/_data/requirements/sanity.changelog.txt +1 -1
  486. ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
  487. ansible_test/_data/requirements/sanity.pylint.txt +4 -4
  488. ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
  489. ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
  490. ansible_test/_data/requirements/units.txt +1 -0
  491. ansible_test/_internal/__init__.py +1 -0
  492. ansible_test/_internal/ansible_util.py +2 -0
  493. ansible_test/_internal/become.py +1 -0
  494. ansible_test/_internal/bootstrap.py +1 -0
  495. ansible_test/_internal/cache.py +1 -0
  496. ansible_test/_internal/cgroup.py +1 -0
  497. ansible_test/_internal/ci/__init__.py +1 -0
  498. ansible_test/_internal/ci/azp.py +1 -0
  499. ansible_test/_internal/ci/local.py +1 -0
  500. ansible_test/_internal/classification/__init__.py +1 -0
  501. ansible_test/_internal/classification/common.py +1 -0
  502. ansible_test/_internal/classification/csharp.py +1 -0
  503. ansible_test/_internal/classification/powershell.py +1 -0
  504. ansible_test/_internal/classification/python.py +1 -0
  505. ansible_test/_internal/cli/__init__.py +1 -0
  506. ansible_test/_internal/cli/actions.py +1 -0
  507. ansible_test/_internal/cli/argparsing/__init__.py +1 -0
  508. ansible_test/_internal/cli/argparsing/actions.py +1 -0
  509. ansible_test/_internal/cli/argparsing/argcompletion.py +1 -0
  510. ansible_test/_internal/cli/argparsing/parsers.py +1 -0
  511. ansible_test/_internal/cli/commands/__init__.py +11 -0
  512. ansible_test/_internal/cli/commands/coverage/__init__.py +1 -0
  513. ansible_test/_internal/cli/commands/coverage/analyze/__init__.py +1 -0
  514. ansible_test/_internal/cli/commands/coverage/analyze/targets/__init__.py +1 -0
  515. ansible_test/_internal/cli/commands/coverage/analyze/targets/combine.py +1 -0
  516. ansible_test/_internal/cli/commands/coverage/analyze/targets/expand.py +1 -0
  517. ansible_test/_internal/cli/commands/coverage/analyze/targets/filter.py +1 -0
  518. ansible_test/_internal/cli/commands/coverage/analyze/targets/generate.py +1 -0
  519. ansible_test/_internal/cli/commands/coverage/analyze/targets/missing.py +1 -0
  520. ansible_test/_internal/cli/commands/coverage/combine.py +1 -0
  521. ansible_test/_internal/cli/commands/coverage/erase.py +1 -0
  522. ansible_test/_internal/cli/commands/coverage/html.py +1 -0
  523. ansible_test/_internal/cli/commands/coverage/report.py +1 -0
  524. ansible_test/_internal/cli/commands/coverage/xml.py +1 -0
  525. ansible_test/_internal/cli/commands/env.py +1 -0
  526. ansible_test/_internal/cli/commands/integration/__init__.py +1 -0
  527. ansible_test/_internal/cli/commands/integration/network.py +1 -0
  528. ansible_test/_internal/cli/commands/integration/posix.py +1 -0
  529. ansible_test/_internal/cli/commands/integration/windows.py +1 -0
  530. ansible_test/_internal/cli/commands/sanity.py +9 -0
  531. ansible_test/_internal/cli/commands/shell.py +1 -0
  532. ansible_test/_internal/cli/commands/units.py +1 -0
  533. ansible_test/_internal/cli/compat.py +1 -0
  534. ansible_test/_internal/cli/completers.py +1 -0
  535. ansible_test/_internal/cli/converters.py +1 -0
  536. ansible_test/_internal/cli/environments.py +1 -0
  537. ansible_test/_internal/cli/epilog.py +1 -0
  538. ansible_test/_internal/cli/parsers/__init__.py +1 -0
  539. ansible_test/_internal/cli/parsers/base_argument_parsers.py +1 -0
  540. ansible_test/_internal/cli/parsers/helpers.py +1 -0
  541. ansible_test/_internal/cli/parsers/host_config_parsers.py +1 -0
  542. ansible_test/_internal/cli/parsers/key_value_parsers.py +1 -0
  543. ansible_test/_internal/cli/parsers/value_parsers.py +1 -0
  544. ansible_test/_internal/commands/__init__.py +1 -0
  545. ansible_test/_internal/commands/coverage/__init__.py +2 -1
  546. ansible_test/_internal/commands/coverage/analyze/__init__.py +1 -0
  547. ansible_test/_internal/commands/coverage/analyze/targets/__init__.py +1 -0
  548. ansible_test/_internal/commands/coverage/analyze/targets/combine.py +1 -0
  549. ansible_test/_internal/commands/coverage/analyze/targets/expand.py +1 -0
  550. ansible_test/_internal/commands/coverage/analyze/targets/filter.py +1 -0
  551. ansible_test/_internal/commands/coverage/analyze/targets/generate.py +1 -0
  552. ansible_test/_internal/commands/coverage/analyze/targets/missing.py +1 -0
  553. ansible_test/_internal/commands/coverage/combine.py +2 -1
  554. ansible_test/_internal/commands/coverage/erase.py +1 -0
  555. ansible_test/_internal/commands/coverage/html.py +1 -0
  556. ansible_test/_internal/commands/coverage/report.py +1 -0
  557. ansible_test/_internal/commands/coverage/xml.py +1 -0
  558. ansible_test/_internal/commands/env/__init__.py +2 -0
  559. ansible_test/_internal/commands/integration/__init__.py +4 -0
  560. ansible_test/_internal/commands/integration/cloud/__init__.py +1 -0
  561. ansible_test/_internal/commands/integration/cloud/acme.py +2 -1
  562. ansible_test/_internal/commands/integration/cloud/aws.py +1 -0
  563. ansible_test/_internal/commands/integration/cloud/azure.py +1 -0
  564. ansible_test/_internal/commands/integration/cloud/cs.py +1 -0
  565. ansible_test/_internal/commands/integration/cloud/digitalocean.py +1 -0
  566. ansible_test/_internal/commands/integration/cloud/galaxy.py +3 -2
  567. ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -0
  568. ansible_test/_internal/commands/integration/cloud/httptester.py +2 -1
  569. ansible_test/_internal/commands/integration/cloud/nios.py +2 -1
  570. ansible_test/_internal/commands/integration/cloud/opennebula.py +1 -0
  571. ansible_test/_internal/commands/integration/cloud/openshift.py +1 -0
  572. ansible_test/_internal/commands/integration/cloud/scaleway.py +1 -0
  573. ansible_test/_internal/commands/integration/cloud/vcenter.py +1 -0
  574. ansible_test/_internal/commands/integration/cloud/vultr.py +1 -0
  575. ansible_test/_internal/commands/integration/coverage.py +1 -0
  576. ansible_test/_internal/commands/integration/filters.py +1 -0
  577. ansible_test/_internal/commands/integration/network.py +1 -0
  578. ansible_test/_internal/commands/integration/posix.py +1 -0
  579. ansible_test/_internal/commands/integration/windows.py +1 -0
  580. ansible_test/_internal/commands/sanity/__init__.py +16 -1
  581. ansible_test/_internal/commands/sanity/ansible_doc.py +1 -0
  582. ansible_test/_internal/commands/sanity/bin_symlinks.py +1 -0
  583. ansible_test/_internal/commands/sanity/compile.py +1 -0
  584. ansible_test/_internal/commands/sanity/ignores.py +1 -0
  585. ansible_test/_internal/commands/sanity/import.py +1 -0
  586. ansible_test/_internal/commands/sanity/integration_aliases.py +1 -0
  587. ansible_test/_internal/commands/sanity/pep8.py +1 -0
  588. ansible_test/_internal/commands/sanity/pslint.py +1 -0
  589. ansible_test/_internal/commands/sanity/pylint.py +24 -26
  590. ansible_test/_internal/commands/sanity/shellcheck.py +1 -0
  591. ansible_test/_internal/commands/sanity/validate_modules.py +1 -0
  592. ansible_test/_internal/commands/sanity/yamllint.py +1 -0
  593. ansible_test/_internal/commands/shell/__init__.py +1 -0
  594. ansible_test/_internal/commands/units/__init__.py +1 -0
  595. ansible_test/_internal/compat/__init__.py +1 -0
  596. ansible_test/_internal/compat/packaging.py +1 -0
  597. ansible_test/_internal/compat/yaml.py +1 -0
  598. ansible_test/_internal/completion.py +1 -0
  599. ansible_test/_internal/config.py +2 -0
  600. ansible_test/_internal/connections.py +1 -0
  601. ansible_test/_internal/constants.py +1 -0
  602. ansible_test/_internal/containers.py +1 -0
  603. ansible_test/_internal/content_config.py +1 -0
  604. ansible_test/_internal/core_ci.py +1 -0
  605. ansible_test/_internal/coverage_util.py +11 -10
  606. ansible_test/_internal/data.py +1 -0
  607. ansible_test/_internal/delegation.py +1 -0
  608. ansible_test/_internal/dev/__init__.py +1 -0
  609. ansible_test/_internal/dev/container_probe.py +1 -0
  610. ansible_test/_internal/diff.py +3 -2
  611. ansible_test/_internal/docker_util.py +2 -1
  612. ansible_test/_internal/encoding.py +1 -0
  613. ansible_test/_internal/executor.py +1 -0
  614. ansible_test/_internal/git.py +1 -0
  615. ansible_test/_internal/host_configs.py +1 -0
  616. ansible_test/_internal/host_profiles.py +1 -0
  617. ansible_test/_internal/http.py +1 -0
  618. ansible_test/_internal/init.py +1 -0
  619. ansible_test/_internal/inventory.py +35 -3
  620. ansible_test/_internal/io.py +1 -0
  621. ansible_test/_internal/metadata.py +1 -0
  622. ansible_test/_internal/payload.py +1 -0
  623. ansible_test/_internal/provider/__init__.py +1 -0
  624. ansible_test/_internal/provider/layout/__init__.py +1 -0
  625. ansible_test/_internal/provider/layout/ansible.py +1 -0
  626. ansible_test/_internal/provider/layout/collection.py +1 -0
  627. ansible_test/_internal/provider/layout/unsupported.py +1 -0
  628. ansible_test/_internal/provider/source/__init__.py +1 -0
  629. ansible_test/_internal/provider/source/git.py +1 -0
  630. ansible_test/_internal/provider/source/installed.py +1 -0
  631. ansible_test/_internal/provider/source/unsupported.py +1 -0
  632. ansible_test/_internal/provider/source/unversioned.py +1 -0
  633. ansible_test/_internal/provisioning.py +1 -0
  634. ansible_test/_internal/pypi_proxy.py +6 -5
  635. ansible_test/_internal/python_requirements.py +1 -0
  636. ansible_test/_internal/ssh.py +1 -0
  637. ansible_test/_internal/target.py +1 -0
  638. ansible_test/_internal/test.py +3 -2
  639. ansible_test/_internal/thread.py +1 -0
  640. ansible_test/_internal/timeout.py +1 -0
  641. ansible_test/_internal/util.py +1 -0
  642. ansible_test/_internal/util_common.py +5 -2
  643. ansible_test/_internal/venv.py +1 -0
  644. ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +1 -0
  645. ansible_test/_util/controller/sanity/code-smell/changelog/sphinx.py +1 -0
  646. ansible_test/_util/controller/sanity/code-smell/changelog.py +1 -0
  647. ansible_test/_util/controller/sanity/code-smell/empty-init.py +1 -0
  648. ansible_test/_util/controller/sanity/code-smell/line-endings.py +1 -0
  649. ansible_test/_util/controller/sanity/code-smell/no-assert.py +1 -0
  650. ansible_test/_util/controller/sanity/code-smell/no-get-exception.py +1 -0
  651. ansible_test/_util/controller/sanity/code-smell/no-illegal-filenames.py +1 -0
  652. ansible_test/_util/controller/sanity/code-smell/no-smart-quotes.py +1 -0
  653. ansible_test/_util/controller/sanity/code-smell/replace-urlopen.py +1 -0
  654. ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +28 -1
  655. ansible_test/_util/controller/sanity/code-smell/shebang.py +1 -0
  656. ansible_test/_util/controller/sanity/code-smell/symlinks.py +1 -0
  657. ansible_test/_util/controller/sanity/code-smell/use-argspec-type-path.py +1 -0
  658. ansible_test/_util/controller/sanity/code-smell/use-compat-six.py +1 -0
  659. ansible_test/_util/controller/sanity/integration-aliases/yaml_to_json.py +2 -1
  660. ansible_test/_util/controller/sanity/pep8/current-ignore.txt +4 -0
  661. ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +7 -5
  662. ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +7 -5
  663. ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +7 -5
  664. ansible_test/_util/controller/sanity/pylint/config/collection.cfg +3 -5
  665. ansible_test/_util/controller/sanity/pylint/config/default.cfg +7 -7
  666. ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -13
  667. ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +1 -0
  668. ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +1 -8
  669. ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +1 -8
  670. ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +55 -28
  671. ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +12 -5
  672. ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +13 -2
  673. ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -0
  674. ansible_test/_util/controller/sanity/yamllint/yamllinter.py +35 -17
  675. ansible_test/_util/controller/tools/collection_detail.py +1 -0
  676. ansible_test/_util/controller/tools/yaml_to_json.py +2 -1
  677. ansible_test/_util/target/pytest/plugins/ansible_forked.py +6 -1
  678. ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py +2 -1
  679. ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +1 -0
  680. ansible_test/_util/target/sanity/compile/compile.py +1 -0
  681. ansible_test/_util/target/sanity/import/importer.py +15 -16
  682. ansible_test/_util/target/setup/bootstrap.sh +9 -20
  683. ansible_test/_util/target/setup/probe_cgroups.py +1 -0
  684. ansible_test/_util/target/setup/quiet_pip.py +1 -0
  685. ansible_test/_util/target/setup/requirements.py +35 -27
  686. ansible_test/_util/target/tools/virtualenvcheck.py +2 -1
  687. ansible_test/_util/target/tools/yamlcheck.py +2 -1
  688. ansible/compat/selectors.py +0 -32
  689. ansible/errors/yaml_strings.py +0 -138
  690. ansible/executor/action_write_locks.py +0 -44
  691. ansible/executor/discovery/python_target.py +0 -47
  692. ansible/executor/powershell/module_powershell_wrapper.ps1 +0 -86
  693. ansible/executor/powershell/module_script_wrapper.ps1 +0 -22
  694. ansible/module_utils/compat/importlib.py +0 -26
  695. ansible/module_utils/compat/selectors.py +0 -32
  696. ansible/module_utils/pycompat24.py +0 -73
  697. ansible/parsing/yaml/constructor.py +0 -178
  698. ansible/template/native_helpers.py +0 -251
  699. ansible/template/template.py +0 -43
  700. ansible/template/vars.py +0 -77
  701. ansible/utils/native_jinja.py +0 -11
  702. ansible/vars/fact_cache.py +0 -71
  703. ansible_core-2.18.5rc1.dist-info/RECORD +0 -992
  704. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/Apache-License.txt +0 -0
  705. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/COPYING +0 -0
  706. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/MIT-license.txt +0 -0
  707. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/PSF-license.txt +0 -0
  708. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/entry_points.txt +0 -0
  709. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/simplified_bsd.txt +0 -0
  710. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,91 @@
1
+ from __future__ import annotations
2
+
3
+ import contextlib
4
+ import enum
5
+ import typing as t
6
+
7
+ from ansible.utils.display import Display
8
+ from ansible.constants import config
9
+
10
+ display = Display()
11
+
12
+ # FUTURE: add sanity test to detect use of skip_on_ignore without Skippable (and vice versa)
13
+
14
+
15
+ class ErrorAction(enum.Enum):
16
+ """Action to take when an error is encountered."""
17
+
18
+ IGNORE = enum.auto()
19
+ WARNING = enum.auto()
20
+ ERROR = enum.auto()
21
+
22
+ @classmethod
23
+ def from_config(cls, setting: str, variables: dict[str, t.Any] | None = None) -> t.Self:
24
+ """Return an `ErrorAction` enum from the specified Ansible config setting."""
25
+ return cls[config.get_config_value(setting, variables=variables).upper()]
26
+
27
+
28
+ class _SkipException(BaseException):
29
+ """Internal flow control exception for skipping code blocks within a `Skippable` context manager."""
30
+
31
+ def __init__(self) -> None:
32
+ super().__init__('Skipping ignored action due to use of `skip_on_ignore`. It is a bug to encounter this message outside of debugging.')
33
+
34
+
35
+ class _SkippableContextManager:
36
+ """Internal context manager to support flow control for skipping code blocks."""
37
+
38
+ def __enter__(self) -> None:
39
+ pass
40
+
41
+ def __exit__(self, exc_type, _exc_val, _exc_tb) -> bool:
42
+ if exc_type is None:
43
+ raise RuntimeError('A `Skippable` context manager was entered, but a `skip_on_ignore` handler was never invoked.')
44
+
45
+ return exc_type is _SkipException # only mask a _SkipException, allow all others to raise
46
+
47
+
48
+ Skippable = _SkippableContextManager()
49
+ """Context manager singleton required to enclose `ErrorHandler.handle` invocations when `skip_on_ignore` is `True`."""
50
+
51
+
52
+ class ErrorHandler:
53
+ """
54
+ Provides a configurable error handler context manager for a specific list of exception types.
55
+ Unhandled errors leaving the context manager can be ignored, treated as warnings, or allowed to raise by setting `ErrorAction`.
56
+ """
57
+
58
+ def __init__(self, action: ErrorAction) -> None:
59
+ self.action = action
60
+
61
+ @contextlib.contextmanager
62
+ def handle(self, *args: type[BaseException], skip_on_ignore: bool = False) -> t.Iterator[None]:
63
+ """
64
+ Handle the specified exception(s) using the defined error action.
65
+ If `skip_on_ignore` is `True`, the body of the context manager will be skipped for `ErrorAction.IGNORE`.
66
+ Use of `skip_on_ignore` requires enclosure within the `Skippable` context manager.
67
+ """
68
+ if not args:
69
+ raise ValueError('At least one exception type is required.')
70
+
71
+ if skip_on_ignore and self.action == ErrorAction.IGNORE:
72
+ raise _SkipException() # skipping ignored action
73
+
74
+ try:
75
+ yield
76
+ except args as ex:
77
+ match self.action:
78
+ case ErrorAction.WARNING:
79
+ display.error_as_warning(msg=None, exception=ex)
80
+ case ErrorAction.ERROR:
81
+ raise
82
+ case _: # ErrorAction.IGNORE
83
+ pass
84
+
85
+ if skip_on_ignore:
86
+ raise _SkipException() # completed skippable action, ensures the `Skippable` context was used
87
+
88
+ @classmethod
89
+ def from_config(cls, setting: str, variables: dict[str, t.Any] | None = None) -> t.Self:
90
+ """Return an `ErrorHandler` instance configured using the specified Ansible config setting."""
91
+ return cls(ErrorAction.from_config(setting, variables=variables))
@@ -0,0 +1,310 @@
1
+ from __future__ import annotations
2
+
3
+ import dataclasses
4
+ import itertools
5
+ import pathlib
6
+ import sys
7
+ import textwrap
8
+ import typing as t
9
+
10
+ from ansible.module_utils.common.messages import Detail, ErrorSummary
11
+ from ansible._internal._datatag._tags import Origin
12
+ from ansible.module_utils._internal import _ambient_context, _traceback
13
+ from ansible import errors
14
+
15
+ if t.TYPE_CHECKING:
16
+ from ansible.utils.display import Display
17
+
18
+
19
+ class RedactAnnotatedSourceContext(_ambient_context.AmbientContextBase):
20
+ """
21
+ When active, this context will redact annotated source lines, showing only the origin.
22
+ """
23
+
24
+
25
+ def _dedupe_and_concat_message_chain(message_parts: list[str]) -> str:
26
+ message_parts = list(reversed(message_parts))
27
+
28
+ message = message_parts.pop(0)
29
+
30
+ for message_part in message_parts:
31
+ # avoid duplicate messages where the cause was already concatenated to the exception message
32
+ if message_part.endswith(message):
33
+ message = message_part
34
+ else:
35
+ message = concat_message(message_part, message)
36
+
37
+ return message
38
+
39
+
40
+ def _collapse_error_details(error_details: t.Sequence[Detail]) -> list[Detail]:
41
+ """
42
+ Return a potentially modified error chain, with redundant errors collapsed into previous error(s) in the chain.
43
+ This reduces the verbosity of messages by eliminating repetition when multiple errors in the chain share the same contextual information.
44
+ """
45
+ previous_error = error_details[0]
46
+ previous_warnings: list[str] = []
47
+ collapsed_error_details: list[tuple[Detail, list[str]]] = [(previous_error, previous_warnings)]
48
+
49
+ for error in error_details[1:]:
50
+ details_present = error.formatted_source_context or error.help_text
51
+ details_changed = error.formatted_source_context != previous_error.formatted_source_context or error.help_text != previous_error.help_text
52
+
53
+ if details_present and details_changed:
54
+ previous_error = error
55
+ previous_warnings = []
56
+ collapsed_error_details.append((previous_error, previous_warnings))
57
+ else:
58
+ previous_warnings.append(error.msg)
59
+
60
+ final_error_details: list[Detail] = []
61
+
62
+ for error, messages in collapsed_error_details:
63
+ final_error_details.append(dataclasses.replace(error, msg=_dedupe_and_concat_message_chain([error.msg] + messages)))
64
+
65
+ return final_error_details
66
+
67
+
68
+ def _get_cause(exception: BaseException) -> BaseException | None:
69
+ # deprecated: description='remove support for orig_exc (deprecated in 2.23)' core_version='2.27'
70
+
71
+ if not isinstance(exception, errors.AnsibleError):
72
+ return exception.__cause__
73
+
74
+ if exception.__cause__:
75
+ if exception.orig_exc and exception.orig_exc is not exception.__cause__:
76
+ _get_display().warning(
77
+ msg=f"The `orig_exc` argument to `{type(exception).__name__}` was given, but differed from the cause given by `raise ... from`.",
78
+ )
79
+
80
+ return exception.__cause__
81
+
82
+ if exception.orig_exc:
83
+ # encourage the use of `raise ... from` before deprecating `orig_exc`
84
+ _get_display().warning(msg=f"The `orig_exc` argument to `{type(exception).__name__}` was given without using `raise ... from orig_exc`.")
85
+
86
+ return exception.orig_exc
87
+
88
+ return None
89
+
90
+
91
+ class _TemporaryDisplay:
92
+ # DTFIX-FUTURE: generalize this and hide it in the display module so all users of Display can benefit
93
+
94
+ @staticmethod
95
+ def warning(*args, **kwargs):
96
+ print(f'FALLBACK WARNING: {args} {kwargs}', file=sys.stderr)
97
+
98
+ @staticmethod
99
+ def deprecated(*args, **kwargs):
100
+ print(f'FALLBACK DEPRECATION: {args} {kwargs}', file=sys.stderr)
101
+
102
+
103
+ def _get_display() -> Display | _TemporaryDisplay:
104
+ try:
105
+ from ansible.utils.display import Display
106
+ except ImportError:
107
+ return _TemporaryDisplay()
108
+
109
+ return Display()
110
+
111
+
112
+ def _create_error_summary(exception: BaseException, event: _traceback.TracebackEvent | None = None) -> ErrorSummary:
113
+ from . import _captured # avoid circular import due to AnsibleError import
114
+
115
+ current_exception: BaseException | None = exception
116
+ error_details: list[Detail] = []
117
+
118
+ if event:
119
+ formatted_traceback = _traceback.maybe_extract_traceback(exception, event)
120
+ else:
121
+ formatted_traceback = None
122
+
123
+ while current_exception:
124
+ if isinstance(current_exception, errors.AnsibleError):
125
+ include_cause_message = current_exception._include_cause_message
126
+ edc = Detail(
127
+ msg=current_exception._original_message.strip(),
128
+ formatted_source_context=current_exception._formatted_source_context,
129
+ help_text=current_exception._help_text,
130
+ )
131
+ else:
132
+ include_cause_message = True
133
+ edc = Detail(
134
+ msg=str(current_exception).strip(),
135
+ )
136
+
137
+ error_details.append(edc)
138
+
139
+ if isinstance(current_exception, _captured.AnsibleCapturedError):
140
+ detail = current_exception.error_summary
141
+ error_details.extend(detail.details)
142
+
143
+ if formatted_traceback and detail.formatted_traceback:
144
+ formatted_traceback = (
145
+ f'{detail.formatted_traceback}\n'
146
+ f'The {current_exception.context} exception above was the direct cause of the following controller exception:\n\n'
147
+ f'{formatted_traceback}'
148
+ )
149
+
150
+ if not include_cause_message:
151
+ break
152
+
153
+ current_exception = _get_cause(current_exception)
154
+
155
+ return ErrorSummary(details=tuple(error_details), formatted_traceback=formatted_traceback)
156
+
157
+
158
+ def concat_message(left: str, right: str) -> str:
159
+ """Normalize `left` by removing trailing punctuation and spaces before appending new punctuation and `right`."""
160
+ return f'{left.rstrip(". ")}: {right}'
161
+
162
+
163
+ def get_chained_message(exception: BaseException) -> str:
164
+ """
165
+ Return the full chain of exception messages by concatenating the cause(s) until all are exhausted.
166
+ """
167
+ error_summary = _create_error_summary(exception)
168
+ message_parts = [edc.msg for edc in error_summary.details]
169
+
170
+ return _dedupe_and_concat_message_chain(message_parts)
171
+
172
+
173
+ @dataclasses.dataclass(kw_only=True, frozen=True)
174
+ class SourceContext:
175
+ origin: Origin
176
+ annotated_source_lines: list[str]
177
+ target_line: str | None
178
+
179
+ def __str__(self) -> str:
180
+ msg_lines = [f'Origin: {self.origin}']
181
+
182
+ if self.annotated_source_lines:
183
+ msg_lines.append('')
184
+ msg_lines.extend(self.annotated_source_lines)
185
+
186
+ return '\n'.join(msg_lines)
187
+
188
+ @classmethod
189
+ def from_value(cls, value: t.Any) -> SourceContext | None:
190
+ """Attempt to retrieve source and render a contextual indicator from the value's origin (if any)."""
191
+ if value is None:
192
+ return None
193
+
194
+ if isinstance(value, Origin):
195
+ origin = value
196
+ value = None
197
+ else:
198
+ origin = Origin.get_tag(value)
199
+
200
+ if RedactAnnotatedSourceContext.current(optional=True):
201
+ return cls.error('content redacted')
202
+
203
+ if origin and origin.path:
204
+ return cls.from_origin(origin)
205
+
206
+ # DTFIX-RELEASE: redaction context may not be sufficient to avoid secret disclosure without SensitiveData and other enhancements
207
+ if value is None:
208
+ truncated_value = None
209
+ annotated_source_lines = []
210
+ else:
211
+ # DTFIX-FUTURE: cleanup/share width
212
+ try:
213
+ value = str(value)
214
+ except Exception as ex:
215
+ value = f'<< context unavailable: {ex} >>'
216
+
217
+ truncated_value = textwrap.shorten(value, width=120)
218
+ annotated_source_lines = [truncated_value]
219
+
220
+ return SourceContext(
221
+ origin=origin or Origin.UNKNOWN,
222
+ annotated_source_lines=annotated_source_lines,
223
+ target_line=truncated_value,
224
+ )
225
+
226
+ @staticmethod
227
+ def error(message: str | None, origin: Origin | None = None) -> SourceContext:
228
+ return SourceContext(
229
+ origin=origin,
230
+ annotated_source_lines=[f'(source not shown: {message})'] if message else [],
231
+ target_line=None,
232
+ )
233
+
234
+ @classmethod
235
+ def from_origin(cls, origin: Origin) -> SourceContext:
236
+ """Attempt to retrieve source and render a contextual indicator of an error location."""
237
+ from ansible.parsing.vault import is_encrypted # avoid circular import
238
+
239
+ # DTFIX-FUTURE: support referencing the column after the end of the target line, so we can indicate where a missing character (quote) needs to be added
240
+ # this is also useful for cases like end-of-stream reported by the YAML parser
241
+
242
+ # DTFIX-FUTURE: Implement line wrapping and match annotated line width to the terminal display width.
243
+
244
+ context_line_count: t.Final = 2
245
+ max_annotated_line_width: t.Final = 120
246
+ truncation_marker: t.Final = '...'
247
+
248
+ target_line_num = origin.line_num
249
+
250
+ if RedactAnnotatedSourceContext.current(optional=True):
251
+ return cls.error('content redacted', origin)
252
+
253
+ if not target_line_num or target_line_num < 1:
254
+ return cls.error(None, origin) # message omitted since lack of line number is obvious from pos
255
+
256
+ start_line_idx = max(0, (target_line_num - 1) - context_line_count) # if near start of file
257
+ target_col_num = origin.col_num
258
+
259
+ try:
260
+ with pathlib.Path(origin.path).open() as src:
261
+ first_line = src.readline()
262
+ lines = list(itertools.islice(itertools.chain((first_line,), src), start_line_idx, target_line_num))
263
+ except Exception as ex:
264
+ return cls.error(type(ex).__name__, origin)
265
+
266
+ if is_encrypted(first_line):
267
+ return cls.error('content encrypted', origin)
268
+
269
+ if len(lines) != target_line_num - start_line_idx:
270
+ return cls.error('file truncated', origin)
271
+
272
+ annotated_source_lines = []
273
+
274
+ line_label_width = len(str(target_line_num))
275
+ max_src_line_len = max_annotated_line_width - line_label_width - 1
276
+
277
+ usable_line_len = max_src_line_len
278
+
279
+ for line_num, line in enumerate(lines, start_line_idx + 1):
280
+ line = line.rstrip('\n') # universal newline default mode on `open` ensures we'll never see anything but \n
281
+ line = line.replace('\t', ' ') # mixed tab/space handling is intentionally disabled since we're both format and display config agnostic
282
+
283
+ if len(line) > max_src_line_len:
284
+ line = line[: max_src_line_len - len(truncation_marker)] + truncation_marker
285
+ usable_line_len = max_src_line_len - len(truncation_marker)
286
+
287
+ annotated_source_lines.append(f'{str(line_num).rjust(line_label_width)}{" " if line else ""}{line}')
288
+
289
+ if target_col_num and usable_line_len >= target_col_num >= 1:
290
+ column_marker = f'column {target_col_num}'
291
+
292
+ target_col_idx = target_col_num - 1
293
+
294
+ if target_col_idx + 2 + len(column_marker) > max_src_line_len:
295
+ column_marker = f'{" " * (target_col_idx - len(column_marker) - 1)}{column_marker} ^'
296
+ else:
297
+ column_marker = f'{" " * target_col_idx}^ {column_marker}'
298
+
299
+ column_marker = f'{" " * line_label_width} {column_marker}'
300
+
301
+ annotated_source_lines.append(column_marker)
302
+ elif target_col_num is None:
303
+ underline_length = len(annotated_source_lines[-1]) - line_label_width - 1
304
+ annotated_source_lines.append(f'{" " * line_label_width} {"^" * underline_length}')
305
+
306
+ return SourceContext(
307
+ origin=origin,
308
+ annotated_source_lines=annotated_source_lines,
309
+ target_line=lines[-1].rstrip('\n'), # universal newline default mode on `open` ensures we'll never see anything but \n
310
+ )
@@ -0,0 +1,203 @@
1
+ """Internal utilities for serialization and deserialization."""
2
+
3
+ # DTFIX-RELEASE: most of this isn't JSON specific, find a better home
4
+
5
+ from __future__ import annotations
6
+
7
+ import enum
8
+ import json
9
+ import typing as t
10
+
11
+ from ansible.errors import AnsibleVariableTypeError
12
+
13
+ from ansible.module_utils._internal._datatag import (
14
+ _ANSIBLE_ALLOWED_MAPPING_VAR_TYPES,
15
+ _ANSIBLE_ALLOWED_NON_SCALAR_COLLECTION_VAR_TYPES,
16
+ _ANSIBLE_ALLOWED_VAR_TYPES,
17
+ _AnsibleTaggedStr,
18
+ AnsibleTagHelper,
19
+ )
20
+ from ansible.module_utils._internal._json._profiles import _tagless
21
+ from ansible.parsing.vault import EncryptedString
22
+ from ansible._internal._datatag._tags import Origin, TrustedAsTemplate
23
+ from ansible._internal._templating import _transform
24
+ from ansible.module_utils import _internal
25
+ from ansible.module_utils._internal import _datatag
26
+
27
+ _T = t.TypeVar('_T')
28
+ _sentinel = object()
29
+
30
+
31
+ class HasCurrent(t.Protocol):
32
+ """Utility protocol for mixin type safety."""
33
+
34
+ _current: t.Any
35
+
36
+
37
+ class StateTrackingMixIn(HasCurrent):
38
+ """Mixin for use with `AnsibleVariableVisitor` to track current visitation context."""
39
+
40
+ def __init__(self, *args, **kwargs) -> None:
41
+ super().__init__(*args, **kwargs)
42
+
43
+ self._stack: list[t.Any] = []
44
+
45
+ def __enter__(self) -> None:
46
+ self._stack.append(self._current)
47
+
48
+ def __exit__(self, *_args, **_kwargs) -> None:
49
+ self._stack.pop()
50
+
51
+ def _get_stack(self) -> list[t.Any]:
52
+ if not self._stack:
53
+ return []
54
+
55
+ return self._stack[1:] + [self._current]
56
+
57
+
58
+ class EncryptedStringBehavior(enum.Enum):
59
+ """How `AnsibleVariableVisitor` will handle instances of `EncryptedString`."""
60
+
61
+ PRESERVE = enum.auto()
62
+ """Preserves the unmodified `EncryptedString` instance."""
63
+ DECRYPT = enum.auto()
64
+ """Replaces the value with its decrypted plaintext."""
65
+ REDACT = enum.auto()
66
+ """Replaces the value with a placeholder string."""
67
+ FAIL = enum.auto()
68
+ """Raises an `AnsibleVariableTypeError` error."""
69
+
70
+
71
+ class AnsibleVariableVisitor:
72
+ """Utility visitor base class to recursively apply various behaviors and checks to variable object graphs."""
73
+
74
+ def __init__(
75
+ self,
76
+ *,
77
+ trusted_as_template: bool = False,
78
+ origin: Origin | None = None,
79
+ convert_mapping_to_dict: bool = False,
80
+ convert_sequence_to_list: bool = False,
81
+ convert_custom_scalars: bool = False,
82
+ convert_to_native_values: bool = False,
83
+ apply_transforms: bool = False,
84
+ encrypted_string_behavior: EncryptedStringBehavior = EncryptedStringBehavior.DECRYPT,
85
+ ):
86
+ super().__init__() # supports StateTrackingMixIn
87
+
88
+ self.trusted_as_template = trusted_as_template
89
+ self.origin = origin
90
+ self.convert_mapping_to_dict = convert_mapping_to_dict
91
+ self.convert_sequence_to_list = convert_sequence_to_list
92
+ self.convert_custom_scalars = convert_custom_scalars
93
+ self.convert_to_native_values = convert_to_native_values
94
+ self.apply_transforms = apply_transforms
95
+ self.encrypted_string_behavior = encrypted_string_behavior
96
+
97
+ if apply_transforms:
98
+ from ansible._internal._templating import _engine
99
+
100
+ self._template_engine = _engine.TemplateEngine()
101
+ else:
102
+ self._template_engine = None
103
+
104
+ self._current: t.Any = None # supports StateTrackingMixIn
105
+
106
+ def __enter__(self) -> t.Any:
107
+ """No-op context manager dispatcher (delegates to mixin behavior if present)."""
108
+ if func := getattr(super(), '__enter__', None):
109
+ func()
110
+
111
+ def __exit__(self, *args, **kwargs) -> t.Any:
112
+ """No-op context manager dispatcher (delegates to mixin behavior if present)."""
113
+ if func := getattr(super(), '__exit__', None):
114
+ func(*args, **kwargs)
115
+
116
+ def visit(self, value: _T) -> _T:
117
+ """
118
+ Enforces Ansible's variable type system restrictions before a var is accepted in inventory. Also, conditionally implements template trust
119
+ compatibility, depending on the plugin's declared understanding (or lack thereof). This always recursively copies inputs to fully isolate
120
+ inventory data from what the plugin provided, and prevent any later mutation.
121
+ """
122
+ return self._visit(None, value)
123
+
124
+ def _early_visit(self, value, value_type) -> t.Any:
125
+ """Overridable hook point to allow custom string handling in derived visitors."""
126
+ if value_type in (str, _AnsibleTaggedStr):
127
+ # apply compatibility behavior
128
+ if self.trusted_as_template:
129
+ result = TrustedAsTemplate().tag(value)
130
+ else:
131
+ result = value
132
+ else:
133
+ result = _sentinel
134
+
135
+ return result
136
+
137
+ def _visit(self, key: t.Any, value: _T) -> _T:
138
+ """Internal implementation to recursively visit a data structure's contents."""
139
+ self._current = key # supports StateTrackingMixIn
140
+
141
+ value_type = type(value)
142
+
143
+ if self.apply_transforms and value_type in _transform._type_transform_mapping:
144
+ value = self._template_engine.transform(value)
145
+ value_type = type(value)
146
+
147
+ # DTFIX-RELEASE: need to handle native copy for keys too
148
+ if self.convert_to_native_values and isinstance(value, _datatag.AnsibleTaggedObject):
149
+ value = value._native_copy()
150
+ value_type = type(value)
151
+
152
+ result: _T
153
+
154
+ # DTFIX-RELEASE: the visitor is ignoring dict/mapping keys except for debugging and schema-aware checking, it should be doing type checks on keys
155
+ # keep in mind the allowed types for keys is a more restrictive set than for values (str and taggged str only, not EncryptedString)
156
+ # DTFIX-RELEASE: some type lists being consulted (the ones from datatag) are probably too permissive, and perhaps should not be dynamic
157
+
158
+ if (result := self._early_visit(value, value_type)) is not _sentinel:
159
+ pass
160
+ # DTFIX-RELEASE: de-duplicate and optimize; extract inline generator expressions and fallback function or mapping for native type calculation?
161
+ elif value_type in _ANSIBLE_ALLOWED_MAPPING_VAR_TYPES: # check mappings first, because they're also collections
162
+ with self: # supports StateTrackingMixIn
163
+ result = AnsibleTagHelper.tag_copy(value, ((k, self._visit(k, v)) for k, v in value.items()), value_type=value_type)
164
+ elif value_type in _ANSIBLE_ALLOWED_NON_SCALAR_COLLECTION_VAR_TYPES:
165
+ with self: # supports StateTrackingMixIn
166
+ result = AnsibleTagHelper.tag_copy(value, (self._visit(k, v) for k, v in enumerate(t.cast(t.Iterable, value))), value_type=value_type)
167
+ elif self.encrypted_string_behavior != EncryptedStringBehavior.FAIL and isinstance(value, EncryptedString):
168
+ match self.encrypted_string_behavior:
169
+ case EncryptedStringBehavior.REDACT:
170
+ result = "<redacted>" # type: ignore[assignment]
171
+ case EncryptedStringBehavior.PRESERVE:
172
+ result = value # type: ignore[assignment]
173
+ case EncryptedStringBehavior.DECRYPT:
174
+ result = str(value) # type: ignore[assignment]
175
+ elif self.convert_mapping_to_dict and _internal.is_intermediate_mapping(value):
176
+ with self: # supports StateTrackingMixIn
177
+ result = {k: self._visit(k, v) for k, v in value.items()} # type: ignore[assignment]
178
+ elif self.convert_sequence_to_list and _internal.is_intermediate_iterable(value):
179
+ with self: # supports StateTrackingMixIn
180
+ result = [self._visit(k, v) for k, v in enumerate(t.cast(t.Iterable, value))] # type: ignore[assignment]
181
+ elif self.convert_custom_scalars and isinstance(value, str):
182
+ result = str(value) # type: ignore[assignment]
183
+ elif self.convert_custom_scalars and isinstance(value, float):
184
+ result = float(value) # type: ignore[assignment]
185
+ elif self.convert_custom_scalars and isinstance(value, int) and not isinstance(value, bool):
186
+ result = int(value) # type: ignore[assignment]
187
+ else:
188
+ if value_type not in _ANSIBLE_ALLOWED_VAR_TYPES:
189
+ raise AnsibleVariableTypeError.from_value(obj=value)
190
+
191
+ # supported scalar type that requires no special handling, just return as-is
192
+ result = value
193
+
194
+ if self.origin and not Origin.is_tagged_on(result):
195
+ # apply shared instance default origin tag
196
+ result = self.origin.tag(result)
197
+
198
+ return result
199
+
200
+
201
+ def json_dumps_formatted(value: object) -> str:
202
+ """Return a JSON dump of `value` with formatting and keys sorted."""
203
+ return json.dumps(value, cls=_tagless.Encoder, sort_keys=True, indent=4)
@@ -0,0 +1,34 @@
1
+ from __future__ import annotations as _annotations
2
+
3
+ import typing as _t
4
+
5
+ from ansible.module_utils._internal._json import _profiles
6
+ from ansible._internal._json._profiles import _legacy
7
+ from ansible.parsing import vault as _vault
8
+
9
+
10
+ class LegacyControllerJSONEncoder(_legacy.Encoder):
11
+ """Compatibility wrapper over `legacy` profile JSON encoder to support trust stripping and vault value plaintext conversion."""
12
+
13
+ def __init__(self, preprocess_unsafe: bool = False, vault_to_text: bool = False, _decode_bytes: bool = False, **kwargs) -> None:
14
+ self._preprocess_unsafe = preprocess_unsafe
15
+ self._vault_to_text = vault_to_text
16
+ self._decode_bytes = _decode_bytes
17
+
18
+ super().__init__(**kwargs)
19
+
20
+ def default(self, o: _t.Any) -> _t.Any:
21
+ """Hooked default that can conditionally bypass base encoder behavior based on this instance's config."""
22
+ if type(o) is _profiles._WrappedValue: # pylint: disable=unidiomatic-typecheck
23
+ o = o.wrapped
24
+
25
+ if not self._preprocess_unsafe and type(o) is _legacy._Untrusted: # pylint: disable=unidiomatic-typecheck
26
+ return o.value # if not emitting unsafe markers, bypass custom unsafe serialization and just return the raw value
27
+
28
+ if self._vault_to_text and type(o) is _vault.EncryptedString: # pylint: disable=unidiomatic-typecheck
29
+ return str(o) # decrypt and return the plaintext (or fail trying)
30
+
31
+ if self._decode_bytes and isinstance(o, bytes):
32
+ return o.decode(errors='surrogateescape') # backward compatibility with `ansible.module_utils.basic.jsonify`
33
+
34
+ return super().default(o)
File without changes