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
ansible/utils/display.py CHANGED
@@ -17,6 +17,9 @@
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
+ import dataclasses
21
+ import datetime
22
+
20
23
  try:
21
24
  import curses
22
25
  except ImportError:
@@ -47,13 +50,17 @@ from functools import wraps
47
50
  from struct import unpack, pack
48
51
 
49
52
  from ansible import constants as C
50
- from ansible.errors import AnsibleError, AnsibleAssertionError, AnsiblePromptInterrupt, AnsiblePromptNoninteractive
53
+ from ansible.errors import AnsibleAssertionError, AnsiblePromptInterrupt, AnsiblePromptNoninteractive, AnsibleError
54
+ from ansible._internal._errors import _utils
55
+ from ansible.module_utils._internal import _ambient_context, _plugin_exec_context
51
56
  from ansible.module_utils.common.text.converters import to_bytes, to_text
57
+ from ansible._internal._datatag._tags import TrustedAsTemplate
58
+ from ansible.module_utils.common.messages import ErrorSummary, WarningSummary, DeprecationSummary, Detail, SummaryBase, PluginInfo
52
59
  from ansible.module_utils.six import text_type
60
+ from ansible.module_utils._internal import _traceback
53
61
  from ansible.utils.color import stringc
54
62
  from ansible.utils.multiprocessing import context as multiprocessing_context
55
63
  from ansible.utils.singleton import Singleton
56
- from ansible.utils.unsafe_proxy import wrap_var
57
64
 
58
65
  if t.TYPE_CHECKING:
59
66
  # avoid circular import at runtime
@@ -69,10 +76,28 @@ _LIBC.wcswidth.argtypes = (ctypes.c_wchar_p, ctypes.c_int)
69
76
  # Max for c_int
70
77
  _MAX_INT = 2 ** (ctypes.sizeof(ctypes.c_int) * 8 - 1) - 1
71
78
 
79
+ _UNSET = t.cast(t.Any, object())
80
+
72
81
  MOVE_TO_BOL = b'\r'
73
82
  CLEAR_TO_EOL = b'\x1b[K'
74
83
 
75
84
 
85
+ def _is_controller_traceback_enabled(event: _traceback.TracebackEvent) -> bool:
86
+ """Controller utility function to determine if traceback collection is enabled for the specified event."""
87
+ flag_values: set[str] = set(value for value in C.config.get_config_value('DISPLAY_TRACEBACK'))
88
+
89
+ if 'always' in flag_values:
90
+ return True
91
+
92
+ if 'never' in flag_values:
93
+ return False
94
+
95
+ return event.name.lower() in flag_values
96
+
97
+
98
+ _traceback._is_traceback_enabled = _is_controller_traceback_enabled
99
+
100
+
76
101
  def get_text_width(text: str) -> int:
