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
ansible/vars/manager.py CHANGED
@@ -19,38 +19,60 @@ from __future__ import annotations
19
19
 
20
20
  import os
21
21
  import sys
22
+ import typing as t
22
23
 
23
24
  from collections import defaultdict
24
- from collections.abc import Mapping, MutableMapping, Sequence
25
- from hashlib import sha1
26
-
27
- from jinja2.exceptions import UndefinedError
25
+ from collections.abc import Mapping, MutableMapping
28
26
 
29
27
  from ansible import constants as C
30
- from ansible.errors import AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleFileNotFound, AnsibleAssertionError
28
+ from ansible.errors import (AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleFileNotFound,
29
+ AnsibleAssertionError, AnsibleValueOmittedError)
31
30
  from ansible.inventory.host import Host
32
31
  from ansible.inventory.helpers import sort_groups, get_group_vars
33
- from ansible.module_utils.common.text.converters import to_text
32
+ from ansible.inventory.manager import InventoryManager
33
+ from ansible.module_utils.datatag import native_type_name
34
34
  from ansible.module_utils.six import text_type
35
- from ansible.vars.fact_cache import FactCache
36
- from ansible.template import Templar
35
+ from ansible.module_utils.datatag import deprecate_value
36
+ from ansible.parsing.dataloader import DataLoader
37
+ from ansible._internal._templating._engine import TemplateEngine
38
+ from ansible.plugins.loader import cache_loader
37
39
  from ansible.utils.display import Display
38
40
  from ansible.utils.vars import combine_vars, load_extra_vars, load_options_vars
39
- from ansible.utils.unsafe_proxy import wrap_var
40
41
  from ansible.vars.clean import namespace_facts, clean_facts
42
+ from ansible.vars.hostvars import HostVars
41
43
  from ansible.vars.plugins import get_vars_from_inventory_sources, get_vars_from_path
42
44
  from ansible.vars.reserved import warn_if_reserved
43
45
 
46
+ if t.TYPE_CHECKING:
47
+ from ansible.playbook import Play
48
+ from ansible.playbook.task import Task
49
+
44
50
  display = Display()
45
51
 
52
+ # deprecated: description='enable top-level facts deprecation' core_version='2.20'
53
+ # _DEPRECATE_TOP_LEVEL_FACT_MSG = sys.intern('Top-level facts are deprecated, use `ansible_facts` instead.')
54
+ # _DEPRECATE_TOP_LEVEL_FACT_REMOVAL_VERSION = sys.intern('2.22')
55
+
56
+
57
+ def _deprecate_top_level_fact(value: t.Any) -> t.Any:
58
+ """
59
+ Deprecate the given top-level fact value.
60
+ The inner values are shared to aid in message de-duplication across hosts/values, and reduce intra-process memory usage.
61
+ Unique tag instances are required to achieve the correct de-duplication within a top-level templating operation.
62
+ """
63
+ # deprecated: description='enable top-level facts deprecation' core_version='2.20'
64
+ # return deprecate_value(value, _DEPRECATE_TOP_LEVEL_FACT_MSG, removal_version=_DEPRECATE_TOP_LEVEL_FACT_REMOVAL_VERSION)
65
+ return value
66
+
46
67
 
47
68
  def preprocess_vars(a):
