ansible-core 2.18.5rc1__py3-none-any.whl → 2.19.0b2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (710) hide show
  1. ansible/_internal/__init__.py +53 -0
  2. ansible/_internal/_ansiballz.py +265 -0
  3. ansible/_internal/_collection_proxy.py +47 -0
  4. ansible/_internal/_datatag/__init__.py +0 -0
  5. ansible/_internal/_datatag/_tags.py +130 -0
  6. ansible/_internal/_datatag/_utils.py +19 -0
  7. ansible/_internal/_datatag/_wrappers.py +33 -0
  8. ansible/_internal/_errors/__init__.py +0 -0
  9. ansible/_internal/_errors/_captured.py +128 -0
  10. ansible/_internal/_errors/_handler.py +91 -0
  11. ansible/_internal/_errors/_utils.py +310 -0
  12. ansible/_internal/_json/__init__.py +203 -0
  13. ansible/_internal/_json/_legacy_encoder.py +34 -0
  14. ansible/_internal/_json/_profiles/__init__.py +0 -0
  15. ansible/_internal/_json/_profiles/_cache_persistence.py +55 -0
  16. ansible/_internal/_json/_profiles/_inventory_legacy.py +40 -0
  17. ansible/_internal/_json/_profiles/_legacy.py +197 -0
  18. ansible/_internal/_locking.py +21 -0
  19. ansible/_internal/_plugins/__init__.py +0 -0
  20. ansible/_internal/_plugins/_cache.py +57 -0
  21. ansible/_internal/_task.py +78 -0
  22. ansible/_internal/_templating/__init__.py +10 -0
  23. ansible/_internal/_templating/_access.py +86 -0
  24. ansible/_internal/_templating/_chain_templar.py +63 -0
  25. ansible/_internal/_templating/_datatag.py +95 -0
  26. ansible/_internal/_templating/_engine.py +588 -0
  27. ansible/_internal/_templating/_errors.py +28 -0
  28. ansible/_internal/_templating/_jinja_bits.py +1066 -0
  29. ansible/_internal/_templating/_jinja_common.py +332 -0
  30. ansible/_internal/_templating/_jinja_patches.py +44 -0
  31. ansible/_internal/_templating/_jinja_plugins.py +345 -0
  32. ansible/_internal/_templating/_lazy_containers.py +633 -0
  33. ansible/_internal/_templating/_marker_behaviors.py +103 -0
  34. ansible/_internal/_templating/_transform.py +63 -0
  35. ansible/_internal/_templating/_utils.py +107 -0
  36. ansible/_internal/_wrapt.py +1052 -0
  37. ansible/_internal/_yaml/__init__.py +0 -0
  38. ansible/_internal/_yaml/_constructor.py +240 -0
  39. ansible/_internal/_yaml/_dumper.py +62 -0
  40. ansible/_internal/_yaml/_errors.py +166 -0
  41. ansible/_internal/_yaml/_loader.py +66 -0
  42. ansible/_internal/ansible_collections/ansible/_protomatter/README.md +11 -0
  43. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/debug.py +36 -0
  44. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/apply_trust.py +19 -0
  45. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/dump_object.py +18 -0
  46. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/finalize.py +16 -0
  47. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/origin.py +18 -0
  48. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.py +24 -0
  49. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.yml +33 -0
  50. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/tag_names.py +16 -0
  51. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +17 -0
  52. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +49 -0
  53. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.py +21 -0
  54. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.yml +2 -0
  55. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.py +15 -0
  56. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.yml +19 -0
  57. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.py +18 -0
  58. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.yml +19 -0
  59. ansible/cli/__init__.py +159 -89
  60. ansible/cli/_ssh_askpass.py +47 -0
  61. ansible/cli/adhoc.py +14 -7
  62. ansible/cli/arguments/option_helpers.py +154 -7
  63. ansible/cli/config.py +43 -68
  64. ansible/cli/console.py +10 -8
  65. ansible/cli/doc.py +62 -53
  66. ansible/cli/galaxy.py +27 -20
  67. ansible/cli/inventory.py +28 -26
  68. ansible/cli/playbook.py +4 -12
  69. ansible/cli/pull.py +51 -11
  70. ansible/cli/scripts/ansible_connection_cli_stub.py +7 -7
  71. ansible/cli/vault.py +12 -11
  72. ansible/compat/__init__.py +2 -2
  73. ansible/config/base.yml +166 -112
  74. ansible/config/manager.py +52 -49
  75. ansible/constants.py +3 -4
  76. ansible/errors/__init__.py +277 -235
  77. ansible/executor/interpreter_discovery.py +28 -149
  78. ansible/executor/module_common.py +426 -493
  79. ansible/executor/play_iterator.py +22 -27
  80. ansible/executor/playbook_executor.py +11 -11
  81. ansible/executor/powershell/async_watchdog.ps1 +97 -102
  82. ansible/executor/powershell/async_wrapper.ps1 +202 -151
  83. ansible/executor/powershell/become_wrapper.ps1 +89 -144
  84. ansible/executor/powershell/bootstrap_wrapper.ps1 +24 -9
  85. ansible/executor/powershell/coverage_wrapper.ps1 +82 -135
  86. ansible/executor/powershell/exec_wrapper.ps1 +462 -196
  87. ansible/executor/powershell/module_manifest.py +417 -265
  88. ansible/executor/powershell/module_wrapper.ps1 +169 -186
  89. ansible/executor/powershell/psrp_fetch_file.ps1 +41 -0
  90. ansible/executor/powershell/psrp_put_file.ps1 +122 -0
  91. ansible/executor/powershell/winrm_fetch_file.ps1 +46 -0
  92. ansible/executor/powershell/winrm_put_file.ps1 +36 -0
  93. ansible/executor/process/worker.py +161 -96
  94. ansible/executor/stats.py +5 -5
  95. ansible/executor/task_executor.py +268 -258
  96. ansible/executor/task_queue_manager.py +124 -90
  97. ansible/executor/task_result.py +183 -78
  98. ansible/galaxy/__init__.py +2 -2
  99. ansible/galaxy/api.py +22 -18
  100. ansible/galaxy/collection/__init__.py +1 -1
  101. ansible/galaxy/collection/concrete_artifact_manager.py +8 -11
  102. ansible/galaxy/dependency_resolution/dataclasses.py +14 -4
  103. ansible/galaxy/dependency_resolution/providers.py +1 -1
  104. ansible/galaxy/dependency_resolution/reporters.py +81 -0
  105. ansible/galaxy/role.py +4 -8
  106. ansible/galaxy/token.py +28 -21
  107. ansible/inventory/data.py +47 -57
  108. ansible/inventory/group.py +44 -72
  109. ansible/inventory/helpers.py +9 -0
  110. ansible/inventory/host.py +32 -54
  111. ansible/inventory/manager.py +78 -34
  112. ansible/keyword_desc.yml +1 -1
  113. ansible/module_utils/_internal/__init__.py +55 -0
  114. ansible/module_utils/_internal/_ambient_context.py +58 -0
  115. ansible/module_utils/_internal/_ansiballz.py +133 -0
  116. ansible/module_utils/_internal/_concurrent/_daemon_threading.py +1 -0
  117. ansible/module_utils/_internal/_dataclass_annotation_patch.py +64 -0
  118. ansible/module_utils/_internal/_dataclass_validation.py +217 -0
  119. ansible/module_utils/_internal/_datatag/__init__.py +928 -0
  120. ansible/module_utils/_internal/_datatag/_tags.py +38 -0
  121. ansible/module_utils/_internal/_debugging.py +31 -0
  122. ansible/module_utils/_internal/_errors.py +30 -0
  123. ansible/module_utils/_internal/_json/__init__.py +63 -0
  124. ansible/module_utils/_internal/_json/_legacy_encoder.py +26 -0
  125. ansible/module_utils/_internal/_json/_profiles/__init__.py +410 -0
  126. ansible/module_utils/_internal/_json/_profiles/_fallback_to_str.py +73 -0
  127. ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +31 -0
  128. ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +35 -0
  129. ansible/module_utils/_internal/_json/_profiles/_module_modern_c2m.py +35 -0
  130. ansible/module_utils/_internal/_json/_profiles/_module_modern_m2c.py +33 -0
  131. ansible/module_utils/_internal/_json/_profiles/_tagless.py +50 -0
  132. ansible/module_utils/_internal/_patches/__init__.py +66 -0
  133. ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +55 -0
  134. ansible/module_utils/_internal/_patches/_socket_patch.py +34 -0
  135. ansible/module_utils/_internal/_patches/_sys_intern_patch.py +34 -0
  136. ansible/module_utils/_internal/_plugin_exec_context.py +49 -0
  137. ansible/module_utils/_internal/_testing.py +0 -0
  138. ansible/module_utils/_internal/_traceback.py +89 -0
  139. ansible/module_utils/ansible_release.py +2 -2
  140. ansible/module_utils/api.py +1 -2
  141. ansible/module_utils/basic.py +152 -120
  142. ansible/module_utils/common/_utils.py +24 -28
  143. ansible/module_utils/common/collections.py +1 -2
  144. ansible/module_utils/common/dict_transformations.py +2 -2
  145. ansible/module_utils/common/file.py +2 -2
  146. ansible/module_utils/common/json.py +90 -84
  147. ansible/module_utils/common/locale.py +2 -2
  148. ansible/module_utils/common/messages.py +108 -0
  149. ansible/module_utils/common/parameters.py +27 -24
  150. ansible/module_utils/common/process.py +2 -2
  151. ansible/module_utils/common/respawn.py +41 -19
  152. ansible/module_utils/common/sentinel.py +66 -0
  153. ansible/module_utils/common/sys_info.py +8 -8
  154. ansible/module_utils/common/text/converters.py +16 -37
  155. ansible/module_utils/common/validation.py +35 -24
  156. ansible/module_utils/common/warnings.py +86 -25
  157. ansible/module_utils/common/yaml.py +29 -3
  158. ansible/module_utils/compat/datetime.py +33 -21
  159. ansible/module_utils/compat/paramiko.py +21 -10
  160. ansible/module_utils/compat/typing.py +6 -5
  161. ansible/module_utils/connection.py +2 -2
  162. ansible/module_utils/csharp/Ansible.Basic.cs +14 -11
  163. ansible/module_utils/csharp/Ansible.Become.cs +1 -0
  164. ansible/module_utils/csharp/Ansible._Async.cs +517 -0
  165. ansible/module_utils/datatag.py +46 -0
  166. ansible/module_utils/distro/__init__.py +2 -2
  167. ansible/module_utils/facts/ansible_collector.py +4 -5
  168. ansible/module_utils/facts/collector.py +13 -14
  169. ansible/module_utils/facts/compat.py +4 -4
  170. ansible/module_utils/facts/default_collectors.py +1 -1
  171. ansible/module_utils/facts/hardware/aix.py +34 -0
  172. ansible/module_utils/facts/hardware/base.py +1 -1
  173. ansible/module_utils/facts/hardware/darwin.py +1 -3
  174. ansible/module_utils/facts/hardware/freebsd.py +2 -2
  175. ansible/module_utils/facts/hardware/linux.py +4 -4
  176. ansible/module_utils/facts/namespace.py +1 -1
  177. ansible/module_utils/facts/network/base.py +1 -1
  178. ansible/module_utils/facts/network/fc_wwn.py +1 -2
  179. ansible/module_utils/facts/network/iscsi.py +1 -2
  180. ansible/module_utils/facts/network/nvme.py +1 -2
  181. ansible/module_utils/facts/other/facter.py +1 -2
  182. ansible/module_utils/facts/other/ohai.py +2 -3
  183. ansible/module_utils/facts/system/apparmor.py +1 -2
  184. ansible/module_utils/facts/system/caps.py +1 -1
  185. ansible/module_utils/facts/system/chroot.py +1 -2
  186. ansible/module_utils/facts/system/cmdline.py +1 -2
  187. ansible/module_utils/facts/system/date_time.py +5 -3
  188. ansible/module_utils/facts/system/distribution.py +9 -8
  189. ansible/module_utils/facts/system/dns.py +1 -1
  190. ansible/module_utils/facts/system/env.py +1 -2
  191. ansible/module_utils/facts/system/fips.py +7 -20
  192. ansible/module_utils/facts/system/loadavg.py +1 -2
  193. ansible/module_utils/facts/system/local.py +1 -2
  194. ansible/module_utils/facts/system/lsb.py +1 -2
  195. ansible/module_utils/facts/system/pkg_mgr.py +1 -2
  196. ansible/module_utils/facts/system/platform.py +1 -2
  197. ansible/module_utils/facts/system/python.py +1 -2
  198. ansible/module_utils/facts/system/selinux.py +1 -1
  199. ansible/module_utils/facts/system/service_mgr.py +1 -2
  200. ansible/module_utils/facts/system/ssh_pub_keys.py +1 -1
  201. ansible/module_utils/facts/system/systemd.py +1 -1
  202. ansible/module_utils/facts/system/user.py +1 -2
  203. ansible/module_utils/facts/utils.py +3 -3
  204. ansible/module_utils/facts/virtual/base.py +1 -1
  205. ansible/module_utils/facts/virtual/sunos.py +3 -15
  206. ansible/module_utils/facts/virtual/sysctl.py +3 -16
  207. ansible/module_utils/json_utils.py +2 -2
  208. ansible/module_utils/parsing/convert_bool.py +1 -1
  209. ansible/module_utils/service.py +18 -21
  210. ansible/module_utils/splitter.py +7 -7
  211. ansible/module_utils/testing.py +31 -0
  212. ansible/module_utils/urls.py +60 -31
  213. ansible/modules/add_host.py +4 -4
  214. ansible/modules/apt.py +60 -46
  215. ansible/modules/apt_key.py +19 -12
  216. ansible/modules/apt_repository.py +19 -16
  217. ansible/modules/assemble.py +6 -6
  218. ansible/modules/assert.py +4 -4
  219. ansible/modules/async_status.py +10 -12
  220. ansible/modules/async_wrapper.py +8 -3
  221. ansible/modules/blockinfile.py +6 -7
  222. ansible/modules/command.py +10 -17
  223. ansible/modules/copy.py +57 -144
  224. ansible/modules/cron.py +20 -15
  225. ansible/modules/deb822_repository.py +8 -9
  226. ansible/modules/debconf.py +5 -5
  227. ansible/modules/debug.py +4 -4
  228. ansible/modules/dnf.py +8 -8
  229. ansible/modules/dnf5.py +39 -13
  230. ansible/modules/dpkg_selections.py +4 -4
  231. ansible/modules/expect.py +8 -10
  232. ansible/modules/fail.py +4 -4
  233. ansible/modules/fetch.py +4 -4
  234. ansible/modules/file.py +174 -133
  235. ansible/modules/find.py +19 -17
  236. ansible/modules/gather_facts.py +3 -3
  237. ansible/modules/get_url.py +59 -53
  238. ansible/modules/getent.py +7 -9
  239. ansible/modules/git.py +28 -25
  240. ansible/modules/group.py +6 -6
  241. ansible/modules/group_by.py +4 -4
  242. ansible/modules/hostname.py +13 -29
  243. ansible/modules/import_playbook.py +6 -6
  244. ansible/modules/import_role.py +6 -6
  245. ansible/modules/import_tasks.py +6 -6
  246. ansible/modules/include_role.py +6 -6
  247. ansible/modules/include_tasks.py +6 -6
  248. ansible/modules/include_vars.py +6 -6
  249. ansible/modules/iptables.py +86 -73
  250. ansible/modules/known_hosts.py +10 -10
  251. ansible/modules/lineinfile.py +5 -5
  252. ansible/modules/meta.py +4 -4
  253. ansible/modules/mount_facts.py +2 -2
  254. ansible/modules/package.py +4 -4
  255. ansible/modules/package_facts.py +22 -10
  256. ansible/modules/pause.py +6 -6
  257. ansible/modules/ping.py +6 -6
  258. ansible/modules/pip.py +10 -11
  259. ansible/modules/raw.py +4 -4
  260. ansible/modules/reboot.py +6 -6
  261. ansible/modules/replace.py +9 -13
  262. ansible/modules/rpm_key.py +7 -8
  263. ansible/modules/script.py +4 -4
  264. ansible/modules/service.py +7 -8
  265. ansible/modules/service_facts.py +87 -10
  266. ansible/modules/set_fact.py +5 -5
  267. ansible/modules/set_stats.py +4 -4
  268. ansible/modules/setup.py +2 -2
  269. ansible/modules/shell.py +6 -6
  270. ansible/modules/slurp.py +6 -6
  271. ansible/modules/stat.py +9 -23
  272. ansible/modules/subversion.py +15 -15
  273. ansible/modules/systemd.py +6 -6
  274. ansible/modules/systemd_service.py +6 -6
  275. ansible/modules/sysvinit.py +6 -6
  276. ansible/modules/tempfile.py +5 -6
  277. ansible/modules/template.py +6 -6
  278. ansible/modules/unarchive.py +32 -11
  279. ansible/modules/uri.py +33 -26
  280. ansible/modules/user.py +53 -34
  281. ansible/modules/validate_argument_spec.py +10 -7
  282. ansible/modules/wait_for.py +32 -27
  283. ansible/modules/wait_for_connection.py +6 -6
  284. ansible/modules/yum_repository.py +6 -6
  285. ansible/parsing/ajson.py +14 -32
  286. ansible/parsing/dataloader.py +99 -54
  287. ansible/parsing/mod_args.py +28 -44
  288. ansible/parsing/plugin_docs.py +21 -86
  289. ansible/parsing/quoting.py +1 -1
  290. ansible/parsing/splitter.py +27 -12
  291. ansible/parsing/utils/addresses.py +24 -24
  292. ansible/parsing/utils/jsonify.py +5 -1
  293. ansible/parsing/utils/yaml.py +32 -61
  294. ansible/parsing/vault/__init__.py +319 -87
  295. ansible/parsing/yaml/__init__.py +0 -18
  296. ansible/parsing/yaml/dumper.py +6 -120
  297. ansible/parsing/yaml/loader.py +6 -39
  298. ansible/parsing/yaml/objects.py +43 -335
  299. ansible/playbook/__init__.py +1 -1
  300. ansible/playbook/attribute.py +8 -3
  301. ansible/playbook/base.py +182 -132
  302. ansible/playbook/block.py +26 -24
  303. ansible/playbook/collectionsearch.py +1 -15
  304. ansible/playbook/conditional.py +3 -77
  305. ansible/playbook/handler.py +8 -2
  306. ansible/playbook/helpers.py +41 -53
  307. ansible/playbook/included_file.py +31 -27
  308. ansible/playbook/loop_control.py +2 -2
  309. ansible/playbook/play.py +85 -44
  310. ansible/playbook/play_context.py +12 -17
  311. ansible/playbook/playbook_include.py +14 -15
  312. ansible/playbook/role/__init__.py +24 -26
  313. ansible/playbook/role/definition.py +15 -17
  314. ansible/playbook/role/include.py +2 -4
  315. ansible/playbook/role/metadata.py +10 -11
  316. ansible/playbook/role_include.py +3 -3
  317. ansible/playbook/taggable.py +13 -8
  318. ansible/playbook/task.py +188 -118
  319. ansible/playbook/task_include.py +5 -5
  320. ansible/plugins/__init__.py +68 -21
  321. ansible/plugins/action/__init__.py +209 -176
  322. ansible/plugins/action/add_host.py +1 -1
  323. ansible/plugins/action/assemble.py +1 -1
  324. ansible/plugins/action/assert.py +54 -66
  325. ansible/plugins/action/copy.py +7 -11
  326. ansible/plugins/action/debug.py +37 -31
  327. ansible/plugins/action/dnf.py +3 -4
  328. ansible/plugins/action/fail.py +1 -1
  329. ansible/plugins/action/fetch.py +4 -5
  330. ansible/plugins/action/gather_facts.py +7 -6
  331. ansible/plugins/action/group_by.py +1 -1
  332. ansible/plugins/action/include_vars.py +10 -11
  333. ansible/plugins/action/package.py +3 -6
  334. ansible/plugins/action/pause.py +2 -2
  335. ansible/plugins/action/script.py +15 -8
  336. ansible/plugins/action/service.py +6 -11
  337. ansible/plugins/action/set_fact.py +3 -12
  338. ansible/plugins/action/set_stats.py +3 -8
  339. ansible/plugins/action/template.py +35 -59
  340. ansible/plugins/action/unarchive.py +1 -1
  341. ansible/plugins/action/validate_argument_spec.py +5 -5
  342. ansible/plugins/action/wait_for_connection.py +1 -1
  343. ansible/plugins/become/__init__.py +31 -8
  344. ansible/plugins/become/runas.py +71 -0
  345. ansible/plugins/become/su.py +13 -8
  346. ansible/plugins/become/sudo.py +19 -0
  347. ansible/plugins/cache/__init__.py +35 -44
  348. ansible/plugins/cache/base.py +8 -0
  349. ansible/plugins/cache/jsonfile.py +10 -16
  350. ansible/plugins/cache/memory.py +6 -12
  351. ansible/plugins/callback/__init__.py +284 -179
  352. ansible/plugins/callback/default.py +99 -92
  353. ansible/plugins/callback/junit.py +44 -39
  354. ansible/plugins/callback/minimal.py +28 -25
  355. ansible/plugins/callback/oneline.py +28 -21
  356. ansible/plugins/callback/tree.py +16 -11
  357. ansible/plugins/connection/__init__.py +47 -34
  358. ansible/plugins/connection/local.py +150 -54
  359. ansible/plugins/connection/paramiko_ssh.py +21 -18
  360. ansible/plugins/connection/psrp.py +76 -165
  361. ansible/plugins/connection/ssh.py +301 -78
  362. ansible/plugins/connection/winrm.py +58 -140
  363. ansible/plugins/doc_fragments/action_common_attributes.py +14 -14
  364. ansible/plugins/doc_fragments/action_core.py +6 -6
  365. ansible/plugins/doc_fragments/backup.py +2 -2
  366. ansible/plugins/doc_fragments/checksum_common.py +27 -0
  367. ansible/plugins/doc_fragments/constructed.py +6 -2
  368. ansible/plugins/doc_fragments/decrypt.py +2 -2
  369. ansible/plugins/doc_fragments/default_callback.py +2 -2
  370. ansible/plugins/doc_fragments/files.py +2 -2
  371. ansible/plugins/doc_fragments/inventory_cache.py +2 -2
  372. ansible/plugins/doc_fragments/result_format_callback.py +2 -2
  373. ansible/plugins/doc_fragments/return_common.py +2 -2
  374. ansible/plugins/doc_fragments/template_common.py +4 -4
  375. ansible/plugins/doc_fragments/url.py +17 -1
  376. ansible/plugins/doc_fragments/url_windows.py +2 -2
  377. ansible/plugins/doc_fragments/validate.py +2 -2
  378. ansible/plugins/doc_fragments/vars_plugin_staging.py +2 -2
  379. ansible/plugins/filter/__init__.py +6 -2
  380. ansible/plugins/filter/b64decode.yml +22 -0
  381. ansible/plugins/filter/b64encode.yml +22 -0
  382. ansible/plugins/filter/bool.yml +11 -4
  383. ansible/plugins/filter/core.py +225 -108
  384. ansible/plugins/filter/encryption.py +32 -32
  385. ansible/plugins/filter/flatten.yml +3 -2
  386. ansible/plugins/filter/human_to_bytes.yml +1 -1
  387. ansible/plugins/filter/mathstuff.py +30 -37
  388. ansible/plugins/filter/password_hash.yml +8 -0
  389. ansible/plugins/filter/regex_search.yml +1 -4
  390. ansible/plugins/filter/split.yml +1 -1
  391. ansible/plugins/filter/to_nice_yaml.yml +0 -4
  392. ansible/plugins/filter/to_yaml.yml +0 -4
  393. ansible/plugins/filter/unvault.yml +1 -1
  394. ansible/plugins/filter/urls.py +1 -1
  395. ansible/plugins/filter/urlsplit.py +8 -9
  396. ansible/plugins/filter/vault.yml +14 -9
  397. ansible/plugins/filter/win_basename.yml +6 -1
  398. ansible/plugins/filter/win_dirname.yml +5 -0
  399. ansible/plugins/inventory/__init__.py +97 -77
  400. ansible/plugins/inventory/advanced_host_list.py +7 -5
  401. ansible/plugins/inventory/auto.py +11 -4
  402. ansible/plugins/inventory/constructed.py +21 -24
  403. ansible/plugins/inventory/generator.py +16 -11
  404. ansible/plugins/inventory/host_list.py +7 -5
  405. ansible/plugins/inventory/ini.py +78 -44
  406. ansible/plugins/inventory/script.py +189 -119
  407. ansible/plugins/inventory/toml.py +16 -126
  408. ansible/plugins/inventory/yaml.py +10 -8
  409. ansible/plugins/list.py +3 -3
  410. ansible/plugins/loader.py +197 -82
  411. ansible/plugins/lookup/__init__.py +21 -4
  412. ansible/plugins/lookup/config.py +21 -35
  413. ansible/plugins/lookup/csvfile.py +3 -2
  414. ansible/plugins/lookup/dict.py +1 -6
  415. ansible/plugins/lookup/env.py +12 -9
  416. ansible/plugins/lookup/file.py +5 -8
  417. ansible/plugins/lookup/first_found.py +86 -55
  418. ansible/plugins/lookup/indexed_items.py +1 -10
  419. ansible/plugins/lookup/ini.py +14 -13
  420. ansible/plugins/lookup/items.py +1 -1
  421. ansible/plugins/lookup/lines.py +8 -1
  422. ansible/plugins/lookup/list.py +1 -1
  423. ansible/plugins/lookup/nested.py +2 -18
  424. ansible/plugins/lookup/password.py +5 -5
  425. ansible/plugins/lookup/pipe.py +5 -7
  426. ansible/plugins/lookup/sequence.py +18 -8
  427. ansible/plugins/lookup/subelements.py +1 -4
  428. ansible/plugins/lookup/template.py +42 -36
  429. ansible/plugins/lookup/together.py +0 -12
  430. ansible/plugins/lookup/unvault.py +1 -5
  431. ansible/plugins/lookup/url.py +2 -8
  432. ansible/plugins/lookup/vars.py +16 -24
  433. ansible/plugins/shell/__init__.py +2 -2
  434. ansible/plugins/shell/cmd.py +2 -2
  435. ansible/plugins/shell/powershell.py +39 -22
  436. ansible/plugins/shell/sh.py +3 -2
  437. ansible/plugins/strategy/__init__.py +159 -184
  438. ansible/plugins/strategy/debug.py +2 -2
  439. ansible/plugins/strategy/free.py +16 -31
  440. ansible/plugins/strategy/host_pinned.py +2 -2
  441. ansible/plugins/strategy/linear.py +41 -41
  442. ansible/plugins/terminal/__init__.py +4 -4
  443. ansible/plugins/test/__init__.py +7 -2
  444. ansible/plugins/test/core.py +55 -21
  445. ansible/plugins/test/files.py +1 -1
  446. ansible/plugins/test/mathstuff.py +3 -3
  447. ansible/plugins/test/uri.py +3 -3
  448. ansible/plugins/vars/host_group_vars.py +7 -14
  449. ansible/release.py +2 -2
  450. ansible/template/__init__.py +370 -944
  451. ansible/utils/__init__.py +0 -18
  452. ansible/utils/_ssh_agent.py +657 -0
  453. ansible/utils/collection_loader/__init__.py +52 -5
  454. ansible/utils/collection_loader/_collection_config.py +5 -6
  455. ansible/utils/collection_loader/_collection_finder.py +79 -93
  456. ansible/utils/collection_loader/_collection_meta.py +13 -8
  457. ansible/utils/display.py +433 -63
  458. ansible/utils/encrypt.py +27 -19
  459. ansible/utils/fqcn.py +2 -2
  460. ansible/utils/hashing.py +2 -2
  461. ansible/utils/helpers.py +2 -2
  462. ansible/utils/listify.py +8 -8
  463. ansible/utils/lock.py +2 -2
  464. ansible/utils/path.py +4 -4
  465. ansible/utils/plugin_docs.py +14 -13
  466. ansible/utils/sentinel.py +4 -62
  467. ansible/utils/singleton.py +2 -0
  468. ansible/utils/ssh_functions.py +1 -1
  469. ansible/utils/unsafe_proxy.py +23 -332
  470. ansible/utils/vars.py +51 -8
  471. ansible/utils/version.py +2 -2
  472. ansible/vars/clean.py +5 -5
  473. ansible/vars/hostvars.py +60 -90
  474. ansible/vars/manager.py +206 -282
  475. ansible/vars/reserved.py +8 -9
  476. ansible_core-2.19.0b2.dist-info/BSD-3-Clause.txt +28 -0
  477. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/METADATA +5 -4
  478. ansible_core-2.19.0b2.dist-info/RECORD +1072 -0
  479. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/WHEEL +1 -1
  480. ansible_test/_data/completion/docker.txt +7 -7
  481. ansible_test/_data/completion/remote.txt +6 -6
  482. ansible_test/_data/completion/windows.txt +1 -0
  483. ansible_test/_data/requirements/ansible.txt +2 -2
  484. ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
  485. ansible_test/_data/requirements/sanity.changelog.txt +1 -1
  486. ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
  487. ansible_test/_data/requirements/sanity.pylint.txt +4 -4
  488. ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
  489. ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
  490. ansible_test/_data/requirements/units.txt +1 -0
  491. ansible_test/_internal/__init__.py +1 -0
  492. ansible_test/_internal/ansible_util.py +2 -0
  493. ansible_test/_internal/become.py +1 -0
  494. ansible_test/_internal/bootstrap.py +1 -0
  495. ansible_test/_internal/cache.py +1 -0
  496. ansible_test/_internal/cgroup.py +1 -0
  497. ansible_test/_internal/ci/__init__.py +1 -0
  498. ansible_test/_internal/ci/azp.py +1 -0
  499. ansible_test/_internal/ci/local.py +1 -0
  500. ansible_test/_internal/classification/__init__.py +1 -0
  501. ansible_test/_internal/classification/common.py +1 -0
  502. ansible_test/_internal/classification/csharp.py +1 -0
  503. ansible_test/_internal/classification/powershell.py +1 -0
  504. ansible_test/_internal/classification/python.py +1 -0
  505. ansible_test/_internal/cli/__init__.py +1 -0
  506. ansible_test/_internal/cli/actions.py +1 -0
  507. ansible_test/_internal/cli/argparsing/__init__.py +1 -0
  508. ansible_test/_internal/cli/argparsing/actions.py +1 -0
  509. ansible_test/_internal/cli/argparsing/argcompletion.py +1 -0
  510. ansible_test/_internal/cli/argparsing/parsers.py +1 -0
  511. ansible_test/_internal/cli/commands/__init__.py +11 -0
  512. ansible_test/_internal/cli/commands/coverage/__init__.py +1 -0
  513. ansible_test/_internal/cli/commands/coverage/analyze/__init__.py +1 -0
  514. ansible_test/_internal/cli/commands/coverage/analyze/targets/__init__.py +1 -0
  515. ansible_test/_internal/cli/commands/coverage/analyze/targets/combine.py +1 -0
  516. ansible_test/_internal/cli/commands/coverage/analyze/targets/expand.py +1 -0
  517. ansible_test/_internal/cli/commands/coverage/analyze/targets/filter.py +1 -0
  518. ansible_test/_internal/cli/commands/coverage/analyze/targets/generate.py +1 -0
  519. ansible_test/_internal/cli/commands/coverage/analyze/targets/missing.py +1 -0
  520. ansible_test/_internal/cli/commands/coverage/combine.py +1 -0
  521. ansible_test/_internal/cli/commands/coverage/erase.py +1 -0
  522. ansible_test/_internal/cli/commands/coverage/html.py +1 -0
  523. ansible_test/_internal/cli/commands/coverage/report.py +1 -0
  524. ansible_test/_internal/cli/commands/coverage/xml.py +1 -0
  525. ansible_test/_internal/cli/commands/env.py +1 -0
  526. ansible_test/_internal/cli/commands/integration/__init__.py +1 -0
  527. ansible_test/_internal/cli/commands/integration/network.py +1 -0
  528. ansible_test/_internal/cli/commands/integration/posix.py +1 -0
  529. ansible_test/_internal/cli/commands/integration/windows.py +1 -0
  530. ansible_test/_internal/cli/commands/sanity.py +9 -0
  531. ansible_test/_internal/cli/commands/shell.py +1 -0
  532. ansible_test/_internal/cli/commands/units.py +1 -0
  533. ansible_test/_internal/cli/compat.py +1 -0
  534. ansible_test/_internal/cli/completers.py +1 -0
  535. ansible_test/_internal/cli/converters.py +1 -0
  536. ansible_test/_internal/cli/environments.py +1 -0
  537. ansible_test/_internal/cli/epilog.py +1 -0
  538. ansible_test/_internal/cli/parsers/__init__.py +1 -0
  539. ansible_test/_internal/cli/parsers/base_argument_parsers.py +1 -0
  540. ansible_test/_internal/cli/parsers/helpers.py +1 -0
  541. ansible_test/_internal/cli/parsers/host_config_parsers.py +1 -0
  542. ansible_test/_internal/cli/parsers/key_value_parsers.py +1 -0
  543. ansible_test/_internal/cli/parsers/value_parsers.py +1 -0
  544. ansible_test/_internal/commands/__init__.py +1 -0
  545. ansible_test/_internal/commands/coverage/__init__.py +2 -1
  546. ansible_test/_internal/commands/coverage/analyze/__init__.py +1 -0
  547. ansible_test/_internal/commands/coverage/analyze/targets/__init__.py +1 -0
  548. ansible_test/_internal/commands/coverage/analyze/targets/combine.py +1 -0
  549. ansible_test/_internal/commands/coverage/analyze/targets/expand.py +1 -0
  550. ansible_test/_internal/commands/coverage/analyze/targets/filter.py +1 -0
  551. ansible_test/_internal/commands/coverage/analyze/targets/generate.py +1 -0
  552. ansible_test/_internal/commands/coverage/analyze/targets/missing.py +1 -0
  553. ansible_test/_internal/commands/coverage/combine.py +2 -1
  554. ansible_test/_internal/commands/coverage/erase.py +1 -0
  555. ansible_test/_internal/commands/coverage/html.py +1 -0
  556. ansible_test/_internal/commands/coverage/report.py +1 -0
  557. ansible_test/_internal/commands/coverage/xml.py +1 -0
  558. ansible_test/_internal/commands/env/__init__.py +2 -0
  559. ansible_test/_internal/commands/integration/__init__.py +4 -0
  560. ansible_test/_internal/commands/integration/cloud/__init__.py +1 -0
  561. ansible_test/_internal/commands/integration/cloud/acme.py +2 -1
  562. ansible_test/_internal/commands/integration/cloud/aws.py +1 -0
  563. ansible_test/_internal/commands/integration/cloud/azure.py +1 -0
  564. ansible_test/_internal/commands/integration/cloud/cs.py +1 -0
  565. ansible_test/_internal/commands/integration/cloud/digitalocean.py +1 -0
  566. ansible_test/_internal/commands/integration/cloud/galaxy.py +3 -2
  567. ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -0
  568. ansible_test/_internal/commands/integration/cloud/httptester.py +2 -1
  569. ansible_test/_internal/commands/integration/cloud/nios.py +2 -1
  570. ansible_test/_internal/commands/integration/cloud/opennebula.py +1 -0
  571. ansible_test/_internal/commands/integration/cloud/openshift.py +1 -0
  572. ansible_test/_internal/commands/integration/cloud/scaleway.py +1 -0
  573. ansible_test/_internal/commands/integration/cloud/vcenter.py +1 -0
  574. ansible_test/_internal/commands/integration/cloud/vultr.py +1 -0
  575. ansible_test/_internal/commands/integration/coverage.py +1 -0
  576. ansible_test/_internal/commands/integration/filters.py +1 -0
  577. ansible_test/_internal/commands/integration/network.py +1 -0
  578. ansible_test/_internal/commands/integration/posix.py +1 -0
  579. ansible_test/_internal/commands/integration/windows.py +1 -0
  580. ansible_test/_internal/commands/sanity/__init__.py +16 -1
  581. ansible_test/_internal/commands/sanity/ansible_doc.py +1 -0
  582. ansible_test/_internal/commands/sanity/bin_symlinks.py +1 -0
  583. ansible_test/_internal/commands/sanity/compile.py +1 -0
  584. ansible_test/_internal/commands/sanity/ignores.py +1 -0
  585. ansible_test/_internal/commands/sanity/import.py +1 -0
  586. ansible_test/_internal/commands/sanity/integration_aliases.py +1 -0
  587. ansible_test/_internal/commands/sanity/pep8.py +1 -0
  588. ansible_test/_internal/commands/sanity/pslint.py +1 -0
  589. ansible_test/_internal/commands/sanity/pylint.py +24 -26
  590. ansible_test/_internal/commands/sanity/shellcheck.py +1 -0
  591. ansible_test/_internal/commands/sanity/validate_modules.py +1 -0
  592. ansible_test/_internal/commands/sanity/yamllint.py +1 -0
  593. ansible_test/_internal/commands/shell/__init__.py +1 -0
  594. ansible_test/_internal/commands/units/__init__.py +1 -0
  595. ansible_test/_internal/compat/__init__.py +1 -0
  596. ansible_test/_internal/compat/packaging.py +1 -0
  597. ansible_test/_internal/compat/yaml.py +1 -0
  598. ansible_test/_internal/completion.py +1 -0
  599. ansible_test/_internal/config.py +2 -0
  600. ansible_test/_internal/connections.py +1 -0
  601. ansible_test/_internal/constants.py +1 -0
  602. ansible_test/_internal/containers.py +1 -0
  603. ansible_test/_internal/content_config.py +1 -0
  604. ansible_test/_internal/core_ci.py +1 -0
  605. ansible_test/_internal/coverage_util.py +11 -10
  606. ansible_test/_internal/data.py +1 -0
  607. ansible_test/_internal/delegation.py +1 -0
  608. ansible_test/_internal/dev/__init__.py +1 -0
  609. ansible_test/_internal/dev/container_probe.py +1 -0
  610. ansible_test/_internal/diff.py +3 -2
  611. ansible_test/_internal/docker_util.py +2 -1
  612. ansible_test/_internal/encoding.py +1 -0
  613. ansible_test/_internal/executor.py +1 -0
  614. ansible_test/_internal/git.py +1 -0
  615. ansible_test/_internal/host_configs.py +1 -0
  616. ansible_test/_internal/host_profiles.py +1 -0
  617. ansible_test/_internal/http.py +1 -0
  618. ansible_test/_internal/init.py +1 -0
  619. ansible_test/_internal/inventory.py +35 -3
  620. ansible_test/_internal/io.py +1 -0
  621. ansible_test/_internal/metadata.py +1 -0
  622. ansible_test/_internal/payload.py +1 -0
  623. ansible_test/_internal/provider/__init__.py +1 -0
  624. ansible_test/_internal/provider/layout/__init__.py +1 -0
  625. ansible_test/_internal/provider/layout/ansible.py +1 -0
  626. ansible_test/_internal/provider/layout/collection.py +1 -0
  627. ansible_test/_internal/provider/layout/unsupported.py +1 -0
  628. ansible_test/_internal/provider/source/__init__.py +1 -0
  629. ansible_test/_internal/provider/source/git.py +1 -0
  630. ansible_test/_internal/provider/source/installed.py +1 -0
  631. ansible_test/_internal/provider/source/unsupported.py +1 -0
  632. ansible_test/_internal/provider/source/unversioned.py +1 -0
  633. ansible_test/_internal/provisioning.py +1 -0
  634. ansible_test/_internal/pypi_proxy.py +6 -5
  635. ansible_test/_internal/python_requirements.py +1 -0
  636. ansible_test/_internal/ssh.py +1 -0
  637. ansible_test/_internal/target.py +1 -0
  638. ansible_test/_internal/test.py +3 -2
  639. ansible_test/_internal/thread.py +1 -0
  640. ansible_test/_internal/timeout.py +1 -0
  641. ansible_test/_internal/util.py +1 -0
  642. ansible_test/_internal/util_common.py +5 -2
  643. ansible_test/_internal/venv.py +1 -0
  644. ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +1 -0
  645. ansible_test/_util/controller/sanity/code-smell/changelog/sphinx.py +1 -0
  646. ansible_test/_util/controller/sanity/code-smell/changelog.py +1 -0
  647. ansible_test/_util/controller/sanity/code-smell/empty-init.py +1 -0
  648. ansible_test/_util/controller/sanity/code-smell/line-endings.py +1 -0
  649. ansible_test/_util/controller/sanity/code-smell/no-assert.py +1 -0
  650. ansible_test/_util/controller/sanity/code-smell/no-get-exception.py +1 -0
  651. ansible_test/_util/controller/sanity/code-smell/no-illegal-filenames.py +1 -0
  652. ansible_test/_util/controller/sanity/code-smell/no-smart-quotes.py +1 -0
  653. ansible_test/_util/controller/sanity/code-smell/replace-urlopen.py +1 -0
  654. ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +28 -1
  655. ansible_test/_util/controller/sanity/code-smell/shebang.py +1 -0
  656. ansible_test/_util/controller/sanity/code-smell/symlinks.py +1 -0
  657. ansible_test/_util/controller/sanity/code-smell/use-argspec-type-path.py +1 -0
  658. ansible_test/_util/controller/sanity/code-smell/use-compat-six.py +1 -0
  659. ansible_test/_util/controller/sanity/integration-aliases/yaml_to_json.py +2 -1
  660. ansible_test/_util/controller/sanity/pep8/current-ignore.txt +4 -0
  661. ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +7 -5
  662. ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +7 -5
  663. ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +7 -5
  664. ansible_test/_util/controller/sanity/pylint/config/collection.cfg +3 -5
  665. ansible_test/_util/controller/sanity/pylint/config/default.cfg +7 -7
  666. ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -13
  667. ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +1 -0
  668. ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +1 -8
  669. ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +1 -8
  670. ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +55 -28
  671. ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +12 -5
  672. ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +13 -2
  673. ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -0
  674. ansible_test/_util/controller/sanity/yamllint/yamllinter.py +35 -17
  675. ansible_test/_util/controller/tools/collection_detail.py +1 -0
  676. ansible_test/_util/controller/tools/yaml_to_json.py +2 -1
  677. ansible_test/_util/target/pytest/plugins/ansible_forked.py +6 -1
  678. ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py +2 -1
  679. ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +1 -0
  680. ansible_test/_util/target/sanity/compile/compile.py +1 -0
  681. ansible_test/_util/target/sanity/import/importer.py +15 -16
  682. ansible_test/_util/target/setup/bootstrap.sh +9 -20
  683. ansible_test/_util/target/setup/probe_cgroups.py +1 -0
  684. ansible_test/_util/target/setup/quiet_pip.py +1 -0
  685. ansible_test/_util/target/setup/requirements.py +35 -27
  686. ansible_test/_util/target/tools/virtualenvcheck.py +2 -1
  687. ansible_test/_util/target/tools/yamlcheck.py +2 -1
  688. ansible/compat/selectors.py +0 -32
  689. ansible/errors/yaml_strings.py +0 -138
  690. ansible/executor/action_write_locks.py +0 -44
  691. ansible/executor/discovery/python_target.py +0 -47
  692. ansible/executor/powershell/module_powershell_wrapper.ps1 +0 -86
  693. ansible/executor/powershell/module_script_wrapper.ps1 +0 -22
  694. ansible/module_utils/compat/importlib.py +0 -26
  695. ansible/module_utils/compat/selectors.py +0 -32
  696. ansible/module_utils/pycompat24.py +0 -73
  697. ansible/parsing/yaml/constructor.py +0 -178
  698. ansible/template/native_helpers.py +0 -251
  699. ansible/template/template.py +0 -43
  700. ansible/template/vars.py +0 -77
  701. ansible/utils/native_jinja.py +0 -11
  702. ansible/vars/fact_cache.py +0 -71
  703. ansible_core-2.18.5rc1.dist-info/RECORD +0 -992
  704. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/Apache-License.txt +0 -0
  705. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/COPYING +0 -0
  706. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/MIT-license.txt +0 -0
  707. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/PSF-license.txt +0 -0
  708. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/entry_points.txt +0 -0
  709. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/simplified_bsd.txt +0 -0
  710. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/top_level.txt +0 -0
