ansible-core 2.18.7__py3-none-any.whl → 2.19.0__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.

Potentially problematic release.


This version of ansible-core might be problematic. Click here for more details.

Files changed (757) hide show
  1. ansible/_internal/__init__.py +53 -0
  2. ansible/_internal/_ansiballz/__init__.py +0 -0
  3. ansible/_internal/_ansiballz/_builder.py +101 -0
  4. ansible/_internal/_ansiballz/_wrapper.py +262 -0
  5. ansible/_internal/_collection_proxy.py +47 -0
  6. ansible/_internal/_datatag/__init__.py +0 -0
  7. ansible/_internal/_datatag/_tags.py +130 -0
  8. ansible/_internal/_datatag/_utils.py +19 -0
  9. ansible/_internal/_datatag/_wrappers.py +33 -0
  10. ansible/_internal/_errors/__init__.py +0 -0
  11. ansible/_internal/_errors/_alarm_timeout.py +66 -0
  12. ansible/_internal/_errors/_captured.py +123 -0
  13. ansible/_internal/_errors/_error_factory.py +89 -0
  14. ansible/_internal/_errors/_error_utils.py +240 -0
  15. ansible/_internal/_errors/_handler.py +91 -0
  16. ansible/_internal/_errors/_task_timeout.py +28 -0
  17. ansible/_internal/_event_formatting.py +127 -0
  18. ansible/_internal/_json/__init__.py +214 -0
  19. ansible/_internal/_json/_legacy_encoder.py +34 -0
  20. ansible/_internal/_json/_profiles/__init__.py +0 -0
  21. ansible/_internal/_json/_profiles/_cache_persistence.py +57 -0
  22. ansible/_internal/_json/_profiles/_inventory_legacy.py +40 -0
  23. ansible/_internal/_json/_profiles/_legacy.py +189 -0
  24. ansible/_internal/_locking.py +21 -0
  25. ansible/_internal/_plugins/__init__.py +0 -0
  26. ansible/_internal/_plugins/_cache.py +57 -0
  27. ansible/_internal/_ssh/__init__.py +0 -0
  28. ansible/_internal/_ssh/_agent_launch.py +91 -0
  29. ansible/_internal/_ssh/_ssh_agent.py +619 -0
  30. ansible/_internal/_task.py +78 -0
  31. ansible/_internal/_templating/__init__.py +12 -0
  32. ansible/_internal/_templating/_access.py +86 -0
  33. ansible/_internal/_templating/_chain_templar.py +63 -0
  34. ansible/_internal/_templating/_datatag.py +95 -0
  35. ansible/_internal/_templating/_engine.py +592 -0
  36. ansible/_internal/_templating/_errors.py +28 -0
  37. ansible/_internal/_templating/_jinja_bits.py +1106 -0
  38. ansible/_internal/_templating/_jinja_common.py +323 -0
  39. ansible/_internal/_templating/_jinja_patches.py +44 -0
  40. ansible/_internal/_templating/_jinja_plugins.py +375 -0
  41. ansible/_internal/_templating/_lazy_containers.py +633 -0
  42. ansible/_internal/_templating/_marker_behaviors.py +103 -0
  43. ansible/_internal/_templating/_template_vars.py +72 -0
  44. ansible/_internal/_templating/_transform.py +70 -0
  45. ansible/_internal/_templating/_utils.py +108 -0
  46. ansible/_internal/_testing.py +26 -0
  47. ansible/_internal/_wrapt.py +1052 -0
  48. ansible/_internal/_yaml/__init__.py +0 -0
  49. ansible/_internal/_yaml/_constructor.py +240 -0
  50. ansible/_internal/_yaml/_dumper.py +70 -0
  51. ansible/_internal/_yaml/_errors.py +166 -0
  52. ansible/_internal/_yaml/_loader.py +66 -0
  53. ansible/_internal/ansible_collections/ansible/_protomatter/README.md +11 -0
  54. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/debug.py +36 -0
  55. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/apply_trust.py +19 -0
  56. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/dump_object.py +27 -0
  57. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/finalize.py +16 -0
  58. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/origin.py +18 -0
  59. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.py +24 -0
  60. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.yml +33 -0
  61. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/tag_names.py +16 -0
  62. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +17 -0
  63. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +49 -0
  64. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.py +21 -0
  65. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.yml +2 -0
  66. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.py +15 -0
  67. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.yml +19 -0
  68. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.py +18 -0
  69. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.yml +19 -0
  70. ansible/cli/__init__.py +93 -104
  71. ansible/cli/_ssh_askpass.py +54 -0
  72. ansible/cli/adhoc.py +20 -10
  73. ansible/cli/arguments/option_helpers.py +163 -10
  74. ansible/cli/config.py +43 -68
  75. ansible/cli/console.py +13 -11
  76. ansible/cli/doc.py +134 -77
  77. ansible/cli/galaxy.py +27 -20
  78. ansible/cli/inventory.py +28 -28
  79. ansible/cli/playbook.py +4 -12
  80. ansible/cli/pull.py +6 -3
  81. ansible/cli/scripts/ansible_connection_cli_stub.py +7 -7
  82. ansible/cli/vault.py +12 -11
  83. ansible/compat/__init__.py +2 -2
  84. ansible/compat/importlib_resources.py +9 -12
  85. ansible/config/base.yml +218 -133
  86. ansible/config/manager.py +220 -159
  87. ansible/constants.py +2 -65
  88. ansible/errors/__init__.py +350 -256
  89. ansible/executor/interpreter_discovery.py +28 -149
  90. ansible/executor/module_common.py +480 -514
  91. ansible/executor/play_iterator.py +22 -27
  92. ansible/executor/playbook_executor.py +11 -11
  93. ansible/executor/powershell/async_watchdog.ps1 +97 -102
  94. ansible/executor/powershell/async_wrapper.ps1 +204 -153
  95. ansible/executor/powershell/become_wrapper.ps1 +107 -144
  96. ansible/executor/powershell/bootstrap_wrapper.ps1 +46 -9
  97. ansible/executor/powershell/coverage_wrapper.ps1 +91 -135
  98. ansible/executor/powershell/exec_wrapper.ps1 +675 -196
  99. ansible/executor/powershell/module_manifest.py +469 -265
  100. ansible/executor/powershell/module_wrapper.ps1 +195 -186
  101. ansible/executor/powershell/powershell_expand_user.ps1 +20 -0
  102. ansible/executor/powershell/powershell_mkdtemp.ps1 +17 -0
  103. ansible/executor/powershell/psrp_fetch_file.ps1 +41 -0
  104. ansible/executor/powershell/psrp_put_file.ps1 +122 -0
  105. ansible/executor/powershell/winrm_fetch_file.ps1 +46 -0
  106. ansible/executor/powershell/winrm_put_file.ps1 +36 -0
  107. ansible/executor/process/worker.py +139 -149
  108. ansible/executor/stats.py +5 -5
  109. ansible/executor/task_executor.py +270 -297
  110. ansible/executor/task_queue_manager.py +135 -137
  111. ansible/executor/task_result.py +182 -79
  112. ansible/galaxy/__init__.py +2 -2
  113. ansible/galaxy/api.py +26 -25
  114. ansible/galaxy/collection/__init__.py +6 -14
  115. ansible/galaxy/collection/concrete_artifact_manager.py +12 -21
  116. ansible/galaxy/dependency_resolution/dataclasses.py +14 -4
  117. ansible/galaxy/dependency_resolution/providers.py +4 -4
  118. ansible/galaxy/dependency_resolution/reporters.py +81 -0
  119. ansible/galaxy/role.py +6 -10
  120. ansible/galaxy/token.py +28 -21
  121. ansible/inventory/data.py +47 -57
  122. ansible/inventory/group.py +50 -73
  123. ansible/inventory/helpers.py +9 -0
  124. ansible/inventory/host.py +37 -54
  125. ansible/inventory/manager.py +79 -34
  126. ansible/keyword_desc.yml +1 -1
  127. ansible/module_utils/_internal/__init__.py +55 -0
  128. ansible/module_utils/_internal/_ambient_context.py +58 -0
  129. ansible/module_utils/_internal/_ansiballz/__init__.py +0 -0
  130. ansible/module_utils/_internal/_ansiballz/_extensions/__init__.py +0 -0
  131. ansible/module_utils/_internal/_ansiballz/_extensions/_coverage.py +45 -0
  132. ansible/module_utils/_internal/_ansiballz/_extensions/_pydevd.py +62 -0
  133. ansible/module_utils/_internal/_ansiballz/_loader.py +81 -0
  134. ansible/module_utils/_internal/_ansiballz/_respawn.py +32 -0
  135. ansible/module_utils/_internal/_ansiballz/_respawn_wrapper.py +23 -0
  136. ansible/module_utils/_internal/_concurrent/_daemon_threading.py +1 -0
  137. ansible/module_utils/_internal/_dataclass_validation.py +217 -0
  138. ansible/module_utils/_internal/_datatag/__init__.py +961 -0
  139. ansible/module_utils/_internal/_datatag/_tags.py +16 -0
  140. ansible/module_utils/_internal/_debugging.py +31 -0
  141. ansible/module_utils/_internal/_deprecator.py +157 -0
  142. ansible/module_utils/_internal/_errors.py +101 -0
  143. ansible/module_utils/_internal/_event_utils.py +61 -0
  144. ansible/module_utils/_internal/_json/__init__.py +63 -0
  145. ansible/module_utils/_internal/_json/_legacy_encoder.py +26 -0
  146. ansible/module_utils/_internal/_json/_profiles/__init__.py +428 -0
  147. ansible/module_utils/_internal/_json/_profiles/_fallback_to_str.py +73 -0
  148. ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +33 -0
  149. ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +37 -0
  150. ansible/module_utils/_internal/_json/_profiles/_module_modern_c2m.py +35 -0
  151. ansible/module_utils/_internal/_json/_profiles/_module_modern_m2c.py +33 -0
  152. ansible/module_utils/_internal/_json/_profiles/_tagless.py +52 -0
  153. ansible/module_utils/_internal/_messages.py +130 -0
  154. ansible/module_utils/_internal/_patches/__init__.py +66 -0
  155. ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +53 -0
  156. ansible/module_utils/_internal/_patches/_socket_patch.py +34 -0
  157. ansible/module_utils/_internal/_patches/_sys_intern_patch.py +34 -0
  158. ansible/module_utils/_internal/_plugin_info.py +38 -0
  159. ansible/module_utils/_internal/_stack.py +22 -0
  160. ansible/module_utils/_internal/_testing.py +0 -0
  161. ansible/module_utils/_internal/_text_utils.py +6 -0
  162. ansible/module_utils/_internal/_traceback.py +92 -0
  163. ansible/module_utils/_internal/_validation.py +14 -0
  164. ansible/module_utils/ansible_release.py +2 -2
  165. ansible/module_utils/api.py +1 -2
  166. ansible/module_utils/basic.py +303 -202
  167. ansible/module_utils/common/_utils.py +24 -28
  168. ansible/module_utils/common/arg_spec.py +8 -3
  169. ansible/module_utils/common/collections.py +7 -2
  170. ansible/module_utils/common/dict_transformations.py +2 -2
  171. ansible/module_utils/common/file.py +2 -2
  172. ansible/module_utils/common/json.py +90 -84
  173. ansible/module_utils/common/locale.py +2 -2
  174. ansible/module_utils/common/parameters.py +27 -24
  175. ansible/module_utils/common/process.py +2 -3
  176. ansible/module_utils/common/respawn.py +11 -33
  177. ansible/module_utils/common/sentinel.py +66 -0
  178. ansible/module_utils/common/sys_info.py +8 -8
  179. ansible/module_utils/common/text/converters.py +16 -37
  180. ansible/module_utils/common/validation.py +35 -24
  181. ansible/module_utils/common/warnings.py +143 -25
  182. ansible/module_utils/common/yaml.py +29 -3
  183. ansible/module_utils/compat/datetime.py +33 -21
  184. ansible/module_utils/compat/paramiko.py +21 -10
  185. ansible/module_utils/compat/typing.py +6 -5
  186. ansible/module_utils/connection.py +10 -13
  187. ansible/module_utils/csharp/Ansible.Basic.cs +15 -12
  188. ansible/module_utils/csharp/Ansible.Become.cs +1 -0
  189. ansible/module_utils/csharp/Ansible.Privilege.cs +2 -2
  190. ansible/module_utils/csharp/Ansible._Async.cs +517 -0
  191. ansible/module_utils/datatag.py +49 -0
  192. ansible/module_utils/distro/__init__.py +2 -2
  193. ansible/module_utils/facts/ansible_collector.py +4 -5
  194. ansible/module_utils/facts/collector.py +13 -14
  195. ansible/module_utils/facts/compat.py +4 -4
  196. ansible/module_utils/facts/default_collectors.py +1 -1
  197. ansible/module_utils/facts/hardware/aix.py +34 -0
  198. ansible/module_utils/facts/hardware/base.py +2 -2
  199. ansible/module_utils/facts/hardware/darwin.py +1 -3
  200. ansible/module_utils/facts/hardware/freebsd.py +2 -2
  201. ansible/module_utils/facts/hardware/linux.py +5 -5
  202. ansible/module_utils/facts/namespace.py +1 -1
  203. ansible/module_utils/facts/network/base.py +1 -1
  204. ansible/module_utils/facts/network/fc_wwn.py +1 -2
  205. ansible/module_utils/facts/network/iscsi.py +1 -2
  206. ansible/module_utils/facts/network/nvme.py +1 -2
  207. ansible/module_utils/facts/other/facter.py +2 -3
  208. ansible/module_utils/facts/other/ohai.py +2 -3
  209. ansible/module_utils/facts/sysctl.py +4 -6
  210. ansible/module_utils/facts/system/apparmor.py +1 -2
  211. ansible/module_utils/facts/system/caps.py +3 -3
  212. ansible/module_utils/facts/system/chroot.py +1 -2
  213. ansible/module_utils/facts/system/cmdline.py +1 -2
  214. ansible/module_utils/facts/system/date_time.py +5 -3
  215. ansible/module_utils/facts/system/distribution.py +27 -13
  216. ansible/module_utils/facts/system/dns.py +1 -1
  217. ansible/module_utils/facts/system/env.py +1 -2
  218. ansible/module_utils/facts/system/fips.py +7 -20
  219. ansible/module_utils/facts/system/loadavg.py +1 -2
  220. ansible/module_utils/facts/system/local.py +2 -3
  221. ansible/module_utils/facts/system/lsb.py +1 -2
  222. ansible/module_utils/facts/system/pkg_mgr.py +1 -2
  223. ansible/module_utils/facts/system/platform.py +1 -2
  224. ansible/module_utils/facts/system/python.py +1 -2
  225. ansible/module_utils/facts/system/selinux.py +1 -1
  226. ansible/module_utils/facts/system/service_mgr.py +1 -2
  227. ansible/module_utils/facts/system/ssh_pub_keys.py +1 -1
  228. ansible/module_utils/facts/system/systemd.py +1 -1
  229. ansible/module_utils/facts/system/user.py +1 -2
  230. ansible/module_utils/facts/utils.py +3 -3
  231. ansible/module_utils/facts/virtual/base.py +1 -1
  232. ansible/module_utils/facts/virtual/linux.py +3 -3
  233. ansible/module_utils/facts/virtual/sunos.py +3 -15
  234. ansible/module_utils/facts/virtual/sysctl.py +3 -16
  235. ansible/module_utils/json_utils.py +2 -2
  236. ansible/module_utils/parsing/convert_bool.py +7 -1
  237. ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 +1 -1
  238. ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 +1 -1
  239. ansible/module_utils/powershell/Ansible.ModuleUtils.CommandUtil.psm1 +1 -1
  240. ansible/module_utils/powershell/Ansible.ModuleUtils.WebRequest.psm1 +1 -1
  241. ansible/module_utils/service.py +21 -31
  242. ansible/module_utils/splitter.py +7 -7
  243. ansible/module_utils/testing.py +31 -0
  244. ansible/module_utils/urls.py +64 -35
  245. ansible/modules/add_host.py +4 -4
  246. ansible/modules/apt.py +69 -49
  247. ansible/modules/apt_key.py +19 -12
  248. ansible/modules/apt_repository.py +32 -51
  249. ansible/modules/assemble.py +16 -14
  250. ansible/modules/assert.py +4 -4
  251. ansible/modules/async_status.py +24 -24
  252. ansible/modules/async_wrapper.py +20 -25
  253. ansible/modules/blockinfile.py +6 -7
  254. ansible/modules/command.py +13 -20
  255. ansible/modules/copy.py +60 -147
  256. ansible/modules/cron.py +24 -21
  257. ansible/modules/deb822_repository.py +8 -9
  258. ansible/modules/debconf.py +5 -5
  259. ansible/modules/debug.py +4 -4
  260. ansible/modules/dnf.py +8 -8
  261. ansible/modules/dnf5.py +39 -13
  262. ansible/modules/dpkg_selections.py +4 -4
  263. ansible/modules/expect.py +13 -15
  264. ansible/modules/fail.py +4 -4
  265. ansible/modules/fetch.py +4 -4
  266. ansible/modules/file.py +184 -144
  267. ansible/modules/find.py +22 -20
  268. ansible/modules/gather_facts.py +3 -3
  269. ansible/modules/get_url.py +77 -54
  270. ansible/modules/getent.py +7 -9
  271. ansible/modules/git.py +38 -38
  272. ansible/modules/group.py +6 -6
  273. ansible/modules/group_by.py +4 -4
  274. ansible/modules/hostname.py +15 -32
  275. ansible/modules/import_playbook.py +6 -6
  276. ansible/modules/import_role.py +6 -6
  277. ansible/modules/import_tasks.py +6 -6
  278. ansible/modules/include_role.py +6 -6
  279. ansible/modules/include_tasks.py +6 -6
  280. ansible/modules/include_vars.py +6 -6
  281. ansible/modules/iptables.py +86 -73
  282. ansible/modules/known_hosts.py +22 -24
  283. ansible/modules/lineinfile.py +5 -5
  284. ansible/modules/meta.py +4 -4
  285. ansible/modules/mount_facts.py +2 -2
  286. ansible/modules/package.py +10 -4
  287. ansible/modules/package_facts.py +22 -10
  288. ansible/modules/pause.py +6 -6
  289. ansible/modules/ping.py +6 -6
  290. ansible/modules/pip.py +21 -26
  291. ansible/modules/raw.py +6 -6
  292. ansible/modules/reboot.py +6 -6
  293. ansible/modules/replace.py +10 -14
  294. ansible/modules/rpm_key.py +7 -8
  295. ansible/modules/script.py +4 -4
  296. ansible/modules/service.py +10 -17
  297. ansible/modules/service_facts.py +87 -10
  298. ansible/modules/set_fact.py +5 -5
  299. ansible/modules/set_stats.py +4 -4
  300. ansible/modules/setup.py +2 -2
  301. ansible/modules/shell.py +6 -6
  302. ansible/modules/slurp.py +16 -19
  303. ansible/modules/stat.py +15 -31
  304. ansible/modules/subversion.py +15 -15
  305. ansible/modules/systemd.py +7 -7
  306. ansible/modules/systemd_service.py +7 -7
  307. ansible/modules/sysvinit.py +9 -9
  308. ansible/modules/tempfile.py +5 -6
  309. ansible/modules/template.py +6 -6
  310. ansible/modules/unarchive.py +38 -17
  311. ansible/modules/uri.py +33 -26
  312. ansible/modules/user.py +45 -32
  313. ansible/modules/validate_argument_spec.py +10 -7
  314. ansible/modules/wait_for.py +70 -60
  315. ansible/modules/wait_for_connection.py +6 -6
  316. ansible/modules/yum_repository.py +10 -9
  317. ansible/parsing/ajson.py +17 -37
  318. ansible/parsing/dataloader.py +99 -54
  319. ansible/parsing/mod_args.py +62 -60
  320. ansible/parsing/plugin_docs.py +21 -86
  321. ansible/parsing/quoting.py +1 -1
  322. ansible/parsing/splitter.py +27 -12
  323. ansible/parsing/utils/addresses.py +24 -24
  324. ansible/parsing/utils/jsonify.py +5 -1
  325. ansible/parsing/utils/yaml.py +32 -61
  326. ansible/parsing/vault/__init__.py +327 -99
  327. ansible/parsing/yaml/__init__.py +0 -18
  328. ansible/parsing/yaml/dumper.py +6 -120
  329. ansible/parsing/yaml/loader.py +6 -39
  330. ansible/parsing/yaml/objects.py +43 -335
  331. ansible/playbook/__init__.py +1 -1
  332. ansible/playbook/attribute.py +8 -3
  333. ansible/playbook/base.py +187 -134
  334. ansible/playbook/block.py +26 -24
  335. ansible/playbook/collectionsearch.py +1 -15
  336. ansible/playbook/conditional.py +3 -77
  337. ansible/playbook/handler.py +8 -2
  338. ansible/playbook/helpers.py +41 -53
  339. ansible/playbook/included_file.py +32 -26
  340. ansible/playbook/loop_control.py +2 -2
  341. ansible/playbook/play.py +85 -44
  342. ansible/playbook/play_context.py +14 -17
  343. ansible/playbook/playbook_include.py +27 -62
  344. ansible/playbook/role/__init__.py +64 -49
  345. ansible/playbook/role/definition.py +15 -17
  346. ansible/playbook/role/include.py +2 -4
  347. ansible/playbook/role/metadata.py +10 -11
  348. ansible/playbook/role_include.py +3 -3
  349. ansible/playbook/taggable.py +28 -12
  350. ansible/playbook/task.py +192 -121
  351. ansible/playbook/task_include.py +5 -5
  352. ansible/plugins/__init__.py +58 -26
  353. ansible/plugins/action/__init__.py +188 -186
  354. ansible/plugins/action/add_host.py +2 -2
  355. ansible/plugins/action/assemble.py +11 -18
  356. ansible/plugins/action/assert.py +55 -67
  357. ansible/plugins/action/async_status.py +7 -2
  358. ansible/plugins/action/copy.py +14 -17
  359. ansible/plugins/action/debug.py +37 -31
  360. ansible/plugins/action/dnf.py +3 -4
  361. ansible/plugins/action/fail.py +1 -1
  362. ansible/plugins/action/fetch.py +7 -8
  363. ansible/plugins/action/gather_facts.py +13 -14
  364. ansible/plugins/action/group_by.py +1 -1
  365. ansible/plugins/action/include_vars.py +10 -11
  366. ansible/plugins/action/package.py +8 -14
  367. ansible/plugins/action/pause.py +2 -2
  368. ansible/plugins/action/script.py +27 -38
  369. ansible/plugins/action/service.py +9 -18
  370. ansible/plugins/action/set_fact.py +3 -12
  371. ansible/plugins/action/set_stats.py +3 -8
  372. ansible/plugins/action/template.py +47 -67
  373. ansible/plugins/action/unarchive.py +6 -16
  374. ansible/plugins/action/uri.py +9 -20
  375. ansible/plugins/action/validate_argument_spec.py +5 -5
  376. ansible/plugins/action/wait_for_connection.py +1 -1
  377. ansible/plugins/become/__init__.py +31 -8
  378. ansible/plugins/become/runas.py +71 -0
  379. ansible/plugins/become/su.py +13 -8
  380. ansible/plugins/become/sudo.py +19 -0
  381. ansible/plugins/cache/__init__.py +52 -63
  382. ansible/plugins/cache/base.py +8 -0
  383. ansible/plugins/cache/jsonfile.py +10 -16
  384. ansible/plugins/cache/memory.py +6 -12
  385. ansible/plugins/callback/__init__.py +294 -201
  386. ansible/plugins/callback/default.py +99 -95
  387. ansible/plugins/callback/junit.py +44 -43
  388. ansible/plugins/callback/minimal.py +28 -25
  389. ansible/plugins/callback/oneline.py +34 -21
  390. ansible/plugins/callback/tree.py +27 -16
  391. ansible/plugins/connection/__init__.py +47 -34
  392. ansible/plugins/connection/local.py +156 -60
  393. ansible/plugins/connection/paramiko_ssh.py +34 -24
  394. ansible/plugins/connection/psrp.py +76 -165
  395. ansible/plugins/connection/ssh.py +326 -86
  396. ansible/plugins/connection/winrm.py +62 -141
  397. ansible/plugins/doc_fragments/action_common_attributes.py +14 -14
  398. ansible/plugins/doc_fragments/action_core.py +6 -6
  399. ansible/plugins/doc_fragments/backup.py +2 -2
  400. ansible/plugins/doc_fragments/checksum_common.py +27 -0
  401. ansible/plugins/doc_fragments/constructed.py +8 -4
  402. ansible/plugins/doc_fragments/decrypt.py +2 -2
  403. ansible/plugins/doc_fragments/default_callback.py +2 -2
  404. ansible/plugins/doc_fragments/files.py +2 -2
  405. ansible/plugins/doc_fragments/inventory_cache.py +2 -2
  406. ansible/plugins/doc_fragments/result_format_callback.py +2 -2
  407. ansible/plugins/doc_fragments/return_common.py +2 -2
  408. ansible/plugins/doc_fragments/template_common.py +4 -4
  409. ansible/plugins/doc_fragments/url.py +17 -1
  410. ansible/plugins/doc_fragments/url_windows.py +2 -2
  411. ansible/plugins/doc_fragments/validate.py +2 -2
  412. ansible/plugins/doc_fragments/vars_plugin_staging.py +2 -2
  413. ansible/plugins/filter/__init__.py +6 -2
  414. ansible/plugins/filter/b64decode.yml +22 -0
  415. ansible/plugins/filter/b64encode.yml +22 -0
  416. ansible/plugins/filter/bool.yml +11 -4
  417. ansible/plugins/filter/core.py +245 -120
  418. ansible/plugins/filter/encryption.py +42 -34
  419. ansible/plugins/filter/flatten.yml +3 -2
  420. ansible/plugins/filter/human_to_bytes.yml +1 -1
  421. ansible/plugins/filter/mathstuff.py +30 -37
  422. ansible/plugins/filter/password_hash.yml +8 -0
  423. ansible/plugins/filter/pow.yml +1 -1
  424. ansible/plugins/filter/regex_search.yml +1 -4
  425. ansible/plugins/filter/root.yml +1 -1
  426. ansible/plugins/filter/split.yml +1 -1
  427. ansible/plugins/filter/strftime.yml +3 -3
  428. ansible/plugins/filter/to_nice_yaml.yml +0 -4
  429. ansible/plugins/filter/to_uuid.yml +1 -1
  430. ansible/plugins/filter/to_yaml.yml +0 -4
  431. ansible/plugins/filter/unvault.yml +1 -1
  432. ansible/plugins/filter/urls.py +1 -1
  433. ansible/plugins/filter/urlsplit.py +8 -9
  434. ansible/plugins/filter/vault.yml +14 -9
  435. ansible/plugins/filter/win_basename.yml +6 -1
  436. ansible/plugins/filter/win_dirname.yml +5 -0
  437. ansible/plugins/inventory/__init__.py +107 -86
  438. ansible/plugins/inventory/advanced_host_list.py +7 -5
  439. ansible/plugins/inventory/auto.py +11 -4
  440. ansible/plugins/inventory/constructed.py +21 -24
  441. ansible/plugins/inventory/generator.py +16 -11
  442. ansible/plugins/inventory/host_list.py +7 -5
  443. ansible/plugins/inventory/ini.py +78 -44
  444. ansible/plugins/inventory/script.py +190 -120
  445. ansible/plugins/inventory/toml.py +16 -126
  446. ansible/plugins/inventory/yaml.py +10 -8
  447. ansible/plugins/list.py +72 -19
  448. ansible/plugins/loader.py +383 -198
  449. ansible/plugins/lookup/__init__.py +21 -4
  450. ansible/plugins/lookup/config.py +21 -35
  451. ansible/plugins/lookup/csvfile.py +19 -73
  452. ansible/plugins/lookup/dict.py +1 -6
  453. ansible/plugins/lookup/env.py +12 -9
  454. ansible/plugins/lookup/file.py +5 -8
  455. ansible/plugins/lookup/first_found.py +87 -55
  456. ansible/plugins/lookup/indexed_items.py +1 -10
  457. ansible/plugins/lookup/ini.py +14 -13
  458. ansible/plugins/lookup/items.py +1 -1
  459. ansible/plugins/lookup/lines.py +8 -1
  460. ansible/plugins/lookup/list.py +1 -1
  461. ansible/plugins/lookup/nested.py +2 -18
  462. ansible/plugins/lookup/password.py +5 -5
  463. ansible/plugins/lookup/pipe.py +5 -7
  464. ansible/plugins/lookup/sequence.py +18 -8
  465. ansible/plugins/lookup/subelements.py +1 -4
  466. ansible/plugins/lookup/template.py +47 -36
  467. ansible/plugins/lookup/together.py +0 -12
  468. ansible/plugins/lookup/unvault.py +1 -5
  469. ansible/plugins/lookup/url.py +4 -10
  470. ansible/plugins/lookup/vars.py +16 -24
  471. ansible/plugins/shell/__init__.py +58 -4
  472. ansible/plugins/shell/cmd.py +2 -2
  473. ansible/plugins/shell/powershell.py +106 -31
  474. ansible/plugins/shell/sh.py +13 -7
  475. ansible/plugins/strategy/__init__.py +168 -193
  476. ansible/plugins/strategy/debug.py +2 -2
  477. ansible/plugins/strategy/free.py +16 -31
  478. ansible/plugins/strategy/host_pinned.py +2 -2
  479. ansible/plugins/strategy/linear.py +41 -41
  480. ansible/plugins/terminal/__init__.py +4 -4
  481. ansible/plugins/test/__init__.py +7 -2
  482. ansible/plugins/test/core.py +75 -35
  483. ansible/plugins/test/files.py +1 -1
  484. ansible/plugins/test/finished.yml +1 -1
  485. ansible/plugins/test/mathstuff.py +3 -3
  486. ansible/plugins/test/uri.py +5 -8
  487. ansible/plugins/vars/host_group_vars.py +7 -14
  488. ansible/release.py +2 -2
  489. ansible/template/__init__.py +353 -943
  490. ansible/utils/__init__.py +0 -18
  491. ansible/utils/collection_loader/__init__.py +54 -5
  492. ansible/utils/collection_loader/_collection_config.py +5 -6
  493. ansible/utils/collection_loader/_collection_finder.py +82 -96
  494. ansible/utils/collection_loader/_collection_meta.py +15 -8
  495. ansible/utils/display.py +485 -73
  496. ansible/utils/encrypt.py +27 -19
  497. ansible/utils/fqcn.py +2 -2
  498. ansible/utils/galaxy.py +2 -2
  499. ansible/utils/hashing.py +8 -10
  500. ansible/utils/helpers.py +2 -2
  501. ansible/utils/listify.py +10 -8
  502. ansible/utils/lock.py +2 -2
  503. ansible/utils/path.py +10 -12
  504. ansible/utils/plugin_docs.py +16 -14
  505. ansible/utils/py3compat.py +2 -7
  506. ansible/utils/sentinel.py +4 -62
  507. ansible/utils/singleton.py +2 -0
  508. ansible/utils/ssh_functions.py +6 -2
  509. ansible/utils/unsafe_proxy.py +23 -332
  510. ansible/utils/vars.py +55 -8
  511. ansible/utils/version.py +2 -2
  512. ansible/vars/clean.py +5 -5
  513. ansible/vars/hostvars.py +60 -90
  514. ansible/vars/manager.py +220 -285
  515. ansible/vars/plugins.py +4 -4
  516. ansible/vars/reserved.py +13 -12
  517. {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/METADATA +4 -3
  518. ansible_core-2.19.0.dist-info/RECORD +1097 -0
  519. ansible_core-2.19.0.dist-info/licenses/licenses/BSD-3-Clause.txt +28 -0
  520. ansible_test/_data/completion/docker.txt +7 -7
  521. ansible_test/_data/completion/remote.txt +6 -6
  522. ansible_test/_data/completion/windows.txt +1 -0
  523. ansible_test/_data/requirements/ansible.txt +2 -2
  524. ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
  525. ansible_test/_data/requirements/sanity.changelog.txt +2 -2
  526. ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
  527. ansible_test/_data/requirements/sanity.pep8.txt +1 -1
  528. ansible_test/_data/requirements/sanity.pylint.txt +5 -5
  529. ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
  530. ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
  531. ansible_test/_data/requirements/units.txt +1 -0
  532. ansible_test/_internal/__init__.py +6 -0
  533. ansible_test/_internal/ansible_util.py +3 -1
  534. ansible_test/_internal/become.py +1 -0
  535. ansible_test/_internal/bootstrap.py +1 -0
  536. ansible_test/_internal/cache.py +1 -0
  537. ansible_test/_internal/cgroup.py +1 -0
  538. ansible_test/_internal/ci/__init__.py +1 -0
  539. ansible_test/_internal/ci/azp.py +1 -0
  540. ansible_test/_internal/ci/local.py +1 -0
  541. ansible_test/_internal/classification/__init__.py +1 -0
  542. ansible_test/_internal/classification/common.py +1 -0
  543. ansible_test/_internal/classification/csharp.py +1 -0
  544. ansible_test/_internal/classification/powershell.py +1 -0
  545. ansible_test/_internal/classification/python.py +1 -0
  546. ansible_test/_internal/cli/__init__.py +1 -0
  547. ansible_test/_internal/cli/actions.py +1 -0
  548. ansible_test/_internal/cli/argparsing/__init__.py +1 -0
  549. ansible_test/_internal/cli/argparsing/actions.py +1 -0
  550. ansible_test/_internal/cli/argparsing/argcompletion.py +1 -0
  551. ansible_test/_internal/cli/argparsing/parsers.py +1 -0
  552. ansible_test/_internal/cli/commands/__init__.py +11 -5
  553. ansible_test/_internal/cli/commands/coverage/__init__.py +1 -0
  554. ansible_test/_internal/cli/commands/coverage/analyze/__init__.py +1 -0
  555. ansible_test/_internal/cli/commands/coverage/analyze/targets/__init__.py +1 -0
  556. ansible_test/_internal/cli/commands/coverage/analyze/targets/combine.py +1 -0
  557. ansible_test/_internal/cli/commands/coverage/analyze/targets/expand.py +1 -0
  558. ansible_test/_internal/cli/commands/coverage/analyze/targets/filter.py +1 -0
  559. ansible_test/_internal/cli/commands/coverage/analyze/targets/generate.py +1 -0
  560. ansible_test/_internal/cli/commands/coverage/analyze/targets/missing.py +1 -0
  561. ansible_test/_internal/cli/commands/coverage/combine.py +1 -0
  562. ansible_test/_internal/cli/commands/coverage/erase.py +1 -0
  563. ansible_test/_internal/cli/commands/coverage/html.py +1 -0
  564. ansible_test/_internal/cli/commands/coverage/report.py +1 -0
  565. ansible_test/_internal/cli/commands/coverage/xml.py +1 -0
  566. ansible_test/_internal/cli/commands/env.py +1 -0
  567. ansible_test/_internal/cli/commands/integration/__init__.py +1 -0
  568. ansible_test/_internal/cli/commands/integration/network.py +1 -0
  569. ansible_test/_internal/cli/commands/integration/posix.py +1 -0
  570. ansible_test/_internal/cli/commands/integration/windows.py +1 -0
  571. ansible_test/_internal/cli/commands/sanity.py +9 -0
  572. ansible_test/_internal/cli/commands/shell.py +1 -0
  573. ansible_test/_internal/cli/commands/units.py +1 -0
  574. ansible_test/_internal/cli/compat.py +1 -0
  575. ansible_test/_internal/cli/completers.py +1 -0
  576. ansible_test/_internal/cli/converters.py +1 -0
  577. ansible_test/_internal/cli/environments.py +52 -5
  578. ansible_test/_internal/cli/epilog.py +1 -0
  579. ansible_test/_internal/cli/parsers/__init__.py +1 -0
  580. ansible_test/_internal/cli/parsers/base_argument_parsers.py +1 -0
  581. ansible_test/_internal/cli/parsers/helpers.py +1 -0
  582. ansible_test/_internal/cli/parsers/host_config_parsers.py +1 -0
  583. ansible_test/_internal/cli/parsers/key_value_parsers.py +1 -0
  584. ansible_test/_internal/cli/parsers/value_parsers.py +1 -0
  585. ansible_test/_internal/commands/__init__.py +1 -0
  586. ansible_test/_internal/commands/coverage/__init__.py +3 -2
  587. ansible_test/_internal/commands/coverage/analyze/__init__.py +1 -0
  588. ansible_test/_internal/commands/coverage/analyze/targets/__init__.py +1 -0
  589. ansible_test/_internal/commands/coverage/analyze/targets/combine.py +1 -0
  590. ansible_test/_internal/commands/coverage/analyze/targets/expand.py +1 -0
  591. ansible_test/_internal/commands/coverage/analyze/targets/filter.py +1 -0
  592. ansible_test/_internal/commands/coverage/analyze/targets/generate.py +1 -0
  593. ansible_test/_internal/commands/coverage/analyze/targets/missing.py +1 -0
  594. ansible_test/_internal/commands/coverage/combine.py +2 -1
  595. ansible_test/_internal/commands/coverage/erase.py +1 -0
  596. ansible_test/_internal/commands/coverage/html.py +1 -0
  597. ansible_test/_internal/commands/coverage/report.py +1 -0
  598. ansible_test/_internal/commands/coverage/xml.py +1 -0
  599. ansible_test/_internal/commands/env/__init__.py +2 -0
  600. ansible_test/_internal/commands/integration/__init__.py +22 -5
  601. ansible_test/_internal/commands/integration/cloud/__init__.py +1 -0
  602. ansible_test/_internal/commands/integration/cloud/acme.py +2 -1
  603. ansible_test/_internal/commands/integration/cloud/aws.py +1 -0
  604. ansible_test/_internal/commands/integration/cloud/azure.py +1 -0
  605. ansible_test/_internal/commands/integration/cloud/cs.py +1 -0
  606. ansible_test/_internal/commands/integration/cloud/digitalocean.py +1 -0
  607. ansible_test/_internal/commands/integration/cloud/galaxy.py +3 -2
  608. ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -0
  609. ansible_test/_internal/commands/integration/cloud/httptester.py +3 -2
  610. ansible_test/_internal/commands/integration/cloud/nios.py +2 -1
  611. ansible_test/_internal/commands/integration/cloud/opennebula.py +1 -0
  612. ansible_test/_internal/commands/integration/cloud/openshift.py +1 -0
  613. ansible_test/_internal/commands/integration/cloud/scaleway.py +1 -0
  614. ansible_test/_internal/commands/integration/cloud/vcenter.py +1 -0
  615. ansible_test/_internal/commands/integration/cloud/vultr.py +1 -0
  616. ansible_test/_internal/commands/integration/coverage.py +8 -2
  617. ansible_test/_internal/commands/integration/filters.py +1 -0
  618. ansible_test/_internal/commands/integration/network.py +1 -0
  619. ansible_test/_internal/commands/integration/posix.py +1 -0
  620. ansible_test/_internal/commands/integration/windows.py +1 -0
  621. ansible_test/_internal/commands/sanity/__init__.py +19 -2
  622. ansible_test/_internal/commands/sanity/ansible_doc.py +1 -0
  623. ansible_test/_internal/commands/sanity/bin_symlinks.py +1 -0
  624. ansible_test/_internal/commands/sanity/compile.py +1 -0
  625. ansible_test/_internal/commands/sanity/ignores.py +1 -0
  626. ansible_test/_internal/commands/sanity/import.py +1 -0
  627. ansible_test/_internal/commands/sanity/integration_aliases.py +12 -0
  628. ansible_test/_internal/commands/sanity/pep8.py +1 -0
  629. ansible_test/_internal/commands/sanity/pslint.py +1 -0
  630. ansible_test/_internal/commands/sanity/pylint.py +25 -26
  631. ansible_test/_internal/commands/sanity/shellcheck.py +1 -0
  632. ansible_test/_internal/commands/sanity/validate_modules.py +1 -0
  633. ansible_test/_internal/commands/sanity/yamllint.py +1 -0
  634. ansible_test/_internal/commands/shell/__init__.py +44 -4
  635. ansible_test/_internal/commands/units/__init__.py +5 -1
  636. ansible_test/_internal/compat/__init__.py +1 -0
  637. ansible_test/_internal/compat/packaging.py +1 -0
  638. ansible_test/_internal/compat/yaml.py +1 -0
  639. ansible_test/_internal/completion.py +1 -0
  640. ansible_test/_internal/config.py +23 -13
  641. ansible_test/_internal/connections.py +1 -0
  642. ansible_test/_internal/constants.py +1 -0
  643. ansible_test/_internal/containers.py +1 -0
  644. ansible_test/_internal/content_config.py +1 -0
  645. ansible_test/_internal/core_ci.py +1 -0
  646. ansible_test/_internal/coverage_util.py +11 -10
  647. ansible_test/_internal/data.py +1 -0
  648. ansible_test/_internal/debugging.py +166 -0
  649. ansible_test/_internal/delegation.py +22 -13
  650. ansible_test/_internal/dev/__init__.py +1 -0
  651. ansible_test/_internal/dev/container_probe.py +1 -0
  652. ansible_test/_internal/diff.py +3 -2
  653. ansible_test/_internal/docker_util.py +2 -1
  654. ansible_test/_internal/encoding.py +1 -0
  655. ansible_test/_internal/executor.py +1 -0
  656. ansible_test/_internal/git.py +1 -0
  657. ansible_test/_internal/host_configs.py +1 -0
  658. ansible_test/_internal/host_profiles.py +260 -16
  659. ansible_test/_internal/http.py +1 -0
  660. ansible_test/_internal/init.py +1 -0
  661. ansible_test/_internal/inventory.py +39 -3
  662. ansible_test/_internal/io.py +1 -0
  663. ansible_test/_internal/metadata.py +95 -4
  664. ansible_test/_internal/payload.py +1 -0
  665. ansible_test/_internal/processes.py +80 -0
  666. ansible_test/_internal/provider/__init__.py +1 -0
  667. ansible_test/_internal/provider/layout/__init__.py +1 -0
  668. ansible_test/_internal/provider/layout/ansible.py +1 -0
  669. ansible_test/_internal/provider/layout/collection.py +1 -0
  670. ansible_test/_internal/provider/layout/unsupported.py +1 -0
  671. ansible_test/_internal/provider/source/__init__.py +1 -0
  672. ansible_test/_internal/provider/source/git.py +1 -0
  673. ansible_test/_internal/provider/source/installed.py +1 -0
  674. ansible_test/_internal/provider/source/unsupported.py +1 -0
  675. ansible_test/_internal/provider/source/unversioned.py +1 -0
  676. ansible_test/_internal/provisioning.py +11 -4
  677. ansible_test/_internal/pypi_proxy.py +6 -5
  678. ansible_test/_internal/python_requirements.py +28 -0
  679. ansible_test/_internal/ssh.py +2 -5
  680. ansible_test/_internal/target.py +9 -0
  681. ansible_test/_internal/test.py +3 -2
  682. ansible_test/_internal/thread.py +3 -1
  683. ansible_test/_internal/timeout.py +2 -1
  684. ansible_test/_internal/util.py +41 -12
  685. ansible_test/_internal/util_common.py +18 -5
  686. ansible_test/_internal/venv.py +1 -0
  687. ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +1 -0
  688. ansible_test/_util/controller/sanity/code-smell/changelog/sphinx.py +1 -0
  689. ansible_test/_util/controller/sanity/code-smell/changelog.py +1 -0
  690. ansible_test/_util/controller/sanity/code-smell/empty-init.py +1 -0
  691. ansible_test/_util/controller/sanity/code-smell/line-endings.py +1 -0
  692. ansible_test/_util/controller/sanity/code-smell/no-assert.py +1 -0
  693. ansible_test/_util/controller/sanity/code-smell/no-get-exception.py +1 -0
  694. ansible_test/_util/controller/sanity/code-smell/no-illegal-filenames.py +1 -0
  695. ansible_test/_util/controller/sanity/code-smell/no-smart-quotes.py +1 -0
  696. ansible_test/_util/controller/sanity/code-smell/replace-urlopen.py +1 -0
  697. ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +28 -1
  698. ansible_test/_util/controller/sanity/code-smell/shebang.py +1 -0
  699. ansible_test/_util/controller/sanity/code-smell/symlinks.py +1 -0
  700. ansible_test/_util/controller/sanity/code-smell/use-argspec-type-path.py +1 -0
  701. ansible_test/_util/controller/sanity/code-smell/use-compat-six.py +1 -0
  702. ansible_test/_util/controller/sanity/integration-aliases/yaml_to_json.py +2 -1
  703. ansible_test/_util/controller/sanity/pep8/current-ignore.txt +4 -0
  704. ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +8 -5
  705. ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +8 -5
  706. ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +8 -5
  707. ansible_test/_util/controller/sanity/pylint/config/collection.cfg +4 -5
  708. ansible_test/_util/controller/sanity/pylint/config/default.cfg +8 -7
  709. ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +541 -0
  710. ansible_test/_util/controller/sanity/pylint/plugins/deprecated_comment.py +137 -0
  711. ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +1 -0
  712. ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +1 -8
  713. ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +1 -8
  714. ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +55 -28
  715. ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +12 -5
  716. ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +13 -2
  717. ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -0
  718. ansible_test/_util/controller/sanity/yamllint/yamllinter.py +35 -17
  719. ansible_test/_util/controller/tools/collection_detail.py +1 -0
  720. ansible_test/_util/controller/tools/yaml_to_json.py +2 -1
  721. ansible_test/_util/target/injector/python.py +8 -0
  722. ansible_test/_util/target/pytest/plugins/ansible_forked.py +6 -1
  723. ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py +2 -1
  724. ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +1 -0
  725. ansible_test/_util/target/sanity/compile/compile.py +1 -0
  726. ansible_test/_util/target/sanity/import/importer.py +15 -16
  727. ansible_test/_util/target/setup/bootstrap.sh +9 -20
  728. ansible_test/_util/target/setup/probe_cgroups.py +1 -0
  729. ansible_test/_util/target/setup/quiet_pip.py +1 -0
  730. ansible_test/_util/target/setup/requirements.py +38 -36
  731. ansible_test/_util/target/tools/virtualenvcheck.py +2 -1
  732. ansible_test/_util/target/tools/yamlcheck.py +2 -1
  733. ansible/compat/selectors.py +0 -32
  734. ansible/errors/yaml_strings.py +0 -138
  735. ansible/executor/action_write_locks.py +0 -44
  736. ansible/executor/discovery/python_target.py +0 -47
  737. ansible/executor/powershell/module_powershell_wrapper.ps1 +0 -86
  738. ansible/executor/powershell/module_script_wrapper.ps1 +0 -22
  739. ansible/module_utils/compat/importlib.py +0 -26
  740. ansible/module_utils/compat/selectors.py +0 -32
  741. ansible/module_utils/pycompat24.py +0 -73
  742. ansible/parsing/yaml/constructor.py +0 -178
  743. ansible/template/native_helpers.py +0 -251
  744. ansible/template/template.py +0 -43
  745. ansible/template/vars.py +0 -77
  746. ansible/utils/native_jinja.py +0 -11
  747. ansible/vars/fact_cache.py +0 -71
  748. ansible_core-2.18.7.dist-info/RECORD +0 -992
  749. ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +0 -411
  750. {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/WHEEL +0 -0
  751. {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/entry_points.txt +0 -0
  752. {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/licenses/COPYING +0 -0
  753. {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/Apache-License.txt +0 -0
  754. {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/MIT-license.txt +0 -0
  755. {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/PSF-license.txt +0 -0
  756. {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
  757. {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/top_level.txt +0 -0
ansible/utils/display.py CHANGED
@@ -17,6 +17,9 @@
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
+ import contextlib
21
+ import dataclasses
22
+
20
23
  try:
21
24
  import curses
22
25
  except ImportError:
@@ -37,7 +40,6 @@ import secrets
37
40
  import subprocess
38
41
  import sys
39
42
  import termios
40
- import textwrap
41
43
  import threading
42
44
  import time
43
45
  import tty
@@ -47,13 +49,19 @@ from functools import wraps
47
49
  from struct import unpack, pack
48
50
 
49
51
  from ansible import constants as C
50
- from ansible.errors import AnsibleError, AnsibleAssertionError, AnsiblePromptInterrupt, AnsiblePromptNoninteractive
52
+ from ansible.constants import config
53
+ from ansible.errors import AnsibleAssertionError, AnsiblePromptInterrupt, AnsiblePromptNoninteractive, AnsibleError
54
+ from ansible._internal._errors import _error_utils, _error_factory
55
+ from ansible._internal import _event_formatting
56
+ from ansible.module_utils._internal import _ambient_context, _deprecator, _messages
51
57
  from ansible.module_utils.common.text.converters import to_bytes, to_text
58
+ from ansible.module_utils.datatag import deprecator_from_collection_name
59
+ from ansible._internal._datatag._tags import TrustedAsTemplate
52
60
  from ansible.module_utils.six import text_type
61
+ from ansible.module_utils._internal import _traceback, _errors
53
62
  from ansible.utils.color import stringc
54
63
  from ansible.utils.multiprocessing import context as multiprocessing_context
55
64
  from ansible.utils.singleton import Singleton
56
- from ansible.utils.unsafe_proxy import wrap_var
57
65
 
58
66
  if t.TYPE_CHECKING:
59
67
  # avoid circular import at runtime
@@ -73,6 +81,25 @@ MOVE_TO_BOL = b'\r'
73
81
  CLEAR_TO_EOL = b'\x1b[K'
74
82
 
75
83
 
84
+ def _is_controller_traceback_enabled(event: _traceback.TracebackEvent) -> bool:
85
+ """Controller utility function to determine if traceback collection is enabled for the specified event."""
86
+ flag_values: set[str] = set(value for value in C.config.get_config_value('DISPLAY_TRACEBACK'))
87
+
88
+ if 'always' in flag_values:
89
+ return True
90
+
91
+ if 'never' in flag_values:
92
+ return False
93
+
94
+ if _traceback.TracebackEvent.DEPRECATED_VALUE.name.lower() in flag_values:
95
+ flag_values.add(_traceback.TracebackEvent.DEPRECATED.name.lower()) # DEPRECATED_VALUE implies DEPRECATED
96
+
97
+ return event.name.lower() in flag_values
98
+
99
+
100
+ _traceback._is_traceback_enabled = _is_controller_traceback_enabled
101
+
102
+
76
103
  def get_text_width(text: str) -> int:
77
104
  """Function that utilizes ``wcswidth`` or ``wcwidth`` to determine the
78
105
  number of columns used to display a text string.
@@ -189,10 +216,22 @@ b_COW_PATHS = (
189
216
 
190
217
 
191
218
  def _synchronize_textiowrapper(tio: t.TextIO, lock: threading.RLock):
192
- # Ensure that a background thread can't hold the internal buffer lock on a file object
193
- # during a fork, which causes forked children to hang. We're using display's existing lock for
194
- # convenience (and entering the lock before a fork).
219
+ """
220
+ This decorator ensures that the supplied RLock is held before invoking the wrapped methods.
221
+ It is intended to prevent background threads from holding the Python stdout/stderr buffer lock on a file object during a fork.
222
+ Since background threads are abandoned in child forks, locks they hold are orphaned in a locked state.
223
+ Attempts to acquire an orphaned lock in this state will block forever, effectively hanging the child process on stdout/stderr writes.
224
+ The shared lock is permanently disabled immediately after a fork.
225
+ This prevents hangs in early post-fork code (e.g., stdio writes from pydevd, coverage, etc.) before user code has resumed and released the lock.
226
+ """
227
+
195
228
  def _wrap_with_lock(f, lock):
229
+ def disable_lock():
230
+ nonlocal lock
231
+ lock = contextlib.nullcontext()
232
+
233
+ os.register_at_fork(after_in_child=disable_lock)
234
+
196
235
  @wraps(f)
197
236
  def locking_wrapper(*args, **kwargs):
198
237
  with lock:
@@ -281,9 +320,9 @@ class Display(metaclass=Singleton):
281
320
  self.log_verbosity = max(verbosity, C.LOG_VERBOSITY)
282
321
 
283
322
  # list of all deprecation messages to prevent duplicate display
284
- self._deprecations: dict[str, int] = {}
285
- self._warns: dict[str, int] = {}
286
- self._errors: dict[str, int] = {}
323
+ self._deprecations: set[str] = set()
324
+ self._warns: set[str] = set()
325
+ self._errors: set[str] = set()
287
326
 
288
327
  self.b_cowsay: bytes | None = None
289
328
  self.noncow = C.ANSIBLE_COW_SELECTION
@@ -322,12 +361,9 @@ class Display(metaclass=Singleton):
322
361
  self.setup_curses = False
323
362
 
324
363
  def _replacing_warning_handler(self, exception: UnicodeError) -> tuple[str | bytes, int]:
325
- # TODO: This should probably be deferred until after the current display is completed
326
- # this will require some amount of new functionality
327
- self.deprecated(
328
- 'Non UTF-8 encoded data replaced with "?" while displaying text to stdout/stderr, this is temporary and will become an error',
329
- version='2.18',
330
- )
364
+ # This can't be removed as long as we have the possibility of encountering un-renderable strings
365
+ # created with `surrogateescape`; the alternative of having display methods hard fail is untenable.
366
+ self.warning('Non UTF-8 encoded data replaced with "?" while displaying text to stdout/stderr.')
331
367
  return '?', exception.end
332
368
 
333
369
  def set_queue(self, queue: FinalQueue) -> None:
@@ -412,6 +448,10 @@ class Display(metaclass=Singleton):
412
448
  if not isinstance(msg, str):
413
449
  raise TypeError(f'Display message must be str, not: {msg.__class__.__name__}')
414
450
 
451
+ # Convert Windows newlines to Unix newlines.
452
+ # Some environments, such as Azure Pipelines, render `\r` as an additional `\n`.
453
+ msg = msg.replace('\r\n', '\n')
454
+
415
455
  nocolor = msg
416
456
 
417
457
  if not log_only:
@@ -445,7 +485,7 @@ class Display(metaclass=Singleton):
445
485
  # final flush at shutdown.
446
486
  # try:
447
487
  # fileobj.flush()
448
- # except IOError as e:
488
+ # except OSError as e:
449
489
  # # Ignore EPIPE in case fileobj has been prematurely closed, eg.
450
490
  # # when piping to "head -n1"
451
491
  # if e.errno != errno.EPIPE:
@@ -535,41 +575,107 @@ class Display(metaclass=Singleton):
535
575
  date: str | None = None,
536
576
  collection_name: str | None = None,
537
577
  ) -> str:
538
- ''' used to print out a deprecation message.'''
539
- msg = msg.strip()
540
- if msg and msg[-1] not in ['!', '?', '.']:
541
- msg += '.'
578
+ """Return a deprecation message and help text for non-display purposes (e.g., exception messages)."""
579
+ self.deprecated(
580
+ msg="The `get_deprecation_message` method is deprecated.",
581
+ help_text="Use the `deprecated` method instead.",
582
+ version="2.23",
583
+ )
542
584
 
543
- if collection_name == 'ansible.builtin':
544
- collection_name = 'ansible-core'
585
+ msg = self._get_deprecation_message_with_plugin_info(
586
+ msg=msg,
587
+ version=version,
588
+ removed=removed,
589
+ date=date,
590
+ deprecator=deprecator_from_collection_name(collection_name),
591
+ )
592
+
593
+ if removed:
594
+ msg = f'[DEPRECATED]: {msg}'
595
+ else:
596
+ msg = f'[DEPRECATION WARNING]: {msg}'
597
+
598
+ return msg
599
+
600
+ def _get_deprecation_message_with_plugin_info(
601
+ self,
602
+ *,
603
+ msg: str,
604
+ version: str | None,
605
+ removed: bool = False,
606
+ date: str | None,
607
+ deprecator: _messages.PluginInfo | None,
608
+ ) -> str:
609
+ """Internal use only. Return a deprecation message and help text for display."""
610
+ # DTFIX-FUTURE: the logic for omitting date/version doesn't apply to the payload, so it shows up in vars in some cases when it should not
545
611
 
546
612
  if removed:
547
- header = '[DEPRECATED]: {0}'.format(msg)
548
613
  removal_fragment = 'This feature was removed'
549
- help_text = 'Please update your playbooks.'
550
614
  else:
551
- header = '[DEPRECATION WARNING]: {0}'.format(msg)
552
615
  removal_fragment = 'This feature will be removed'
553
- # FUTURE: make this a standalone warning so it only shows up once?
554
- help_text = 'Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.'
555
616
 
556
- if collection_name:
557
- from_fragment = 'from {0}'.format(collection_name)
617
+ if not deprecator or not deprecator.type:
618
+ # indeterminate has no resolved_name or type
619
+ # collections have a resolved_name but no type
620
+ collection = deprecator.resolved_name if deprecator else None
621
+ plugin_fragment = ''
622
+ elif deprecator.resolved_name == 'ansible.builtin':
623
+ # core deprecations from base classes (the API) have no plugin name, only 'ansible.builtin'
624
+ plugin_type_name = str(deprecator.type) if deprecator.type is _messages.PluginType.MODULE else f'{deprecator.type} plugin'
625
+
626
+ collection = deprecator.resolved_name
627
+ plugin_fragment = f'the {plugin_type_name} API'
558
628
  else:
559
- from_fragment = ''
629
+ parts = deprecator.resolved_name.split('.')
630
+ plugin_name = parts[-1]
631
+ plugin_type_name = str(deprecator.type) if deprecator.type is _messages.PluginType.MODULE else f'{deprecator.type} plugin'
632
+
633
+ collection = '.'.join(parts[:2]) if len(parts) > 2 else None
634
+ plugin_fragment = f'{plugin_type_name} {plugin_name!r}'
560
635
 
561
- if date:
562
- when = 'in a release after {0}.'.format(date)
636
+ if collection and plugin_fragment:
637
+ plugin_fragment += ' in'
638
+
639
+ if collection == 'ansible.builtin':
640
+ collection_fragment = 'ansible-core'
641
+ elif collection:
642
+ collection_fragment = f'collection {collection!r}'
643
+ else:
644
+ collection_fragment = ''
645
+
646
+ if not collection:
647
+ when_fragment = 'in the future' if not removed else ''
648
+ elif date:
649
+ when_fragment = f'in a release after {date}'
563
650
  elif version:
564
- when = 'in version {0}.'.format(version)
651
+ when_fragment = f'version {version}'
565
652
  else:
566
- when = 'in a future release.'
653
+ when_fragment = 'in a future release' if not removed else ''
567
654
 
568
- message_text = ' '.join(f for f in [header, removal_fragment, from_fragment, when, help_text] if f)
655
+ if plugin_fragment or collection_fragment:
656
+ from_fragment = 'from'
657
+ else:
658
+ from_fragment = ''
569
659
 
570
- return message_text
660
+ deprecation_msg = ' '.join(f for f in [removal_fragment, from_fragment, plugin_fragment, collection_fragment, when_fragment] if f) + '.'
661
+
662
+ return _join_sentences(msg, deprecation_msg)
663
+
664
+ @staticmethod
665
+ def _deduplicate(msg: str, messages: set[str]) -> bool:
666
+ """
667
+ Return True if the given message was previously seen, otherwise record the message as seen and return False.
668
+ This is done very late (at display-time) to avoid loss of attribution of messages to individual tasks.
669
+ Duplicates included in task results will always be visible to registered variables and callbacks.
670
+ """
671
+
672
+ if msg in messages:
673
+ return True
674
+
675
+ messages.add(msg)
676
+
677
+ return False
571
678
 
572
- @_proxy
573
679
  def deprecated(
574
680
  self,
575
681
  msg: str,
@@ -577,35 +683,155 @@ class Display(metaclass=Singleton):
577
683
  removed: bool = False,
578
684
  date: str | None = None,
579
685
  collection_name: str | None = None,
686
+ *,
687
+ deprecator: _messages.PluginInfo | None = None,
688
+ help_text: str | None = None,
689
+ obj: t.Any = None,
580
690
  ) -> None:
581
- if not removed and not C.DEPRECATION_WARNINGS:
582
- return
691
+ """
692
+ Display a deprecation warning message, if enabled.
693
+ Most callers do not need to provide `collection_name` or `deprecator` -- but provide only one if needed.
694
+ Specify `version` or `date`, but not both.
695
+ If `date` is a string, it must be in the form `YYYY-MM-DD`.
696
+ """
697
+ # DTFIX3: are there any deprecation calls where the feature is switching from enabled to disabled, rather than being removed entirely?
698
+ # DTFIX3: are there deprecated features which should going through deferred deprecation instead?
699
+
700
+ _skip_stackwalk = True
701
+
702
+ self._deprecated_with_plugin_info(
703
+ msg=msg,
704
+ version=version,
705
+ removed=removed,
706
+ date=date,
707
+ help_text=help_text,
708
+ obj=obj,
709
+ deprecator=_deprecator.get_best_deprecator(deprecator=deprecator, collection_name=collection_name),
710
+ formatted_traceback=_traceback.maybe_capture_traceback(msg, _traceback.TracebackEvent.DEPRECATED),
711
+ )
583
712
 
584
- message_text = self.get_deprecation_message(msg, version=version, removed=removed, date=date, collection_name=collection_name)
713
+ def _deprecated_with_plugin_info(
714
+ self,
715
+ *,
716
+ msg: str,
717
+ version: str | None,
718
+ removed: bool = False,
719
+ date: str | None,
720
+ help_text: str | None,
721
+ obj: t.Any,
722
+ deprecator: _messages.PluginInfo | None,
723
+ formatted_traceback: str | None = None,
724
+ ) -> None:
725
+ """
726
+ This is the internal pre-proxy half of the `deprecated` implementation.
727
+ Any logic that must occur on workers needs to be implemented here.
728
+ """
729
+ _skip_stackwalk = True
585
730
 
586
731
  if removed:
587
- raise AnsibleError(message_text)
732
+ formatted_msg = self._get_deprecation_message_with_plugin_info(
733
+ msg=msg,
734
+ version=version,
735
+ removed=removed,
736
+ date=date,
737
+ deprecator=deprecator,
738
+ )
588
739
 
589
- wrapped = textwrap.wrap(message_text, self.columns, drop_whitespace=False)
590
- message_text = "\n".join(wrapped) + "\n"
740
+ raise AnsibleError(formatted_msg)
591
741
 
592
- if message_text not in self._deprecations:
593
- self.display(message_text.strip(), color=C.COLOR_DEPRECATE, stderr=True)
594
- self._deprecations[message_text] = 1
742
+ if source_context := _error_utils.SourceContext.from_value(obj):
743
+ formatted_source_context = str(source_context)
744
+ else:
745
+ formatted_source_context = None
746
+
747
+ deprecation = _messages.DeprecationSummary(
748
+ event=_messages.Event(
749
+ msg=msg,
750
+ formatted_source_context=formatted_source_context,
751
+ help_text=help_text,
752
+ formatted_traceback=formatted_traceback,
753
+ ),
754
+ version=version,
755
+ date=date,
756
+ deprecator=deprecator,
757
+ )
758
+
759
+ if warning_ctx := _DeferredWarningContext.current(optional=True):
760
+ warning_ctx.capture(deprecation)
761
+ return
762
+
763
+ self._deprecated(deprecation)
595
764
 
596
765
  @_proxy
597
- def warning(self, msg: str, formatted: bool = False) -> None:
766
+ def _deprecated(self, warning: _messages.DeprecationSummary) -> None:
767
+ """Internal implementation detail, use `deprecated` instead."""
768
+
769
+ # This is the post-proxy half of the `deprecated` implementation.
770
+ # Any logic that must occur in the primary controller process needs to be implemented here.
771
+
772
+ if not _DeferredWarningContext.deprecation_warnings_enabled():
773
+ return
774
+
775
+ self.warning('Deprecation warnings can be disabled by setting `deprecation_warnings=False` in ansible.cfg.')
776
+
777
+ msg = _format_message(warning, _traceback.is_traceback_enabled(_traceback.TracebackEvent.DEPRECATED))
778
+ msg = f'[DEPRECATION WARNING]: {msg}'
779
+
780
+ if self._deduplicate(msg, self._deprecations):
781
+ return
782
+
783
+ self.display(msg, color=C.config.get_config_value('COLOR_DEPRECATE'), stderr=True)
784
+
785
+ def warning(
786
+ self,
787
+ msg: str,
788
+ formatted: bool = False,
789
+ *,
790
+ help_text: str | None = None,
791
+ obj: t.Any = None
792
+ ) -> None:
793
+ """Display a warning message."""
794
+ _skip_stackwalk = True
795
+
796
+ # deprecated: description='The formatted argument has no effect.' core_version='2.23'
797
+
798
+ # This is the pre-proxy half of the `warning` implementation.
799
+ # Any logic that must occur on workers needs to be implemented here.
598
800
 
599
- if not formatted:
600
- new_msg = "[WARNING]: %s" % msg
601
- wrapped = textwrap.wrap(new_msg, self.columns)
602
- new_msg = "\n".join(wrapped) + "\n"
801
+ if source_context := _error_utils.SourceContext.from_value(obj):
802
+ formatted_source_context = str(source_context)
603
803
  else:
604
- new_msg = "\n[WARNING]: \n%s" % msg
804
+ formatted_source_context = None
805
+
806
+ warning = _messages.WarningSummary(
807
+ event=_messages.Event(
808
+ msg=msg,
809
+ help_text=help_text,
810
+ formatted_source_context=formatted_source_context,
811
+ formatted_traceback=_traceback.maybe_capture_traceback(msg, _traceback.TracebackEvent.WARNING),
812
+ ),
813
+ )
814
+
815
+ if warning_ctx := _DeferredWarningContext.current(optional=True):
816
+ warning_ctx.capture(warning)
817
+ return
818
+
819
+ self._warning(warning)
820
+
821
+ @_proxy
822
+ def _warning(self, warning: _messages.WarningSummary) -> None:
823
+ """Internal implementation detail, use `warning` instead."""
824
+
825
+ # This is the post-proxy half of the `warning` implementation.
826
+ # Any logic that must occur in the primary controller process needs to be implemented here.
827
+
828
+ msg = _format_message(warning, _traceback.is_traceback_enabled(_traceback.TracebackEvent.WARNING))
829
+ msg = f"[WARNING]: {msg}"
830
+
831
+ if self._deduplicate(msg, self._warns):
832
+ return
605
833
 
606
- if new_msg not in self._warns:
607
- self.display(new_msg, color=C.COLOR_WARN, stderr=True, caplevel=-2)
608
- self._warns[new_msg] = 1
834
+ self.display(msg, color=C.config.get_config_value('COLOR_WARN'), stderr=True, caplevel=-2)
609
835
 
610
836
  @_proxy
611
837
  def system_warning(self, msg: str) -> None:
@@ -614,9 +840,9 @@ class Display(metaclass=Singleton):
614
840
 
615
841
  @_proxy
616
842
  def banner(self, msg: str, color: str | None = None, cows: bool = True) -> None:
617
- '''
843
+ """
618
844
  Prints a header-looking line with cowsay or stars with length depending on terminal width (3 minimum)
619
- '''
845
+ """
620
846
  msg = to_text(msg)
621
847
 
622
848
  if self.b_cowsay and cows:
@@ -654,17 +880,85 @@ class Display(metaclass=Singleton):
654
880
  (out, err) = cmd.communicate()
655
881
  self.display(u"%s\n" % to_text(out), color=color)
656
882
 
657
- @_proxy
658
- def error(self, msg: str, wrap_text: bool = True) -> None:
659
- if wrap_text:
660
- new_msg = u"\n[ERROR]: %s" % msg
661
- wrapped = textwrap.wrap(new_msg, self.columns)
662
- new_msg = u"\n".join(wrapped) + u"\n"
883
+ def error_as_warning(
884
+ self,
885
+ msg: str | None,
886
+ exception: BaseException,
887
+ *,
888
+ help_text: str | None = None,
889
+ obj: t.Any = None,
890
+ ) -> None:
891
+ """Display an exception as a warning."""
892
+ _skip_stackwalk = True
893
+
894
+ event = _error_factory.ControllerEventFactory.from_exception(exception, _traceback.is_traceback_enabled(_traceback.TracebackEvent.WARNING))
895
+
896
+ if msg:
897
+ if source_context := _error_utils.SourceContext.from_value(obj):
898
+ formatted_source_context = str(source_context)
899
+ else:
900
+ formatted_source_context = None
901
+
902
+ event = _messages.Event(
903
+ msg=msg,
904
+ help_text=help_text,
905
+ formatted_source_context=formatted_source_context,
906
+ formatted_traceback=_traceback.maybe_capture_traceback(msg, _traceback.TracebackEvent.WARNING),
907
+ chain=_messages.EventChain(
908
+ msg_reason=_errors.MSG_REASON_DIRECT_CAUSE,
909
+ traceback_reason=_errors.TRACEBACK_REASON_EXCEPTION_DIRECT_WARNING,
910
+ event=event,
911
+ ),
912
+ )
913
+
914
+ warning = _messages.WarningSummary(
915
+ event=event,
916
+ )
917
+
918
+ if warning_ctx := _DeferredWarningContext.current(optional=True):
919
+ warning_ctx.capture(warning)
920
+ return
921
+
922
+ self._warning(warning)
923
+
924
+ def error(self, msg: str | BaseException, wrap_text: bool = True, stderr: bool = True) -> None:
925
+ """Display an error message."""
926
+ _skip_stackwalk = True
927
+
928
+ # deprecated: description='The wrap_text argument has no effect.' core_version='2.23'
929
+ # deprecated: description='The stderr argument has no effect.' core_version='2.23'
930
+
931
+ # This is the pre-proxy half of the `error` implementation.
932
+ # Any logic that must occur on workers needs to be implemented here.
933
+
934
+ if isinstance(msg, BaseException):
935
+ event = _error_factory.ControllerEventFactory.from_exception(msg, _traceback.is_traceback_enabled(_traceback.TracebackEvent.ERROR))
663
936
  else:
664
- new_msg = u"ERROR! %s" % msg
665
- if new_msg not in self._errors:
666
- self.display(new_msg, color=C.COLOR_ERROR, stderr=True, caplevel=-1)
667
- self._errors[new_msg] = 1
937
+ event = _messages.Event(
938
+ msg=msg,
939
+ formatted_traceback=_traceback.maybe_capture_traceback(msg, _traceback.TracebackEvent.ERROR),
940
+ )
941
+
942
+ error = _messages.ErrorSummary(
943
+ event=event,
944
+ )
945
+
946
+ self._error(error, stderr=True)
947
+
948
+ @_proxy
949
+ def _error(self, error: _messages.ErrorSummary, stderr: bool) -> None:
950
+ """Internal implementation detail, use `error` instead."""
951
+
952
+ # This is the post-proxy half of the `error` implementation.
953
+ # Any logic that must occur in the primary controller process needs to be implemented here.
954
+
955
+ msg = _format_message(error, _traceback.is_traceback_enabled(_traceback.TracebackEvent.ERROR))
956
+ msg = f'[ERROR]: {msg}'
957
+
958
+ if self._deduplicate(msg, self._errors):
959
+ return
960
+
961
+ self.display(msg, color=C.config.get_config_value('COLOR_ERROR'), stderr=stderr, caplevel=-1)
668
962
 
669
963
  @staticmethod
670
964
  def prompt(msg: str, private: bool = False) -> str:
@@ -722,8 +1016,10 @@ class Display(metaclass=Singleton):
722
1016
  # handle utf-8 chars
723
1017
  result = to_text(result, errors='surrogate_or_strict')
724
1018
 
725
- if unsafe:
726
- result = wrap_var(result)
1019
+ if not unsafe:
1020
+ # to maintain backward compatibility, assume these values are safe to template
1021
+ result = TrustedAsTemplate().tag(result)
1022
+
727
1023
  return result
728
1024
 
729
1025
  def _set_column_width(self) -> None:
@@ -738,8 +1034,8 @@ class Display(metaclass=Singleton):
738
1034
  msg: str,
739
1035
  private: bool = False,
740
1036
  seconds: int | None = None,
741
- interrupt_input: c.Container[bytes] | None = None,
742
- complete_input: c.Container[bytes] | None = None,
1037
+ interrupt_input: c.Iterable[bytes] | None = None,
1038
+ complete_input: c.Iterable[bytes] | None = None,
743
1039
  ) -> bytes:
744
1040
  if self._final_q:
745
1041
  from ansible.executor.process.worker import current_worker
@@ -794,8 +1090,8 @@ class Display(metaclass=Singleton):
794
1090
  self,
795
1091
  echo: bool = False,
796
1092
  seconds: int | None = None,
797
- interrupt_input: c.Container[bytes] | None = None,
798
- complete_input: c.Container[bytes] | None = None,
1093
+ interrupt_input: c.Iterable[bytes] | None = None,
1094
+ complete_input: c.Iterable[bytes] | None = None,
799
1095
  ) -> bytes:
800
1096
  if self._final_q:
801
1097
  raise NotImplementedError
@@ -872,3 +1168,119 @@ class Display(metaclass=Singleton):
872
1168
  return self._stdout.fileno()
873
1169
  except (ValueError, AttributeError):
874
1170
  return None
1171
+
1172
+
1173
+ _display = Display()
1174
+
1175
+
1176
+ class _DeferredWarningContext(_ambient_context.AmbientContextBase):
1177
+ """
1178
+ Calls to `Display.warning()` and `Display.deprecated()` within this context will cause the resulting warnings to be captured and not displayed.
1179
+ The intended use is for task-initiated warnings to be recorded with the task result, which makes them visible to registered results, callbacks, etc.
1180
+ The active display callback is responsible for communicating any warnings to the user.
1181
+ """
1182
+
1183
+ # DTFIX-FUTURE: once we start implementing nested scoped contexts for our own bookkeeping, this should be an interface facade that forwards to the nearest
1184
+ # context that actually implements the warnings collection capability
1185
+
1186
+ def __init__(self, *, variables: dict[str, object]) -> None:
1187
+ self._variables = variables # DTFIX-FUTURE: move this to an AmbientContext-derived TaskContext (once it exists)
1188
+ self._deprecation_warnings: list[_messages.DeprecationSummary] = []
1189
+ self._warnings: list[_messages.WarningSummary] = []
1190
+ self._seen: set[_messages.WarningSummary] = set()
1191
+
1192
+ @classmethod
1193
+ def deprecation_warnings_enabled(cls) -> bool:
1194
+ """Return True if deprecation warnings are enabled for the current calling context, otherwise False."""
1195
+ # DTFIX-FUTURE: move this capability into config using an AmbientContext-derived TaskContext (once it exists)
1196
+ if warning_ctx := cls.current(optional=True):
1197
+ variables = warning_ctx._variables
1198
+ else:
1199
+ variables = None
1200
+
1201
+ return C.config.get_config_value('DEPRECATION_WARNINGS', variables=variables)
1202
+
1203
+ def capture(self, warning: _messages.WarningSummary) -> None:
1204
+ """Add the warning/deprecation to the context if it has not already been seen by this context."""
1205
+ if warning in self._seen:
1206
+ return
1207
+
1208
+ self._seen.add(warning)
1209
+
1210
+ if isinstance(warning, _messages.DeprecationSummary):
1211
+ self._deprecation_warnings.append(warning)
1212
+ else:
1213
+ self._warnings.append(warning)
1214
+
1215
+ def get_warnings(self) -> list[_messages.WarningSummary]:
1216
+ """Return a list of the captured non-deprecation warnings."""
1217
+ # DTFIX-FUTURE: return a read-only list proxy instead
1218
+ return self._warnings
1219
+
1220
+ def get_deprecation_warnings(self) -> list[_messages.DeprecationSummary]:
1221
+ """Return a list of the captured deprecation warnings."""
1222
+ # DTFIX-FUTURE: return a read-only list proxy instead
1223
+ return self._deprecation_warnings
1224
+
1225
+
1226
+ def _join_sentences(first: str | None, second: str | None) -> str:
1227
+ """Join two sentences together."""
1228
+ first = (first or '').strip()
1229
+ second = (second or '').strip()
1230
+
1231
+ if first and first[-1] not in ('!', '?', '.'):
1232
+ first += '.'
1233
+
1234
+ if second and second[-1] not in ('!', '?', '.'):
1235
+ second += '.'
1236
+
1237
+ if first and not second:
1238
+ return first
1239
+
1240
+ if not first and second:
1241
+ return second
1242
+
1243
+ return ' '.join((first, second))
1244
+
1245
+
1246
+ def _format_message(summary: _messages.SummaryBase, include_traceback: bool) -> str:
1247
+ if isinstance(summary, _messages.DeprecationSummary):
1248
+ deprecation_message = _display._get_deprecation_message_with_plugin_info(
1249
+ msg=summary.event.msg,
1250
+ version=summary.version,
1251
+ date=summary.date,
1252
+ deprecator=summary.deprecator,
1253
+ )
1254
+
1255
+ event = dataclasses.replace(summary.event, msg=deprecation_message)
1256
+ else:
1257
+ event = summary.event
1258
+
1259
+ return _event_formatting.format_event(event, include_traceback)
1260
+
1261
+
1262
+ def _report_config_warnings(deprecator: _messages.PluginInfo) -> None:
1263
+ """Called by config to report warnings/deprecations collected during a config parse."""
1264
+ while config._errors:
1265
+ msg, exception = config._errors.pop()
1266
+ _display.error_as_warning(msg=msg, exception=exception)
1267
+
1268
+ while config.WARNINGS:
1269
+ warn = config.WARNINGS.pop()
1270
+ _display.warning(warn)
1271
+
1272
+ while config.DEPRECATED:
1273
+ # tuple with name and options
1274
+ dep = config.DEPRECATED.pop(0)
1275
+ msg = config.get_deprecated_msg_from_config(dep[1]).replace("\t", "")
1276
+
1277
+ _display.deprecated( # pylint: disable=ansible-deprecated-unnecessary-collection-name,ansible-invalid-deprecated-version
1278
+ msg=f"{dep[0]} option. {msg}",
1279
+ version=dep[1]['version'],
1280
+ deprecator=deprecator,
1281
+ )
1282
+
1283
+
1284
+ # emit any warnings or deprecations
1285
+ # in the event config fails before display is up, we'll lose warnings -- but that's OK, since everything is broken anyway
1286
+ _report_config_warnings(_deprecator.ANSIBLE_CORE_DEPRECATOR)