48
- '''
69
+ """
49
70
  Ensures that vars contained in the parameter passed in are
50
71
  returned as a list of dictionaries, to ensure for instance
51
72
  that vars loaded from a file conform to an expected state.
52
- '''
73
+ """
53
74
 
75
+ # FIXME: this does not properly handle omit, undefined, or dynamic structure from templated `vars` ; templating should be done earlier
54
76
  if a is None:
55
77
  return None
56
78
  elif not isinstance(a, list):
@@ -60,7 +82,11 @@ def preprocess_vars(a):
60
82
 
61
83
  for item in data:
62
84
  if not isinstance(item, MutableMapping):
63
- raise AnsibleError("variable files must contain either a dictionary of variables, or a list of dictionaries. Got: %s (%s)" % (a, type(a)))
85
+ raise AnsibleParserError(
86
+ message="Invalid variable file contents.",
87
+ obj=item,
88
+ help_text="Variable files must contain either a dictionary of variables, or a list of dictionaries.",
89
+ )
64
90
 
65
91
  return data
66
92
 
@@ -70,16 +96,12 @@ class VariableManager:
70
96
  _ALLOWED = frozenset(['plugins_by_group', 'groups_plugins_play', 'groups_plugins_inventory', 'groups_inventory',
71
97
  'all_plugins_play', 'all_plugins_inventory', 'all_inventory'])
72
98
 
73
- def __init__(self, loader=None, inventory=None, version_info=None):
74
- self._nonpersistent_fact_cache = defaultdict(dict)
75
- self._vars_cache = defaultdict(dict)
76
- self._extra_vars = defaultdict(dict)
77
- self._host_vars_files = defaultdict(dict)
78
- self._group_vars_files = defaultdict(dict)
99
+ def __init__(self, loader: DataLoader | None = None, inventory: InventoryManager | None = None, version_info: dict[str, str] | None = None) -> None:
100
+ self._nonpersistent_fact_cache: defaultdict[str, dict] = defaultdict(dict)
101
+ self._vars_cache: defaultdict[str, dict] = defaultdict(dict)
79
102
  self._inventory = inventory
80
103
  self._loader = loader
81
- self._hostvars = None
82
- self._omit_token = '__omit_place_holder__%s' % sha1(os.urandom(64)).hexdigest()
104
+ self._hostvars: HostVars | None = None
83
105
 
84
106
  self._options_vars = load_options_vars(version_info)
85
107
 
@@ -93,41 +115,12 @@ class VariableManager:
93
115
 
94
116
  # load fact cache
95
117
  try:
96
- self._fact_cache = FactCache()
97
- except AnsibleError as e:
118
+ self._fact_cache = cache_loader.get(C.CACHE_PLUGIN)
119
+ except Exception as ex:
98
120
  # bad cache plugin is not fatal error
99
- # fallback to a dict as in memory cache
100
- display.warning(to_text(e))
101
- self._fact_cache = {}
102
-
103
- def __getstate__(self):
104
- data = dict(
105
- fact_cache=self._fact_cache,
106
- np_fact_cache=self._nonpersistent_fact_cache,
107
- vars_cache=self._vars_cache,
108
- extra_vars=self._extra_vars,
109
- host_vars_files=self._host_vars_files,
110
- group_vars_files=self._group_vars_files,
111
- omit_token=self._omit_token,
112
- options_vars=self._options_vars,
113
- inventory=self._inventory,
114
- safe_basedir=self.safe_basedir,
115
- )
116
- return data
117
-
118
- def __setstate__(self, data):
119
- self._fact_cache = data.get('fact_cache', defaultdict(dict))
120
- self._nonpersistent_fact_cache = data.get('np_fact_cache', defaultdict(dict))
121
- self._vars_cache = data.get('vars_cache', defaultdict(dict))
122
- self._extra_vars = data.get('extra_vars', dict())
123
- self._host_vars_files = data.get('host_vars_files', defaultdict(dict))
124
- self._group_vars_files = data.get('group_vars_files', defaultdict(dict))
125
- self._omit_token = data.get('omit_token', '__omit_place_holder__%s' % sha1(os.urandom(64)).hexdigest())
126
- self._inventory = data.get('inventory', None)
127
- self._options_vars = data.get('options_vars', dict())
128
- self.safe_basedir = data.get('safe_basedir', False)
129
- self._loader = None
130
- self._hostvars = None
121
+ # fallback to builtin memory cache plugin
122
+ display.error_as_warning(None, ex)
123
+ self._fact_cache = cache_loader.get('ansible.builtin.memory') # use FQCN to ensure the builtin version is used
131
124
 
132
125
  @property
133
126
  def extra_vars(self):
@@ -136,9 +129,18 @@ class VariableManager:
136
129
  def set_inventory(self, inventory):
137
130
  self._inventory = inventory
138
131
 
139
- def get_vars(self, play=None, host=None, task=None, include_hostvars=True, include_delegate_to=False, use_cache=True,
140
- _hosts=None, _hosts_all=None, stage='task'):
141
- '''
132
+ def get_vars(
133
+ self,
134
+ play: Play | None = None,
135
+ host: Host | None = None,
136
+ task: Task | None = None,
137
+ include_hostvars: bool = True,
138
+ use_cache: bool = True,
139
+ _hosts: list[str] | None = None,
140
+ _hosts_all: list[str] | None = None,
141
+ stage: str = 'task',
142
+ ) -> dict[str, t.Any]:
143
+ """
142
144
  Returns the variables, with optional "context" given via the parameters