@@ -29,6 +29,8 @@ DOCUMENTATION = '''
29
29
  - The plugin does not cache results because external inventory scripts are responsible for their own caching.
30
30
  - To write your own inventory script see (R(Developing dynamic inventory,developing_inventory) from the documentation site.
31
31
  - To find the scripts that used to be part of the code release, go to U(https://github.com/ansible-community/contrib-scripts/).
32
+ - Since 2.19 using a directory as an inventory source will no longer ignore .ini files by default,
33
+ but you can still update the configuration to do so.
32
34
  '''
33
35
 
34
36
  EXAMPLES = r'''# fmt: code
@@ -151,148 +153,136 @@ EXAMPLES = r'''# fmt: code
151
153
  '''
152
154
 
153
155
 
156
+ import json
154
157
  import os
158
+ import shlex
155
159
  import subprocess
160
+ import typing as t
156
161
 
157
- from collections.abc import Mapping
158
-
159
- from ansible.errors import AnsibleError, AnsibleParserError
160
- from ansible.module_utils.basic import json_dict_bytes_to_unicode
161
- from ansible.module_utils.common.text.converters import to_native, to_text
162
+ from ansible.errors import AnsibleError, AnsibleJSONParserError
163
+ from ansible.inventory.data import InventoryData
164
+ from ansible.module_utils.datatag import native_type_name
165
+ from ansible.module_utils.common.json import get_decoder
166
+ from ansible.parsing.dataloader import DataLoader
162
167
  from ansible.plugins.inventory import BaseInventoryPlugin
168
+ from ansible._internal._datatag._tags import TrustedAsTemplate, Origin
163
169
  from ansible.utils.display import Display
170
+ from ansible._internal._json._profiles import _legacy, _inventory_legacy
164
171
 
165
172
  display = Display()
166
173
 
167
174
 
168
175
  class InventoryModule(BaseInventoryPlugin):
169
- ''' Host inventory parser for ansible using external inventory scripts. '''
176
+ """Host inventory parser for ansible using external inventory scripts."""
170
177
 
171
178
  NAME = 'script'
172
179
 
173
- def __init__(self):
174
-
180
+ def __init__(self) -> None:
175
181
  super(InventoryModule, self).__init__()
176
182
 
177
- self._hosts = set()
178
-
179
- def verify_file(self, path):
180
- ''' Verify if file is usable by this plugin, base does minimal accessibility check '''
181
-
182
- valid = super(InventoryModule, self).verify_file(path)
183
-
184
- if valid:
185
- # not only accessible, file must be executable and/or have shebang
186
- shebang_present = False
187
- try:
188
- with open(path, 'rb') as inv_file:
189
- initial_chars = inv_file.read(2)
190
- if initial_chars.startswith(b'#!'):
191
- shebang_present = True
192
- except Exception:
193
- pass
183
+ self._hosts: set[str] = set()
194
184
 
195
- if not os.access(path, os.X_OK) and not shebang_present:
196
- valid = False
197
-
198
- return valid
199
-
200
- def parse(self, inventory, loader, path, cache=None):
185
+ def verify_file(self, path: str) -> bool:
186
+ return super(InventoryModule, self).verify_file(path) and os.access(path, os.X_OK)
201
187
 
188
+ def parse(self, inventory: InventoryData, loader: DataLoader, path: str, cache: bool = False) -> None:
202
189
  super(InventoryModule, self).parse(inventory, loader, path)
203
- self.set_options()
204
190
 
205
- # Support inventory scripts that are not prefixed with some
206
- # path information but happen to be in the current working
207
- # directory when '.' is not in PATH.
208
- cmd = [path, "--list"]
209
-
210
- try:
211
- try:
212
- sp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
213
- except OSError as e:
214
- raise AnsibleParserError("problem running %s (%s)" % (' '.join(cmd), to_native(e)))
215
- (stdout, stderr) = sp.communicate()
191
+ self.set_options()
216
192
 
217
- path = to_native(path)
218
- err = to_native(stderr or "")
193
+ origin = Origin(description=f'<inventory script output from {path!r}>')
219
194
 
220
- if err and not err.endswith('\n'):
221
- err += '\n'
195
+ data, stderr, stderr_help_text = run_command(path, ['--list'], origin)
222
196
 
223
- if sp.returncode != 0:
224
- raise AnsibleError("Inventory script (%s) had an execution error: %s " % (path, err))
197
+ try:
198
+ profile_name = detect_profile_name(data)
199
+ decoder = get_decoder(profile_name)
200
+ except Exception as ex:
201
+ raise AnsibleError(
202
+ message="Unable to get JSON decoder for inventory script result.",
203
+ help_text=stderr_help_text,
204
+ # obj will be added by inventory manager
205
+ ) from ex
225
206
 
226
- # make sure script output is unicode so that json loader will output unicode strings itself
207
+ try:
227
208
  try:
228
- data = to_text(stdout, errors="strict")
229
- except Exception as e:
230
- raise AnsibleError("Inventory {0} contained characters that cannot be interpreted as UTF-8: {1}".format(path, to_native(e)))
209
+ processed = json.loads(data, cls=decoder)
210
+ except Exception as json_ex:
211
+ AnsibleJSONParserError.handle_exception(json_ex, origin)
212
+ except Exception as ex:
213
+ raise AnsibleError(
214
+ message="Inventory script result could not be parsed as JSON.",
215
+ help_text=stderr_help_text,
216
+ # obj will be added by inventory manager
217
+ ) from ex
218
+
219
+ # if no other errors happened, and you want to force displaying stderr, do so now
220
+ if stderr and self.get_option('always_show_stderr'):
221
+ self.display.error(msg=stderr)
222
+
223
+ data_from_meta: dict | None = None
224
+
225
+ # A "_meta" subelement may contain a variable "hostvars" which contains a hash for each host
226
+ # if this "hostvars" exists at all then do not call --host for each # host.
227
+ # This is for efficiency and scripts should still return data
228
+ # if called with --host for backwards compat with 1.2 and earlier.
229
+ for (group, gdata) in processed.items():
230
+ if group == '_meta':
231
+ data_from_meta = gdata.get('hostvars')
232
+
233
+ if not isinstance(data_from_meta, dict):
234
+ raise TypeError(f"Value contains '_meta.hostvars' which is {native_type_name(data_from_meta)!r} instead of {native_type_name(dict)!r}.")
235
+ else:
236
+ self._parse_group(group, gdata, origin)
237
+
238
+ if data_from_meta is None:
239
+ display.deprecated(
240
+ msg="Inventory scripts should always provide 'meta.hostvars'. "
241
+ "Host variables will be collected by running the inventory script with the '--host' option for each host.",
242
+ version='2.23',
243
+ obj=origin,
244
+ )
245
+
246
+ for host in self._hosts:
247
+ if data_from_meta is None:
248
+ got = self.get_host_variables(path, host, origin)
249
+ else:
250
+ got = data_from_meta.get(host, {})
231
251
 
232
- try:
233
- processed = self.loader.load(data, json_only=True)
234
- except Exception as e:
235
- raise AnsibleError("failed to parse executable inventory script results from {0}: {1}\n{2}".format(path, to_native(e), err))
236
-
237
- # if no other errors happened and you want to force displaying stderr, do so now
238
- if stderr and self.get_option('always_show_stderr'):
239
- self.display.error(msg=to_text(err))
240
-
241
- if not isinstance(processed, Mapping):
242
- raise AnsibleError("failed to parse executable inventory script results from {0}: needs to be a json dict\n{1}".format(path, err))
243
-
244
- group = None
245
- data_from_meta = None
246
-
247
- # A "_meta" subelement may contain a variable "hostvars" which contains a hash for each host
248
- # if this "hostvars" exists at all then do not call --host for each # host.
249
- # This is for efficiency and scripts should still return data
250
- # if called with --host for backwards compat with 1.2 and earlier.
251
- for (group, gdata) in processed.items():
252
- if group == '_meta':
253
- if 'hostvars' in gdata:
254
- data_from_meta = gdata['hostvars']
255
- else:
256
- self._parse_group(group, gdata)
257
-
258
- for host in self._hosts:
259
- got = {}
260
- if data_from_meta is None:
261
- got = self.get_host_variables(path, host)
262
- else:
263
- try:
264
- got = data_from_meta.get(host, {})
265
- except AttributeError as e:
266
- raise AnsibleError("Improperly formatted host information for %s: %s" % (host, to_native(e)), orig_exc=e)
267
-
268
- self._populate_host_vars([host], got)
269
-
270
- except Exception as e:
271
- raise AnsibleParserError(to_native(e))
272
-
273
- def _parse_group(self, group, data):
252
+ self._populate_host_vars([host], got)
274
253
 
254
+ def _parse_group(self, group: str, data: t.Any, origin: Origin) -> None:
255
+ """Normalize and ingest host/var information for the named group."""
275
256
  group = self.inventory.add_group(group)
276
257
 
277
258
  if not isinstance(data, dict):
278
259
  data = {'hosts': data}
279
- # is not those subkeys, then simplified syntax, host with vars
260
+ display.deprecated(
261
+ msg=f"Group {group!r} was converted to {native_type_name(dict)!r} from {native_type_name(data)!r}.",
262
+ version='2.23',
263
+ obj=origin,
264
+ )
280
265
  elif not any(k in data for k in ('hosts', 'vars', 'children')):
281
266
  data = {'hosts': [group], 'vars': data}
267
+ display.deprecated(
268
+ msg=f"Treating malformed group {group!r} as the sole host of that group. Variables provided in this manner cannot be templated.",
269
+ version='2.23',
270
+ obj=origin,
271
+ )
282
272
 
283
- if 'hosts' in data:
284
- if not isinstance(data['hosts'], list):
285
- raise AnsibleError("You defined a group '%s' with bad data for the host list:\n %s" % (group, data))
273
+ if (data_hosts := data.get('hosts', ...)) is not ...:
274
+ if not isinstance(data_hosts, list):
275
+ raise TypeError(f"Value contains '{group}.hosts' which is {native_type_name(data_hosts)!r} instead of {native_type_name(list)!r}.")
286
276
 
287
- for hostname in data['hosts']:
277
+ for hostname in data_hosts:
288
278
  self._hosts.add(hostname)
289
279
  self.inventory.add_host(hostname, group)
290
280
 
291
- if 'vars' in data:
292
- if not isinstance(data['vars'], dict):
293
- raise AnsibleError("You defined a group '%s' with bad data for variables:\n %s" % (group, data))
281
+ if (data_vars := data.get('vars', ...)) is not ...:
282
+ if not isinstance(data_vars, dict):
283
+ raise TypeError(f"Value contains '{group}.vars' which is {native_type_name(data_vars)!r} instead of {native_type_name(dict)!r}.")
294
284
 
295
- for k, v in data['vars'].items():
285
+ for k, v in data_vars.items():
296
286
  self.inventory.set_variable(group, k, v)
297
287
 
298
288
  if group != '_meta' and isinstance(data, dict) and 'children' in data:
@@ -300,22 +290,102 @@ class InventoryModule(BaseInventoryPlugin):
300
290
  child_name = self.inventory.add_group(child_name)
301
291
  self.inventory.add_child(group, child_name)
302
292
 
303
- def get_host_variables(self, path, host):
304
- """ Runs <script> --host <hostname>, to determine additional host variables """
293
+ @staticmethod
294
+ def get_host_variables(path: str, host: str, origin: Origin) -> dict:
295
+ """Runs <script> --host <hostname>, to determine additional host variables."""
296
+ origin = origin.replace(description=f'{origin.description} for host {host!r}')
305
297
 
306
- cmd = [path, "--host", host]
307
- try:
308
- sp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
309
- except OSError as e:
310
- raise AnsibleError("problem running %s (%s)" % (' '.join(cmd), e))
311
- (out, stderr) = sp.communicate()
298
+ data, stderr, stderr_help_text = run_command(path, ['--host', host], origin)
312
299
 
313
- if sp.returncode != 0:
314
- raise AnsibleError("Inventory script (%s) had an execution error: %s" % (path, to_native(stderr)))
315
-
316
- if out.strip() == '':
300
+ if not data.strip():
317
301
  return {}
302
+
318
303
  try:
319
- return json_dict_bytes_to_unicode(self.loader.load(out, file_name=path))
320
- except ValueError:
321
- raise AnsibleError("could not parse post variable response: %s, %s" % (cmd, out))
304
+ try:
305
+ # Use standard legacy trust inversion here.
306
+ # Unlike the normal inventory output, everything here is considered a variable and thus supports trust (and trust inversion).
307
+ processed = json.loads(data, cls=_legacy.Decoder)
308
+ except Exception as json_ex:
309
+ AnsibleJSONParserError.handle_exception(json_ex, origin)
310
+ except Exception as ex:
311
+ raise AnsibleError(
312
+ message=f"Inventory script result for host {host!r} could not be parsed as JSON.",
313
+ help_text=stderr_help_text,
314
+ # obj will be added by inventory manager
315
+ ) from ex
316
+
317
+ return processed
318
+
319
+
320
+ def detect_profile_name(value: str) -> str:
321
+ """
322
+ Detect (optional) JSON profile name from an inventory JSON document.
323
+ Defaults to `inventory_legacy`.
324
+ """
325
+ try:
326
+ data = json.loads(value)
327
+ except Exception as ex:
328
+ raise ValueError('Value could not be parsed as JSON.') from ex
329
+
330
+ if not isinstance(data, dict):
331
+ raise TypeError(f'Value is {native_type_name(data)!r} instead of {native_type_name(dict)!r}.')
332
+
333
+ if (meta := data.get('_meta', ...)) is ...:
334
+ return _inventory_legacy.Decoder.profile_name
335
+
336
+ if not isinstance(meta, dict):
337
+ raise TypeError(f"Value contains '_meta' which is {native_type_name(meta)!r} instead of {native_type_name(dict)!r}.")
338
+
339
+ if (profile := meta.get('profile', ...)) is ...:
340
+ return _inventory_legacy.Decoder.profile_name
341
+
342
+ if not isinstance(profile, str):
343
+ raise TypeError(f"Value contains '_meta.profile' which is {native_type_name(profile)!r} instead of {native_type_name(str)!r}.")
344
+
345
+ if not profile.startswith('inventory_'):
346
+ raise ValueError(f"Non-inventory profile {profile!r} is not allowed.")
347
+
348
+ return profile
349
+
350
+
351
+ def run_command(path: str, options: list[str], origin: Origin) -> tuple[str, str, str]:
352
+ """Run an inventory script, normalize and validate output."""
353
+ cmd = [path] + options
354
+
355
+ try:
356
+ sp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
357
+ except OSError as ex:
358
+ raise AnsibleError(
359
+ message=f"Failed to execute inventory script command {shlex.join(cmd)!r}.",
360
+ # obj will be added by inventory manager
361
+ ) from ex
362
+
363
+ stdout_bytes, stderr_bytes = sp.communicate()
364
+
365
+ stderr = stderr_bytes.decode(errors='surrogateescape')
366
+
367
+ if stderr and not stderr.endswith('\n'):
368
+ stderr += '\n'
369
+
370
+ # DTFIX-RELEASE: another use case for the "not quite help text, definitely not message" diagnostic output on errors
371
+ stderr_help_text = f'Standard error from inventory script:\n{stderr}' if stderr.strip() else None
372
+
373
+ if sp.returncode != 0:
374
+ raise AnsibleError(
375
+ message=f"Inventory script returned non-zero exit code {sp.returncode}.",
376
+ help_text=stderr_help_text,
377
+ # obj will be added by inventory manager
378
+ )
379
+
380
+ try:
381
+ data = stdout_bytes.decode()
382
+ except Exception as ex:
383
+ raise AnsibleError(
384
+ "Inventory script result contained characters that cannot be interpreted as UTF-8.",
385
+ help_text=stderr_help_text,
386
+ # obj will be added by inventory manager
387
+ ) from ex
388
+ else:
389
+ data = TrustedAsTemplate().tag(origin.tag(data))
390
+
391
+ return data, stderr, stderr_help_text
@@ -3,19 +3,16 @@
3
3
 
4
4
  from __future__ import annotations
5
5
 
6
- DOCUMENTATION = r'''
6
+ DOCUMENTATION = r"""
7
7
  name: toml
8
8
  version_added: "2.8"
9
9
  short_description: Uses a specific TOML file as an inventory source.
10
10
  description:
11
11
  - TOML based inventory format
12
12
  - File MUST have a valid '.toml' file extension
13
- notes:
14
- - >
15
- Requires one of the following python libraries: 'toml', 'tomli', or 'tomllib'
16
- '''
13
+ """
17
14
 
