ansible-core 2.18.5rc1__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 +39 -13
  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 +19 -17
  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 +6 -6
  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 +33 -26
  279. ansible/modules/user.py +53 -34
  280. ansible/modules/validate_argument_spec.py +10 -7
  281. ansible/modules/wait_for.py +32 -27
  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 +7 -6
  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 +1 -1
  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.5rc1.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.5rc1.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.5rc1.dist-info/RECORD +0 -992
  703. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/Apache-License.txt +0 -0
  704. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/COPYING +0 -0
  705. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/MIT-license.txt +0 -0
  706. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/PSF-license.txt +0 -0
  707. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/entry_points.txt +0 -0
  708. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/simplified_bsd.txt +0 -0
  709. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,633 @@
1
+ from __future__ import annotations
2
+
3
+ import copy
4
+ import dataclasses
5
+ import functools
6
+ import types
7
+ import typing as t
8
+
9
+ from jinja2.environment import TemplateModule
10
+
11
+ from ansible.module_utils._internal._datatag import (
12
+ AnsibleTagHelper,
13
+ AnsibleTaggedObject,
14
+ _AnsibleTaggedDict,
15
+ _AnsibleTaggedList,
16
+ _AnsibleTaggedTuple,
17
+ _NO_INSTANCE_STORAGE,
18
+ _try_get_internal_tags_mapping,
19
+ )
20
+
21
+ from ansible.utils.sentinel import Sentinel
22
+ from ansible.errors import AnsibleVariableTypeError
23
+ from ansible._internal._errors._handler import Skippable
24
+ from ansible.vars.hostvars import HostVarsVars, HostVars
25
+
26
+ from ._access import AnsibleAccessContext
27
+ from ._jinja_common import Marker, _TemplateConfig
28
+ from ._utils import TemplateContext, PASS_THROUGH_SCALAR_VAR_TYPES, LazyOptions
29
+
30
+ if t.TYPE_CHECKING:
31
+ from ._engine import TemplateEngine
32
+
33
+ _KNOWN_TYPES: t.Final[set[type]] = (
34
+ {
35
+ HostVars, # example: hostvars
36
+ HostVarsVars, # example: hostvars.localhost | select
37
+ type, # example: range(20) | list # triggered on retrieval of `range` type from globals
38
+ range, # example: range(20) | list # triggered when returning a `range` instance from a call
39
+ types.FunctionType, # example: undef() | default("blah")
40
+ types.MethodType, # example: ansible_facts.get | type_debug
41
+ functools.partial,
42
+ type(''.startswith), # example: inventory_hostname.upper | type_debug # using `startswith` to resolve `builtin_function_or_method`
43
+ TemplateModule, # example: '{% import "importme.j2" as im %}{{ im | type_debug }}'
44
+ }
45
+ | set(PASS_THROUGH_SCALAR_VAR_TYPES)
46
+ | set(Marker.concrete_subclasses)
47
+ )
48
+ """
49
+ These types are known to the templating system.
50
+ In addition to the statically defined types, additional types will be added at runtime.
51
+ When enabled in config, this set will be used to determine if an encountered type should trigger a warning or error.
52
+ """
53
+
54
+
55
+ def register_known_types(*args: type) -> None:
56
+ """Register a type with the template engine so it will not trigger warnings or errors when encountered."""
57
+ _KNOWN_TYPES.update(args)
58
+
59
+
60
+ class UnsupportedConstructionMethodError(RuntimeError):
61
+ """Error raised when attempting to construct a lazy container with unsupported arguments."""
62
+
63
+ def __init__(self):
64
+ super().__init__("Direct construction of lazy containers is not supported.")
65
+
66
+
67
+ @t.final
68
+ @dataclasses.dataclass(frozen=True, slots=True)
69
+ class _LazyValue:
70
+ """Wrapper around values to indicate lazy behavior has not yet been applied."""
71
+
72
+ value: t.Any
73
+
74
+
75
+ @t.final
76
+ @dataclasses.dataclass(frozen=True, kw_only=True, slots=True)
77
+ class _LazyValueSource:
78
+ """Intermediate value source for lazy-eligible collection copy operations."""
79
+
80
+ source: t.Iterable
81
+ templar: TemplateEngine
82
+ lazy_options: LazyOptions
83
+
84
+
85
+ @t.final
86
+ class _NoKeySentinel(Sentinel):
87
+ """Sentinel used to indicate a requested key was not found."""
88
+
89
+
90
+ # There are several operations performed by lazy containers, with some variation between types.
91
+ #
92
+ # Columns: D=dict, L=list, T=tuple
93
+ # Cells: l=lazy (upon access), n=non-lazy (__init__/__new__)
94
+ #
95
+ # D L T Feature Description
96
+ # - - - ----------- ---------------------------------------------------------------
97
+ # l l n propagation when container items which are containers become lazy instances
98
+ # l l n transform when transforms are applied to container items
99
+ # l l n templating when templating is performed on container items
100
+ # l l l access when access calls are performed on container items
101
+
102
+
103
+ class _AnsibleLazyTemplateMixin:
104
+ __slots__ = _NO_INSTANCE_STORAGE
105
+
106
+ _dispatch_types: t.ClassVar[dict[type, type[_AnsibleLazyTemplateMixin]]] = {} # populated by __init_subclass__
107
+ _container_types: t.ClassVar[set[type]] = set() # populated by __init_subclass__
108
+
109
+ _native_type: t.ClassVar[type] # from AnsibleTaggedObject
110
+
111
+ _SLOTS: t.Final = (
112
+ '_templar',
113
+ '_lazy_options',
114
+ )
115
+
116
+ _templar: TemplateEngine
117
+ _lazy_options: LazyOptions
118
+
119
+ def __init_subclass__(cls, **kwargs) -> None:
120
+ tagged_type = cls.__mro__[1]
121
+ native_type = tagged_type.__mro__[1]
122
+
123
+ for check_type in (tagged_type, native_type):
124
+ if conflicting_type := cls._dispatch_types.get(check_type):
125
+ raise TypeError(f"Lazy mixin {cls.__name__!r} type {check_type.__name__!r} conflicts with {conflicting_type.__name__!r}.")
126
+
127
+ cls._dispatch_types[native_type] = cls
128
+ cls._dispatch_types[tagged_type] = cls
129
+ cls._container_types.add(native_type)
130
+ cls._empty_tags_as_native = False # never revert to the native type when no tags remain
131
+
132
+ register_known_types(cls)
133
+
134
+ def __init__(self, contents: t.Iterable | _LazyValueSource) -> None:
135
+ if isinstance(contents, _LazyValueSource):
136
+ self._templar = contents.templar
137
+ self._lazy_options = contents.lazy_options
138
+ elif isinstance(contents, _AnsibleLazyTemplateMixin):
139
+ self._templar = contents._templar
140
+ self._lazy_options = contents._lazy_options
141
+ else:
142
+ raise UnsupportedConstructionMethodError()
143
+
144
+ def __reduce_ex__(self, protocol):
145
+ raise NotImplementedError("Pickling of Ansible lazy objects is not permitted.")
146
+
147
+ @staticmethod
148
+ def _try_create(item: t.Any, lazy_options: LazyOptions = LazyOptions.DEFAULT) -> t.Any:
149
+ """
150
+ If `item` is a container type which supports lazy access and/or templating, return a lazy wrapped version -- otherwise return it as-is.
151
+ When returning as-is, a warning or error may be generated for unknown types.
152
+ The `lazy_options.skip_templates` argument should be set to `True` when `item` is sourced from a plugin instead of Ansible variable storage.
153
+ This provides backwards compatibility and reduces lazy overhead, as plugins do not normally introduce templates.
154
+ If a plugin needs to introduce templates, the plugin is responsible for invoking the templar and returning the result.
155
+ """
156
+ item_type = type(item)
157
+
158
+ # Try to use exact type match first to determine which wrapper (if any) to apply; isinstance checks
159
+ # are extremely expensive, so try to avoid them for our commonly-supported types.
160
+ if (dispatcher := _AnsibleLazyTemplateMixin._dispatch_types.get(item_type)) is not None:
161
+ # Create a generator that yields the elements of `item` wrapped in a `_LazyValue` wrapper.
162
+ # The wrapper is used to signal to the lazy container that the value must be processed before being returned.
163
+ # Values added to the lazy container later through other means will be returned as-is, without any special processing.
164
+ lazy_values = dispatcher._lazy_values(item, lazy_options)
165
+ tags_mapping = _try_get_internal_tags_mapping(item)
166
+ value = t.cast(AnsibleTaggedObject, dispatcher)._instance_factory(lazy_values, tags_mapping)
167
+
168
+ return value
169
+
170
+ with Skippable, _TemplateConfig.unknown_type_encountered_handler.handle(AnsibleVariableTypeError, skip_on_ignore=True):
171
+ if item_type not in _KNOWN_TYPES:
172
+ raise AnsibleVariableTypeError(
173
+ message=f"Encountered unknown type {item_type.__name__!r} during template operation.",
174
+ help_text="Use supported types to avoid unexpected behavior.",
175
+ obj=TemplateContext.current().template_value,
176
+ )
177
+
178
+ return item
179
+
180
+ def _is_not_lazy_combine_candidate(self, other: object) -> bool:
181
+ """Returns `True` if `other` cannot be lazily combined with the current instance due to differing templar/options, otherwise returns `False`."""
182
+ return isinstance(other, _AnsibleLazyTemplateMixin) and (self._templar is not other._templar or self._lazy_options != other._lazy_options)
183
+
184
+ def _non_lazy_copy(self) -> t.Collection:
185
+ """
186
+ Return a non-lazy copy of this collection.
187
+ Any remaining lazy wrapped values will be unwrapped without further processing.
188
+ Tags on this instance will be preserved on the returned copy.
189
+ """
190
+ raise NotImplementedError() # pragma: nocover
191
+
192
+ @staticmethod
193
+ def _lazy_values(values: t.Any, lazy_options: LazyOptions) -> _LazyValueSource:
194
+ """
195
+ Return an iterable that wraps each of the given elements in a lazy wrapper.
196
+ Only elements wrapped this way will receive lazy processing when retrieved from the collection.
197
+ """
198
+ # DTFIX-RELEASE: check relative performance of method-local vs stored generator expressions on implementations of this method
199
+ raise NotImplementedError() # pragma: nocover
200
+
201
+ def _proxy_or_render_lazy_value(self, key: t.Any, value: t.Any) -> t.Any:
202
+ """
203
+ Ensure that the value is lazy-proxied or rendered, and if a key is provided, replace the original value with the result.
204
+ """
205
+ if type(value) is not _LazyValue: # pylint: disable=unidiomatic-typecheck
206
+ if self._lazy_options.access:
207
+ AnsibleAccessContext.current().access(value)
208
+
209
+ return value
210
+
211
+ original_value = value.value
212
+
213
+ if self._lazy_options.access:
214
+ AnsibleAccessContext.current().access(original_value)
215
+
216
+ new_value = self._templar.template(original_value, lazy_options=self._lazy_options)
217
+
218
+ if new_value is not original_value and self._lazy_options.access:
219
+ AnsibleAccessContext.current().access(new_value)
220
+
221
+ if key is not _NoKeySentinel:
222
+ self._native_type.__setitem__(self, key, new_value) # type: ignore # pylint: disable=unnecessary-dunder-call
223
+
224
+ return new_value
225
+
226
+
227
+ @t.final # consumers of lazy collections rely heavily on the concrete types being final
228
+ class _AnsibleLazyTemplateDict(_AnsibleTaggedDict, _AnsibleLazyTemplateMixin):
229
+ __slots__ = _AnsibleLazyTemplateMixin._SLOTS
230
+
231
+ def __init__(self, contents: t.Iterable | _LazyValueSource, /, **kwargs) -> None:
232
+ _AnsibleLazyTemplateMixin.__init__(self, contents)
233
+
234
+ if isinstance(contents, _AnsibleLazyTemplateDict):
235
+ super().__init__(dict.items(contents), **kwargs)
236
+ elif isinstance(contents, _LazyValueSource):
237
+ super().__init__(contents.source, **kwargs)
238
+ else:
239
+ raise UnsupportedConstructionMethodError()
240
+
241
+ def get(self, key: t.Any, default: t.Any = None) -> t.Any:
242
+ if (value := super().get(key, _NoKeySentinel)) is _NoKeySentinel:
243
+ return default
244
+
245
+ return self._proxy_or_render_lazy_value(key, value)
246
+
247
+ def __getitem__(self, key: t.Any, /) -> t.Any:
248
+ return self._proxy_or_render_lazy_value(key, super().__getitem__(key))
249
+
250
+ def __str__(self):
251
+ return str(self.copy()._native_copy()) # inefficient, but avoids mutating the current instance (to make debugging practical)
252
+
253
+ def __repr__(self):
254
+ return repr(self.copy()._native_copy()) # inefficient, but avoids mutating the current instance (to make debugging practical)
255
+
256
+ def __iter__(self):
257
+ # We're using the base implementation, but must override `__iter__` to skip `dict` fast-path copy, which would bypass lazy behavior.
258
+ # See: https://github.com/python/cpython/blob/ffcc450a9b8b6927549b501eff7ac14abc238448/Objects/dictobject.c#L3861-L3864
259
+ return super().__iter__()
260
+
261
+ def setdefault(self, key, default=None, /) -> t.Any:
262
+ if (value := self.get(key, _NoKeySentinel)) is not _NoKeySentinel:
263
+ return value
264
+
265
+ super().__setitem__(key, default)
266
+
267
+ return default
268
+
269
+ def items(self):
270
+ for key, value in super().items():
271
+ yield key, self._proxy_or_render_lazy_value(key, value)
272
+
273
+ def values(self):
274
+ for _key, value in self.items():
275
+ yield value
276
+
277
+ def pop(self, key, default=_NoKeySentinel, /) -> t.Any:
278
+ if (value := super().get(key, _NoKeySentinel)) is _NoKeySentinel:
279
+ if default is _NoKeySentinel:
280
+ raise KeyError(key)
281
+
282
+ return default
283
+
284
+ value = self._proxy_or_render_lazy_value(_NoKeySentinel, value)
285
+
286
+ del self[key]
287
+
288
+ return value
289
+
290
+ def popitem(self) -> t.Any:
291
+ try:
292
+ key = next(reversed(self))
293
+ except StopIteration:
294
+ raise KeyError("popitem(): dictionary is empty")
295
+
296
+ value = self._proxy_or_render_lazy_value(_NoKeySentinel, self[key])
297
+
298
+ del self[key]
299
+
300
+ return key, value
301
+
302
+ def _native_copy(self) -> dict:
303
+ return dict(self.items())
304
+
305
+ @staticmethod
306
+ def _item_source(value: dict) -> dict | _LazyValueSource:
307
+ if isinstance(value, _AnsibleLazyTemplateDict):
308
+ return _LazyValueSource(source=dict.items(value), templar=value._templar, lazy_options=value._lazy_options)
309
+
310
+ return value
311
+
312
+ def _yield_non_lazy_dict_items(self) -> t.Iterator[tuple[str, t.Any]]:
313
+ """
314
+ Delegate to the base collection items iterator to yield the raw contents.
315
+ As of Python 3.13, generator functions are significantly faster than inline generator expressions.
316
+ """
317
+ for k, v in dict.items(self):
318
+ yield k, v.value if type(v) is _LazyValue else v # pylint: disable=unidiomatic-typecheck
319
+
320
+ def _non_lazy_copy(self) -> dict:
321
+ return AnsibleTagHelper.tag_copy(self, self._yield_non_lazy_dict_items(), value_type=dict)
322
+
323
+ @staticmethod
324
+ def _lazy_values(values: dict, lazy_options: LazyOptions) -> _LazyValueSource:
325
+ return _LazyValueSource(source=((k, _LazyValue(v)) for k, v in values.items()), templar=TemplateContext.current().templar, lazy_options=lazy_options)
326
+
327
+ @staticmethod
328
+ def _proxy_or_render_other(other: t.Any | None) -> None:
329
+ """Call `_proxy_or_render_lazy_values` if `other` is a lazy dict. Used internally by comparison methods."""
330
+ if type(other) is _AnsibleLazyTemplateDict: # pylint: disable=unidiomatic-typecheck
331
+ other._proxy_or_render_lazy_values()
332
+
333
+ def _proxy_or_render_lazy_values(self) -> None:
334
+ """Ensure all `_LazyValue` wrapped values have been processed."""
335
+ for _unused in self.values():
336
+ pass
337
+
338
+ def __eq__(self, other):
339
+ self._proxy_or_render_lazy_values()
340
+ self._proxy_or_render_other(other)
341
+ return super().__eq__(other)
342
+
343
+ def __ne__(self, other):
344
+ self._proxy_or_render_lazy_values()
345
+ self._proxy_or_render_other(other)
346
+ return super().__ne__(other)
347
+
348
+ def __or__(self, other):
349
+ # DTFIX-RELEASE: support preservation of laziness when possible like we do for list
350
+ # Both sides end up going through _proxy_or_render_lazy_value, so there's no Templar preservation needed.
351
+ # In the future this could be made more lazy when both Templar instances are the same, or if per-value Templar tracking was used.
352
+ return super().__or__(other)
353
+
354
+ def __ror__(self, other):
355
+ # DTFIX-RELEASE: support preservation of laziness when possible like we do for list
356
+ # Both sides end up going through _proxy_or_render_lazy_value, so there's no Templar preservation needed.
357
+ # In the future this could be made more lazy when both Templar instances are the same, or if per-value Templar tracking was used.
358
+ return super().__ror__(other)
359
+
360
+ def __deepcopy__(self, memo):
361
+ return _AnsibleLazyTemplateDict(
362
+ _LazyValueSource(
363
+ source=((copy.deepcopy(k), copy.deepcopy(v)) for k, v in super().items()),
364
+ templar=copy.deepcopy(self._templar),
365
+ lazy_options=copy.deepcopy(self._lazy_options),
366
+ )
367
+ )
368
+
369
+
370
+ @t.final # consumers of lazy collections rely heavily on the concrete types being final
371
+ class _AnsibleLazyTemplateList(_AnsibleTaggedList, _AnsibleLazyTemplateMixin):
372
+ __slots__ = _AnsibleLazyTemplateMixin._SLOTS
373
+
374
+ def __init__(self, contents: t.Iterable | _LazyValueSource, /) -> None:
375
+ _AnsibleLazyTemplateMixin.__init__(self, contents)
376
+
377
+ if isinstance(contents, _AnsibleLazyTemplateList):
378
+ super().__init__(list.__iter__(contents))
379
+ elif isinstance(contents, _LazyValueSource):
380
+ super().__init__(contents.source)
381
+ else:
382
+ raise UnsupportedConstructionMethodError()
383
+
384
+ def __getitem__(self, key: t.SupportsIndex | slice, /) -> t.Any:
385
+ if type(key) is slice: # pylint: disable=unidiomatic-typecheck
386
+ return _AnsibleLazyTemplateList(_LazyValueSource(source=super().__getitem__(key), templar=self._templar, lazy_options=self._lazy_options))
387
+
388
+ return self._proxy_or_render_lazy_value(key, super().__getitem__(key))
389
+
390
+ def __iter__(self):
391
+ for key, value in enumerate(super().__iter__()):
392
+ yield self._proxy_or_render_lazy_value(key, value)
393
+
394
+ def pop(self, idx: t.SupportsIndex = -1, /) -> t.Any:
395
+ if not self:
396
+ raise IndexError('pop from empty list')
397
+
398
+ try:
399
+ value = self[idx]
400
+ except IndexError:
401
+ raise IndexError('pop index out of range')
402
+
403
+ value = self._proxy_or_render_lazy_value(_NoKeySentinel, value)
404
+
405
+ del self[idx]
406
+
407
+ return value
408
+
409
+ def __str__(self):
410
+ return str(self.copy()._native_copy()) # inefficient, but avoids mutating the current instance (to make debugging practical)
411
+
412
+ def __repr__(self):
413
+ return repr(self.copy()._native_copy()) # inefficient, but avoids mutating the current instance (to make debugging practical)
414
+
415
+ @staticmethod
416
+ def _item_source(value: list) -> list | _LazyValueSource:
417
+ if isinstance(value, _AnsibleLazyTemplateList):
418
+ return _LazyValueSource(source=list.__iter__(value), templar=value._templar, lazy_options=value._lazy_options)
419
+
420
+ return value
421
+
422
+ def _yield_non_lazy_list_items(self):
423
+ """
424
+ Delegate to the base collection iterator to yield the raw contents.
425
+ As of Python 3.13, generator functions are significantly faster than inline generator expressions.
426
+ """
427
+ for v in list.__iter__(self):
428
+ yield v.value if type(v) is _LazyValue else v # pylint: disable=unidiomatic-typecheck
429
+
430
+ def _non_lazy_copy(self) -> list:
431
+ return AnsibleTagHelper.tag_copy(self, self._yield_non_lazy_list_items(), value_type=list)
432
+
433
+ @staticmethod
434
+ def _lazy_values(values: list, lazy_options: LazyOptions) -> _LazyValueSource:
435
+ return _LazyValueSource(source=(_LazyValue(v) for v in values), templar=TemplateContext.current().templar, lazy_options=lazy_options)
436
+
437
+ @staticmethod
438
+ def _proxy_or_render_other(other: t.Any | None) -> None:
439
+ """Call `_proxy_or_render_lazy_values` if `other` is a lazy list. Used internally by comparison methods."""
440
+ if type(other) is _AnsibleLazyTemplateList: # pylint: disable=unidiomatic-typecheck
441
+ other._proxy_or_render_lazy_values()
442
+
443
+ def _proxy_or_render_lazy_values(self) -> None:
444
+ """Ensure all `_LazyValue` wrapped values have been processed."""
445
+ for _unused in self:
446
+ pass
447
+
448
+ def __eq__(self, other):
449
+ self._proxy_or_render_lazy_values()
450
+ self._proxy_or_render_other(other)
451
+ return super().__eq__(other)
452
+
453
+ def __ne__(self, other):
454
+ self._proxy_or_render_lazy_values()
455
+ self._proxy_or_render_other(other)
456
+ return super().__ne__(other)
457
+
458
+ def __gt__(self, other):
459
+ self._proxy_or_render_lazy_values()
460
+ self._proxy_or_render_other(other)
461
+ return super().__gt__(other)
462
+
463
+ def __ge__(self, other):
464
+ self._proxy_or_render_lazy_values()
465
+ self._proxy_or_render_other(other)
466
+ return super().__ge__(other)
467
+
468
+ def __lt__(self, other):
469
+ self._proxy_or_render_lazy_values()
470
+ self._proxy_or_render_other(other)
471
+ return super().__lt__(other)
472
+
473
+ def __le__(self, other):
474
+ self._proxy_or_render_lazy_values()
475
+ self._proxy_or_render_other(other)
476
+ return super().__le__(other)
477
+
478
+ def __contains__(self, item):
479
+ self._proxy_or_render_lazy_values()
480
+ return super().__contains__(item)
481
+
482
+ def __reversed__(self):
483
+ for idx in range(self.__len__() - 1, -1, -1):
484
+ yield self[idx]
485
+
486
+ def __add__(self, other):
487
+ if self._is_not_lazy_combine_candidate(other):
488
+ # When other is lazy with a different templar/options, it cannot be lazily combined with self and a plain list must be returned.
489
+ # If other is a list, de-lazify both, otherwise just let the operation fail.
490
+
491
+ if isinstance(other, _AnsibleLazyTemplateList):
492
+ self._proxy_or_render_lazy_values()
493
+ other._proxy_or_render_lazy_values()
494
+
495
+ return super().__add__(other)
496
+
497
+ # For all other cases, the new list inherits our templar and all values stay lazy.
498
+ # We use list.__add__ to avoid implementing all its error behavior.
499
+ return _AnsibleLazyTemplateList(_LazyValueSource(source=super().__add__(other), templar=self._templar, lazy_options=self._lazy_options))
500
+
501
+ def __radd__(self, other):
502
+ if not (other_add := getattr(other, '__add__', None)):
503
+ raise TypeError(f'unsupported operand type(s) for +: {type(other).__name__!r} and {type(self).__name__!r}') from None
504
+
505
+ return _AnsibleLazyTemplateList(_LazyValueSource(source=other_add(self), templar=self._templar, lazy_options=self._lazy_options))
506
+
507
+ def __mul__(self, other):
508
+ return _AnsibleLazyTemplateList(_LazyValueSource(source=super().__mul__(other), templar=self._templar, lazy_options=self._lazy_options))
509
+
510
+ def __rmul__(self, other):
511
+ return _AnsibleLazyTemplateList(_LazyValueSource(source=super().__rmul__(other), templar=self._templar, lazy_options=self._lazy_options))
512
+
513
+ def index(self, *args, **kwargs) -> int:
514
+ self._proxy_or_render_lazy_values()
515
+ return super().index(*args, **kwargs)
516
+
517
+ def remove(self, *args, **kwargs) -> None:
518
+ self._proxy_or_render_lazy_values()
519
+ super().remove(*args, **kwargs)
520
+
521
+ def sort(self, *args, **kwargs) -> None:
522
+ self._proxy_or_render_lazy_values()
523
+ super().sort(*args, **kwargs)
524
+
525
+ def __deepcopy__(self, memo):
526
+ return _AnsibleLazyTemplateList(
527
+ _LazyValueSource(
528
+ source=(copy.deepcopy(v) for v in super().__iter__()),
529
+ templar=copy.deepcopy(self._templar),
530
+ lazy_options=copy.deepcopy(self._lazy_options),
531
+ )
532
+ )
533
+
534
+
535
+ @t.final # consumers of lazy collections rely heavily on the concrete types being final
536
+ class _AnsibleLazyAccessTuple(_AnsibleTaggedTuple, _AnsibleLazyTemplateMixin):
537
+ """
538
+ A tagged tuple subclass that provides only managed access for existing lazy values.
539
+
540
+ Since tuples are immutable, they cannot support lazy templating (which would change the tuple's value as templates were resolved).
541
+ When this type is created, each value in the source tuple is lazified:
542
+
543
+ * template strings are templated immediately (possibly resulting in lazy containers)
544
+ * non-tuple containers are lazy-wrapped
545
+ * tuples are immediately recursively lazy-wrapped
546
+ * transformations are applied immediately
547
+
548
+ The resulting object provides only managed access to its values (e.g., deprecation warnings, tripwires), and propagates to new lazy containers
549
+ created as a results of managed access.
550
+ """
551
+
552
+ # DTFIX-RELEASE: ensure we have tests that explicitly verify this behavior
553
+
554
+ # nonempty __slots__ not supported for subtype of 'tuple'
555
+
556
+ def __new__(cls, contents: t.Iterable | _LazyValueSource, /) -> t.Self:
557
+ if isinstance(contents, _AnsibleLazyAccessTuple):
558
+ return super().__new__(cls, tuple.__iter__(contents))
559
+
560
+ if isinstance(contents, _LazyValueSource):
561
+ return super().__new__(cls, contents.source)
562
+
563
+ raise UnsupportedConstructionMethodError()
564
+
565
+ def __init__(self, contents: t.Iterable | _LazyValueSource, /) -> None:
566
+ _AnsibleLazyTemplateMixin.__init__(self, contents)
567
+
568
+ def __getitem__(self, key: t.SupportsIndex | slice, /) -> t.Any:
569
+ if type(key) is slice: # pylint: disable=unidiomatic-typecheck
570
+ return _AnsibleLazyAccessTuple(super().__getitem__(key))
571
+
572
+ value = super().__getitem__(key)
573
+
574
+ if self._lazy_options.access:
575
+ AnsibleAccessContext.current().access(value)
576
+
577
+ return value
578
+
579
+ @staticmethod
580
+ def _item_source(value: tuple) -> tuple | _LazyValueSource:
581
+ if isinstance(value, _AnsibleLazyAccessTuple):
582
+ return _LazyValueSource(source=tuple.__iter__(value), templar=value._templar, lazy_options=value._lazy_options)
583
+
584
+ return value
585
+
586
+ @staticmethod
587
+ def _lazy_values(values: t.Any, lazy_options: LazyOptions) -> _LazyValueSource:
588
+ templar = TemplateContext.current().templar
589
+
590
+ return _LazyValueSource(source=(templar.template(value, lazy_options=lazy_options) for value in values), templar=templar, lazy_options=lazy_options)
591
+
592
+ def _non_lazy_copy(self) -> tuple:
593
+ return AnsibleTagHelper.tag_copy(self, self, value_type=tuple)
594
+
595
+ def __deepcopy__(self, memo):
596
+ return _AnsibleLazyAccessTuple(
597
+ _LazyValueSource(
598
+ source=(copy.deepcopy(v) for v in super().__iter__()),
599
+ templar=copy.deepcopy(self._templar),
600
+ lazy_options=copy.deepcopy(self._lazy_options),
601
+ )
602
+ )
603
+
604
+
605
+ def lazify_container(value: t.Any) -> t.Any:
606
+ """
607
+ If the given value is a supported container type, return its lazy version, otherwise return the value as-is.
608
+ This is used to ensure that managed access and templating occur on args and kwargs to a callable, even if they were sourced from Jinja constants.
609
+
610
+ Since both variable access and plugin output are already lazified, this mostly affects Jinja constant containers.
611
+ However, plugins that directly invoke other plugins (e.g., `Environment.call_filter`) are another potential source of non-lazy containers.
612
+ In these cases, templating will occur for trusted templates automatically upon access.
613
+
614
+ Sets, tuples, and dictionary keys cannot be lazy, since their correct operation requires hashability and equality.
615
+ These properties are mutually exclusive with the following lazy features:
616
+
617
+ - managed access on encrypted strings - may raise errors on both operations when decryption fails
618
+ - managed access on markers - must raise errors on both operations
619
+ - templating - mutates values
620
+
621
+ That leaves non-raising managed access as the only remaining feature, which is insufficient to warrant lazy support.
622
+ """
623
+ return _AnsibleLazyTemplateMixin._try_create(value)
624
+
625
+
626
+ def lazify_container_args(item: tuple) -> tuple:
627
+ """Return the given args with values converted to lazy containers as needed."""
628
+ return tuple(lazify_container(value) for value in item)
629
+
630
+
631
+ def lazify_container_kwargs(item: dict[str, t.Any]) -> dict[str, t.Any]:
632
+ """Return the given kwargs with values converted to lazy containers as needed."""
633
+ return {key: lazify_container(value) for key, value in item.items()}