77
102
  """Function that utilizes ``wcswidth`` or ``wcwidth`` to determine the
78
103
  number of columns used to display a text string.
@@ -281,14 +306,15 @@ class Display(metaclass=Singleton):
281
306
  self.log_verbosity = max(verbosity, C.LOG_VERBOSITY)
282
307
 
283
308
  # 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] = {}
309
+ self._deprecations: set[str] = set()
310
+ self._warns: set[str] = set()
311
+ self._errors: set[str] = set()
287
312
 
288
313
  self.b_cowsay: bytes | None = None
289
314
  self.noncow = C.ANSIBLE_COW_SELECTION
290
315
 
291
316
  self.set_cowsay_info()
317
+ self._wrap_stderr = C.WRAP_STDERR
292
318
 
293
319
  if self.b_cowsay:
294
320
  try:
@@ -322,12 +348,9 @@ class Display(metaclass=Singleton):
322
348
  self.setup_curses = False
323
349
 
324
350
  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
- )
351
+ # This can't be removed as long as we have the possibility of encountering un-renderable strings
352
+ # created with `surrogateescape`; the alternative of having display methods hard fail is untenable.
353
+ self.warning('Non UTF-8 encoded data replaced with "?" while displaying text to stdout/stderr.')
331
354
  return '?', exception.end
332
355
 
333
356
  def set_queue(self, queue: FinalQueue) -> None:
@@ -532,29 +555,54 @@ class Display(metaclass=Singleton):
532
555
  msg: str,
533
556
  version: str | None = None,
534
557
  removed: bool = False,
535
- date: str | None = None,
558
+ date: str | datetime.date | None = None,
536
559
  collection_name: str | None = None,
537
560
  ) -> str:
538
- ''' used to print out a deprecation message.'''
561
+ """Return a deprecation message and help text for non-display purposes (e.g., exception messages)."""
562
+ self.deprecated(
563
+ msg="The `get_deprecation_message` method is deprecated.",
564
+ help_text="Use the `deprecated` method instead.",
565
+ version="2.23",
566
+ )
567
+
568
+ msg = self._get_deprecation_message_with_plugin_info(
569
+ msg=msg,
570
+ version=version,
571
+ removed=removed,
572
+ date=date,
573
+ plugin=_plugin_exec_context.PluginExecContext.get_current_plugin_info(),
574
+ )
575
+
576
+ if removed:
577
+ msg = f'[DEPRECATED]: {msg}'
578
+ else:
579
+ msg = f'[DEPRECATION WARNING]: {msg}'
580
+
581
+ return msg
582
+
583
+ def _get_deprecation_message_with_plugin_info(
584
+ self,
585
+ msg: str,
586
+ version: str | None = None,
587
+ removed: bool = False,
588
+ date: str | datetime.date | None = None,
589
+ plugin: PluginInfo | None = None,
590
+ ) -> str:
591
+ """Internal use only. Return a deprecation message and help text for display."""
539
592
  msg = msg.strip()
593
+
540
594
  if msg and msg[-1] not in ['!', '?', '.']:
541
595
  msg += '.'
542
596
 
543
- if collection_name == 'ansible.builtin':
544
- collection_name = 'ansible-core'
545
-
546
597
  if removed:
547
- header = '[DEPRECATED]: {0}'.format(msg)
548
598
  removal_fragment = 'This feature was removed'
549
599
  help_text = 'Please update your playbooks.'
550
600
  else:
551
- header = '[DEPRECATION WARNING]: {0}'.format(msg)
552
601
  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.'
602
+ help_text = ''
555
603
 
556
- if collection_name:
557
- from_fragment = 'from {0}'.format(collection_name)
604
+ if plugin:
605
+ from_fragment = f'from the {self._describe_plugin_info(plugin)}'
558
606
  else:
559
607
  from_fragment = ''
560
608
 
@@ -565,47 +613,203 @@ class Display(metaclass=Singleton):
565
613
  else:
566
614
  when = 'in a future release.'
567
615
 
568
- message_text = ' '.join(f for f in [header, removal_fragment, from_fragment, when, help_text] if f)
616
+ message_text = ' '.join(f for f in [msg, removal_fragment, from_fragment, when, help_text] if f)
569
617
 
570
618
  return message_text
571
619
 
572
- @_proxy
620
+ @staticmethod
621
+ def _describe_plugin_info(plugin_info: PluginInfo) -> str:
622
+ """Return a brief description of the plugin info, including name(s) and type."""
623
+ name = repr(plugin_info.resolved_name)
624
+ clarification = f' (requested as {plugin_info.requested_name!r})' if plugin_info.requested_name != plugin_info.resolved_name else ''
625
+
626
+ if plugin_info.type in ("module", "modules"):
627
+ # DTFIX-RELEASE: pluginloader or AnsiblePlugin needs a "type desc" property that doesn't suffer from legacy "inconsistencies" like this
628
+ plugin_type = "module"
629
+ elif plugin_info.type == "collection":
630
+ # not a real plugin type, but used for tombstone errors generated by plugin loader
631
+ plugin_type = plugin_info.type
632
+ else:
633
+ plugin_type = f'{plugin_info.type} plugin'
634
+
635
+ return f'{name} {plugin_type}{clarification}'
636
+
637
+ def _wrap_message(self, msg: str, wrap_text: bool) -> str:
638
+ if wrap_text and self._wrap_stderr:
639
+ wrapped = textwrap.wrap(msg, self.columns, drop_whitespace=False)
640
+ msg = "\n".join(wrapped) + "\n"
641
+
642
+ return msg
643
+
644
+ @staticmethod
645
+ def _deduplicate(msg: str, messages: set[str]) -> bool:
646
+ """
647
+ Return True if the given message was previously seen, otherwise record the message as seen and return False.
648
+ This is done very late (at display-time) to avoid loss of attribution of messages to individual tasks.
649
+ Duplicates included in task results will always be visible to registered variables and callbacks.
650
+ """
651
+
652
+ if msg in messages:
653
+ return True
654
+
655
+ messages.add(msg)
656
+
657
+ return False
658
+
573
659
  def deprecated(
574
660
  self,
575
661
  msg: str,
576
662
  version: str | None = None,
577
663
  removed: bool = False,
578
- date: str | None = None,
579
- collection_name: str | None = None,
664
+ date: str | datetime.date | None = None,
665
+ collection_name: str | None = _UNSET,
666
+ *,
667
+ help_text: str | None = None,
668
+ obj: t.Any = None,
580
669
  ) -> None:
581
- if not removed and not C.DEPRECATION_WARNINGS:
582
- return
583
-
584
- message_text = self.get_deprecation_message(msg, version=version, removed=removed, date=date, collection_name=collection_name)
670
+ """Display a deprecation warning message, if enabled."""
671
+ # deprecated: description='enable the deprecation message for collection_name' core_version='2.23'
672
+ # if collection_name is not _UNSET:
673
+ # self.deprecated('The `collection_name` argument to `deprecated` is deprecated.', version='2.27')
674
+
675
+ # DTFIX-RELEASE: are there any deprecation calls where the feature is switching from enabled to disabled, rather than being removed entirely?
676
+ # DTFIX-RELEASE: are there deprecated features which should going through deferred deprecation instead?
677
+
678
+ self._deprecated_with_plugin_info(
679
+ msg=msg,
680
+ version=version,
681
+ removed=removed,
682
+ date=date,
683
+ help_text=help_text,
684
+ obj=obj,
685
+ plugin=_plugin_exec_context.PluginExecContext.get_current_plugin_info(),
686
+ )
585
687
 
688
+ def _deprecated_with_plugin_info(
689
+ self,
690
+ msg: str,
691
+ version: str | None = None,
692
+ removed: bool = False,
693
+ date: str | datetime.date | None = None,
694
+ *,
695
+ help_text: str | None = None,
696
+ obj: t.Any = None,
697
+ plugin: PluginInfo | None = None,
698
+ ) -> None:
699
+ """
700
+ This is the internal pre-proxy half of the `deprecated` implementation.
701
+ Any logic that must occur on workers needs to be implemented here.
702
+ """
586
703
  if removed:
587
- raise AnsibleError(message_text)
704
+ raise AnsibleError(self._get_deprecation_message_with_plugin_info(
705
+ msg=msg,
706
+ version=version,
707
+ removed=removed,
708
+ date=date,
709
+ plugin=plugin,
710
+ ))
711
+
712
+ if source_context := _utils.SourceContext.from_value(obj):
713
+ formatted_source_context = str(source_context)
714
+ else:
715
+ formatted_source_context = None
716
+
717
+ deprecation = DeprecationSummary(
718
+ details=(
719
+ Detail(
720
+ msg=msg,
721
+ formatted_source_context=formatted_source_context,
722
+ help_text=help_text,
723
+ ),
724
+ ),
725
+ version=version,
726
+ date=str(date) if isinstance(date, datetime.date) else date,
727
+ plugin=plugin,
728
+ formatted_traceback=_traceback.maybe_capture_traceback(_traceback.TracebackEvent.DEPRECATED),
729
+ )
588
730
 
589
- wrapped = textwrap.wrap(message_text, self.columns, drop_whitespace=False)
590
- message_text = "\n".join(wrapped) + "\n"
731
+ if warning_ctx := _DeferredWarningContext.current(optional=True):
732
+ warning_ctx.capture(deprecation)
733
+ return
591
734
 
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
735
+ self._deprecated(deprecation)
595
736
 
596
737
  @_proxy
597
- def warning(self, msg: str, formatted: bool = False) -> None:
738
+ def _deprecated(self, warning: DeprecationSummary) -> None:
739
+ """Internal implementation detail, use `deprecated` instead."""
740
+
741
+ # This is the post-proxy half of the `deprecated` implementation.
742
+ # Any logic that must occur in the primary controller process needs to be implemented here.
743
+
744
+ if not _DeferredWarningContext.deprecation_warnings_enabled():
745
+ return
746
+
747
+ self.warning('Deprecation warnings can be disabled by setting `deprecation_warnings=False` in ansible.cfg.')
748
+
749
+ msg = format_message(warning)
750
+ msg = f'[DEPRECATION WARNING]: {msg}'
751
+
752
+ # DTFIX-RELEASE: what should we do with wrap_message?
753
+ msg = self._wrap_message(msg=msg, wrap_text=True)
754
+
755
+ if self._deduplicate(msg, self._deprecations):
756
+ return
757
+
758
+ self.display(msg, color=C.config.get_config_value('COLOR_DEPRECATE'), stderr=True)
598
759
 
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"
760
+ def warning(
761
+ self,
762
+ msg: str,
763
+ formatted: bool = False,
764
+ *,
765
+ help_text: str | None = None,
766
+ obj: t.Any = None
767
+ ) -> None:
768
+ """Display a warning message."""
769
+
770
+ # This is the pre-proxy half of the `warning` implementation.
771
+ # Any logic that must occur on workers needs to be implemented here.
772
+
773
+ if source_context := _utils.SourceContext.from_value(obj):
774
+ formatted_source_context = str(source_context)
603
775
  else:
604
- new_msg = "\n[WARNING]: \n%s" % msg
776
+ formatted_source_context = None
777
+
778
+ warning = WarningSummary(
779
+ details=(
780
+ Detail(
781
+ msg=msg,
782
+ help_text=help_text,
783
+ formatted_source_context=formatted_source_context,
784
+ ),
785
+ ),
786
+ formatted_traceback=_traceback.maybe_capture_traceback(_traceback.TracebackEvent.WARNING),
787
+ )
788
+
789
+ if warning_ctx := _DeferredWarningContext.current(optional=True):
790
+ warning_ctx.capture(warning)
791
+ # DTFIX-RELEASE: what to do about propagating wrap_text?
792
+ return
793
+
794
+ self._warning(warning, wrap_text=not formatted)
795
+
796
+ @_proxy
797
+ def _warning(self, warning: WarningSummary, wrap_text: bool) -> None:
798
+ """Internal implementation detail, use `warning` instead."""
799
+
800
+ # This is the post-proxy half of the `warning` implementation.
801
+ # Any logic that must occur in the primary controller process needs to be implemented here.
802
+
803
+ msg = format_message(warning)
804
+ msg = f"[WARNING]: {msg}"
805
+
806
+ if self._deduplicate(msg, self._warns):
807
+ return
808
+
809
+ # DTFIX-RELEASE: what should we do with wrap_message?
810
+ msg = self._wrap_message(msg=msg, wrap_text=wrap_text)
605
811
 
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
812
+ self.display(msg, color=C.config.get_config_value('COLOR_WARN'), stderr=True, caplevel=-2)
609
813
 
610
814
  @_proxy
611
815
  def system_warning(self, msg: str) -> None:
@@ -614,9 +818,9 @@ class Display(metaclass=Singleton):
614
818
 
615
819
  @_proxy
616
820
  def banner(self, msg: str, color: str | None = None, cows: bool = True) -> None:
617
- '''
821
+ """
618
822
  Prints a header-looking line with cowsay or stars with length depending on terminal width (3 minimum)
