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
ansible/modules/apt.py CHANGED
@@ -9,7 +9,7 @@
9
9
  from __future__ import annotations
10
10
 
11
11
 
12
- DOCUMENTATION = '''
12
+ DOCUMENTATION = """
13
13
  ---
14
14
  module: apt
15
15
  short_description: Manages apt-packages
@@ -17,6 +17,12 @@ description:
17
17
  - Manages I(apt) packages (such as for Debian/Ubuntu).
18
18
  version_added: "0.0.2"
19
19
  options:
20
+ auto_install_module_deps:
21
+ description:
22
+ - Automatically install dependencies required to run this module.
23
+ type: bool
24
+ default: yes
25
+ version_added: 2.19
20
26
  name:
21
27
  description:
22
28
  - A list of package names, like V(foo), or package specifier with version, like V(foo=1.0) or V(foo>=1.0).
@@ -191,8 +197,7 @@ options:
191
197
  default: 60
192
198
  version_added: "2.12"
193
199
  requirements:
194
- - python-apt (python 2)
195
- - python3-apt (python 3)
200
+ - python3-apt
196
201
  - aptitude (before 2.4)
197
202
  author: "Matthew Williams (@mgwilliams)"
198
203
  extends_documentation_fragment: action_common_attributes
@@ -214,12 +219,12 @@ notes:
214
219
  - When used with a C(loop:) each package will be processed individually, it is much more efficient to pass the list directly to the O(name) option.
215
220
  - When O(default_release) is used, an implicit priority of 990 is used. This is the same behavior as C(apt-get -t).
216
221
  - When an exact version is specified, an implicit priority of 1001 is used.
217
- - If the interpreter can't import C(python-apt)/C(python3-apt) the module will check for it in system-owned interpreters as well.
218
- If the dependency can't be found, the module will attempt to install it.
222
+ - If the interpreter can't import C(python3-apt) the module will check for it in system-owned interpreters as well.
223
+ If the dependency can't be found, depending on the value of O(auto_install_module_deps) the module will attempt to install it.
219
224
  If the dependency is found or installed, the module will be respawned under the correct interpreter.
220
- '''
225
+ """
221
226
 
222
- EXAMPLES = '''
227
+ EXAMPLES = """
223
228
  - name: Install apache httpd (state=present is optional)
224
229
  ansible.builtin.apt:
225
230
  name: apache2
@@ -327,9 +332,9 @@ EXAMPLES = '''
327
332
  - name: Run the equivalent of "apt-get clean" as a separate step
328
333
  ansible.builtin.apt:
329
334
  clean: yes
330
- '''
335
+ """
331
336
 
332
- RETURN = '''
337
+ RETURN = """
333
338
  cache_updated:
334
339
  description: if the cache was updated or not
335
340
  returned: success, in some cases
@@ -355,7 +360,7 @@ stderr:
355
360
  returned: success, when needed
356
361
  type: str
357
362
  sample: "AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the 'ServerName' directive globally to ..."