143
145
  for the play, host, and task (which could possibly result in different
144
146
  sets of variables being returned due to the additional context).
@@ -146,7 +148,6 @@ class VariableManager:
146
148
  The order of precedence is:
147
149
  - play->roles->get_default_vars (if there is a play context)
148
150
  - group_vars_files[host] (if there is a host context)
149
- - host_vars_files[host] (if there is a host context)
150
151
  - host->get_vars (if there is a host context)
151
152
  - fact_cache[host] (if there is a host context)
152
153
  - play vars (if there is a play context)
@@ -159,16 +160,11 @@ class VariableManager:
159
160
  ``_hosts`` and ``_hosts_all`` should be considered private args, with only internal trusted callers relying
160
161
  on the functionality they provide. These arguments may be removed at a later date without a deprecation
161
162
  period and without warning.
162
- '''
163
- if include_delegate_to:
164
- display.deprecated(
165
- "`VariableManager.get_vars`'s argument `include_delegate_to` has no longer any effect.",
166
- version="2.19",
167
- )
163
+ """
168
164
 
169
165
  display.debug("in VariableManager get_vars()")
170
166
 
171
- all_vars = dict()
167
+ all_vars: dict[str, t.Any] = dict()
172
168
  magic_variables = self._get_magic_variables(
173
169
  play=play,
174
170
  host=host,
@@ -178,21 +174,11 @@ class VariableManager:
178
174
  _hosts_all=_hosts_all,
179
175
  )
180
176
 
181
- _vars_sources = {}
182
-
183
177
  def _combine_and_track(data, new_data, source):
184
- '''
185
- Wrapper function to update var sources dict and call combine_vars()
186
-
187
- See notes in the VarsWithSources docstring for caveats and limitations of the source tracking
188
- '''
178
+ # FIXME: this no longer does any tracking, only a slight optimization for empty new_data
189
179
  if new_data == {}:
190
180
  return data
191
181
 
192
- if C.DEFAULT_DEBUG:
193
- # Populate var sources dict
194
- for key in new_data:
195
- _vars_sources[key] = source
196
182
  return combine_vars(data, new_data)
197
183
 
198
184
  # default for all cases
@@ -226,7 +212,7 @@ class VariableManager:
226
212
  if host:
227
213
  # THE 'all' group and the rest of groups for a host, used below
228
214
  all_group = self._inventory.groups.get('all')
229
- host_groups = sort_groups([g for g in host.get_groups() if g.name not in ['all']])
215
+ host_groups = sort_groups([g for g in host.get_groups() if g.name != 'all'])
230
216
 
231
217
  def _get_plugin_vars(plugin, path, entities):
232
218
  data = {}
@@ -248,11 +234,11 @@ class VariableManager:
248
234
 
249
235
  # internal functions that actually do the work
250
236
  def _plugins_inventory(entities):
251
- ''' merges all entities by inventory source '''
237
+ """ merges all entities by inventory source """
252
238
  return get_vars_from_inventory_sources(self._loader, self._inventory._sources, entities, stage)
253
239
 
254
240
  def _plugins_play(entities):
255
- ''' merges all entities adjacent to play '''
241
+ """ merges all entities adjacent to play """
256
242
  data = {}
257
243
  for path in basedirs:
258
244
  data = _combine_and_track(data, get_vars_from_path(self._loader, path, entities, stage), "path '%s'" % path)
@@ -269,22 +255,22 @@ class VariableManager:
269
255
  return _plugins_play([all_group])
270
256
 
271
257
  def groups_inventory():
272
- ''' gets group vars from inventory '''
258
+ """ gets group vars from inventory """
273
259
  return get_group_vars(host_groups)
274
260
 
275
261
  def groups_plugins_inventory():
276
- ''' gets plugin sources from inventory for groups '''
262
+ """ gets plugin sources from inventory for groups """
277
263
  return _plugins_inventory(host_groups)
278
264
 
279
265
  def groups_plugins_play():
280
- ''' gets plugin sources from play for groups '''
266
+ """ gets plugin sources from play for groups """
281
267
  return _plugins_play(host_groups)
282
268
 
283
269
  def plugins_by_groups():
284
- '''
270
+ """
285
271
  merges all plugin sources by group,
286
272
  This should be used instead, NOT in combination with the other groups_plugins* functions
287
- '''
273
+ """
288
274
  data = {}