18
- EXAMPLES = r'''# fmt: toml
15
+ EXAMPLES = r"""# fmt: toml
19
16
  # Example 1
20
17
  [all.vars]
21
18
  has_java = false
@@ -84,115 +81,27 @@ host4 = {}
84
81
 
85
82
  [g2.hosts]
86
83
  host4 = {}
87
- '''
84
+ """
88
85
 
89
86
  import os
90
- import typing as t
87
+ import tomllib
91
88
 
92
89
  from collections.abc import MutableMapping, MutableSequence
93
- from functools import partial
94
90
 
95
- from ansible.errors import AnsibleFileNotFound, AnsibleParserError, AnsibleRuntimeError
96
- from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
97
- from ansible.module_utils.six import string_types, text_type
98
- from ansible.parsing.yaml.objects import AnsibleSequence, AnsibleUnicode
91
+ from ansible.errors import AnsibleFileNotFound, AnsibleParserError
92
+ from ansible.module_utils.common.text.converters import to_bytes, to_native
93
+ from ansible.module_utils.six import string_types
99
94
  from ansible.plugins.inventory import BaseFileInventoryPlugin
100
95
  from ansible.utils.display import Display
101
- from ansible.utils.unsafe_proxy import AnsibleUnsafeBytes, AnsibleUnsafeText
102
-
103
- HAS_TOML = False
104
- try:
105
- import toml
106
- HAS_TOML = True
107
- except ImportError:
108
- pass
109
-
110
- HAS_TOMLIW = False
111
- try:
112
- import tomli_w # type: ignore[import]
113
- HAS_TOMLIW = True
114
- except ImportError:
115
- pass
116
-
117
- HAS_TOMLLIB = False
118
- try:
119
- import tomllib # type: ignore[import]
120
- HAS_TOMLLIB = True
121
- except ImportError:
122
- try:
123
- import tomli as tomllib # type: ignore[no-redef]
124
- HAS_TOMLLIB = True
125
- except ImportError:
126
- pass
127
96
 
128
97
  display = Display()
129
98
 
130
99
 
131
- # dumps
132
- if HAS_TOML and hasattr(toml, 'TomlEncoder'):
133
- # toml>=0.10.0
134
- class AnsibleTomlEncoder(toml.TomlEncoder):
135
- def __init__(self, *args, **kwargs):
136
- super(AnsibleTomlEncoder, self).__init__(*args, **kwargs)
137
- # Map our custom YAML object types to dump_funcs from ``toml``
138
- self.dump_funcs.update({
139
- AnsibleSequence: self.dump_funcs.get(list),
140
- AnsibleUnicode: self.dump_funcs.get(str),
141
- AnsibleUnsafeBytes: self.dump_funcs.get(str),
142
- AnsibleUnsafeText: self.dump_funcs.get(str),
143
- })
144
- toml_dumps = partial(toml.dumps, encoder=AnsibleTomlEncoder()) # type: t.Callable[[t.Any], str]
145
- else:
146
- # toml<0.10.0
147
- # tomli-w
148
- def toml_dumps(data): # type: (t.Any) -> str
149
- if HAS_TOML:
150
- return toml.dumps(convert_yaml_objects_to_native(data))
151
- elif HAS_TOMLIW:
152
- return tomli_w.dumps(convert_yaml_objects_to_native(data))
153
- raise AnsibleRuntimeError(
154
- 'The python "toml" or "tomli-w" library is required when using the TOML output format'
155
- )
156
-
157
- # loads
158
- if HAS_TOML:
159
- # prefer toml if installed, since it supports both encoding and decoding
160
- toml_loads = toml.loads # type: ignore[assignment]
161
- TOMLDecodeError = toml.TomlDecodeError # type: t.Any
162
- elif HAS_TOMLLIB:
163
- toml_loads = tomllib.loads # type: ignore[assignment]
164
- TOMLDecodeError = tomllib.TOMLDecodeError # type: t.Any # type: ignore[no-redef]
165
-
166
-
167
- def convert_yaml_objects_to_native(obj):
168
- """Older versions of the ``toml`` python library, and tomllib, don't have
169
- a pluggable way to tell the encoder about custom types, so we need to
170
- ensure objects that we pass are native types.
171
-
172
- Used with:
173
- - ``toml<0.10.0`` where ``toml.TomlEncoder`` is missing
174
- - ``tomli`` or ``tomllib``
175
-
176
- This function recurses an object and ensures we cast any of the types from
177
- ``ansible.parsing.yaml.objects`` into their native types, effectively cleansing
178
- the data before we hand it over to the toml library.
179
-
180
- This function doesn't directly check for the types from ``ansible.parsing.yaml.objects``
181
- but instead checks for the types those objects inherit from, to offer more flexibility.
182
- """
183
- if isinstance(obj, dict):
184
- return dict((k, convert_yaml_objects_to_native(v)) for k, v in obj.items())
185
- elif isinstance(obj, list):
186
- return [convert_yaml_objects_to_native(v) for v in obj]
187
- elif isinstance(obj, text_type):
188
- return text_type(obj)
189
- else:
190
- return obj
191
-
192
-
193
100
  class InventoryModule(BaseFileInventoryPlugin):
194
101
  NAME = 'toml'
195
102
 
103
+ trusted_by_default = True # we need the inventory system to mark trust for us, since we're not manually traversing var assignments
104
+
196
105
  def _parse_group(self, group, group_data):
197
106
  if group_data is not None and not isinstance(group_data, MutableMapping):
198
107
  self.display.warning("Skipping '%s' as this is not a valid group definition" % group)
@@ -246,33 +155,14 @@ class InventoryModule(BaseFileInventoryPlugin):
246
155
  raise AnsibleFileNotFound("Unable to retrieve file contents", file_name=file_name)
247
156
 
248
157
  try:
249
- (b_data, private) = self.loader._get_file_contents(file_name)
250
- return toml_loads(to_text(b_data, errors='surrogate_or_strict'))
251
- except TOMLDecodeError as e:
252
- raise AnsibleParserError(
253
- 'TOML file (%s) is invalid: %s' % (file_name, to_native(e)),
254
- orig_exc=e
255
- )
256
- except (IOError, OSError) as e:
257
- raise AnsibleParserError(
258
- "An error occurred while trying to read the file '%s': %s" % (file_name, to_native(e)),
259
- orig_exc=e
260
- )
261
- except Exception as e:
262
- raise AnsibleParserError(
263
- "An unexpected error occurred while parsing the file '%s': %s" % (file_name, to_native(e)),
264
- orig_exc=e
265
- )
158
+ return tomllib.loads(self.loader.get_text_file_contents(file_name))
159
+ except tomllib.TOMLDecodeError as ex:
160
+ raise AnsibleParserError(f'TOML file {file_name!r} is invalid.') from ex
161
+ except Exception as ex:
162
+ raise AnsibleParserError(f'An error occurred while parsing the file {file_name!r}.') from ex
266
163
 
267
164
  def parse(self, inventory, loader, path, cache=True):
268
- ''' parses the inventory file '''
269
- if not HAS_TOMLLIB and not HAS_TOML:
270
- # tomllib works here too, but we don't call it out in the error,
271
- # since you either have it or not as part of cpython stdlib >= 3.11
272
- raise AnsibleParserError(
273
- 'The TOML inventory plugin requires the python "toml", or "tomli" library'
274
- )
275
-
165
+ """ parses the inventory file """
276
166
  super(InventoryModule, self).parse(inventory, loader, path)
277
167
  self.set_options()
278
168
 
@@ -3,7 +3,7 @@
3
3
 
4
4
  from __future__ import annotations
5
5
 
6
- DOCUMENTATION = '''
6
+ DOCUMENTATION = """
7
7
  name: yaml