358
- ''' # NOQA
363
+ """ # NOQA
359
364
 
360
365
  # added to stave off future warnings about apt api
361
366
  import warnings
@@ -483,7 +488,7 @@ class PolicyRcD(object):
483
488
 
484
489
 
485
490
  def package_split(pkgspec):
486
- parts = re.split(r'(>?=)', pkgspec, 1)
491
+ parts = re.split(r'(>?=)', pkgspec, maxsplit=1)
487
492
  if len(parts) > 1:
488
493
  return parts
489
494
  return parts[0], None, None
@@ -1184,7 +1189,7 @@ def get_updated_cache_time():
1184
1189
 
1185
1190
  # https://github.com/ansible/ansible-modules-core/issues/2951
1186
1191
  def get_cache(module):
1187
- '''Attempt to get the cache object and update till it works'''
1192
+ """Attempt to get the cache object and update till it works"""
1188
1193
  cache = None
1189
1194
  try:
1190
1195
  cache = apt.Cache()
@@ -1233,6 +1238,7 @@ def main():
1233
1238
  allow_downgrade=dict(type='bool', default=False, aliases=['allow-downgrade', 'allow_downgrades', 'allow-downgrades']),
1234
1239
  allow_change_held_packages=dict(type='bool', default=False),
1235
1240
  lock_timeout=dict(type='int', default=60),
1241
+ auto_install_module_deps=dict(type='bool', default=True),
1236
1242
  ),
1237
1243
  mutually_exclusive=[['deb', 'package', 'upgrade']],
1238
1244
  required_one_of=[['autoremove', 'deb', 'package', 'update_cache', 'upgrade']],
@@ -1268,7 +1274,7 @@ def main():
1268
1274
  if not HAS_PYTHON_APT:
1269
1275
  # This interpreter can't see the apt Python library- we'll do the following to try and fix that:
1270
1276
  # 1) look in common locations for system-owned interpreters that can see it; if we find one, respawn under it
1271
- # 2) finding none, try to install a matching python-apt package for the current interpreter version;
1277
+ # 2) finding none, try to install a matching python3-apt package for the current interpreter version;
1272
1278
  # we limit to the current interpreter version to try and avoid installing a whole other Python just
1273
1279
  # for apt support
1274
1280
  # 3) if we installed a support package, try to respawn under what we think is the right interpreter (could be
@@ -1294,39 +1300,47 @@ def main():
1294
1300
 
1295
1301
  # don't make changes if we're in check_mode
1296
1302
  if module.check_mode:
1297
- module.fail_json(msg="%s must be installed to use check mode. "
1298
- "If run normally this module can auto-install it." % apt_pkg_name)
1299
-
1300
- # We skip cache update in auto install the dependency if the
1301
- # user explicitly declared it with update_cache=no.
1302
- if module.params.get('update_cache') is False:
1303
- module.warn("Auto-installing missing dependency without updating cache: %s" % apt_pkg_name)
1304
- else:
1305
- module.warn("Updating cache and auto-installing missing dependency: %s" % apt_pkg_name)
1306
- module.run_command([APT_GET_CMD, 'update'], check_rc=True)
1307
-
1308
- # try to install the apt Python binding
1309
- apt_pkg_cmd = [APT_GET_CMD, 'install', apt_pkg_name, '-y', '-q', dpkg_options]
1310
-
1311
- if install_recommends is False:
1312
- apt_pkg_cmd.extend(["-o", "APT::Install-Recommends=no"])
1313
- elif install_recommends is True:
1314
- apt_pkg_cmd.extend(["-o", "APT::Install-Recommends=yes"])
1315
- # install_recommends is None uses the OS default
1316
-
1317
- module.run_command(apt_pkg_cmd, check_rc=True)
1318
-
1319
- # try again to find the bindings in common places
1320
- interpreter = probe_interpreters_for_module(interpreters, 'apt')
1321
-
1322
- if interpreter:
1323
- # found the Python bindings; respawn this module under the interpreter where we found them
1324
- # NB: respawn is somewhat wasteful if it's this interpreter, but simplifies the code
1325
- respawn_module(interpreter)
1326
- # this is the end of the line for this process, it will exit here once the respawned module has completed
1327
- else:
1328
- # we've done all we can do; just tell the user it's busted and get out
1329
- module.fail_json(msg="{0} must be installed and visible from {1}.".format(apt_pkg_name, sys.executable))
1303
+ module.fail_json(
1304
+ msg=f"{apt_pkg_name} must be installed to use check mode. "
1305
+ "If run normally this module can auto-install it, "
1306
+ "see the auto_install_module_deps option.",
1307
+ )
1308
+ elif p['auto_install_module_deps']:
1309
+ # We skip cache update in auto install the dependency if the
1310
+ # user explicitly declared it with update_cache=no.
1311
+ if module.params.get('update_cache') is False:
1312
+ module.warn("Auto-installing missing dependency without updating cache: %s" % apt_pkg_name)
1313
+ else:
1314
+ module.warn("Updating cache and auto-installing missing dependency: %s" % apt_pkg_name)
1315
+ module.run_command([APT_GET_CMD, 'update'], check_rc=True)
1316
+
1317
+ # try to install the apt Python binding
1318
+ apt_pkg_cmd = [APT_GET_CMD, 'install', apt_pkg_name, '-y', '-q', dpkg_options]
1319
+
1320
+ if install_recommends is False:
1321
+ apt_pkg_cmd.extend(["-o", "APT::Install-Recommends=no"])
1322
+ elif install_recommends is True:
1323
+ apt_pkg_cmd.extend(["-o", "APT::Install-Recommends=yes"])
1324
+ # install_recommends is None uses the OS default
1325
+
1326
+ module.run_command(apt_pkg_cmd, check_rc=True)
1327
+
1328
+ # try again to find the bindings in common places
1329
+ interpreter = probe_interpreters_for_module(interpreters, 'apt')
1330
+
1331
+ if interpreter:
1332
+ # found the Python bindings; respawn this module under the interpreter where we found them
1333
+ # NB: respawn is somewhat wasteful if it's this interpreter, but simplifies the code
1334
+ respawn_module(interpreter)
1335
+ # this is the end of the line for this process, it will exit here once the respawned module has completed
1336
+
1337
+ # we've done all we can do; just tell the user it's busted and get out
1338
+ py_version = sys.version.replace("\n", "")
1339
+ module.fail_json(
1340
+ msg=f"Could not import the {apt_pkg_name} module using {sys.executable} ({py_version}). "
1341
+ f"Ensure {apt_pkg_name} package is installed (either manually or via the auto_install_module_deps option) "
1342
+ f"or that you have specified the correct ansible_python_interpreter. (attempted {interpreters}).",
1343
+ )
1330
1344
 
1331
1345
  if p['clean'] is True:
1332
1346
  aptclean_stdout, aptclean_stderr, aptclean_diff = aptclean(module)
@@ -8,7 +8,7 @@
8
8
  from __future__ import annotations
9
9
 
10
10
 
11
- DOCUMENTATION = '''
11
+ DOCUMENTATION = """
12
12
  ---
13
13
  module: apt_key
14
14
  author:
@@ -33,6 +33,8 @@ notes:
33
33
  To generate a full-fingerprint imported key: C(apt-key adv --list-public-keys --with-fingerprint --with-colons)."
34
34
  - If you specify both the key O(id) and the O(url) with O(state=present), the task can verify or add the key as needed.
35
35
  - Adding a new key requires an apt cache update (e.g. using the M(ansible.builtin.apt) module's C(update_cache) option).
36
+ - The C(apt-key) utility has been deprecated and removed in modern debian versions, use M(ansible.builtin.deb822_repository) as an alternative
37
+ to M(ansible.builtin.apt_repository) + apt_key combinations.
36
38
  requirements:
37
39
  - gpg
38
40
  seealso:
@@ -79,9 +81,9 @@ options:
79
81
  on personally controlled sites using self-signed certificates.
80
82
  type: bool
81
83
  default: 'yes'
82
- '''
84
+ """
83
85
 