289
275
  for group in host_groups:
290
276
  data[group] = _combine_and_track(data[group], _plugins_inventory(group), "inventory group_vars for '%s'" % group)
@@ -308,15 +294,20 @@ class VariableManager:
308
294
  # finally, the facts caches for this host, if it exists
309
295
  # TODO: cleaning of facts should eventually become part of taskresults instead of vars
310
296
  try:
311
- facts = wrap_var(self._fact_cache.get(host.name, {}))
297
+ try:
298
+ facts = self._fact_cache.get(host.name)
299
+ except KeyError:
300
+ facts = {}
301
+
312
302
  all_vars |= namespace_facts(facts)
313
303
 
314
304
  # push facts to main namespace
315
305
  if C.INJECT_FACTS_AS_VARS:
316
- all_vars = _combine_and_track(all_vars, wrap_var(clean_facts(facts)), "facts")
306
+ deprecated_facts_vars = {k: _deprecate_top_level_fact(v) for k, v in clean_facts(facts).items()}
307
+ all_vars = _combine_and_track(all_vars, deprecated_facts_vars, "facts")
317
308
  else:
318
309
  # always 'promote' ansible_local
319
- all_vars = _combine_and_track(all_vars, wrap_var({'ansible_local': facts.get('ansible_local', {})}), "facts")
310
+ all_vars = _combine_and_track(all_vars, {'ansible_local': facts.get('ansible_local', {})}, "facts")
320
311
  except KeyError:
321
312
  pass
322
313
 
@@ -324,63 +315,68 @@ class VariableManager:
324
315
  all_vars = _combine_and_track(all_vars, play.get_vars(), "play vars")
325
316
 
326
317
  vars_files = play.get_vars_files()
