ansible-core 2.18.4rc1__py3-none-any.whl → 2.19.0b1__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 (709) hide show
  1. ansible/_internal/__init__.py +53 -0
  2. ansible/_internal/_ansiballz.py +265 -0
  3. ansible/_internal/_datatag/__init__.py +0 -0
  4. ansible/_internal/_datatag/_tags.py +130 -0
  5. ansible/_internal/_datatag/_utils.py +19 -0
  6. ansible/_internal/_datatag/_wrappers.py +33 -0
  7. ansible/_internal/_errors/__init__.py +0 -0
  8. ansible/_internal/_errors/_captured.py +128 -0
  9. ansible/_internal/_errors/_handler.py +91 -0
  10. ansible/_internal/_errors/_utils.py +310 -0
  11. ansible/_internal/_json/__init__.py +160 -0
  12. ansible/_internal/_json/_legacy_encoder.py +34 -0
  13. ansible/_internal/_json/_profiles/__init__.py +0 -0
  14. ansible/_internal/_json/_profiles/_cache_persistence.py +55 -0
  15. ansible/_internal/_json/_profiles/_inventory_legacy.py +40 -0
  16. ansible/_internal/_json/_profiles/_legacy.py +198 -0
  17. ansible/_internal/_locking.py +21 -0
  18. ansible/_internal/_plugins/__init__.py +0 -0
  19. ansible/_internal/_plugins/_cache.py +57 -0
  20. ansible/_internal/_task.py +78 -0
  21. ansible/_internal/_templating/__init__.py +10 -0
  22. ansible/_internal/_templating/_access.py +86 -0
  23. ansible/_internal/_templating/_chain_templar.py +63 -0
  24. ansible/_internal/_templating/_datatag.py +95 -0
  25. ansible/_internal/_templating/_engine.py +588 -0
  26. ansible/_internal/_templating/_errors.py +28 -0
  27. ansible/_internal/_templating/_jinja_bits.py +1066 -0
  28. ansible/_internal/_templating/_jinja_common.py +332 -0
  29. ansible/_internal/_templating/_jinja_patches.py +44 -0
  30. ansible/_internal/_templating/_jinja_plugins.py +351 -0
  31. ansible/_internal/_templating/_lazy_containers.py +633 -0
  32. ansible/_internal/_templating/_marker_behaviors.py +103 -0
  33. ansible/_internal/_templating/_transform.py +63 -0
  34. ansible/_internal/_templating/_utils.py +107 -0
  35. ansible/_internal/_wrapt.py +1052 -0
  36. ansible/_internal/_yaml/__init__.py +0 -0
  37. ansible/_internal/_yaml/_constructor.py +240 -0
  38. ansible/_internal/_yaml/_dumper.py +62 -0
  39. ansible/_internal/_yaml/_errors.py +166 -0
  40. ansible/_internal/_yaml/_loader.py +66 -0
  41. ansible/_internal/ansible_collections/ansible/_protomatter/README.md +11 -0
  42. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/debug.py +36 -0
  43. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/apply_trust.py +19 -0
  44. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/dump_object.py +18 -0
  45. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/finalize.py +16 -0
  46. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/origin.py +18 -0
  47. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.py +24 -0
  48. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.yml +33 -0
  49. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/tag_names.py +16 -0
  50. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +17 -0
  51. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +49 -0
  52. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.py +21 -0
  53. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.yml +2 -0
  54. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.py +15 -0
  55. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.yml +19 -0
  56. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.py +18 -0
  57. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.yml +19 -0
  58. ansible/cli/__init__.py +153 -89
  59. ansible/cli/_ssh_askpass.py +47 -0
  60. ansible/cli/adhoc.py +14 -7
  61. ansible/cli/arguments/option_helpers.py +154 -7
  62. ansible/cli/config.py +43 -68
  63. ansible/cli/console.py +10 -8
  64. ansible/cli/doc.py +48 -46
  65. ansible/cli/galaxy.py +27 -20
  66. ansible/cli/inventory.py +28 -26
  67. ansible/cli/playbook.py +4 -12
  68. ansible/cli/pull.py +51 -11
  69. ansible/cli/scripts/ansible_connection_cli_stub.py +7 -7
  70. ansible/cli/vault.py +12 -11
  71. ansible/compat/__init__.py +2 -2
  72. ansible/config/base.yml +165 -108
  73. ansible/config/manager.py +52 -49
  74. ansible/constants.py +3 -4
  75. ansible/errors/__init__.py +277 -235
  76. ansible/executor/interpreter_discovery.py +28 -149
  77. ansible/executor/module_common.py +426 -493
  78. ansible/executor/play_iterator.py +22 -27
  79. ansible/executor/playbook_executor.py +11 -11
  80. ansible/executor/powershell/async_watchdog.ps1 +97 -102
  81. ansible/executor/powershell/async_wrapper.ps1 +202 -151
  82. ansible/executor/powershell/become_wrapper.ps1 +89 -144
  83. ansible/executor/powershell/bootstrap_wrapper.ps1 +24 -9
  84. ansible/executor/powershell/coverage_wrapper.ps1 +82 -135
  85. ansible/executor/powershell/exec_wrapper.ps1 +462 -196
  86. ansible/executor/powershell/module_manifest.py +417 -265
  87. ansible/executor/powershell/module_wrapper.ps1 +169 -186
  88. ansible/executor/powershell/psrp_fetch_file.ps1 +41 -0
  89. ansible/executor/powershell/psrp_put_file.ps1 +122 -0
  90. ansible/executor/powershell/winrm_fetch_file.ps1 +46 -0
  91. ansible/executor/powershell/winrm_put_file.ps1 +36 -0
  92. ansible/executor/process/worker.py +136 -76
  93. ansible/executor/stats.py +5 -5
  94. ansible/executor/task_executor.py +237 -236
  95. ansible/executor/task_queue_manager.py +62 -38
  96. ansible/executor/task_result.py +21 -12
  97. ansible/galaxy/__init__.py +2 -2
  98. ansible/galaxy/api.py +22 -18
  99. ansible/galaxy/collection/__init__.py +1 -1
  100. ansible/galaxy/collection/concrete_artifact_manager.py +8 -11
  101. ansible/galaxy/dependency_resolution/dataclasses.py +14 -4
  102. ansible/galaxy/dependency_resolution/providers.py +1 -1
  103. ansible/galaxy/dependency_resolution/reporters.py +81 -0
  104. ansible/galaxy/role.py +4 -8
  105. ansible/galaxy/token.py +28 -21
  106. ansible/inventory/data.py +47 -57
  107. ansible/inventory/group.py +44 -72
  108. ansible/inventory/helpers.py +9 -0
  109. ansible/inventory/host.py +32 -54
  110. ansible/inventory/manager.py +77 -34
  111. ansible/keyword_desc.yml +1 -1
  112. ansible/module_utils/_internal/__init__.py +55 -0
  113. ansible/module_utils/_internal/_ambient_context.py +58 -0
  114. ansible/module_utils/_internal/_ansiballz.py +133 -0
  115. ansible/module_utils/_internal/_concurrent/_daemon_threading.py +1 -0
  116. ansible/module_utils/_internal/_dataclass_annotation_patch.py +64 -0
  117. ansible/module_utils/_internal/_dataclass_validation.py +217 -0
  118. ansible/module_utils/_internal/_datatag/__init__.py +928 -0
  119. ansible/module_utils/_internal/_datatag/_tags.py +38 -0
  120. ansible/module_utils/_internal/_debugging.py +31 -0
  121. ansible/module_utils/_internal/_errors.py +30 -0
  122. ansible/module_utils/_internal/_json/__init__.py +63 -0
  123. ansible/module_utils/_internal/_json/_legacy_encoder.py +26 -0
  124. ansible/module_utils/_internal/_json/_profiles/__init__.py +410 -0
  125. ansible/module_utils/_internal/_json/_profiles/_fallback_to_str.py +73 -0
  126. ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +31 -0
  127. ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +35 -0
  128. ansible/module_utils/_internal/_json/_profiles/_module_modern_c2m.py +35 -0
  129. ansible/module_utils/_internal/_json/_profiles/_module_modern_m2c.py +33 -0
  130. ansible/module_utils/_internal/_json/_profiles/_tagless.py +50 -0
  131. ansible/module_utils/_internal/_patches/__init__.py +66 -0
  132. ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +55 -0
  133. ansible/module_utils/_internal/_patches/_socket_patch.py +34 -0
  134. ansible/module_utils/_internal/_patches/_sys_intern_patch.py +34 -0
  135. ansible/module_utils/_internal/_plugin_exec_context.py +49 -0
  136. ansible/module_utils/_internal/_testing.py +0 -0
  137. ansible/module_utils/_internal/_traceback.py +89 -0
  138. ansible/module_utils/ansible_release.py +2 -2
  139. ansible/module_utils/api.py +1 -2
  140. ansible/module_utils/basic.py +154 -120
  141. ansible/module_utils/common/_utils.py +24 -28
  142. ansible/module_utils/common/collections.py +1 -2
  143. ansible/module_utils/common/dict_transformations.py +2 -2
  144. ansible/module_utils/common/file.py +2 -2
  145. ansible/module_utils/common/json.py +90 -84
  146. ansible/module_utils/common/locale.py +2 -2
  147. ansible/module_utils/common/messages.py +108 -0
  148. ansible/module_utils/common/parameters.py +27 -24
  149. ansible/module_utils/common/process.py +2 -2
  150. ansible/module_utils/common/respawn.py +41 -19
  151. ansible/module_utils/common/sentinel.py +66 -0
  152. ansible/module_utils/common/sys_info.py +8 -8
  153. ansible/module_utils/common/text/converters.py +16 -37
  154. ansible/module_utils/common/validation.py +35 -24
  155. ansible/module_utils/common/warnings.py +86 -25
  156. ansible/module_utils/common/yaml.py +29 -3
  157. ansible/module_utils/compat/datetime.py +33 -21
  158. ansible/module_utils/compat/paramiko.py +21 -10
  159. ansible/module_utils/compat/typing.py +6 -5
  160. ansible/module_utils/connection.py +2 -2
  161. ansible/module_utils/csharp/Ansible.Basic.cs +14 -11
  162. ansible/module_utils/csharp/Ansible.Become.cs +1 -0
  163. ansible/module_utils/csharp/Ansible._Async.cs +517 -0
  164. ansible/module_utils/datatag.py +46 -0
  165. ansible/module_utils/distro/__init__.py +2 -2
  166. ansible/module_utils/facts/ansible_collector.py +4 -5
  167. ansible/module_utils/facts/collector.py +13 -14
  168. ansible/module_utils/facts/compat.py +4 -4
  169. ansible/module_utils/facts/default_collectors.py +1 -1
  170. ansible/module_utils/facts/hardware/aix.py +34 -0
  171. ansible/module_utils/facts/hardware/base.py +1 -1
  172. ansible/module_utils/facts/hardware/darwin.py +1 -3
  173. ansible/module_utils/facts/hardware/freebsd.py +2 -2
  174. ansible/module_utils/facts/hardware/linux.py +4 -4
  175. ansible/module_utils/facts/namespace.py +1 -1
  176. ansible/module_utils/facts/network/base.py +1 -1
  177. ansible/module_utils/facts/network/fc_wwn.py +1 -2
  178. ansible/module_utils/facts/network/iscsi.py +1 -2
  179. ansible/module_utils/facts/network/nvme.py +1 -2
  180. ansible/module_utils/facts/other/facter.py +1 -2
  181. ansible/module_utils/facts/other/ohai.py +2 -3
  182. ansible/module_utils/facts/system/apparmor.py +1 -2
  183. ansible/module_utils/facts/system/caps.py +1 -1
  184. ansible/module_utils/facts/system/chroot.py +1 -2
  185. ansible/module_utils/facts/system/cmdline.py +1 -2
  186. ansible/module_utils/facts/system/date_time.py +5 -3
  187. ansible/module_utils/facts/system/distribution.py +9 -8
  188. ansible/module_utils/facts/system/dns.py +1 -1
  189. ansible/module_utils/facts/system/env.py +1 -2
  190. ansible/module_utils/facts/system/fips.py +7 -20
  191. ansible/module_utils/facts/system/loadavg.py +1 -2
  192. ansible/module_utils/facts/system/local.py +1 -2
  193. ansible/module_utils/facts/system/lsb.py +1 -2
  194. ansible/module_utils/facts/system/pkg_mgr.py +1 -2
  195. ansible/module_utils/facts/system/platform.py +1 -2
  196. ansible/module_utils/facts/system/python.py +1 -2
  197. ansible/module_utils/facts/system/selinux.py +1 -1
  198. ansible/module_utils/facts/system/service_mgr.py +1 -2
  199. ansible/module_utils/facts/system/ssh_pub_keys.py +1 -1
  200. ansible/module_utils/facts/system/systemd.py +1 -1
  201. ansible/module_utils/facts/system/user.py +1 -2
  202. ansible/module_utils/facts/utils.py +3 -3
  203. ansible/module_utils/facts/virtual/base.py +1 -1
  204. ansible/module_utils/facts/virtual/sunos.py +3 -15
  205. ansible/module_utils/facts/virtual/sysctl.py +3 -16
  206. ansible/module_utils/json_utils.py +2 -2
  207. ansible/module_utils/parsing/convert_bool.py +1 -1
  208. ansible/module_utils/service.py +18 -21
  209. ansible/module_utils/splitter.py +7 -7
  210. ansible/module_utils/testing.py +31 -0
  211. ansible/module_utils/urls.py +60 -31
  212. ansible/modules/add_host.py +4 -4
  213. ansible/modules/apt.py +60 -46
  214. ansible/modules/apt_key.py +19 -12
  215. ansible/modules/apt_repository.py +19 -16
  216. ansible/modules/assemble.py +6 -6
  217. ansible/modules/assert.py +4 -4
  218. ansible/modules/async_status.py +10 -12
  219. ansible/modules/async_wrapper.py +8 -3
  220. ansible/modules/blockinfile.py +6 -7
  221. ansible/modules/command.py +10 -17
  222. ansible/modules/copy.py +57 -144
  223. ansible/modules/cron.py +20 -15
  224. ansible/modules/deb822_repository.py +8 -9
  225. ansible/modules/debconf.py +5 -5
  226. ansible/modules/debug.py +4 -4
  227. ansible/modules/dnf.py +8 -8
  228. ansible/modules/dnf5.py +52 -17
  229. ansible/modules/dpkg_selections.py +4 -4
  230. ansible/modules/expect.py +8 -10
  231. ansible/modules/fail.py +4 -4
  232. ansible/modules/fetch.py +4 -4
  233. ansible/modules/file.py +174 -133
  234. ansible/modules/find.py +20 -18
  235. ansible/modules/gather_facts.py +3 -3
  236. ansible/modules/get_url.py +59 -53
  237. ansible/modules/getent.py +7 -9
  238. ansible/modules/git.py +28 -25
  239. ansible/modules/group.py +6 -6
  240. ansible/modules/group_by.py +4 -4
  241. ansible/modules/hostname.py +13 -29
  242. ansible/modules/import_playbook.py +6 -6
  243. ansible/modules/import_role.py +7 -7
  244. ansible/modules/import_tasks.py +6 -6
  245. ansible/modules/include_role.py +6 -6
  246. ansible/modules/include_tasks.py +6 -6
  247. ansible/modules/include_vars.py +6 -6
  248. ansible/modules/iptables.py +86 -73
  249. ansible/modules/known_hosts.py +10 -10
  250. ansible/modules/lineinfile.py +5 -5
  251. ansible/modules/meta.py +4 -4
  252. ansible/modules/mount_facts.py +2 -2
  253. ansible/modules/package.py +4 -4
  254. ansible/modules/package_facts.py +22 -10
  255. ansible/modules/pause.py +6 -6
  256. ansible/modules/ping.py +6 -6
  257. ansible/modules/pip.py +10 -11
  258. ansible/modules/raw.py +4 -4
  259. ansible/modules/reboot.py +6 -6
  260. ansible/modules/replace.py +9 -13
  261. ansible/modules/rpm_key.py +7 -8
  262. ansible/modules/script.py +4 -4
  263. ansible/modules/service.py +7 -8
  264. ansible/modules/service_facts.py +87 -10
  265. ansible/modules/set_fact.py +5 -5
  266. ansible/modules/set_stats.py +4 -4
  267. ansible/modules/setup.py +2 -2
  268. ansible/modules/shell.py +6 -6
  269. ansible/modules/slurp.py +6 -6
  270. ansible/modules/stat.py +9 -23
  271. ansible/modules/subversion.py +15 -15
  272. ansible/modules/systemd.py +6 -6
  273. ansible/modules/systemd_service.py +6 -6
  274. ansible/modules/sysvinit.py +6 -6
  275. ansible/modules/tempfile.py +5 -6
  276. ansible/modules/template.py +6 -6
  277. ansible/modules/unarchive.py +32 -11
  278. ansible/modules/uri.py +35 -49
  279. ansible/modules/user.py +53 -34
  280. ansible/modules/validate_argument_spec.py +10 -7
  281. ansible/modules/wait_for.py +39 -32
  282. ansible/modules/wait_for_connection.py +6 -6
  283. ansible/modules/yum_repository.py +6 -6
  284. ansible/parsing/ajson.py +14 -32
  285. ansible/parsing/dataloader.py +99 -54
  286. ansible/parsing/mod_args.py +28 -44
  287. ansible/parsing/plugin_docs.py +21 -86
  288. ansible/parsing/quoting.py +1 -1
  289. ansible/parsing/splitter.py +27 -12
  290. ansible/parsing/utils/addresses.py +24 -24
  291. ansible/parsing/utils/yaml.py +32 -61
  292. ansible/parsing/vault/__init__.py +319 -87
  293. ansible/parsing/yaml/__init__.py +0 -18
  294. ansible/parsing/yaml/dumper.py +6 -120
  295. ansible/parsing/yaml/loader.py +6 -39
  296. ansible/parsing/yaml/objects.py +36 -339
  297. ansible/playbook/__init__.py +1 -1
  298. ansible/playbook/attribute.py +8 -3
  299. ansible/playbook/base.py +182 -132
  300. ansible/playbook/block.py +26 -24
  301. ansible/playbook/collectionsearch.py +1 -15
  302. ansible/playbook/conditional.py +3 -77
  303. ansible/playbook/handler.py +8 -2
  304. ansible/playbook/helpers.py +41 -53
  305. ansible/playbook/included_file.py +6 -15
  306. ansible/playbook/loop_control.py +2 -2
  307. ansible/playbook/play.py +85 -44
  308. ansible/playbook/play_context.py +12 -17
  309. ansible/playbook/playbook_include.py +14 -15
  310. ansible/playbook/role/__init__.py +24 -26
  311. ansible/playbook/role/definition.py +15 -17
  312. ansible/playbook/role/include.py +2 -4
  313. ansible/playbook/role/metadata.py +10 -11
  314. ansible/playbook/role_include.py +3 -3
  315. ansible/playbook/taggable.py +13 -8
  316. ansible/playbook/task.py +188 -118
  317. ansible/playbook/task_include.py +5 -5
  318. ansible/plugins/__init__.py +68 -21
  319. ansible/plugins/action/__init__.py +209 -176
  320. ansible/plugins/action/add_host.py +1 -1
  321. ansible/plugins/action/assemble.py +1 -1
  322. ansible/plugins/action/assert.py +54 -66
  323. ansible/plugins/action/copy.py +7 -11
  324. ansible/plugins/action/debug.py +37 -31
  325. ansible/plugins/action/dnf.py +3 -4
  326. ansible/plugins/action/fail.py +1 -1
  327. ansible/plugins/action/fetch.py +4 -5
  328. ansible/plugins/action/gather_facts.py +8 -7
  329. ansible/plugins/action/group_by.py +1 -1
  330. ansible/plugins/action/include_vars.py +10 -11
  331. ansible/plugins/action/package.py +3 -6
  332. ansible/plugins/action/pause.py +2 -2
  333. ansible/plugins/action/script.py +15 -8
  334. ansible/plugins/action/service.py +6 -11
  335. ansible/plugins/action/set_fact.py +3 -12
  336. ansible/plugins/action/set_stats.py +3 -8
  337. ansible/plugins/action/template.py +35 -59
  338. ansible/plugins/action/unarchive.py +1 -1
  339. ansible/plugins/action/validate_argument_spec.py +5 -5
  340. ansible/plugins/action/wait_for_connection.py +1 -1
  341. ansible/plugins/become/__init__.py +31 -8
  342. ansible/plugins/become/runas.py +71 -0
  343. ansible/plugins/become/su.py +13 -8
  344. ansible/plugins/become/sudo.py +19 -0
  345. ansible/plugins/cache/__init__.py +35 -44
  346. ansible/plugins/cache/base.py +8 -0
  347. ansible/plugins/cache/jsonfile.py +10 -16
  348. ansible/plugins/cache/memory.py +6 -12
  349. ansible/plugins/callback/__init__.py +141 -123
  350. ansible/plugins/callback/default.py +30 -23
  351. ansible/plugins/callback/junit.py +28 -24
  352. ansible/plugins/callback/minimal.py +17 -14
  353. ansible/plugins/callback/oneline.py +13 -7
  354. ansible/plugins/callback/tree.py +10 -6
  355. ansible/plugins/connection/__init__.py +47 -34
  356. ansible/plugins/connection/local.py +150 -54
  357. ansible/plugins/connection/paramiko_ssh.py +21 -18
  358. ansible/plugins/connection/psrp.py +76 -165
  359. ansible/plugins/connection/ssh.py +301 -78
  360. ansible/plugins/connection/winrm.py +58 -140
  361. ansible/plugins/doc_fragments/action_common_attributes.py +14 -14
  362. ansible/plugins/doc_fragments/action_core.py +6 -6
  363. ansible/plugins/doc_fragments/backup.py +2 -2
  364. ansible/plugins/doc_fragments/checksum_common.py +27 -0
  365. ansible/plugins/doc_fragments/constructed.py +6 -2
  366. ansible/plugins/doc_fragments/decrypt.py +2 -2
  367. ansible/plugins/doc_fragments/default_callback.py +2 -2
  368. ansible/plugins/doc_fragments/files.py +2 -2
  369. ansible/plugins/doc_fragments/inventory_cache.py +2 -2
  370. ansible/plugins/doc_fragments/result_format_callback.py +2 -2
  371. ansible/plugins/doc_fragments/return_common.py +2 -2
  372. ansible/plugins/doc_fragments/template_common.py +4 -4
  373. ansible/plugins/doc_fragments/url.py +17 -1
  374. ansible/plugins/doc_fragments/url_windows.py +2 -2
  375. ansible/plugins/doc_fragments/validate.py +2 -2
  376. ansible/plugins/doc_fragments/vars_plugin_staging.py +2 -2
  377. ansible/plugins/filter/__init__.py +6 -2
  378. ansible/plugins/filter/b64decode.yml +22 -0
  379. ansible/plugins/filter/b64encode.yml +22 -0
  380. ansible/plugins/filter/bool.yml +11 -4
  381. ansible/plugins/filter/core.py +218 -108
  382. ansible/plugins/filter/encryption.py +32 -32
  383. ansible/plugins/filter/flatten.yml +3 -2
  384. ansible/plugins/filter/human_to_bytes.yml +2 -2
  385. ansible/plugins/filter/mathstuff.py +30 -37
  386. ansible/plugins/filter/password_hash.yml +8 -0
  387. ansible/plugins/filter/regex_search.yml +1 -4
  388. ansible/plugins/filter/split.yml +1 -1
  389. ansible/plugins/filter/to_nice_yaml.yml +0 -4
  390. ansible/plugins/filter/to_yaml.yml +0 -4
  391. ansible/plugins/filter/unvault.yml +1 -1
  392. ansible/plugins/filter/urls.py +1 -1
  393. ansible/plugins/filter/urlsplit.py +8 -9
  394. ansible/plugins/filter/vault.yml +14 -9
  395. ansible/plugins/filter/win_basename.yml +6 -1
  396. ansible/plugins/filter/win_dirname.yml +5 -0
  397. ansible/plugins/inventory/__init__.py +97 -77
  398. ansible/plugins/inventory/advanced_host_list.py +7 -5
  399. ansible/plugins/inventory/auto.py +11 -4
  400. ansible/plugins/inventory/constructed.py +21 -24
  401. ansible/plugins/inventory/generator.py +16 -11
  402. ansible/plugins/inventory/host_list.py +7 -5
  403. ansible/plugins/inventory/ini.py +78 -44
  404. ansible/plugins/inventory/script.py +189 -119
  405. ansible/plugins/inventory/toml.py +16 -126
  406. ansible/plugins/inventory/yaml.py +10 -8
  407. ansible/plugins/list.py +3 -3
  408. ansible/plugins/loader.py +197 -82
  409. ansible/plugins/lookup/__init__.py +21 -4
  410. ansible/plugins/lookup/config.py +21 -35
  411. ansible/plugins/lookup/csvfile.py +3 -2
  412. ansible/plugins/lookup/dict.py +1 -6
  413. ansible/plugins/lookup/env.py +12 -9
  414. ansible/plugins/lookup/file.py +5 -8
  415. ansible/plugins/lookup/first_found.py +86 -55
  416. ansible/plugins/lookup/indexed_items.py +1 -10
  417. ansible/plugins/lookup/ini.py +14 -13
  418. ansible/plugins/lookup/items.py +1 -1
  419. ansible/plugins/lookup/lines.py +8 -1
  420. ansible/plugins/lookup/list.py +1 -1
  421. ansible/plugins/lookup/nested.py +2 -18
  422. ansible/plugins/lookup/password.py +5 -5
  423. ansible/plugins/lookup/pipe.py +5 -7
  424. ansible/plugins/lookup/sequence.py +18 -8
  425. ansible/plugins/lookup/subelements.py +1 -4
  426. ansible/plugins/lookup/template.py +42 -36
  427. ansible/plugins/lookup/together.py +0 -12
  428. ansible/plugins/lookup/unvault.py +1 -5
  429. ansible/plugins/lookup/url.py +2 -8
  430. ansible/plugins/lookup/vars.py +16 -24
  431. ansible/plugins/shell/__init__.py +2 -2
  432. ansible/plugins/shell/cmd.py +2 -2
  433. ansible/plugins/shell/powershell.py +39 -22
  434. ansible/plugins/shell/sh.py +3 -2
  435. ansible/plugins/strategy/__init__.py +94 -113
  436. ansible/plugins/strategy/debug.py +2 -2
  437. ansible/plugins/strategy/free.py +13 -28
  438. ansible/plugins/strategy/host_pinned.py +2 -2
  439. ansible/plugins/strategy/linear.py +31 -33
  440. ansible/plugins/terminal/__init__.py +4 -4
  441. ansible/plugins/test/__init__.py +7 -2
  442. ansible/plugins/test/core.py +54 -20
  443. ansible/plugins/test/files.py +1 -1
  444. ansible/plugins/test/mathstuff.py +3 -3
  445. ansible/plugins/test/uri.py +3 -3
  446. ansible/plugins/vars/host_group_vars.py +7 -14
  447. ansible/release.py +2 -2
  448. ansible/template/__init__.py +368 -944
  449. ansible/utils/__init__.py +0 -18
  450. ansible/utils/_ssh_agent.py +657 -0
  451. ansible/utils/collection_loader/__init__.py +52 -5
  452. ansible/utils/collection_loader/_collection_config.py +5 -6
  453. ansible/utils/collection_loader/_collection_finder.py +79 -93
  454. ansible/utils/collection_loader/_collection_meta.py +13 -8
  455. ansible/utils/display.py +428 -58
  456. ansible/utils/encrypt.py +27 -19
  457. ansible/utils/fqcn.py +2 -2
  458. ansible/utils/hashing.py +2 -2
  459. ansible/utils/helpers.py +2 -2
  460. ansible/utils/listify.py +8 -8
  461. ansible/utils/lock.py +2 -2
  462. ansible/utils/path.py +4 -4
  463. ansible/utils/plugin_docs.py +14 -13
  464. ansible/utils/sentinel.py +4 -62
  465. ansible/utils/singleton.py +2 -0
  466. ansible/utils/ssh_functions.py +1 -1
  467. ansible/utils/unsafe_proxy.py +23 -332
  468. ansible/utils/vars.py +28 -8
  469. ansible/utils/version.py +2 -2
  470. ansible/vars/clean.py +4 -4
  471. ansible/vars/hostvars.py +60 -90
  472. ansible/vars/manager.py +205 -264
  473. ansible/vars/reserved.py +8 -9
  474. ansible_core-2.19.0b1.dist-info/BSD-3-Clause.txt +28 -0
  475. {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/METADATA +5 -4
  476. ansible_core-2.19.0b1.dist-info/RECORD +1070 -0
  477. {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/WHEEL +1 -1
  478. ansible_test/_data/completion/docker.txt +7 -7
  479. ansible_test/_data/completion/remote.txt +6 -6
  480. ansible_test/_data/completion/windows.txt +1 -0
  481. ansible_test/_data/requirements/ansible.txt +2 -2
  482. ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
  483. ansible_test/_data/requirements/sanity.changelog.txt +1 -1
  484. ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
  485. ansible_test/_data/requirements/sanity.pylint.txt +4 -4
  486. ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
  487. ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
  488. ansible_test/_data/requirements/units.txt +1 -0
  489. ansible_test/_internal/__init__.py +1 -0
  490. ansible_test/_internal/ansible_util.py +2 -0
  491. ansible_test/_internal/become.py +1 -0
  492. ansible_test/_internal/bootstrap.py +1 -0
  493. ansible_test/_internal/cache.py +1 -0
  494. ansible_test/_internal/cgroup.py +1 -0
  495. ansible_test/_internal/ci/__init__.py +1 -0
  496. ansible_test/_internal/ci/azp.py +1 -0
  497. ansible_test/_internal/ci/local.py +1 -0
  498. ansible_test/_internal/classification/__init__.py +1 -0
  499. ansible_test/_internal/classification/common.py +1 -0
  500. ansible_test/_internal/classification/csharp.py +1 -0
  501. ansible_test/_internal/classification/powershell.py +1 -0
  502. ansible_test/_internal/classification/python.py +1 -0
  503. ansible_test/_internal/cli/__init__.py +1 -0
  504. ansible_test/_internal/cli/actions.py +1 -0
  505. ansible_test/_internal/cli/argparsing/__init__.py +1 -0
  506. ansible_test/_internal/cli/argparsing/actions.py +1 -0
  507. ansible_test/_internal/cli/argparsing/argcompletion.py +1 -0
  508. ansible_test/_internal/cli/argparsing/parsers.py +1 -0
  509. ansible_test/_internal/cli/commands/__init__.py +11 -0
  510. ansible_test/_internal/cli/commands/coverage/__init__.py +1 -0
  511. ansible_test/_internal/cli/commands/coverage/analyze/__init__.py +1 -0
  512. ansible_test/_internal/cli/commands/coverage/analyze/targets/__init__.py +1 -0
  513. ansible_test/_internal/cli/commands/coverage/analyze/targets/combine.py +1 -0
  514. ansible_test/_internal/cli/commands/coverage/analyze/targets/expand.py +1 -0
  515. ansible_test/_internal/cli/commands/coverage/analyze/targets/filter.py +1 -0
  516. ansible_test/_internal/cli/commands/coverage/analyze/targets/generate.py +1 -0
  517. ansible_test/_internal/cli/commands/coverage/analyze/targets/missing.py +1 -0
  518. ansible_test/_internal/cli/commands/coverage/combine.py +1 -0
  519. ansible_test/_internal/cli/commands/coverage/erase.py +1 -0
  520. ansible_test/_internal/cli/commands/coverage/html.py +1 -0
  521. ansible_test/_internal/cli/commands/coverage/report.py +1 -0
  522. ansible_test/_internal/cli/commands/coverage/xml.py +1 -0
  523. ansible_test/_internal/cli/commands/env.py +1 -0
  524. ansible_test/_internal/cli/commands/integration/__init__.py +1 -0
  525. ansible_test/_internal/cli/commands/integration/network.py +1 -0
  526. ansible_test/_internal/cli/commands/integration/posix.py +1 -0
  527. ansible_test/_internal/cli/commands/integration/windows.py +1 -0
  528. ansible_test/_internal/cli/commands/sanity.py +9 -0
  529. ansible_test/_internal/cli/commands/shell.py +1 -0
  530. ansible_test/_internal/cli/commands/units.py +1 -0
  531. ansible_test/_internal/cli/compat.py +1 -0
  532. ansible_test/_internal/cli/completers.py +1 -0
  533. ansible_test/_internal/cli/converters.py +1 -0
  534. ansible_test/_internal/cli/environments.py +1 -0
  535. ansible_test/_internal/cli/epilog.py +1 -0
  536. ansible_test/_internal/cli/parsers/__init__.py +1 -0
  537. ansible_test/_internal/cli/parsers/base_argument_parsers.py +1 -0
  538. ansible_test/_internal/cli/parsers/helpers.py +1 -0
  539. ansible_test/_internal/cli/parsers/host_config_parsers.py +1 -0
  540. ansible_test/_internal/cli/parsers/key_value_parsers.py +1 -0
  541. ansible_test/_internal/cli/parsers/value_parsers.py +1 -0
  542. ansible_test/_internal/commands/__init__.py +1 -0
  543. ansible_test/_internal/commands/coverage/__init__.py +2 -1
  544. ansible_test/_internal/commands/coverage/analyze/__init__.py +1 -0
  545. ansible_test/_internal/commands/coverage/analyze/targets/__init__.py +1 -0
  546. ansible_test/_internal/commands/coverage/analyze/targets/combine.py +1 -0
  547. ansible_test/_internal/commands/coverage/analyze/targets/expand.py +1 -0
  548. ansible_test/_internal/commands/coverage/analyze/targets/filter.py +1 -0
  549. ansible_test/_internal/commands/coverage/analyze/targets/generate.py +1 -0
  550. ansible_test/_internal/commands/coverage/analyze/targets/missing.py +1 -0
  551. ansible_test/_internal/commands/coverage/combine.py +2 -1
  552. ansible_test/_internal/commands/coverage/erase.py +1 -0
  553. ansible_test/_internal/commands/coverage/html.py +1 -0
  554. ansible_test/_internal/commands/coverage/report.py +1 -0
  555. ansible_test/_internal/commands/coverage/xml.py +1 -0
  556. ansible_test/_internal/commands/env/__init__.py +2 -0
  557. ansible_test/_internal/commands/integration/__init__.py +4 -0
  558. ansible_test/_internal/commands/integration/cloud/__init__.py +1 -0
  559. ansible_test/_internal/commands/integration/cloud/acme.py +2 -1
  560. ansible_test/_internal/commands/integration/cloud/aws.py +1 -0
  561. ansible_test/_internal/commands/integration/cloud/azure.py +1 -0
  562. ansible_test/_internal/commands/integration/cloud/cs.py +1 -0
  563. ansible_test/_internal/commands/integration/cloud/digitalocean.py +1 -0
  564. ansible_test/_internal/commands/integration/cloud/galaxy.py +3 -2
  565. ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -0
  566. ansible_test/_internal/commands/integration/cloud/httptester.py +2 -1
  567. ansible_test/_internal/commands/integration/cloud/nios.py +2 -1
  568. ansible_test/_internal/commands/integration/cloud/opennebula.py +1 -0
  569. ansible_test/_internal/commands/integration/cloud/openshift.py +1 -0
  570. ansible_test/_internal/commands/integration/cloud/scaleway.py +1 -0
  571. ansible_test/_internal/commands/integration/cloud/vcenter.py +1 -0
  572. ansible_test/_internal/commands/integration/cloud/vultr.py +1 -0
  573. ansible_test/_internal/commands/integration/coverage.py +1 -0
  574. ansible_test/_internal/commands/integration/filters.py +1 -0
  575. ansible_test/_internal/commands/integration/network.py +1 -0
  576. ansible_test/_internal/commands/integration/posix.py +1 -0
  577. ansible_test/_internal/commands/integration/windows.py +1 -0
  578. ansible_test/_internal/commands/sanity/__init__.py +16 -1
  579. ansible_test/_internal/commands/sanity/ansible_doc.py +1 -0
  580. ansible_test/_internal/commands/sanity/bin_symlinks.py +1 -0
  581. ansible_test/_internal/commands/sanity/compile.py +1 -0
  582. ansible_test/_internal/commands/sanity/ignores.py +1 -0
  583. ansible_test/_internal/commands/sanity/import.py +1 -0
  584. ansible_test/_internal/commands/sanity/integration_aliases.py +1 -0
  585. ansible_test/_internal/commands/sanity/pep8.py +1 -0
  586. ansible_test/_internal/commands/sanity/pslint.py +1 -0
  587. ansible_test/_internal/commands/sanity/pylint.py +24 -26
  588. ansible_test/_internal/commands/sanity/shellcheck.py +1 -0
  589. ansible_test/_internal/commands/sanity/validate_modules.py +1 -0
  590. ansible_test/_internal/commands/sanity/yamllint.py +1 -0
  591. ansible_test/_internal/commands/shell/__init__.py +1 -0
  592. ansible_test/_internal/commands/units/__init__.py +1 -0
  593. ansible_test/_internal/compat/__init__.py +1 -0
  594. ansible_test/_internal/compat/packaging.py +1 -0
  595. ansible_test/_internal/compat/yaml.py +1 -0
  596. ansible_test/_internal/completion.py +1 -0
  597. ansible_test/_internal/config.py +2 -0
  598. ansible_test/_internal/connections.py +1 -0
  599. ansible_test/_internal/constants.py +1 -0
  600. ansible_test/_internal/containers.py +1 -0
  601. ansible_test/_internal/content_config.py +1 -0
  602. ansible_test/_internal/core_ci.py +1 -0
  603. ansible_test/_internal/coverage_util.py +11 -10
  604. ansible_test/_internal/data.py +1 -0
  605. ansible_test/_internal/delegation.py +1 -0
  606. ansible_test/_internal/dev/__init__.py +1 -0
  607. ansible_test/_internal/dev/container_probe.py +1 -0
  608. ansible_test/_internal/diff.py +3 -2
  609. ansible_test/_internal/docker_util.py +2 -1
  610. ansible_test/_internal/encoding.py +1 -0
  611. ansible_test/_internal/executor.py +1 -0
  612. ansible_test/_internal/git.py +1 -0
  613. ansible_test/_internal/host_configs.py +1 -0
  614. ansible_test/_internal/host_profiles.py +1 -0
  615. ansible_test/_internal/http.py +1 -0
  616. ansible_test/_internal/init.py +1 -0
  617. ansible_test/_internal/inventory.py +35 -3
  618. ansible_test/_internal/io.py +1 -0
  619. ansible_test/_internal/metadata.py +1 -0
  620. ansible_test/_internal/payload.py +1 -0
  621. ansible_test/_internal/provider/__init__.py +1 -0
  622. ansible_test/_internal/provider/layout/__init__.py +1 -0
  623. ansible_test/_internal/provider/layout/ansible.py +1 -0
  624. ansible_test/_internal/provider/layout/collection.py +1 -0
  625. ansible_test/_internal/provider/layout/unsupported.py +1 -0
  626. ansible_test/_internal/provider/source/__init__.py +1 -0
  627. ansible_test/_internal/provider/source/git.py +1 -0
  628. ansible_test/_internal/provider/source/installed.py +1 -0
  629. ansible_test/_internal/provider/source/unsupported.py +1 -0
  630. ansible_test/_internal/provider/source/unversioned.py +1 -0
  631. ansible_test/_internal/provisioning.py +1 -0
  632. ansible_test/_internal/pypi_proxy.py +6 -5
  633. ansible_test/_internal/python_requirements.py +1 -0
  634. ansible_test/_internal/ssh.py +1 -0
  635. ansible_test/_internal/target.py +1 -0
  636. ansible_test/_internal/test.py +3 -2
  637. ansible_test/_internal/thread.py +1 -0
  638. ansible_test/_internal/timeout.py +1 -0
  639. ansible_test/_internal/util.py +1 -0
  640. ansible_test/_internal/util_common.py +5 -2
  641. ansible_test/_internal/venv.py +1 -0
  642. ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +1 -0
  643. ansible_test/_util/controller/sanity/code-smell/changelog/sphinx.py +1 -0
  644. ansible_test/_util/controller/sanity/code-smell/changelog.py +1 -0
  645. ansible_test/_util/controller/sanity/code-smell/empty-init.py +1 -0
  646. ansible_test/_util/controller/sanity/code-smell/line-endings.py +1 -0
  647. ansible_test/_util/controller/sanity/code-smell/no-assert.py +1 -0
  648. ansible_test/_util/controller/sanity/code-smell/no-get-exception.py +1 -0
  649. ansible_test/_util/controller/sanity/code-smell/no-illegal-filenames.py +1 -0
  650. ansible_test/_util/controller/sanity/code-smell/no-smart-quotes.py +1 -0
  651. ansible_test/_util/controller/sanity/code-smell/replace-urlopen.py +1 -0
  652. ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +28 -1
  653. ansible_test/_util/controller/sanity/code-smell/shebang.py +1 -0
  654. ansible_test/_util/controller/sanity/code-smell/symlinks.py +1 -0
  655. ansible_test/_util/controller/sanity/code-smell/use-argspec-type-path.py +1 -0
  656. ansible_test/_util/controller/sanity/code-smell/use-compat-six.py +1 -0
  657. ansible_test/_util/controller/sanity/integration-aliases/yaml_to_json.py +2 -1
  658. ansible_test/_util/controller/sanity/pep8/current-ignore.txt +4 -0
  659. ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +7 -5
  660. ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +7 -5
  661. ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +7 -5
  662. ansible_test/_util/controller/sanity/pylint/config/collection.cfg +3 -5
  663. ansible_test/_util/controller/sanity/pylint/config/default.cfg +7 -7
  664. ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -13
  665. ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +1 -0
  666. ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +1 -8
  667. ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +1 -8
  668. ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +55 -28
  669. ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +12 -5
  670. ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +13 -2
  671. ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -0
  672. ansible_test/_util/controller/sanity/yamllint/yamllinter.py +35 -17
  673. ansible_test/_util/controller/tools/collection_detail.py +1 -0
  674. ansible_test/_util/controller/tools/yaml_to_json.py +2 -1
  675. ansible_test/_util/target/pytest/plugins/ansible_forked.py +6 -1
  676. ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py +2 -1
  677. ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +1 -0
  678. ansible_test/_util/target/sanity/compile/compile.py +1 -0
  679. ansible_test/_util/target/sanity/import/importer.py +15 -16
  680. ansible_test/_util/target/setup/bootstrap.sh +9 -20
  681. ansible_test/_util/target/setup/probe_cgroups.py +1 -0
  682. ansible_test/_util/target/setup/quiet_pip.py +1 -0
  683. ansible_test/_util/target/setup/requirements.py +35 -27
  684. ansible_test/_util/target/tools/virtualenvcheck.py +2 -1
  685. ansible_test/_util/target/tools/yamlcheck.py +2 -1
  686. ansible/compat/selectors.py +0 -32
  687. ansible/errors/yaml_strings.py +0 -138
  688. ansible/executor/action_write_locks.py +0 -44
  689. ansible/executor/discovery/python_target.py +0 -47
  690. ansible/executor/powershell/module_powershell_wrapper.ps1 +0 -86
  691. ansible/executor/powershell/module_script_wrapper.ps1 +0 -22
  692. ansible/module_utils/compat/importlib.py +0 -26
  693. ansible/module_utils/compat/selectors.py +0 -32
  694. ansible/module_utils/pycompat24.py +0 -73
  695. ansible/parsing/utils/jsonify.py +0 -36
  696. ansible/parsing/yaml/constructor.py +0 -178
  697. ansible/template/native_helpers.py +0 -251
  698. ansible/template/template.py +0 -43
  699. ansible/template/vars.py +0 -77
  700. ansible/utils/native_jinja.py +0 -11
  701. ansible/vars/fact_cache.py +0 -71
  702. ansible_core-2.18.4rc1.dist-info/RECORD +0 -992
  703. {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/Apache-License.txt +0 -0
  704. {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/COPYING +0 -0
  705. {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/MIT-license.txt +0 -0
  706. {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/PSF-license.txt +0 -0
  707. {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/entry_points.txt +0 -0
  708. {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/simplified_bsd.txt +0 -0
  709. {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/top_level.txt +0 -0
@@ -27,18 +27,22 @@ import multiprocessing.queues
27
27
 
28
28
  from ansible import constants as C
29
29
  from ansible import context
30
- from ansible.errors import AnsibleError
30
+ from ansible.errors import AnsibleError, ExitCode, AnsibleCallbackError
31
+ from ansible._internal._errors._handler import ErrorHandler
31
32
  from ansible.executor.play_iterator import PlayIterator
32
33
  from ansible.executor.stats import AggregateStats
33
34
  from ansible.executor.task_result import TaskResult
35
+ from ansible.inventory.data import InventoryData
34
36
  from ansible.module_utils.six import string_types
35
- from ansible.module_utils.common.text.converters import to_text, to_native
37
+ from ansible.module_utils.common.text.converters import to_native
38
+ from ansible.parsing.dataloader import DataLoader
36
39
  from ansible.playbook.play_context import PlayContext
37
40
  from ansible.playbook.task import Task
38
41
  from ansible.plugins.loader import callback_loader, strategy_loader, module_loader
39
42
  from ansible.plugins.callback import CallbackBase
40
- from ansible.template import Templar
43
+ from ansible._internal._templating._engine import TemplateEngine
41
44
  from ansible.vars.hostvars import HostVars
45
+ from ansible.vars.manager import VariableManager
42
46
  from ansible.utils.display import Display
43
47
  from ansible.utils.lock import lock_decorator
44
48
  from ansible.utils.multiprocessing import context as multiprocessing_context
@@ -47,6 +51,10 @@ from dataclasses import dataclass
47
51
 
48
52
  __all__ = ['TaskQueueManager']
49
53
 
54
+ STDIN_FILENO = 0
55
+ STDOUT_FILENO = 1
56
+ STDERR_FILENO = 2
57
+
50
58
  display = Display()
51
59
 
52
60
 
@@ -111,7 +119,7 @@ class AnsibleEndPlay(Exception):
111
119
 
112
120
  class TaskQueueManager:
113
121
 
114
- '''
122
+ """
115
123
  This class handles the multiprocessing requirements of Ansible by
116
124
  creating a pool of worker forks, a result handler fork, and a
117
125
  manager object with shared datastructures/queues for coordinating
@@ -119,29 +127,40 @@ class TaskQueueManager:
119
127
 
120
128
  The queue manager is responsible for loading the play strategy plugin,
121
129
  which dispatches the Play's tasks to hosts.
122
- '''
123
-
124
- RUN_OK = 0
125
- RUN_ERROR = 1
126
- RUN_FAILED_HOSTS = 2
127
- RUN_UNREACHABLE_HOSTS = 4
128
- RUN_FAILED_BREAK_PLAY = 8
129
- RUN_UNKNOWN_ERROR = 255
130
-
131
- def __init__(self, inventory, variable_manager, loader, passwords, stdout_callback=None, run_additional_callbacks=True, run_tree=False, forks=None):
132
-
130
+ """
131
+
132
+ RUN_OK = ExitCode.SUCCESS
133
+ RUN_ERROR = ExitCode.GENERIC_ERROR
134
+ RUN_FAILED_HOSTS = ExitCode.HOST_FAILED
135
+ RUN_UNREACHABLE_HOSTS = ExitCode.HOST_UNREACHABLE
136
+ RUN_FAILED_BREAK_PLAY = 8 # never leaves PlaybookExecutor.run
137
+ RUN_UNKNOWN_ERROR = 255 # never leaves PlaybookExecutor.run, intentionally includes the bit value for 8
138
+
139
+ _callback_dispatch_error_handler = ErrorHandler.from_config('_CALLBACK_DISPATCH_ERROR_BEHAVIOR')
140
+
141
+ def __init__(
142
+ self,
143
+ inventory: InventoryData,
144
+ variable_manager: VariableManager,
145
+ loader: DataLoader,
146
+ passwords: dict[str, str | None],
147
+ stdout_callback: str | None = None,
148
+ run_additional_callbacks: bool = True,
149
+ run_tree: bool = False,
150
+ forks: int | None = None,
151
+ ) -> None:
133
152
  self._inventory = inventory
134
153
  self._variable_manager = variable_manager
135
154
  self._loader = loader
136
155
  self._stats = AggregateStats()
137
156
  self.passwords = passwords
138
- self._stdout_callback = stdout_callback
157
+ self._stdout_callback: str | None | CallbackBase = stdout_callback
139
158
  self._run_additional_callbacks = run_additional_callbacks
140
159
  self._run_tree = run_tree
141
160
  self._forks = forks or 5
142
161
 
143
162
  self._callbacks_loaded = False
144
- self._callback_plugins = []
163
+ self._callback_plugins: list[CallbackBase] = []
145
164
  self._start_at_done = False
146
165
 
147
166
  # make sure any module paths (if specified) are added to the module_loader
@@ -154,14 +173,21 @@ class TaskQueueManager:
154
173
  self._terminated = False
155
174
 
156
175
  # dictionaries to keep track of failed/unreachable hosts
157
- self._failed_hosts = dict()
158
- self._unreachable_hosts = dict()
176
+ self._failed_hosts: dict[str, t.Literal[True]] = dict()
177
+ self._unreachable_hosts: dict[str, t.Literal[True]] = dict()
159
178
 
160
179
  try:
161
180
  self._final_q = FinalQueue()
162
181
  except OSError as e:
163
182
  raise AnsibleError("Unable to use multiprocessing, this is normally caused by lack of access to /dev/shm: %s" % to_native(e))
164
183
 
184
+ try:
185
+ # Done in tqm, and not display, because this is only needed for commands that execute tasks
186
+ for fd in (STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO):
187
+ os.set_inheritable(fd, False)
188
+ except Exception as ex:
189
+ self.warning(f"failed to set stdio as non inheritable: {ex}")
190
+
165
191
  self._callback_lock = threading.Lock()
166
192
 
167
193
  # A temporary file (opened pre-fork) used by connection
@@ -175,11 +201,11 @@ class TaskQueueManager:
175
201
  self._workers.append(None)
176
202
 
177
203
  def load_callbacks(self):
178
- '''
204
+ """
179
205
  Loads all available callbacks, with the exception of those which
180
206
  utilize the CALLBACK_TYPE option. When CALLBACK_TYPE is set to 'stdout',
181
207
  only one such callback plugin will be loaded.
182
- '''
208
+ """
183
209
 
184
210
  if self._callbacks_loaded:
185
211
  return
@@ -268,19 +294,19 @@ class TaskQueueManager:
268
294
  self._callbacks_loaded = True
269
295
 
270
296
  def run(self, play):
271
- '''
297
+ """
272
298
  Iterates over the roles/tasks in a play, using the given (or default)
273
299
  strategy for queueing tasks. The default is the linear strategy, which
274
300
  operates like classic Ansible by keeping all hosts in lock-step with
275
301
  a given task (meaning no hosts move on to the next task until all hosts
276
302
  are done with the current task).
277
- '''
303
+ """
278
304
 
279
305
  if not self._callbacks_loaded:
280
306
  self.load_callbacks()
281
307
 
282
308
  all_vars = self._variable_manager.get_vars(play=play)
283
- templar = Templar(loader=self._loader, variables=all_vars)
309
+ templar = TemplateEngine(loader=self._loader, variables=all_vars)
284
310
 
285
311
  new_play = play.copy()
286
312
  new_play.post_validate(templar)
@@ -383,25 +409,25 @@ class TaskQueueManager:
383
409
  except AttributeError:
384
410
  pass
385
411
 
386
- def clear_failed_hosts(self):
412
+ def clear_failed_hosts(self) -> None:
387
413
  self._failed_hosts = dict()
388
414
 
389
- def get_inventory(self):
415
+ def get_inventory(self) -> InventoryData:
390
416
  return self._inventory
391
417
 
392
- def get_variable_manager(self):
418
+ def get_variable_manager(self) -> VariableManager:
393
419
  return self._variable_manager
394
420
 
395
- def get_loader(self):
421
+ def get_loader(self) -> DataLoader:
396
422
  return self._loader
397
423
 
398
424
  def get_workers(self):
399
425
  return self._workers[:]
400
426
 
401
- def terminate(self):
427
+ def terminate(self) -> None:
402
428
  self._terminated = True
403
429
 
404
- def has_dead_workers(self):
430
+ def has_dead_workers(self) -> bool:
405
431
 
406
432
  # [<WorkerProcess(WorkerProcess-2, stopped[SIGKILL])>,
407
433
  # <WorkerProcess(WorkerProcess-2, stopped[SIGTERM])>
@@ -414,6 +440,7 @@ class TaskQueueManager:
414
440
 
415
441
  @lock_decorator(attr='_callback_lock')
416
442
  def send_callback(self, method_name, *args, **kwargs):
443
+ # We always send events to stdout callback first, rest should follow config order
417
444
  for callback_plugin in [self._stdout_callback] + self._callback_plugins:
418
445
  # a plugin that set self.disabled to True will not be called
419
446
  # see osx_say.py example for such a plugin
@@ -457,11 +484,8 @@ class TaskQueueManager:
457
484
  continue
458
485
 
459
486
  for method in methods:
460
- try:
461
- method(*new_args, **kwargs)
462
- except Exception as e:
463
- # TODO: add config toggle to make this fatal or not?
464
- display.warning(u"Failure using method (%s) in callback plugin (%s): %s" % (to_text(method_name), to_text(callback_plugin), to_text(e)))
465
- from traceback import format_tb
466
- from sys import exc_info
467
- display.vvv('Callback Exception: \n' + ' '.join(format_tb(exc_info()[2])))
487
+ with self._callback_dispatch_error_handler.handle(AnsibleCallbackError):
488
+ try:
489
+ method(*new_args, **kwargs)
490
+ except Exception as ex:
491
+ raise AnsibleCallbackError(f"Callback dispatch {method_name!r} failed for plugin {callback_plugin._load_name!r}.") from ex
@@ -4,12 +4,14 @@
4
4
 
5
5
  from __future__ import annotations
6
6
 
7
+ import typing as t
8
+
7
9
  from ansible import constants as C
8
10
  from ansible.parsing.dataloader import DataLoader
9
11
  from ansible.vars.clean import module_response_deepcopy, strip_internal_keys
10
12
 
11
13
  _IGNORE = ('failed', 'skipped')
12
- _PRESERVE = ('attempts', 'changed', 'retries')
14
+ _PRESERVE = ('attempts', 'changed', 'retries', '_ansible_no_log')
13
15
  _SUB_PRESERVE = {'_ansible_delegated_vars': ('ansible_host', 'ansible_port', 'ansible_user', 'ansible_connection')}
14
16
 
15
17
  # stuff callbacks need
@@ -22,11 +24,11 @@ CLEAN_EXCEPTIONS = (
22
24
 
23
25
 
24
26
  class TaskResult:
25
- '''
27
+ """
26
28
  This class is responsible for interpreting the resulting data
27
29
  from an executed task, and provides helper methods for determining
28
30
  the result of a given task.
29
- '''
31
+ """
30
32
 
31
33
  def __init__(self, host, task, return_data, task_fields=None):
32
34
  self._host = host
@@ -93,7 +95,7 @@ class TaskResult:
93
95
  return ret
94
96
 
95
97
  def _check_key(self, key):
96
- '''get a specific key from the result or its items'''
98
+ """get a specific key from the result or its items"""
97
99
 
98
100
  if isinstance(self._result, dict) and key in self._result:
99
101
  return self._result.get(key, False)
@@ -106,7 +108,7 @@ class TaskResult:
106
108
 
107
109
  def clean_copy(self):
108
110
 
109
- ''' returns 'clean' taskresult object '''
111
+ """ returns 'clean' taskresult object """
110
112
 
111
113
  # FIXME: clean task_fields, _task and _host copies
112
114
  result = TaskResult(self._host, self._task, {}, self._task_fields)
@@ -127,15 +129,15 @@ class TaskResult:
127
129
  if key in self._result[sub]:
128
130
  subset[sub][key] = self._result[sub][key]
129
131
 
130
- if isinstance(self._task.no_log, bool) and self._task.no_log or self._result.get('_ansible_no_log', False):
131
- x = {"censored": "the output has been hidden due to the fact that 'no_log: true' was specified for this result"}
132
+ # DTFIX-FUTURE: is checking no_log here redundant now that we use _ansible_no_log everywhere?
133
+ if isinstance(self._task.no_log, bool) and self._task.no_log or self._result.get('_ansible_no_log'):
134
+ censored_result = censor_result(self._result)
132
135
 
133
- # preserve full
134
- for preserve in _PRESERVE:
135
- if preserve in self._result:
136
- x[preserve] = self._result[preserve]
136
+ if results := self._result.get('results'):
137
+ # maintain shape for loop results so callback behavior recognizes a loop was performed
138
+ censored_result.update(results=[censor_result(item) if item.get('_ansible_no_log') else item for item in results])
137
139
 
138
- result._result = x
140
+ result._result = censored_result
139
141
  elif self._result:
140
142
  result._result = module_response_deepcopy(self._result)
141
143
 
@@ -151,3 +153,10 @@ class TaskResult:
151
153
  result._result.update(subset)
152
154
 
153
155
  return result
156
+
157
+
158
+ def censor_result(result: dict[str, t.Any]) -> dict[str, t.Any]:
159
+ censored_result = {key: value for key in _PRESERVE if (value := result.get(key, ...)) is not ...}
160
+ censored_result.update(censored="the output has been hidden due to the fact that 'no_log: true' was specified for this result")
161
+
162
+ return censored_result
@@ -18,7 +18,7 @@
18
18
  # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
19
19
  #
20
20
  ########################################################################
21
- ''' This manages remote shared Ansible objects, mainly roles'''
21
+ """ This manages remote shared Ansible objects, mainly roles"""
22
22
 
23
23
  from __future__ import annotations
24
24
 
@@ -40,7 +40,7 @@ def get_collections_galaxy_meta_info():
40
40
 
41
41
 
42
42
  class Galaxy(object):
43
- ''' Keeps global galaxy info '''
43
+ """ Keeps global galaxy info """
44
44
 
45
45
  def __init__(self):
46
46
  # TODO: eventually remove this as it contains a mismash of properties that aren't really global
ansible/galaxy/api.py CHANGED
@@ -57,13 +57,13 @@ def should_retry_error(exception):
57
57
  if isinstance(exception, GalaxyError) and exception.http_code in RETRY_HTTP_ERROR_CODES:
58
58
  return True
59
59
 
60
- if isinstance(exception, AnsibleError) and (orig_exc := getattr(exception, 'orig_exc', None)):
60
+ if isinstance(exception, AnsibleError) and (cause := exception.__cause__):
61
61
  # URLError is often a proxy for an underlying error, handle wrapped exceptions
62
- if isinstance(orig_exc, URLError):
63
- orig_exc = orig_exc.reason
62
+ if isinstance(cause, URLError):
63
+ cause = cause.reason
64
64
 
65
65
  # Handle common URL related errors
66
- if isinstance(orig_exc, (TimeoutError, BadStatusLine, IncompleteRead)):
66
+ if isinstance(cause, (TimeoutError, BadStatusLine, IncompleteRead)):
67
67
  return True
68
68
 
69
69
  return False
@@ -408,11 +408,8 @@ class GalaxyAPI:
408
408
  method=method, timeout=self._server_timeout, http_agent=user_agent(), follow_redirects='safe')
409
409
  except HTTPError as e:
410
410
  raise GalaxyError(e, error_context_msg)
411
- except Exception as e:
412
- raise AnsibleError(
413
- "Unknown error when attempting to call Galaxy at '%s': %s" % (url, to_native(e)),
414
- orig_exc=e
415
- )
411
+ except Exception as ex:
412
+ raise AnsibleError(f"Unknown error when attempting to call Galaxy at {url!r}.") from ex
416
413
 
417
414
  resp_data = to_text(resp.read(), errors='surrogate_or_strict')
418
415
  try:
@@ -471,8 +468,8 @@ class GalaxyAPI:
471
468
  resp = open_url(url, data=args, validate_certs=self.validate_certs, method="POST", http_agent=user_agent(), timeout=self._server_timeout)
472
469
  except HTTPError as e:
473
470
  raise GalaxyError(e, 'Attempting to authenticate to galaxy')
474
- except Exception as e:
475
- raise AnsibleError('Unable to authenticate to galaxy: %s' % to_native(e), orig_exc=e)
471
+ except Exception as ex:
472
+ raise AnsibleError('Unable to authenticate to galaxy.') from ex
476
473
 
477
474
  data = json.loads(to_text(resp.read(), errors='surrogate_or_strict'))
478
475
  return data
@@ -817,8 +814,17 @@ class GalaxyAPI:
817
814
 
818
815
  signatures = data.get('signatures') or []
819
816
 
817
+ download_url_info = urlparse(data['download_url'])
818
+ if not download_url_info.scheme and not download_url_info.path.startswith('/'):
819
+ # galaxy does a lot of redirects, with much more complex pathing than we use
820
+ # within this codebase, without updating _call_galaxy to be able to return
821
+ # the final URL, we can't reliably build a relative URL.
822
+ raise AnsibleError(f'Invalid non absolute download_url: {data["download_url"]}')
823
+
824
+ download_url = urljoin(self.api_server, data['download_url'])
825
+
820
826
  return CollectionVersionMetadata(data['namespace']['name'], data['collection']['name'], data['version'],
821
- data['download_url'], data['artifact']['sha256'],
827
+ download_url, data['artifact']['sha256'],
822
828
  data['metadata']['dependencies'], data['href'], signatures)
823
829
 
824
830
  @g_connect(['v2', 'v3'])
@@ -896,12 +902,10 @@ class GalaxyAPI:
896
902
  if not next_link:
897
903
  break
898
904
  elif relative_link:
899
- # TODO: This assumes the pagination result is relative to the root server. Will need to be verified
900
- # with someone who knows the AH API.
901
-
902
- # Remove the query string from the versions_url to use the next_link's query
903
- versions_url = urljoin(versions_url, urlparse(versions_url).path)
904
- next_link = versions_url.replace(versions_url_info.path, next_link)
905
+ next_link_info = urlparse(next_link)
906
+ if not next_link_info.scheme and not next_link_info.path.startswith('/'):
907
+ raise AnsibleError(f'Invalid non absolute pagination link: {next_link}')
908
+ next_link = urljoin(self.api_server, next_link)
905
909
 
906
910
  data = self._call_galaxy(to_native(next_link, errors='surrogate_or_strict'),
907
911
  error_context_msg=error_context_msg, cache=True, cache_key=cache_key)
@@ -126,13 +126,13 @@ from ansible.galaxy.dependency_resolution.dataclasses import (
126
126
  from ansible.galaxy.dependency_resolution.versioning import meets_requirements
127
127
  from ansible.plugins.loader import get_all_plugin_loaders
128
128
  from ansible.module_utils.common.file import S_IRWU_RG_RO, S_IRWXU_RXG_RXO, S_IXANY
129
+ from ansible.module_utils.common.sentinel import Sentinel
129
130
  from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
130
131
  from ansible.module_utils.common.collections import is_sequence
131
132
  from ansible.module_utils.common.yaml import yaml_dump
132
133
  from ansible.utils.collection_loader import AnsibleCollectionRef
133
134
  from ansible.utils.display import Display
134
135
  from ansible.utils.hashing import secure_hash, secure_hash_s
135
- from ansible.utils.sentinel import Sentinel
136
136
 
137
137
 
138
138
  display = Display()
@@ -35,10 +35,10 @@ from ansible.module_utils.common.text.converters import to_bytes, to_native, to_
35
35
  from ansible.module_utils.api import retry_with_delays_and_condition
36
36
  from ansible.module_utils.api import generate_jittered_backoff
37
37
  from ansible.module_utils.common.process import get_bin_path
38
+ from ansible.module_utils.common.sentinel import Sentinel
38
39
  from ansible.module_utils.common.yaml import yaml_load
39
40
  from ansible.module_utils.urls import open_url
40
41
  from ansible.utils.display import Display
41
- from ansible.utils.sentinel import Sentinel
42
42
 
43
43
  import ansible.constants as C
44
44
 
@@ -485,16 +485,13 @@ def _download_file(url, b_path, expected_hash, validate_certs, token=None, timeo
485
485
  display.display("Downloading %s to %s" % (url, to_text(b_tarball_dir)))
486
486
  # NOTE: Galaxy redirects downloads to S3 which rejects the request
487
487
  # NOTE: if an Authorization header is attached so don't redirect it
488
- try:
489
- resp = open_url(
490
- to_native(url, errors='surrogate_or_strict'),
491
- validate_certs=validate_certs,
492
- headers=None if token is None else token.headers(),
493
- unredirected_headers=['Authorization'], http_agent=user_agent(),
494
- timeout=timeout
495
- )
496
- except Exception as err:
497
- raise AnsibleError(to_native(err), orig_exc=err)
488
+ resp = open_url(
489
+ to_native(url, errors='surrogate_or_strict'),
490
+ validate_certs=validate_certs,
491
+ headers=None if token is None else token.headers(),
492
+ unredirected_headers=['Authorization'], http_agent=user_agent(),
493
+ timeout=timeout
494
+ )
498
495
 
499
496
  with open(b_file_path, 'wb') as download_file: # type: t.BinaryIO
500
497
  actual_hash = _consume_file(resp, write_to=download_file)
@@ -7,6 +7,7 @@
7
7
  from __future__ import annotations
8
8
 
9
9
  import os
10
+ import pathlib
10
11
  import typing as t
11
12
 
12
13
  from collections import namedtuple
@@ -25,6 +26,8 @@ if t.TYPE_CHECKING:
25
26
  '_ComputedReqKindsMixin',
26
27
  )
27
28
 
29
+ import ansible
30
+ import ansible.release
28
31
 
29
32
  from ansible.errors import AnsibleError, AnsibleAssertionError
30
33
  from ansible.galaxy.api import GalaxyAPI
@@ -39,6 +42,7 @@ _ALLOW_CONCRETE_POINTER_IN_SOURCE = False # NOTE: This is a feature flag
39
42
  _GALAXY_YAML = b'galaxy.yml'
40
43
  _MANIFEST_JSON = b'MANIFEST.json'
41
44
  _SOURCE_METADATA_FILE = b'GALAXY.yml'
45
+ _ANSIBLE_PACKAGE_PATH = pathlib.Path(ansible.__file__).parent
42
46
 
43
47
  display = Display()
44
48
 
@@ -224,6 +228,13 @@ class _ComputedReqKindsMixin:
224
228
  if dir_path.endswith(to_bytes(os.path.sep)):
225
229
  dir_path = dir_path.rstrip(to_bytes(os.path.sep))
226
230
  if not _is_collection_dir(dir_path):
231
+ dir_pathlib = pathlib.Path(to_text(dir_path))
232
+
233
+ # special handling for bundled collections without manifests, e.g., ansible._protomatter
234
+ if dir_pathlib.is_relative_to(_ANSIBLE_PACKAGE_PATH):
235
+ req_name = f'{dir_pathlib.parent.name}.{dir_pathlib.name}'
236
+ return cls(req_name, ansible.release.__version__, dir_path, 'dir', None)
237
+
227
238
  display.warning(
228
239
  u"Collection at '{path!s}' does not have a {manifest_json!s} "
229
240
  u'file, nor has it {galaxy_yml!s}: cannot detect version.'.
@@ -578,10 +589,9 @@ class _ComputedReqKindsMixin:
578
589
 
579
590
  See https://github.com/ansible/ansible/pull/81606 for extra context.
580
591
  """
581
- version_string = self.ver[0]
582
- return version_string.isdigit() or not (
583
- version_string == '*' or
584
- version_string.startswith(('<', '>', '!='))
592
+ version_spec_start_char = self.ver[0]
593
+ return version_spec_start_char.isdigit() or not (
594
+ version_spec_start_char.startswith(('<', '>', '!', '*'))
585
595
  )
586
596
 
587
597
  @property
@@ -39,7 +39,7 @@ except ImportError:
39
39
 
40
40
  # TODO: add python requirements to ansible-test's ansible-core distribution info and remove the hardcoded lowerbound/upperbound fallback
41
41
  RESOLVELIB_LOWERBOUND = SemanticVersion("0.5.3")
42
- RESOLVELIB_UPPERBOUND = SemanticVersion("1.1.0")
42
+ RESOLVELIB_UPPERBOUND = SemanticVersion("2.0.0")
43
43
  RESOLVELIB_VERSION = SemanticVersion.from_loose_version(LooseVersion(resolvelib_version))
44
44
 
45
45
 
@@ -5,12 +5,46 @@
5
5
 
6
6
  from __future__ import annotations
7
7
 
8
+ from collections import defaultdict
9
+
8
10
  try:
9
11
  from resolvelib import BaseReporter
10
12
  except ImportError:
11
13
  class BaseReporter: # type: ignore[no-redef]
12
14
  pass
13
15
 
16
+ try:
17
+ from resolvelib.resolvers import Criterion
18
+ except ImportError:
19
+ class Criterion: # type: ignore[no-redef]
20
+ pass
21
+
22
+ from ansible.utils.display import Display
23
+ from .dataclasses import Candidate, Requirement
24
+
25
+
26
+ display = Display()
27
+
28
+
29
+ _CLI_APP_NAME = 'ansible-galaxy'
30
+ _MESSAGES_AT_REJECT_COUNT = {
31
+ 1: (
32
+ f'{_CLI_APP_NAME} is looking at multiple versions of {{fqcn}} to '
33
+ 'determine which version is compatible with other '
34
+ 'requirements. This could take a while.'
35
+ ),
36
+ 8: (
37
+ f'{_CLI_APP_NAME} is looking at multiple versions of {{fqcn}} to '
38
+ 'determine which version is compatible with other '
39
+ 'requirements. This could take a while.'
40
+ ),
41
+ 13: (
42
+ 'This is taking longer than usual. You might need to provide '
43
+ 'the dependency resolver with stricter constraints to reduce '
44
+ 'runtime. If you want to abort this run, press Ctrl + C.'
45
+ ),
46
+ }
47
+
14
48
 
15
49
  class CollectionDependencyReporter(BaseReporter):
16
50
  """A dependency reporter for Ansible Collections.
@@ -18,3 +52,50 @@ class CollectionDependencyReporter(BaseReporter):
18
52
  This is a proxy class allowing us to abstract away importing resolvelib
19
53
  outside of the `ansible.galaxy.dependency_resolution` Python package.
20
54
  """
55
+
56
+ def __init__(self) -> None:
57
+ """Initialize the collection rejection counter."""
58
+ super().__init__()
59
+
60
+ self.reject_count_by_fqcn: defaultdict[str, int] = defaultdict(int)
61
+
62
+ def _maybe_log_rejection_message(self, candidate: Candidate) -> bool:
63
+ """Print out rejection messages on pre-defined limit hits."""
64
+ # Inspired by https://github.com/pypa/pip/commit/9731131
65
+ self.reject_count_by_fqcn[candidate.fqcn] += 1
66
+
67
+ collection_rejections_count = self.reject_count_by_fqcn[candidate.fqcn]
68
+
69
+ if collection_rejections_count not in _MESSAGES_AT_REJECT_COUNT:
70
+ return False
71
+
72
+ collection_rejection_message = _MESSAGES_AT_REJECT_COUNT[
73
+ collection_rejections_count
74
+ ]
75
+ display.display(collection_rejection_message.format(fqcn=candidate.fqcn))
76
+
77
+ return True
78
+
79
+ def rejecting_candidate( # resolvelib >= 0.9.0
80
+ self,
81
+ criterion: Criterion[Candidate, Requirement],
82
+ candidate: Candidate,
83
+ ) -> None:
84
+ """Augment rejection messages with conflict details."""
85
+ if not self._maybe_log_rejection_message(candidate):
86
+ return
87
+
88
+ msg = 'Will try a different candidate, due to conflict:'
89
+ for req_info in criterion.information:
90
+ req, parent = req_info.requirement, req_info.parent
91
+ msg += '\n '
92
+ if parent:
93
+ msg += f'{parent !s} depends on '
94
+ else:
95
+ msg += 'The user requested '
96
+ msg += str(req)
97
+ display.v(msg)
98
+
99
+ def backtracking(self, candidate: Candidate) -> None: # resolvelib < 0.9.0
100
+ """Print out rejection messages on pre-defined limit hits."""
101
+ self._maybe_log_rejection_message(candidate)
ansible/galaxy/role.py CHANGED
@@ -185,13 +185,11 @@ class GalaxyRole(object):
185
185
  info_path = os.path.join(self.path, self.META_INSTALL)
186
186
  if os.path.isfile(info_path):
187
187
  try:
188
- f = open(info_path, 'r')
189
- self._install_info = yaml_load(f)
188
+ with open(info_path, 'r') as f:
189
+ self._install_info = yaml_load(f)
190
190
  except Exception:
191
191
  display.vvvvv("Unable to load Galaxy install info for %s" % self.name)
192
192
  return False
193
- finally:
194
- f.close()
195
193
  return self._install_info
196
194
 
197
195
  @property
@@ -470,12 +468,10 @@ class GalaxyRole(object):
470
468
  meta_path = os.path.join(self.path, meta_requirements)
471
469
  if os.path.isfile(meta_path):
472
470
  try:
473
- f = open(meta_path, 'r')
474
- self._requirements = yaml_load(f)
471
+ with open(meta_path, 'r') as f:
472
+ self._requirements = yaml_load(f)
475
473
  except Exception:
476
474
  display.vvvvv("Unable to load requirements for %s" % self.name)
477
- finally:
478
- f.close()
479
475
 
480
476
  break
481
477