84
- EXAMPLES = '''
86
+ EXAMPLES = """
85
87
  - name: One way to avoid apt_key once it is removed from your distro, armored keys should use .asc extension, binary should use .gpg
86
88
  block:
87
89
  - name: somerepo | no apt key
@@ -133,9 +135,9 @@ EXAMPLES = '''
133
135
  id: 9FED2BCBDCD29CDF762678CBAED4B06F473041FA
134
136
  file: /tmp/apt.gpg
135
137
  state: present
136
- '''
138
+ """
137
139
 
138
- RETURN = '''
140
+ RETURN = """
139
141
  after:
140
142
  description: List of apt key ids or fingerprints after any modification
141
143
  returned: on change
@@ -166,13 +168,10 @@ short_id:
166
168
  returned: always
167
169
  type: str
168
170
  sample: "A88D21E9"
169
- '''
171
+ """
170
172
 
171
173
  import os
172
174
 
173
- # FIXME: standardize into module_common
174
- from traceback import format_exc
175
-
176
175
  from ansible.module_utils.common.text.converters import to_native
177
176
  from ansible.module_utils.basic import AnsibleModule
178
177
  from ansible.module_utils.common.locale import get_best_parsable_locale
@@ -196,8 +195,16 @@ def lang_env(module):
196
195
  def find_needed_binaries(module):