327
- try:
328
- for vars_file_item in vars_files:
329
- # create a set of temporary vars here, which incorporate the extra
330
- # and magic vars so we can properly template the vars_files entries
331
- # NOTE: this makes them depend on host vars/facts so things like
332
- # ansible_facts['os_distribution'] can be used, ala include_vars.
333
- # Consider DEPRECATING this in the future, since we have include_vars ...
334
- temp_vars = combine_vars(all_vars, self._extra_vars)
335
- temp_vars = combine_vars(temp_vars, magic_variables)
336
- templar = Templar(loader=self._loader, variables=temp_vars)
337
-
338
- # we assume each item in the list is itself a list, as we
339
- # support "conditional includes" for vars_files, which mimics
340
- # the with_first_found mechanism.
341
- vars_file_list = vars_file_item
342
- if not isinstance(vars_file_list, list):
343
- vars_file_list = [vars_file_list]
344
-
345
- # now we iterate through the (potential) files, and break out
346
- # as soon as we read one from the list. If none are found, we
347
- # raise an error, which is silently ignored at this point.
348
- try:
349
- for vars_file in vars_file_list:
350
- vars_file = templar.template(vars_file)
351
- if not (isinstance(vars_file, Sequence)):
352
- raise AnsibleError(
353
- "Invalid vars_files entry found: %r\n"
354
- "vars_files entries should be either a string type or "
355
- "a list of string types after template expansion" % vars_file
356
- )
357
- try:
358
- play_search_stack = play.get_search_path()
359
- found_file = self._loader.path_dwim_relative_stack(play_search_stack, 'vars', vars_file)
360
- data = preprocess_vars(self._loader.load_from_file(found_file, unsafe=True, cache='vaulted'))
361
- if data is not None:
362
- for item in data:
363
- all_vars = _combine_and_track(all_vars, item, "play vars_files from '%s'" % vars_file)
364
- break
365
- except AnsibleFileNotFound:
366
- # we continue on loader failures
367
- continue
368
- except AnsibleParserError:
369
- raise
370
- except (UndefinedError, AnsibleUndefinedVariable):
371
- if host is not None and self._fact_cache.get(host.name, dict()).get('module_setup') and task is not None:
372
- raise AnsibleUndefinedVariable("an undefined variable was found when attempting to template the vars_files item '%s'"
373
- % vars_file_item, obj=vars_file_item)
374
- else:
375
- # we do not have a full context here, and the missing variable could be because of that
376
- # so just show a warning and continue
377
- display.vvv("skipping vars_file '%s' due to an undefined variable" % vars_file_item)
318
+
319
+ for vars_file_item in vars_files:
320
+ # create a set of temporary vars here, which incorporate the extra
321
+ # and magic vars so we can properly template the vars_files entries
322
+ # NOTE: this makes them depend on host vars/facts so things like
323
+ # ansible_facts['os_distribution'] can be used, ala include_vars.
324
+ # Consider DEPRECATING this in the future, since we have include_vars ...
325
+ temp_vars = combine_vars(all_vars, self._extra_vars)
326
+ temp_vars = combine_vars(temp_vars, magic_variables)
327
+ templar = TemplateEngine(loader=self._loader, variables=temp_vars)
328
+
329
+ # we assume each item in the list is itself a list, as we
330
+ # support "conditional includes" for vars_files, which mimics
331
+ # the with_first_found mechanism.
332
+ vars_file_list = vars_file_item
333
+ if not isinstance(vars_file_list, list):
334
+ vars_file_list = [vars_file_list]
335
+
336
+ # now we iterate through the (potential) files, and break out
337
+ # as soon as we read one from the list. If none are found, we
338
+ # raise an error, which is silently ignored at this point.
339
+ try:
340
+ for vars_file in vars_file_list:
341
+ vars_file = templar.template(vars_file)
342
+ if not (isinstance(vars_file, str)):
343
+ raise AnsibleParserError(
344
+ message=f"Invalid `vars_files` value of type {native_type_name(vars_file)!r}.",
345
+ obj=vars_file,
346
+ help_text="A `vars_files` value should either be a string or list of strings.",
347
+ )
348
+ try:
349
+ play_search_stack = play.get_search_path()
350
+ found_file = self._loader.path_dwim_relative_stack(play_search_stack, 'vars', vars_file)
351
+ data = preprocess_vars(self._loader.load_from_file(found_file, unsafe=True, cache='vaulted', trusted_as_template=True))
352
+ if data is not None:
353
+ for item in data:
354
+ all_vars = _combine_and_track(all_vars, item, "play vars_files from '%s'" % vars_file)
355
+ display.vvv(f"Read `vars_file` {found_file!r}.")
356
+ break
357
+ except AnsibleFileNotFound:
358
+ # we continue on loader failures
378
359
  continue