619
- '''
823
+ """
620
824
  msg = to_text(msg)
621
825
 
622
826
  if self.b_cowsay and cows:
@@ -654,17 +858,56 @@ class Display(metaclass=Singleton):
654
858
  (out, err) = cmd.communicate()
655
859
  self.display(u"%s\n" % to_text(out), color=color)
656
860
 
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"
861
+ def error_as_warning(self, msg: str | None, exception: BaseException) -> None:
862
+ """Display an exception as a warning."""
863
+
864
+ error = _utils._create_error_summary(exception, _traceback.TracebackEvent.WARNING)
865
+
866
+ if msg:
867
+ error = dataclasses.replace(error, details=(Detail(msg=msg),) + error.details)
868
+
869
+ warning = WarningSummary(
870
+ details=error.details,
871
+ formatted_traceback=error.formatted_traceback,
872
+ )
873
+
874
+ if warning_ctx := _DeferredWarningContext.current(optional=True):
875
+ warning_ctx.capture(warning)
876
+ return
877
+
878
+ self._warning(warning, wrap_text=False)
879
+
880
+ def error(self, msg: str | BaseException, wrap_text: bool = True, stderr: bool = True) -> None:
881
+ """Display an error message."""
882
+
883
+ # This is the pre-proxy half of the `error` implementation.
884
+ # Any logic that must occur on workers needs to be implemented here.
885
+
886
+ if isinstance(msg, BaseException):
887
+ error = _utils._create_error_summary(msg, _traceback.TracebackEvent.ERROR)
888
+ wrap_text = False
663
889
  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
890
+ error = ErrorSummary(details=(Detail(msg=msg),), formatted_traceback=_traceback.maybe_capture_traceback(_traceback.TracebackEvent.ERROR))
891
+
892
+ self._error(error, wrap_text=wrap_text, stderr=stderr)
893
+
894
+ @_proxy
895
+ def _error(self, error: ErrorSummary, wrap_text: bool, stderr: bool) -> None:
896
+ """Internal implementation detail, use `error` instead."""
897
+
898
+ # This is the post-proxy half of the `error` implementation.
899
+ # Any logic that must occur in the primary controller process needs to be implemented here.
900
+
901
+ msg = format_message(error)
902
+ msg = f'[ERROR]: {msg}'
903
+
904
+ if self._deduplicate(msg, self._errors):
905
+ return
906
+
907
+ # DTFIX-RELEASE: what should we do with wrap_message?
908
+ msg = self._wrap_message(msg=msg, wrap_text=wrap_text)
909
+
910
+ self.display(msg, color=C.config.get_config_value('COLOR_ERROR'), stderr=stderr, caplevel=-1)
668
911
 
669
912
  @staticmethod
670
913
  def prompt(msg: str, private: bool = False) -> str:
@@ -722,8 +965,10 @@ class Display(metaclass=Singleton):
722
965
  # handle utf-8 chars
723
966
  result = to_text(result, errors='surrogate_or_strict')
724
967
 
725
- if unsafe:
726
- result = wrap_var(result)
968
+ if not unsafe:
969
+ # to maintain backward compatibility, assume these values are safe to template
970
+ result = TrustedAsTemplate().tag(result)
971
+
727
972
  return result
728
973
 
729
974
  def _set_column_width(self) -> None:
@@ -738,8 +983,8 @@ class Display(metaclass=Singleton):
738
983
  msg: str,
739
984
  private: bool = False,
740
985
  seconds: int | None = None,
741
- interrupt_input: c.Container[bytes] | None = None,
742
- complete_input: c.Container[bytes] | None = None,
986
+ interrupt_input: c.Iterable[bytes] | None = None,
987
+ complete_input: c.Iterable[bytes] | None = None,
743
988
  ) -> bytes:
744
989
  if self._final_q:
745
990
  from ansible.executor.process.worker import current_worker
@@ -794,8 +1039,8 @@ class Display(metaclass=Singleton):
794
1039
  self,
795
1040
  echo: bool = False,
796
1041
  seconds: int | None = None,
797
- interrupt_input: c.Container[bytes] | None = None,
798
- complete_input: c.Container[bytes] | None = None,
1042
+ interrupt_input: c.Iterable[bytes] | None = None,
1043
+ complete_input: c.Iterable[bytes] | None = None,
799
1044
  ) -> bytes:
800
1045
  if self._final_q:
801
1046
  raise NotImplementedError
@@ -872,3 +1117,128 @@ class Display(metaclass=Singleton):
872
1117
  return self._stdout.fileno()
873
1118
  except (ValueError, AttributeError):
874
1119
  return None
1120
+
1121
+
1122
+ _display = Display()
1123
+
1124
+
1125
+ class _DeferredWarningContext(_ambient_context.AmbientContextBase):
1126
+ """
1127
+ Calls to `Display.warning()` and `Display.deprecated()` within this context will cause the resulting warnings to be captured and not displayed.
1128
+ The intended use is for task-initiated warnings to be recorded with the task result, which makes them visible to registered results, callbacks, etc.
1129
+ The active display callback is responsible for communicating any warnings to the user.
1130
+ """
1131
+
1132
+ # DTFIX-FUTURE: once we start implementing nested scoped contexts for our own bookkeeping, this should be an interface facade that forwards to the nearest
1133
+ # context that actually implements the warnings collection capability
1134
+
1135
+ def __init__(self, *, variables: dict[str, object]) -> None:
1136
+ self._variables = variables # DTFIX-FUTURE: move this to an AmbientContext-derived TaskContext (once it exists)
1137
+ self._deprecation_warnings: list[DeprecationSummary] = []
1138
+ self._warnings: list[WarningSummary] = []
1139
+ self._seen: set[WarningSummary] = set()
1140
+
1141
+ @classmethod
1142
+ def deprecation_warnings_enabled(cls) -> bool:
1143
+ """Return True if deprecation warnings are enabled for the current calling context, otherwise False."""
1144
+ # DTFIX-FUTURE: move this capability into config using an AmbientContext-derived TaskContext (once it exists)
1145
+ if warning_ctx := cls.current(optional=True):
1146
+ variables = warning_ctx._variables
1147
+ else:
1148
+ variables = None
1149
+
1150
+ return C.config.get_config_value('DEPRECATION_WARNINGS', variables=variables)
1151
+
1152
+ def capture(self, warning: WarningSummary) -> None:
1153
+ """Add the warning/deprecation to the context if it has not already been seen by this context."""
1154
+ if warning in self._seen:
1155
+ return
1156
+
1157
+ self._seen.add(warning)
1158
+
1159
+ if isinstance(warning, DeprecationSummary):
1160
+ self._deprecation_warnings.append(warning)
1161
+ else:
1162
+ self._warnings.append(warning)
1163
+
1164
+ def get_warnings(self) -> list[WarningSummary]:
1165
+ """Return a list of the captured non-deprecation warnings."""
1166
+ # DTFIX-FUTURE: return a read-only list proxy instead
1167
+ return self._warnings
1168
+
1169
+ def get_deprecation_warnings(self) -> list[DeprecationSummary]:
1170
+ """Return a list of the captured deprecation warnings."""
1171
+ # DTFIX-FUTURE: return a read-only list proxy instead
1172
+ return self._deprecation_warnings
1173
+
1174
+
1175
+ def _format_error_details(details: t.Sequence[Detail], formatted_tb: str | None = None) -> str:
1176
+ details = _utils._collapse_error_details(details)
1177
+
1178
+ message_lines: list[str] = []
1179
+
1180
+ if len(details) > 1:
1181
+ message_lines.append(_utils._dedupe_and_concat_message_chain([md.msg for md in details]))
1182
+ message_lines.append('')
1183
+
1184
+ for idx, edc in enumerate(details):
1185
+ if idx:
1186
+ message_lines.extend((
1187
+ '',
1188
+ '<<< caused by >>>',
1189
+ '',
1190
+ ))
1191
+
1192
+ message_lines.extend(_get_message_lines(edc.msg, edc.help_text, edc.formatted_source_context))
1193
+
1194
+ message_lines = [f'{line}\n' for line in message_lines]
1195
+
1196
+ if formatted_tb:
1197
+ message_lines.append('\n')
1198
+ message_lines.append(formatted_tb)
1199
+
1200
+ msg = "".join(message_lines).strip()
1201
+
1202
+ if '\n' in msg:
1203
+ msg += '\n\n'
1204
+ else:
1205
+ msg += '\n'
1206
+
1207
+ return msg
1208
+
1209
+
1210
+ def _get_message_lines(message: str, help_text: str | None, formatted_source_context: str | None) -> list[str]:
1211
+ """Return a list of error/warning message lines constructed from the given message, help text and source context."""
1212
+
1213
+ if help_text and not formatted_source_context and '\n' not in message and '\n' not in help_text:
1214
+ return [f'{message} {help_text}'] # prefer a single-line message with help text when there is no source context
1215
+
1216
+ message_lines = [message]
1217
+
1218
+ if formatted_source_context:
1219
+ message_lines.append(formatted_source_context)
1220
+
1221
+ if help_text:
1222
+ message_lines.append('')
1223
+ message_lines.append(help_text)
1224
+
1225
+ return message_lines
1226
+
1227
+
1228
+ def format_message(summary: SummaryBase) -> str:
1229
+ details: t.Sequence[Detail]
1230
+
1231
+ if isinstance(summary, DeprecationSummary):
1232
+ details = [detail if idx else dataclasses.replace(
1233
+ detail,
1234
+ msg=_display._get_deprecation_message_with_plugin_info(
1235
+ msg=detail.msg,
1236
+ version=summary.version,
1237
+ date=summary.date,
1238
+ plugin=summary.plugin,
1239
+ ),
1240
+ ) for idx, detail in enumerate(summary.details)]
1241
+ else:
1242
+ details = summary.details
1243
+
1244
+ return _format_error_details(details, summary.formatted_traceback)