197
196
  global apt_key_bin
198
197
  global gpg_bin
199
- apt_key_bin = module.get_bin_path('apt-key', required=True)
200
- gpg_bin = module.get_bin_path('gpg', required=True)
198
+
199
+ try:
200
+ apt_key_bin = module.get_bin_path('apt-key', required=True)
201
+ except ValueError as e:
202
+ module.exit_json(f'{to_native(e)}. Apt-key has been deprecated. See the deb822_repository as an alternative.')
203
+
204
+ try:
205
+ gpg_bin = module.get_bin_path('gpg', required=True)
206
+ except ValueError as e:
207
+ module.exit_json(msg=to_native(e))
201
208
 
202
209
 
203
210
  def add_http_proxy(cmd):
@@ -310,7 +317,7 @@ def download_key(module, url):
310
317
 
311
318
  return rsp.read()
312
319
  except Exception:
313
- module.fail_json(msg="error getting key id from url: %s" % url, traceback=format_exc())
320
+ module.fail_json(msg=f"Error getting key id from url: {url}")
314
321
 
315
322
 
316
323
  def get_key_id_from_file(module, filename, data=None):
@@ -9,7 +9,7 @@
9
9
  from __future__ import annotations
10
10
 
11
11
 
12
- DOCUMENTATION = '''
12
+ DOCUMENTATION = """
13
13
  ---
14
14
  module: apt_repository
15
15
  short_description: Add and remove APT repositories
@@ -101,9 +101,9 @@ requirements:
101
101
  - python-apt (python 2)
102
102
  - python3-apt (python 3)
103
103
  - apt-key or gpg
104
- '''
104
+ """
105
105
 
106
- EXAMPLES = '''
106
+ EXAMPLES = """
107
107
  - name: Add specified repository into sources list
108
108
  ansible.builtin.apt_repository:
109
109
  repo: deb http://archive.canonical.com/ubuntu hardy partner
@@ -143,11 +143,11 @@ EXAMPLES = '''
143
143
 
144
144
  - name: somerepo | apt source
145
145
  ansible.builtin.apt_repository:
146
- repo: "deb [arch=amd64 signed-by=/etc/apt/keyrings/myrepo.asc] https://download.example.com/linux/ubuntu {{ ansible_distribution_release }} stable"
146
+ repo: "deb [arch=amd64 signed-by=/etc/apt/keyrings/somerepo.asc] https://download.example.com/linux/ubuntu {{ ansible_distribution_release }} stable"
147
147
  state: present
148
- '''
148
+ """
149
149
 
150
- RETURN = '''
150
+ RETURN = """
151
151
  repo:
152
152
  description: A source string for the repository
153
153
  returned: always
@@ -167,7 +167,7 @@ sources_removed:
167
167
  type: list
168
168
  sample: ["/etc/apt/sources.list.d/artifacts_elastic_co_packages_6_x_apt.list"]
169
169
  version_added: "2.15"
170
- '''
170
+ """
171
171
 
172
172
  import copy
173
173
  import glob
@@ -245,7 +245,7 @@ class SourcesList(object):
245
245
  self.load(file)
246
246
 
247
247
  def __iter__(self):
248
- '''Simple iterator to go over all sources. Empty, non-source, and other not valid lines will be skipped.'''
248
+ """Simple iterator to go over all sources. Empty, non-source, and other not valid lines will be skipped."""
249
249
  for file, sources in self.files.items():
250
250
  for n, valid, enabled, source, comment in sources:
251
251
  if valid:
@@ -315,9 +315,9 @@ class SourcesList(object):
315
315
 
316
316
  @staticmethod
317
317
  def _apt_cfg_file(filespec):
318
- '''
318
+ """
319
319
  Wrapper for `apt_pkg` module for running with Python 2.5
320
- '''
320
+ """
321
321
  try:
322
322
  result = apt_pkg.config.find_file(filespec)
323
323
  except AttributeError:
@@ -326,9 +326,9 @@ class SourcesList(object):
326
326
 
327
327
  @staticmethod
328
328
  def _apt_cfg_dir(dirspec):
329
- '''
329
+ """
330
330
  Wrapper for `apt_pkg` module for running with Python 2.5
331
- '''
331
+ """
332
332
  try:
333
333
  result = apt_pkg.config.find_dir(dirspec)
334
334
  except AttributeError:
@@ -413,10 +413,10 @@ class SourcesList(object):
413
413
  return new
414
414
 
415
415
  def modify(self, file, n, enabled=None, source=None, comment=None):
416
- '''
416
+ """
417
417
  This function to be used with iterator, so we don't care of invalid sources.
418
418
  If source, enabled, or comment is None, original value from line ``n`` will be preserved.
419
- '''
419
+ """
420
420
  valid, enabled_old, source_old, comment_old = self.files[file][n][1:]
421
421
  self.files[file][n] = (n, valid, self._choice(enabled, enabled_old), self._choice(source, source_old), self._choice(comment, comment_old))
422
422
 
@@ -475,7 +475,10 @@ class UbuntuSourcesList(SourcesList):
475
475
  self.apt_key_bin = self.module.get_bin_path('apt-key', required=False)
476
476
  self.gpg_bin = self.module.get_bin_path('gpg', required=False)
477
477
  if not self.apt_key_bin and not self.gpg_bin:
478
- self.module.fail_json(msg='Either apt-key or gpg binary is required, but neither could be found')
478
+ msg = 'Either apt-key or gpg binary is required, but neither could be found.' \
479
+ 'The apt-key CLI has been deprecated and removed in modern Debian and derivatives, ' \
480
+ 'you might want to use "deb822_repository" instead.'
481
+ self.module.fail_json(msg)
479
482
 
480
483
  def __deepcopy__(self, memo=None):
481
484
  return UbuntuSourcesList(self.module)
@@ -616,7 +619,7 @@ class UbuntuSourcesList(SourcesList):
616
619
 
617
620
 
618
621
  def revert_sources_list(sources_before, sources_after, sourceslist_before):
619
- '''Revert the sourcelist files to their previous state.'''
622
+ """Revert the sourcelist files to their previous state."""
620
623
 
621
624
  # First remove any new files that were created:
622
625
  for filename in set(sources_after.keys()).difference(sources_before.keys()):
@@ -8,7 +8,7 @@
8
8
  from __future__ import annotations
9
9
 
10
10
 
11
- DOCUMENTATION = r'''
11
+ DOCUMENTATION = r"""
12
12
  ---
13
13
  module: assemble
14
14
  short_description: Assemble configuration files from fragments
@@ -102,9 +102,9 @@ extends_documentation_fragment:
102
102
  - action_common_attributes.files
103
103
  - decrypt
104
104
  - files
105
- '''
105
+ """
106
106
 
107
- EXAMPLES = r'''
107
+ EXAMPLES = r"""
108
108
  - name: Assemble from fragments from a directory
109
109
  ansible.builtin.assemble:
110
110
  src: /etc/someapp/fragments
@@ -121,9 +121,9 @@ EXAMPLES = r'''
121
121
  src: /etc/ssh/conf.d/
122
122
  dest: /etc/ssh/sshd_config
123
123
  validate: /usr/sbin/sshd -t -f %s
124
- '''
124
+ """
125
125
 
126
- RETURN = r'''#'''
126
+ RETURN = r"""#"""
127
127
 