360
+ except AnsibleParserError:
361
+ raise
362
+ except AnsibleUndefinedVariable:
363
+ raise
364
+ except Exception as ex:
365
+ raise AnsibleParserError(f"Error reading `vars_files` file {vars_file!r}.", obj=vars_file) from ex
366
+
367
+ except AnsibleUndefinedVariable as ex:
368
+ if host is not None:
369
+ try:
370
+ facts = self._fact_cache.get(host.name)
371
+ except KeyError:
372
+ pass
373
+ else:
374
+ if facts.get('module_setup') and task is not None:
375
+ raise AnsibleUndefinedVariable("an undefined variable was found when attempting to template the vars_files item '%s'"
376
+ % vars_file_item, obj=vars_file_item) from ex
379
377
 
380
- display.vvv("Read vars_file '%s'" % vars_file_item)
381
- except TypeError:
382
- raise AnsibleParserError("Error while reading vars files - please supply a list of file names. "
383
- "Got '%s' of type %s" % (vars_files, type(vars_files)))
378
+ display.warning("skipping vars_file item due to an undefined variable", obj=vars_file_item)
379
+ continue
384
380
 
385
381
  # We now merge in all exported vars from all roles in the play (very high precedence)
386
382
  for role in play.roles:
@@ -433,17 +429,21 @@ class VariableManager:
433
429
  all_vars['vars'] = all_vars.copy()
434
430
 
435
431
  display.debug("done with get_vars()")
436
- if C.DEFAULT_DEBUG:
437
- # Use VarsWithSources wrapper class to display var sources
438
- return VarsWithSources.new_vars_with_sources(all_vars, _vars_sources)
439
- else:
440
- return all_vars
432
+ return all_vars
433
+
434
+ def _facts_gathered_for_host(self, hostname) -> bool:
435
+ try:
436
+ facts = self._fact_cache.get(hostname)
437
+ except KeyError:
438
+ facts = {}
439
+
440
+ return bool(facts.get('_ansible_facts_gathered', False))
441
441
 
442
442
  def _get_magic_variables(self, play, host, task, include_hostvars, _hosts=None, _hosts_all=None):
443
- '''
443
+ """
444
444
  Returns a dictionary of so-called "magic" variables in Ansible,
445
445
  which are special variables we set internally for use.
446
- '''
446
+ """
447
447
 
448
448
  variables = {}
449
449
  variables['playbook_dir'] = os.path.abspath(self._loader.get_basedir())
@@ -480,13 +480,13 @@ class VariableManager:
480
480
  if self._inventory is not None:
481
481
  variables['groups'] = self._inventory.get_groups_dict()
482
482
  if play:
483
- templar = Templar(loader=self._loader)
484
- if not play.finalized and templar.is_template(play.hosts):
485
- pattern = 'all'
486
- else:
487
- pattern = play.hosts or 'all'
488
483
  # add the list of hosts in the play, as adjusted for limit/filters
489
484
  if not _hosts_all:
485
+ if not play.finalized and TemplateEngine().is_template(play.hosts):
486
+ pattern = 'all'
487
+ else:
488
+ pattern = play.hosts or 'all'
489
+
490
490
  _hosts_all = [h.name for h in self._inventory.get_hosts(pattern=pattern, ignore_restrictions=True)]
491
491
  if not _hosts:
492
492
  _hosts = [h.name for h in self._inventory.get_hosts()]
@@ -495,12 +495,12 @@ class VariableManager:
495
495
  variables['ansible_play_hosts'] = [x for x in variables['ansible_play_hosts_all'] if x not in play._removed_hosts]
496
496
  variables['ansible_play_batch'] = [x for x in _hosts if x not in play._removed_hosts]
497
497
 
498
- # DEPRECATED: play_hosts should be deprecated in favor of ansible_play_batch,
499
- # however this would take work in the templating engine, so for now we'll add both
500
- variables['play_hosts'] = variables['ansible_play_batch']
498
+ variables['play_hosts'] = deprecate_value(
499
+ value=variables['ansible_play_batch'],
500
+ msg='Use `ansible_play_batch` instead of `play_hosts`.',
501
+ removal_version='2.23',
502
+ )
501
503
 
502
- # the 'omit' value allows params to be left out if the variable they are based on is undefined
503
- variables['omit'] = self._omit_token
504
504
  # Set options vars
505
505
  for option, option_value in self._options_vars.items():
506
506
  variables[option] = option_value
@@ -517,56 +517,64 @@ class VariableManager:
517
517
  Not used directly be VariableManager, but used primarily within TaskExecutor
518
518
  """