8
8
  version_added: "2.4"
9
9
  short_description: Uses a specific YAML file as an inventory source.
@@ -31,8 +31,8 @@ DOCUMENTATION = '''
31
31
  - section: inventory_plugin_yaml
32
32
  key: yaml_valid_extensions
33
33
 
34
- '''
35
- EXAMPLES = '''
34
+ """
35
+ EXAMPLES = """
36
36
  all: # keys must be unique, i.e. only one 'hosts' per group
37
37
  hosts:
38
38
  test1:
@@ -63,7 +63,7 @@ all: # keys must be unique, i.e. only one 'hosts' per group
63
63
  test1 # same host as above, additional group membership
64
64
  vars:
65
65
  group_last_var: value
66
- '''
66
+ """
67
67
 
68
68
  import os
69
69
 
@@ -81,6 +81,8 @@ class InventoryModule(BaseFileInventoryPlugin):
81
81
 
82
82
  NAME = 'yaml'
83
83
 
84
+ # implicit trust behavior is already added by the YAML parser invoked by the loader
85
+
84
86
  def __init__(self):
85
87
 
86
88
  super(InventoryModule, self).__init__()
@@ -95,13 +97,13 @@ class InventoryModule(BaseFileInventoryPlugin):
95
97
  return valid
96
98
 
97
99
  def parse(self, inventory, loader, path, cache=True):
98
- ''' parses the inventory file '''
100
+ """ parses the inventory file """
99
101
 
100
102
  super(InventoryModule, self).parse(inventory, loader, path)
101
103
  self.set_options()
102
104
 
103
105
  try:
104
- data = self.loader.load_from_file(path, cache='none')
106
+ data = self.loader.load_from_file(path, cache='none', trusted_as_template=True)
105
107
  except Exception as e:
106
108
  raise AnsibleParserError(e)
107
109
 
@@ -170,9 +172,9 @@ class InventoryModule(BaseFileInventoryPlugin):
170
172
  return group
171
173
 
172
174
  def _parse_host(self, host_pattern):
173
- '''
175
+ """
174
176
  Each host key can be a pattern, try to process it and add variables as needed