128
128
  import codecs
129
129
  import os
@@ -136,7 +136,7 @@ from ansible.module_utils.common.text.converters import to_native
136
136
 
137
137
 
138
138
  def assemble_from_fragments(src_path, delimiter=None, compiled_regexp=None, ignore_hidden=False, tmpdir=None):
139
- ''' assemble a file from a directory of fragments '''
139
+ """ assemble a file from a directory of fragments """
140
140
  tmpfd, temp_path = tempfile.mkstemp(dir=tmpdir)
141
141
  tmp = os.fdopen(tmpfd, 'wb')
142
142
  delimit_me = False
ansible/modules/assert.py CHANGED
@@ -6,7 +6,7 @@
6
6
  from __future__ import annotations
7
7
 
8
8
 
9
- DOCUMENTATION = r'''
9
+ DOCUMENTATION = r"""
10
10
  ---
11
11
  module: assert
12
12
  short_description: Asserts given expressions are true
@@ -70,9 +70,9 @@ seealso:
70
70
  author:
71
71
  - Ansible Core Team
72
72
  - Michael DeHaan
73
- '''
73
+ """
74
74
 
75
- EXAMPLES = r'''
75
+ EXAMPLES = r"""
76
76
  - name: A single condition can be supplied as string instead of list
77
77
  ansible.builtin.assert:
78
78
  that: "ansible_os_family != 'RedHat'"
@@ -106,4 +106,4 @@ EXAMPLES = r'''
106
106
  - my_param <= 100
107
107
  - my_param >= 0
108
108
  quiet: true
109
- '''
109
+ """
@@ -5,8 +5,9 @@
5
5
 
6
6
  from __future__ import annotations
7
7
 
8
+ import sys
8
9
 
9
- DOCUMENTATION = r'''
10
+ DOCUMENTATION = r"""
10
11
  ---
11
12
  module: async_status
12
13
  short_description: Obtain status of asynchronous task
@@ -51,9 +52,9 @@ seealso:
51
52
  author:
52
53
  - Ansible Core Team
53
54
  - Michael DeHaan
54
- '''
55
+ """
55
56
 
56
- EXAMPLES = r'''
57
+ EXAMPLES = r"""
57
58
  ---
58
59
  - name: Asynchronous dnf task
59
60
  ansible.builtin.dnf:
@@ -75,9 +76,9 @@ EXAMPLES = r'''
75
76
  ansible.builtin.async_status:
76
77
  jid: '{{ dnf_sleeper.ansible_job_id }}'
77
78
  mode: cleanup
78
- '''
79
+ """
79
80
 
80
- RETURN = r'''
81
+ RETURN = r"""
81
82
  ansible_job_id:
82
83
  description: The asynchronous job id
83
84
  returned: success
@@ -105,14 +106,12 @@ erased:
105
106
  description: Path to erased job file
106
107
  returned: when file is erased
107
108
  type: str
108
- '''
109
+ """
109
110
 
110
111
  import json
111
112
  import os
112
113
 
113
114
  from ansible.module_utils.basic import AnsibleModule
114
- from ansible.module_utils.six import iteritems
115
- from ansible.module_utils.common.text.converters import to_native
116
115
 
117
116
 
118
117
  def main():
@@ -163,10 +162,9 @@ def main():
163
162
  elif 'finished' not in data:
164
163
  data['finished'] = 0
165
164
 
166
- # Fix error: TypeError: exit_json() keywords must be strings
167
- data = {to_native(k): v for k, v in iteritems(data)}
168
-
169
- module.exit_json(**data)
165
+ # just write the module output directly to stdout and exit; bypass other processing done by exit_json since it's already been done
166
+ print(f"\n{json.dumps(data)}") # pylint: disable=ansible-bad-function
167
+ sys.exit(0) # pylint: disable=ansible-bad-function
170
168
 
171
169
 
172
170
  if __name__ == '__main__':
@@ -75,13 +75,13 @@ def daemonize_self():
75
75
  # NB: this function copied from module_utils/json_utils.py. Ensure any changes are propagated there.
76
76
  # FUTURE: AnsibleModule-ify this module so it's Ansiballz-compatible and can use the module_utils copy of this function.
77
77
  def _filter_non_json_lines(data):
78
- '''
78
+ """
79
79
  Used to filter unrelated output around module JSON output, like messages from