519
519
  delegated_vars = {}
520
- delegated_host_name = None
521
- if task.delegate_to:
522
- delegated_host_name = templar.template(task.delegate_to, fail_on_undefined=False)
520
+ delegated_host_name = ... # sentinel value distinct from empty/None, which are errors
523
521
 
524
- # no need to do work if omitted
525
- if delegated_host_name != self._omit_token:
526
-
527
- if not delegated_host_name:
528
- raise AnsibleError('Empty hostname produced from delegate_to: "%s"' % task.delegate_to)
522
+ if task.delegate_to:
523
+ try:
524
+ delegated_host_name = templar.template(task.delegate_to)
525
+ except AnsibleValueOmittedError:
526
+ pass
529
527
 
530
- delegated_host = self._inventory.get_host(delegated_host_name)
531
- if delegated_host is None:
532
- for h in self._inventory.get_hosts(ignore_limits=True, ignore_restrictions=True):
533
- # check if the address matches, or if both the delegated_to host
534
- # and the current host are in the list of localhost aliases
535
- if h.address == delegated_host_name:
536
- delegated_host = h
537
- break
538
- else:
539
- delegated_host = Host(name=delegated_host_name)
540
-
541
- delegated_vars['ansible_delegated_vars'] = {
542
- delegated_host_name: self.get_vars(
543
- play=task.get_play(),
544
- host=delegated_host,
545
- task=task,
546
- include_hostvars=True,
547
- )
548
- }
549
- delegated_vars['ansible_delegated_vars'][delegated_host_name]['inventory_hostname'] = variables.get('inventory_hostname')
528
+ # bypass for unspecified value/omit
529
+ if delegated_host_name is ...:
530
+ return delegated_vars, None
531
+
532
+ if not delegated_host_name:
533
+ raise AnsibleError('Empty hostname produced from delegate_to: "%s"' % task.delegate_to)
534
+
535
+ delegated_host = self._inventory.get_host(delegated_host_name)
536
+ if delegated_host is None:
537
+ for h in self._inventory.get_hosts(ignore_limits=True, ignore_restrictions=True):
538
+ # check if the address matches, or if both the delegated_to host
539
+ # and the current host are in the list of localhost aliases
540
+ if h.address == delegated_host_name:
541
+ delegated_host = h
542
+ break
543
+ else:
544
+ delegated_host = Host(name=delegated_host_name)
545
+
546
+ delegated_vars['ansible_delegated_vars'] = {
547
+ delegated_host_name: self.get_vars(
548
+ play=task.get_play(),
549
+ host=delegated_host,
550
+ task=task,
551
+ include_hostvars=True,
552
+ )
553
+ }
554
+ delegated_vars['ansible_delegated_vars'][delegated_host_name]['inventory_hostname'] = variables.get('inventory_hostname')
550
555
 
551
556
  return delegated_vars, delegated_host_name
552
557
 
553
558
  def clear_facts(self, hostname):
554
- '''
559
+ """
555
560
  Clears the facts for a host
556
- '''
557
- self._fact_cache.pop(hostname, None)
561
+ """
562
+ try:
563
+ self._fact_cache.delete(hostname)
564
+ except KeyError:
565
+ pass
558
566
 
559
567
  def set_host_facts(self, host, facts):
560
- '''
568
+ """
561
569
  Sets or updates the given facts for a host in the fact cache.