175
- '''
177
+ """
176
178
  try:
177
179
  (hostnames, port) = self._expand_hostpattern(host_pattern)
178
180
  except TypeError:
ansible/plugins/list.py CHANGED
@@ -124,7 +124,7 @@ def list_collection_plugins(ptype, collections, search_paths=None):
124
124
  try:
125
125
  ploader = getattr(loader, '{0}_loader'.format(ptype))
126
126
  except AttributeError:
127
- raise AnsibleError('Cannot list plugins, incorrect plugin type supplied: {0}'.format(ptype))
127
+ raise AnsibleError(f"Cannot list plugins, incorrect plugin type {ptype!r} supplied.") from None
128
128
 
129
129
  # get plugins for each collection
130
130
  for collection in collections.keys():
@@ -191,8 +191,8 @@ def list_plugins(ptype, collections=None, search_paths=None):
191
191
  else:
192
192
  try:
193
193
  plugin_collections[collection] = to_bytes(_get_collection_path(collection))
194
- except ValueError as e:
195
- raise AnsibleError("Cannot use supplied collection {0}: {1}".format(collection, to_native(e)), orig_exc=e)
194
+ except ValueError as ex:
195
+ raise AnsibleError(f"Cannot use supplied collection {collection!r}.") from ex
196
196
 
197
197
  if plugin_collections:
198
198
  plugins.update(list_collection_plugins(ptype, plugin_collections))