80
80
  tcagetattr, or where dropbear spews MOTD on every single command (which is nuts).
81
81
 
82
82
  Filters leading lines before first line-starting occurrence of '{', and filter all
83
83
  trailing lines after matching close character (working from the bottom of output).
84
- '''
84
+ """
85
85
  warnings = []
86
86
 
87
87
  # Filter initial junk
@@ -147,6 +147,8 @@ def jwrite(info):
147
147
 
148
148
  def _run_module(wrapped_cmd, jid):
149
149
 
150
+ # DTFIX-FUTURE: needs rework for serialization profiles
151
+
150
152
  jwrite({"started": 1, "finished": 0, "ansible_job_id": jid})
151
153
 
152
154
  result = {}
@@ -188,6 +190,9 @@ def _run_module(wrapped_cmd, jid):
188
190
  module_warnings = result.get('warnings', [])
189
191
  if not isinstance(module_warnings, list):
190
192
  module_warnings = [module_warnings]
193
+
194
+ # this relies on the controller's fallback conversion of string warnings to WarningMessageDetail instances, and assumes
195
+ # that the module result and warning collection are basic JSON datatypes (eg, no tags or other custom collections).
191
196
  module_warnings.extend(json_warnings)
192
197
  result['warnings'] = module_warnings
193
198
 
@@ -257,7 +262,7 @@ def main():
257
262
  end({
258
263
  "failed": 1,
259
264
  "msg": "could not create directory: %s - %s" % (jobdir, to_text(e)),
260
- "exception": to_text(traceback.format_exc()),
265
+ "exception": to_text(traceback.format_exc()), # NB: task executor compat will coerce to the correct dataclass type
261
266
  }, 1)
262
267
 
263
268
  # immediately exit this process, leaving an orphaned process
@@ -7,7 +7,7 @@
7
7
  from __future__ import annotations
8
8
 
9
9
 
10
- DOCUMENTATION = r'''
10
+ DOCUMENTATION = r"""
11
11
  ---
12
12
  module: blockinfile
13
13
  short_description: Insert/update/remove a text block surrounded by marker lines
@@ -125,9 +125,9 @@ attributes:
125
125
  platforms: posix
126
126
  vault:
127
127
  support: none
128
- '''
128
+ """
129
129
 
130
- EXAMPLES = r'''
130
+ EXAMPLES = r"""
131
131
  # Before Ansible 2.3, option 'dest' or 'name' was used instead of 'path'
132
132
  - name: Insert/Update "Match User" configuration block in /etc/ssh/sshd_config prepending and appending a new line
133
133
  ansible.builtin.blockinfile:
@@ -187,7 +187,7 @@ EXAMPLES = r'''
187
187
  insertafter: '(?m)SID_LIST_LISTENER_DG =\n.*\(SID_LIST ='
188
188
  marker: " <!-- {mark} ANSIBLE MANAGED BLOCK -->"
189
189
 
190
- '''
190
+ """
191
191
 
192
192
  import re
193
193
  import os
@@ -200,9 +200,8 @@ from ansible.module_utils.common.text.converters import to_bytes, to_native
200
200
  def write_changes(module, contents, path):
201
201
 
202
202
  tmpfd, tmpfile = tempfile.mkstemp(dir=module.tmpdir)
203
- f = os.fdopen(tmpfd, 'wb')
204
- f.write(contents)
205
- f.close()
203
+ with os.fdopen(tmpfd, 'wb') as tf:
204
+ tf.write(contents)
206
205
 
207
206
  validate = module.params.get('validate', None)
208
207
  valid = not validate