562
- '''
570
+ """
563
571
 
564
572
  if not isinstance(facts, Mapping):
565
573
  raise AnsibleAssertionError("the type of 'facts' to set for host_facts should be a Mapping but is a %s" % type(facts))
566
574
 
567
575
  warn_if_reserved(facts.keys())
568
576
  try:
569
- host_cache = self._fact_cache[host]
577
+ host_cache = self._fact_cache.get(host)
570
578
  except KeyError:
571
579
  # We get to set this as new
572
580
  host_cache = facts
@@ -578,12 +586,12 @@ class VariableManager:
578
586
  host_cache |= facts
579
587
 
580
588
  # Save the facts back to the backing store
581
- self._fact_cache[host] = host_cache
589
+ self._fact_cache.set(host, host_cache)
582
590
 
583
591
  def set_nonpersistent_facts(self, host, facts):
584
- '''
592
+ """
585
593
  Sets or updates the given facts for a host in the fact cache.
586
- '''
594
+ """
587
595
 
588
596
  if not isinstance(facts, Mapping):
589
597
  raise AnsibleAssertionError("the type of 'facts' to set for nonpersistent_facts should be a Mapping but is a %s" % type(facts))
@@ -602,75 +610,8 @@ class VariableManager:
602
610
  warn_if_reserved([varname])
603
611
  if host not in self._vars_cache:
604
612
  self._vars_cache[host] = dict()
613
+
605
614
  if varname in self._vars_cache[host] and isinstance(self._vars_cache[host][varname], MutableMapping) and isinstance(value, MutableMapping):
606
615
  self._vars_cache[host] = combine_vars(self._vars_cache[host], {varname: value})
607
616
  else:
608
617
  self._vars_cache[host][varname] = value
609
-
610
-
611
- class VarsWithSources(MutableMapping):
612
- '''
613
- Dict-like class for vars that also provides source information for each var
614
-
615
- This class can only store the source for top-level vars. It does no tracking
616
- on its own, just shows a debug message with the information that it is provided
617
- when a particular var is accessed.
618
- '''
619
- def __init__(self, *args, **kwargs):
620
- ''' Dict-compatible constructor '''
621
- self.data = dict(*args, **kwargs)
622
- self.sources = {}
623
-
624
- @classmethod
625
- def new_vars_with_sources(cls, data, sources):
626
- ''' Alternate constructor method to instantiate class with sources '''
627
- v = cls(data)
628
- v.sources = sources
629
- return v
630
-
631
- def get_source(self, key):
632
- return self.sources.get(key, None)
633
-
634
- def __getitem__(self, key):
635
- val = self.data[key]
636
- # See notes in the VarsWithSources docstring for caveats and limitations of the source tracking
637
- display.debug("variable '%s' from source: %s" % (key, self.sources.get(key, "unknown")))
638
- return val
639
-
640
- def __setitem__(self, key, value):
641
- self.data[key] = value
642
-
643
- def __delitem__(self, key):
644
- del self.data[key]
645
-
646
- def __iter__(self):
647
- return iter(self.data)
648
-
649
- def __len__(self):
650
- return len(self.data)
651
-
652
- # Prevent duplicate debug messages by defining our own __contains__ pointing at the underlying dict
653
- def __contains__(self, key):
654
- return self.data.__contains__(key)
655
-
656
- def copy(self):
657
- return VarsWithSources.new_vars_with_sources(self.data.copy(), self.sources.copy())
658
-
659
- def __or__(self, other):
660
- if isinstance(other, MutableMapping):
661
- c = self.data.copy()
662
- c.update(other)
663
- return c
664
- return NotImplemented
665
-
666
- def __ror__(self, other):
667
- if isinstance(other, MutableMapping):
668
- c = self.__class__()
669
- c.update(other)
670
- c.update(self.data)
671
- return c
672
- return NotImplemented
673
-
674
- def __ior__(self, other):
675
- self.data.update(other)
676
- return self.data