ansible-core 2.18.7__py3-none-any.whl → 2.19.0__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.

Potentially problematic release.


This version of ansible-core might be problematic. Click here for more details.

Files changed (757) hide show
  1. ansible/_internal/__init__.py +53 -0
  2. ansible/_internal/_ansiballz/__init__.py +0 -0
  3. ansible/_internal/_ansiballz/_builder.py +101 -0
  4. ansible/_internal/_ansiballz/_wrapper.py +262 -0
  5. ansible/_internal/_collection_proxy.py +47 -0
  6. ansible/_internal/_datatag/__init__.py +0 -0
  7. ansible/_internal/_datatag/_tags.py +130 -0
  8. ansible/_internal/_datatag/_utils.py +19 -0
  9. ansible/_internal/_datatag/_wrappers.py +33 -0
  10. ansible/_internal/_errors/__init__.py +0 -0
  11. ansible/_internal/_errors/_alarm_timeout.py +66 -0
  12. ansible/_internal/_errors/_captured.py +123 -0
  13. ansible/_internal/_errors/_error_factory.py +89 -0
  14. ansible/_internal/_errors/_error_utils.py +240 -0
  15. ansible/_internal/_errors/_handler.py +91 -0
  16. ansible/_internal/_errors/_task_timeout.py +28 -0
  17. ansible/_internal/_event_formatting.py +127 -0
  18. ansible/_internal/_json/__init__.py +214 -0
  19. ansible/_internal/_json/_legacy_encoder.py +34 -0
  20. ansible/_internal/_json/_profiles/__init__.py +0 -0
  21. ansible/_internal/_json/_profiles/_cache_persistence.py +57 -0
  22. ansible/_internal/_json/_profiles/_inventory_legacy.py +40 -0
  23. ansible/_internal/_json/_profiles/_legacy.py +189 -0
  24. ansible/_internal/_locking.py +21 -0
  25. ansible/_internal/_plugins/__init__.py +0 -0
  26. ansible/_internal/_plugins/_cache.py +57 -0
  27. ansible/_internal/_ssh/__init__.py +0 -0
  28. ansible/_internal/_ssh/_agent_launch.py +91 -0
  29. ansible/_internal/_ssh/_ssh_agent.py +619 -0
  30. ansible/_internal/_task.py +78 -0
  31. ansible/_internal/_templating/__init__.py +12 -0
  32. ansible/_internal/_templating/_access.py +86 -0
  33. ansible/_internal/_templating/_chain_templar.py +63 -0
  34. ansible/_internal/_templating/_datatag.py +95 -0
  35. ansible/_internal/_templating/_engine.py +592 -0
  36. ansible/_internal/_templating/_errors.py +28 -0
  37. ansible/_internal/_templating/_jinja_bits.py +1106 -0
  38. ansible/_internal/_templating/_jinja_common.py +323 -0
  39. ansible/_internal/_templating/_jinja_patches.py +44 -0
  40. ansible/_internal/_templating/_jinja_plugins.py +375 -0
  41. ansible/_internal/_templating/_lazy_containers.py +633 -0
  42. ansible/_internal/_templating/_marker_behaviors.py +103 -0
  43. ansible/_internal/_templating/_template_vars.py +72 -0
  44. ansible/_internal/_templating/_transform.py +70 -0
  45. ansible/_internal/_templating/_utils.py +108 -0
  46. ansible/_internal/_testing.py +26 -0
  47. ansible/_internal/_wrapt.py +1052 -0
  48. ansible/_internal/_yaml/__init__.py +0 -0
  49. ansible/_internal/_yaml/_constructor.py +240 -0
  50. ansible/_internal/_yaml/_dumper.py +70 -0
  51. ansible/_internal/_yaml/_errors.py +166 -0
  52. ansible/_internal/_yaml/_loader.py +66 -0
  53. ansible/_internal/ansible_collections/ansible/_protomatter/README.md +11 -0
  54. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/debug.py +36 -0
  55. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/apply_trust.py +19 -0
  56. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/dump_object.py +27 -0
  57. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/finalize.py +16 -0
  58. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/origin.py +18 -0
  59. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.py +24 -0
  60. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.yml +33 -0
  61. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/tag_names.py +16 -0
  62. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +17 -0
  63. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +49 -0
  64. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.py +21 -0
  65. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.yml +2 -0
  66. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.py +15 -0
  67. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.yml +19 -0
  68. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.py +18 -0
  69. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.yml +19 -0
  70. ansible/cli/__init__.py +93 -104
  71. ansible/cli/_ssh_askpass.py +54 -0
  72. ansible/cli/adhoc.py +20 -10
  73. ansible/cli/arguments/option_helpers.py +163 -10
  74. ansible/cli/config.py +43 -68
  75. ansible/cli/console.py +13 -11
  76. ansible/cli/doc.py +134 -77
  77. ansible/cli/galaxy.py +27 -20
  78. ansible/cli/inventory.py +28 -28
  79. ansible/cli/playbook.py +4 -12
  80. ansible/cli/pull.py +6 -3
  81. ansible/cli/scripts/ansible_connection_cli_stub.py +7 -7
  82. ansible/cli/vault.py +12 -11
  83. ansible/compat/__init__.py +2 -2
  84. ansible/compat/importlib_resources.py +9 -12
  85. ansible/config/base.yml +218 -133
  86. ansible/config/manager.py +220 -159
  87. ansible/constants.py +2 -65
  88. ansible/errors/__init__.py +350 -256
  89. ansible/executor/interpreter_discovery.py +28 -149
  90. ansible/executor/module_common.py +480 -514
  91. ansible/executor/play_iterator.py +22 -27
  92. ansible/executor/playbook_executor.py +11 -11
  93. ansible/executor/powershell/async_watchdog.ps1 +97 -102
  94. ansible/executor/powershell/async_wrapper.ps1 +204 -153
  95. ansible/executor/powershell/become_wrapper.ps1 +107 -144
  96. ansible/executor/powershell/bootstrap_wrapper.ps1 +46 -9
  97. ansible/executor/powershell/coverage_wrapper.ps1 +91 -135
  98. ansible/executor/powershell/exec_wrapper.ps1 +675 -196
  99. ansible/executor/powershell/module_manifest.py +469 -265
  100. ansible/executor/powershell/module_wrapper.ps1 +195 -186
  101. ansible/executor/powershell/powershell_expand_user.ps1 +20 -0
  102. ansible/executor/powershell/powershell_mkdtemp.ps1 +17 -0
  103. ansible/executor/powershell/psrp_fetch_file.ps1 +41 -0
  104. ansible/executor/powershell/psrp_put_file.ps1 +122 -0
  105. ansible/executor/powershell/winrm_fetch_file.ps1 +46 -0
  106. ansible/executor/powershell/winrm_put_file.ps1 +36 -0
  107. ansible/executor/process/worker.py +139 -149
  108. ansible/executor/stats.py +5 -5
  109. ansible/executor/task_executor.py +270 -297
  110. ansible/executor/task_queue_manager.py +135 -137
  111. ansible/executor/task_result.py +182 -79
  112. ansible/galaxy/__init__.py +2 -2
  113. ansible/galaxy/api.py +26 -25
  114. ansible/galaxy/collection/__init__.py +6 -14
  115. ansible/galaxy/collection/concrete_artifact_manager.py +12 -21
  116. ansible/galaxy/dependency_resolution/dataclasses.py +14 -4
  117. ansible/galaxy/dependency_resolution/providers.py +4 -4
  118. ansible/galaxy/dependency_resolution/reporters.py +81 -0
  119. ansible/galaxy/role.py +6 -10
  120. ansible/galaxy/token.py +28 -21
  121. ansible/inventory/data.py +47 -57
  122. ansible/inventory/group.py +50 -73
  123. ansible/inventory/helpers.py +9 -0
  124. ansible/inventory/host.py +37 -54
  125. ansible/inventory/manager.py +79 -34
  126. ansible/keyword_desc.yml +1 -1
  127. ansible/module_utils/_internal/__init__.py +55 -0
  128. ansible/module_utils/_internal/_ambient_context.py +58 -0
  129. ansible/module_utils/_internal/_ansiballz/__init__.py +0 -0
  130. ansible/module_utils/_internal/_ansiballz/_extensions/__init__.py +0 -0
  131. ansible/module_utils/_internal/_ansiballz/_extensions/_coverage.py +45 -0
  132. ansible/module_utils/_internal/_ansiballz/_extensions/_pydevd.py +62 -0
  133. ansible/module_utils/_internal/_ansiballz/_loader.py +81 -0
  134. ansible/module_utils/_internal/_ansiballz/_respawn.py +32 -0
  135. ansible/module_utils/_internal/_ansiballz/_respawn_wrapper.py +23 -0
  136. ansible/module_utils/_internal/_concurrent/_daemon_threading.py +1 -0
  137. ansible/module_utils/_internal/_dataclass_validation.py +217 -0
  138. ansible/module_utils/_internal/_datatag/__init__.py +961 -0
  139. ansible/module_utils/_internal/_datatag/_tags.py +16 -0
  140. ansible/module_utils/_internal/_debugging.py +31 -0
  141. ansible/module_utils/_internal/_deprecator.py +157 -0
  142. ansible/module_utils/_internal/_errors.py +101 -0
  143. ansible/module_utils/_internal/_event_utils.py +61 -0
  144. ansible/module_utils/_internal/_json/__init__.py +63 -0
  145. ansible/module_utils/_internal/_json/_legacy_encoder.py +26 -0
  146. ansible/module_utils/_internal/_json/_profiles/__init__.py +428 -0
  147. ansible/module_utils/_internal/_json/_profiles/_fallback_to_str.py +73 -0
  148. ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +33 -0
  149. ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +37 -0
  150. ansible/module_utils/_internal/_json/_profiles/_module_modern_c2m.py +35 -0
  151. ansible/module_utils/_internal/_json/_profiles/_module_modern_m2c.py +33 -0
  152. ansible/module_utils/_internal/_json/_profiles/_tagless.py +52 -0
  153. ansible/module_utils/_internal/_messages.py +130 -0
  154. ansible/module_utils/_internal/_patches/__init__.py +66 -0
  155. ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +53 -0
  156. ansible/module_utils/_internal/_patches/_socket_patch.py +34 -0
  157. ansible/module_utils/_internal/_patches/_sys_intern_patch.py +34 -0
  158. ansible/module_utils/_internal/_plugin_info.py +38 -0
  159. ansible/module_utils/_internal/_stack.py +22 -0
  160. ansible/module_utils/_internal/_testing.py +0 -0
  161. ansible/module_utils/_internal/_text_utils.py +6 -0
  162. ansible/module_utils/_internal/_traceback.py +92 -0
  163. ansible/module_utils/_internal/_validation.py +14 -0
  164. ansible/module_utils/ansible_release.py +2 -2
  165. ansible/module_utils/api.py +1 -2
  166. ansible/module_utils/basic.py +303 -202
  167. ansible/module_utils/common/_utils.py +24 -28
  168. ansible/module_utils/common/arg_spec.py +8 -3
  169. ansible/module_utils/common/collections.py +7 -2
  170. ansible/module_utils/common/dict_transformations.py +2 -2
  171. ansible/module_utils/common/file.py +2 -2
  172. ansible/module_utils/common/json.py +90 -84
  173. ansible/module_utils/common/locale.py +2 -2
  174. ansible/module_utils/common/parameters.py +27 -24
  175. ansible/module_utils/common/process.py +2 -3
  176. ansible/module_utils/common/respawn.py +11 -33
  177. ansible/module_utils/common/sentinel.py +66 -0
  178. ansible/module_utils/common/sys_info.py +8 -8
  179. ansible/module_utils/common/text/converters.py +16 -37
  180. ansible/module_utils/common/validation.py +35 -24
  181. ansible/module_utils/common/warnings.py +143 -25
  182. ansible/module_utils/common/yaml.py +29 -3
  183. ansible/module_utils/compat/datetime.py +33 -21
  184. ansible/module_utils/compat/paramiko.py +21 -10
  185. ansible/module_utils/compat/typing.py +6 -5
  186. ansible/module_utils/connection.py +10 -13
  187. ansible/module_utils/csharp/Ansible.Basic.cs +15 -12
  188. ansible/module_utils/csharp/Ansible.Become.cs +1 -0
  189. ansible/module_utils/csharp/Ansible.Privilege.cs +2 -2
  190. ansible/module_utils/csharp/Ansible._Async.cs +517 -0
  191. ansible/module_utils/datatag.py +49 -0
  192. ansible/module_utils/distro/__init__.py +2 -2
  193. ansible/module_utils/facts/ansible_collector.py +4 -5
  194. ansible/module_utils/facts/collector.py +13 -14
  195. ansible/module_utils/facts/compat.py +4 -4
  196. ansible/module_utils/facts/default_collectors.py +1 -1
  197. ansible/module_utils/facts/hardware/aix.py +34 -0
  198. ansible/module_utils/facts/hardware/base.py +2 -2
  199. ansible/module_utils/facts/hardware/darwin.py +1 -3
  200. ansible/module_utils/facts/hardware/freebsd.py +2 -2
  201. ansible/module_utils/facts/hardware/linux.py +5 -5
  202. ansible/module_utils/facts/namespace.py +1 -1
  203. ansible/module_utils/facts/network/base.py +1 -1
  204. ansible/module_utils/facts/network/fc_wwn.py +1 -2
  205. ansible/module_utils/facts/network/iscsi.py +1 -2
  206. ansible/module_utils/facts/network/nvme.py +1 -2
  207. ansible/module_utils/facts/other/facter.py +2 -3
  208. ansible/module_utils/facts/other/ohai.py +2 -3
  209. ansible/module_utils/facts/sysctl.py +4 -6
  210. ansible/module_utils/facts/system/apparmor.py +1 -2
  211. ansible/module_utils/facts/system/caps.py +3 -3
  212. ansible/module_utils/facts/system/chroot.py +1 -2
  213. ansible/module_utils/facts/system/cmdline.py +1 -2
  214. ansible/module_utils/facts/system/date_time.py +5 -3
  215. ansible/module_utils/facts/system/distribution.py +27 -13
  216. ansible/module_utils/facts/system/dns.py +1 -1
  217. ansible/module_utils/facts/system/env.py +1 -2
  218. ansible/module_utils/facts/system/fips.py +7 -20
  219. ansible/module_utils/facts/system/loadavg.py +1 -2
  220. ansible/module_utils/facts/system/local.py +2 -3
  221. ansible/module_utils/facts/system/lsb.py +1 -2
  222. ansible/module_utils/facts/system/pkg_mgr.py +1 -2
  223. ansible/module_utils/facts/system/platform.py +1 -2
  224. ansible/module_utils/facts/system/python.py +1 -2
  225. ansible/module_utils/facts/system/selinux.py +1 -1
  226. ansible/module_utils/facts/system/service_mgr.py +1 -2
  227. ansible/module_utils/facts/system/ssh_pub_keys.py +1 -1
  228. ansible/module_utils/facts/system/systemd.py +1 -1
  229. ansible/module_utils/facts/system/user.py +1 -2
  230. ansible/module_utils/facts/utils.py +3 -3
  231. ansible/module_utils/facts/virtual/base.py +1 -1
  232. ansible/module_utils/facts/virtual/linux.py +3 -3
  233. ansible/module_utils/facts/virtual/sunos.py +3 -15
  234. ansible/module_utils/facts/virtual/sysctl.py +3 -16
  235. ansible/module_utils/json_utils.py +2 -2
  236. ansible/module_utils/parsing/convert_bool.py +7 -1
  237. ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 +1 -1
  238. ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 +1 -1
  239. ansible/module_utils/powershell/Ansible.ModuleUtils.CommandUtil.psm1 +1 -1
  240. ansible/module_utils/powershell/Ansible.ModuleUtils.WebRequest.psm1 +1 -1
  241. ansible/module_utils/service.py +21 -31
  242. ansible/module_utils/splitter.py +7 -7
  243. ansible/module_utils/testing.py +31 -0
  244. ansible/module_utils/urls.py +64 -35
  245. ansible/modules/add_host.py +4 -4
  246. ansible/modules/apt.py +69 -49
  247. ansible/modules/apt_key.py +19 -12
  248. ansible/modules/apt_repository.py +32 -51
  249. ansible/modules/assemble.py +16 -14
  250. ansible/modules/assert.py +4 -4
  251. ansible/modules/async_status.py +24 -24
  252. ansible/modules/async_wrapper.py +20 -25
  253. ansible/modules/blockinfile.py +6 -7
  254. ansible/modules/command.py +13 -20
  255. ansible/modules/copy.py +60 -147
  256. ansible/modules/cron.py +24 -21
  257. ansible/modules/deb822_repository.py +8 -9
  258. ansible/modules/debconf.py +5 -5
  259. ansible/modules/debug.py +4 -4
  260. ansible/modules/dnf.py +8 -8
  261. ansible/modules/dnf5.py +39 -13
  262. ansible/modules/dpkg_selections.py +4 -4
  263. ansible/modules/expect.py +13 -15
  264. ansible/modules/fail.py +4 -4
  265. ansible/modules/fetch.py +4 -4
  266. ansible/modules/file.py +184 -144
  267. ansible/modules/find.py +22 -20
  268. ansible/modules/gather_facts.py +3 -3
  269. ansible/modules/get_url.py +77 -54
  270. ansible/modules/getent.py +7 -9
  271. ansible/modules/git.py +38 -38
  272. ansible/modules/group.py +6 -6
  273. ansible/modules/group_by.py +4 -4
  274. ansible/modules/hostname.py +15 -32
  275. ansible/modules/import_playbook.py +6 -6
  276. ansible/modules/import_role.py +6 -6
  277. ansible/modules/import_tasks.py +6 -6
  278. ansible/modules/include_role.py +6 -6
  279. ansible/modules/include_tasks.py +6 -6
  280. ansible/modules/include_vars.py +6 -6
  281. ansible/modules/iptables.py +86 -73
  282. ansible/modules/known_hosts.py +22 -24
  283. ansible/modules/lineinfile.py +5 -5
  284. ansible/modules/meta.py +4 -4
  285. ansible/modules/mount_facts.py +2 -2
  286. ansible/modules/package.py +10 -4
  287. ansible/modules/package_facts.py +22 -10
  288. ansible/modules/pause.py +6 -6
  289. ansible/modules/ping.py +6 -6
  290. ansible/modules/pip.py +21 -26
  291. ansible/modules/raw.py +6 -6
  292. ansible/modules/reboot.py +6 -6
  293. ansible/modules/replace.py +10 -14
  294. ansible/modules/rpm_key.py +7 -8
  295. ansible/modules/script.py +4 -4
  296. ansible/modules/service.py +10 -17
  297. ansible/modules/service_facts.py +87 -10
  298. ansible/modules/set_fact.py +5 -5
  299. ansible/modules/set_stats.py +4 -4
  300. ansible/modules/setup.py +2 -2
  301. ansible/modules/shell.py +6 -6
  302. ansible/modules/slurp.py +16 -19
  303. ansible/modules/stat.py +15 -31
  304. ansible/modules/subversion.py +15 -15
  305. ansible/modules/systemd.py +7 -7
  306. ansible/modules/systemd_service.py +7 -7
  307. ansible/modules/sysvinit.py +9 -9
  308. ansible/modules/tempfile.py +5 -6
  309. ansible/modules/template.py +6 -6
  310. ansible/modules/unarchive.py +38 -17
  311. ansible/modules/uri.py +33 -26
  312. ansible/modules/user.py +45 -32
  313. ansible/modules/validate_argument_spec.py +10 -7
  314. ansible/modules/wait_for.py +70 -60
  315. ansible/modules/wait_for_connection.py +6 -6
  316. ansible/modules/yum_repository.py +10 -9
  317. ansible/parsing/ajson.py +17 -37
  318. ansible/parsing/dataloader.py +99 -54
  319. ansible/parsing/mod_args.py +62 -60
  320. ansible/parsing/plugin_docs.py +21 -86
  321. ansible/parsing/quoting.py +1 -1
  322. ansible/parsing/splitter.py +27 -12
  323. ansible/parsing/utils/addresses.py +24 -24
  324. ansible/parsing/utils/jsonify.py +5 -1
  325. ansible/parsing/utils/yaml.py +32 -61
  326. ansible/parsing/vault/__init__.py +327 -99
  327. ansible/parsing/yaml/__init__.py +0 -18
  328. ansible/parsing/yaml/dumper.py +6 -120
  329. ansible/parsing/yaml/loader.py +6 -39
  330. ansible/parsing/yaml/objects.py +43 -335
  331. ansible/playbook/__init__.py +1 -1
  332. ansible/playbook/attribute.py +8 -3
  333. ansible/playbook/base.py +187 -134
  334. ansible/playbook/block.py +26 -24
  335. ansible/playbook/collectionsearch.py +1 -15
  336. ansible/playbook/conditional.py +3 -77
  337. ansible/playbook/handler.py +8 -2
  338. ansible/playbook/helpers.py +41 -53
  339. ansible/playbook/included_file.py +32 -26
  340. ansible/playbook/loop_control.py +2 -2
  341. ansible/playbook/play.py +85 -44
  342. ansible/playbook/play_context.py +14 -17
  343. ansible/playbook/playbook_include.py +27 -62
  344. ansible/playbook/role/__init__.py +64 -49
  345. ansible/playbook/role/definition.py +15 -17
  346. ansible/playbook/role/include.py +2 -4
  347. ansible/playbook/role/metadata.py +10 -11
  348. ansible/playbook/role_include.py +3 -3
  349. ansible/playbook/taggable.py +28 -12
  350. ansible/playbook/task.py +192 -121
  351. ansible/playbook/task_include.py +5 -5
  352. ansible/plugins/__init__.py +58 -26
  353. ansible/plugins/action/__init__.py +188 -186
  354. ansible/plugins/action/add_host.py +2 -2
  355. ansible/plugins/action/assemble.py +11 -18
  356. ansible/plugins/action/assert.py +55 -67
  357. ansible/plugins/action/async_status.py +7 -2
  358. ansible/plugins/action/copy.py +14 -17
  359. ansible/plugins/action/debug.py +37 -31
  360. ansible/plugins/action/dnf.py +3 -4
  361. ansible/plugins/action/fail.py +1 -1
  362. ansible/plugins/action/fetch.py +7 -8
  363. ansible/plugins/action/gather_facts.py +13 -14
  364. ansible/plugins/action/group_by.py +1 -1
  365. ansible/plugins/action/include_vars.py +10 -11
  366. ansible/plugins/action/package.py +8 -14
  367. ansible/plugins/action/pause.py +2 -2
  368. ansible/plugins/action/script.py +27 -38
  369. ansible/plugins/action/service.py +9 -18
  370. ansible/plugins/action/set_fact.py +3 -12
  371. ansible/plugins/action/set_stats.py +3 -8
  372. ansible/plugins/action/template.py +47 -67
  373. ansible/plugins/action/unarchive.py +6 -16
  374. ansible/plugins/action/uri.py +9 -20
  375. ansible/plugins/action/validate_argument_spec.py +5 -5
  376. ansible/plugins/action/wait_for_connection.py +1 -1
  377. ansible/plugins/become/__init__.py +31 -8
  378. ansible/plugins/become/runas.py +71 -0
  379. ansible/plugins/become/su.py +13 -8
  380. ansible/plugins/become/sudo.py +19 -0
  381. ansible/plugins/cache/__init__.py +52 -63
  382. ansible/plugins/cache/base.py +8 -0
  383. ansible/plugins/cache/jsonfile.py +10 -16
  384. ansible/plugins/cache/memory.py +6 -12
  385. ansible/plugins/callback/__init__.py +294 -201
  386. ansible/plugins/callback/default.py +99 -95
  387. ansible/plugins/callback/junit.py +44 -43
  388. ansible/plugins/callback/minimal.py +28 -25
  389. ansible/plugins/callback/oneline.py +34 -21
  390. ansible/plugins/callback/tree.py +27 -16
  391. ansible/plugins/connection/__init__.py +47 -34
  392. ansible/plugins/connection/local.py +156 -60
  393. ansible/plugins/connection/paramiko_ssh.py +34 -24
  394. ansible/plugins/connection/psrp.py +76 -165
  395. ansible/plugins/connection/ssh.py +326 -86
  396. ansible/plugins/connection/winrm.py +62 -141
  397. ansible/plugins/doc_fragments/action_common_attributes.py +14 -14
  398. ansible/plugins/doc_fragments/action_core.py +6 -6
  399. ansible/plugins/doc_fragments/backup.py +2 -2
  400. ansible/plugins/doc_fragments/checksum_common.py +27 -0
  401. ansible/plugins/doc_fragments/constructed.py +8 -4
  402. ansible/plugins/doc_fragments/decrypt.py +2 -2
  403. ansible/plugins/doc_fragments/default_callback.py +2 -2
  404. ansible/plugins/doc_fragments/files.py +2 -2
  405. ansible/plugins/doc_fragments/inventory_cache.py +2 -2
  406. ansible/plugins/doc_fragments/result_format_callback.py +2 -2
  407. ansible/plugins/doc_fragments/return_common.py +2 -2
  408. ansible/plugins/doc_fragments/template_common.py +4 -4
  409. ansible/plugins/doc_fragments/url.py +17 -1
  410. ansible/plugins/doc_fragments/url_windows.py +2 -2
  411. ansible/plugins/doc_fragments/validate.py +2 -2
  412. ansible/plugins/doc_fragments/vars_plugin_staging.py +2 -2
  413. ansible/plugins/filter/__init__.py +6 -2
  414. ansible/plugins/filter/b64decode.yml +22 -0
  415. ansible/plugins/filter/b64encode.yml +22 -0
  416. ansible/plugins/filter/bool.yml +11 -4
  417. ansible/plugins/filter/core.py +245 -120
  418. ansible/plugins/filter/encryption.py +42 -34
  419. ansible/plugins/filter/flatten.yml +3 -2
  420. ansible/plugins/filter/human_to_bytes.yml +1 -1
  421. ansible/plugins/filter/mathstuff.py +30 -37
  422. ansible/plugins/filter/password_hash.yml +8 -0
  423. ansible/plugins/filter/pow.yml +1 -1
  424. ansible/plugins/filter/regex_search.yml +1 -4
  425. ansible/plugins/filter/root.yml +1 -1
  426. ansible/plugins/filter/split.yml +1 -1
  427. ansible/plugins/filter/strftime.yml +3 -3
  428. ansible/plugins/filter/to_nice_yaml.yml +0 -4
  429. ansible/plugins/filter/to_uuid.yml +1 -1
  430. ansible/plugins/filter/to_yaml.yml +0 -4
  431. ansible/plugins/filter/unvault.yml +1 -1
  432. ansible/plugins/filter/urls.py +1 -1
  433. ansible/plugins/filter/urlsplit.py +8 -9
  434. ansible/plugins/filter/vault.yml +14 -9
  435. ansible/plugins/filter/win_basename.yml +6 -1
  436. ansible/plugins/filter/win_dirname.yml +5 -0
  437. ansible/plugins/inventory/__init__.py +107 -86
  438. ansible/plugins/inventory/advanced_host_list.py +7 -5
  439. ansible/plugins/inventory/auto.py +11 -4
  440. ansible/plugins/inventory/constructed.py +21 -24
  441. ansible/plugins/inventory/generator.py +16 -11
  442. ansible/plugins/inventory/host_list.py +7 -5
  443. ansible/plugins/inventory/ini.py +78 -44
  444. ansible/plugins/inventory/script.py +190 -120
  445. ansible/plugins/inventory/toml.py +16 -126
  446. ansible/plugins/inventory/yaml.py +10 -8
  447. ansible/plugins/list.py +72 -19
  448. ansible/plugins/loader.py +383 -198
  449. ansible/plugins/lookup/__init__.py +21 -4
  450. ansible/plugins/lookup/config.py +21 -35
  451. ansible/plugins/lookup/csvfile.py +19 -73
  452. ansible/plugins/lookup/dict.py +1 -6
  453. ansible/plugins/lookup/env.py +12 -9
  454. ansible/plugins/lookup/file.py +5 -8
  455. ansible/plugins/lookup/first_found.py +87 -55
  456. ansible/plugins/lookup/indexed_items.py +1 -10
  457. ansible/plugins/lookup/ini.py +14 -13
  458. ansible/plugins/lookup/items.py +1 -1
  459. ansible/plugins/lookup/lines.py +8 -1
  460. ansible/plugins/lookup/list.py +1 -1
  461. ansible/plugins/lookup/nested.py +2 -18
  462. ansible/plugins/lookup/password.py +5 -5
  463. ansible/plugins/lookup/pipe.py +5 -7
  464. ansible/plugins/lookup/sequence.py +18 -8
  465. ansible/plugins/lookup/subelements.py +1 -4
  466. ansible/plugins/lookup/template.py +47 -36
  467. ansible/plugins/lookup/together.py +0 -12
  468. ansible/plugins/lookup/unvault.py +1 -5
  469. ansible/plugins/lookup/url.py +4 -10
  470. ansible/plugins/lookup/vars.py +16 -24
  471. ansible/plugins/shell/__init__.py +58 -4
  472. ansible/plugins/shell/cmd.py +2 -2
  473. ansible/plugins/shell/powershell.py +106 -31
  474. ansible/plugins/shell/sh.py +13 -7
  475. ansible/plugins/strategy/__init__.py +168 -193
  476. ansible/plugins/strategy/debug.py +2 -2
  477. ansible/plugins/strategy/free.py +16 -31
  478. ansible/plugins/strategy/host_pinned.py +2 -2
  479. ansible/plugins/strategy/linear.py +41 -41
  480. ansible/plugins/terminal/__init__.py +4 -4
  481. ansible/plugins/test/__init__.py +7 -2
  482. ansible/plugins/test/core.py +75 -35
  483. ansible/plugins/test/files.py +1 -1
  484. ansible/plugins/test/finished.yml +1 -1
  485. ansible/plugins/test/mathstuff.py +3 -3
  486. ansible/plugins/test/uri.py +5 -8
  487. ansible/plugins/vars/host_group_vars.py +7 -14
  488. ansible/release.py +2 -2
  489. ansible/template/__init__.py +353 -943
  490. ansible/utils/__init__.py +0 -18
  491. ansible/utils/collection_loader/__init__.py +54 -5
  492. ansible/utils/collection_loader/_collection_config.py +5 -6
  493. ansible/utils/collection_loader/_collection_finder.py +82 -96
  494. ansible/utils/collection_loader/_collection_meta.py +15 -8
  495. ansible/utils/display.py +485 -73
  496. ansible/utils/encrypt.py +27 -19
  497. ansible/utils/fqcn.py +2 -2
  498. ansible/utils/galaxy.py +2 -2
  499. ansible/utils/hashing.py +8 -10
  500. ansible/utils/helpers.py +2 -2
  501. ansible/utils/listify.py +10 -8
  502. ansible/utils/lock.py +2 -2
  503. ansible/utils/path.py +10 -12
  504. ansible/utils/plugin_docs.py +16 -14
  505. ansible/utils/py3compat.py +2 -7
  506. ansible/utils/sentinel.py +4 -62
  507. ansible/utils/singleton.py +2 -0
  508. ansible/utils/ssh_functions.py +6 -2
  509. ansible/utils/unsafe_proxy.py +23 -332
  510. ansible/utils/vars.py +55 -8
  511. ansible/utils/version.py +2 -2
  512. ansible/vars/clean.py +5 -5
  513. ansible/vars/hostvars.py +60 -90
  514. ansible/vars/manager.py +220 -285
  515. ansible/vars/plugins.py +4 -4
  516. ansible/vars/reserved.py +13 -12
  517. {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/METADATA +4 -3
  518. ansible_core-2.19.0.dist-info/RECORD +1097 -0
  519. ansible_core-2.19.0.dist-info/licenses/licenses/BSD-3-Clause.txt +28 -0
  520. ansible_test/_data/completion/docker.txt +7 -7
  521. ansible_test/_data/completion/remote.txt +6 -6
  522. ansible_test/_data/completion/windows.txt +1 -0
  523. ansible_test/_data/requirements/ansible.txt +2 -2
  524. ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
  525. ansible_test/_data/requirements/sanity.changelog.txt +2 -2
  526. ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
  527. ansible_test/_data/requirements/sanity.pep8.txt +1 -1
  528. ansible_test/_data/requirements/sanity.pylint.txt +5 -5
  529. ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
  530. ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
  531. ansible_test/_data/requirements/units.txt +1 -0
  532. ansible_test/_internal/__init__.py +6 -0
  533. ansible_test/_internal/ansible_util.py +3 -1
  534. ansible_test/_internal/become.py +1 -0
  535. ansible_test/_internal/bootstrap.py +1 -0
  536. ansible_test/_internal/cache.py +1 -0
  537. ansible_test/_internal/cgroup.py +1 -0
  538. ansible_test/_internal/ci/__init__.py +1 -0
  539. ansible_test/_internal/ci/azp.py +1 -0
  540. ansible_test/_internal/ci/local.py +1 -0
  541. ansible_test/_internal/classification/__init__.py +1 -0
  542. ansible_test/_internal/classification/common.py +1 -0
  543. ansible_test/_internal/classification/csharp.py +1 -0
  544. ansible_test/_internal/classification/powershell.py +1 -0
  545. ansible_test/_internal/classification/python.py +1 -0
  546. ansible_test/_internal/cli/__init__.py +1 -0
  547. ansible_test/_internal/cli/actions.py +1 -0
  548. ansible_test/_internal/cli/argparsing/__init__.py +1 -0
  549. ansible_test/_internal/cli/argparsing/actions.py +1 -0
  550. ansible_test/_internal/cli/argparsing/argcompletion.py +1 -0
  551. ansible_test/_internal/cli/argparsing/parsers.py +1 -0
  552. ansible_test/_internal/cli/commands/__init__.py +11 -5
  553. ansible_test/_internal/cli/commands/coverage/__init__.py +1 -0
  554. ansible_test/_internal/cli/commands/coverage/analyze/__init__.py +1 -0
  555. ansible_test/_internal/cli/commands/coverage/analyze/targets/__init__.py +1 -0
  556. ansible_test/_internal/cli/commands/coverage/analyze/targets/combine.py +1 -0
  557. ansible_test/_internal/cli/commands/coverage/analyze/targets/expand.py +1 -0
  558. ansible_test/_internal/cli/commands/coverage/analyze/targets/filter.py +1 -0
  559. ansible_test/_internal/cli/commands/coverage/analyze/targets/generate.py +1 -0
  560. ansible_test/_internal/cli/commands/coverage/analyze/targets/missing.py +1 -0
  561. ansible_test/_internal/cli/commands/coverage/combine.py +1 -0
  562. ansible_test/_internal/cli/commands/coverage/erase.py +1 -0
  563. ansible_test/_internal/cli/commands/coverage/html.py +1 -0
  564. ansible_test/_internal/cli/commands/coverage/report.py +1 -0
  565. ansible_test/_internal/cli/commands/coverage/xml.py +1 -0
  566. ansible_test/_internal/cli/commands/env.py +1 -0
  567. ansible_test/_internal/cli/commands/integration/__init__.py +1 -0
  568. ansible_test/_internal/cli/commands/integration/network.py +1 -0
  569. ansible_test/_internal/cli/commands/integration/posix.py +1 -0
  570. ansible_test/_internal/cli/commands/integration/windows.py +1 -0
  571. ansible_test/_internal/cli/commands/sanity.py +9 -0
  572. ansible_test/_internal/cli/commands/shell.py +1 -0
  573. ansible_test/_internal/cli/commands/units.py +1 -0
  574. ansible_test/_internal/cli/compat.py +1 -0
  575. ansible_test/_internal/cli/completers.py +1 -0
  576. ansible_test/_internal/cli/converters.py +1 -0
  577. ansible_test/_internal/cli/environments.py +52 -5
  578. ansible_test/_internal/cli/epilog.py +1 -0
  579. ansible_test/_internal/cli/parsers/__init__.py +1 -0
  580. ansible_test/_internal/cli/parsers/base_argument_parsers.py +1 -0
  581. ansible_test/_internal/cli/parsers/helpers.py +1 -0
  582. ansible_test/_internal/cli/parsers/host_config_parsers.py +1 -0
  583. ansible_test/_internal/cli/parsers/key_value_parsers.py +1 -0
  584. ansible_test/_internal/cli/parsers/value_parsers.py +1 -0
  585. ansible_test/_internal/commands/__init__.py +1 -0
  586. ansible_test/_internal/commands/coverage/__init__.py +3 -2
  587. ansible_test/_internal/commands/coverage/analyze/__init__.py +1 -0
  588. ansible_test/_internal/commands/coverage/analyze/targets/__init__.py +1 -0
  589. ansible_test/_internal/commands/coverage/analyze/targets/combine.py +1 -0
  590. ansible_test/_internal/commands/coverage/analyze/targets/expand.py +1 -0
  591. ansible_test/_internal/commands/coverage/analyze/targets/filter.py +1 -0
  592. ansible_test/_internal/commands/coverage/analyze/targets/generate.py +1 -0
  593. ansible_test/_internal/commands/coverage/analyze/targets/missing.py +1 -0
  594. ansible_test/_internal/commands/coverage/combine.py +2 -1
  595. ansible_test/_internal/commands/coverage/erase.py +1 -0
  596. ansible_test/_internal/commands/coverage/html.py +1 -0
  597. ansible_test/_internal/commands/coverage/report.py +1 -0
  598. ansible_test/_internal/commands/coverage/xml.py +1 -0
  599. ansible_test/_internal/commands/env/__init__.py +2 -0
  600. ansible_test/_internal/commands/integration/__init__.py +22 -5
  601. ansible_test/_internal/commands/integration/cloud/__init__.py +1 -0
  602. ansible_test/_internal/commands/integration/cloud/acme.py +2 -1
  603. ansible_test/_internal/commands/integration/cloud/aws.py +1 -0
  604. ansible_test/_internal/commands/integration/cloud/azure.py +1 -0
  605. ansible_test/_internal/commands/integration/cloud/cs.py +1 -0
  606. ansible_test/_internal/commands/integration/cloud/digitalocean.py +1 -0
  607. ansible_test/_internal/commands/integration/cloud/galaxy.py +3 -2
  608. ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -0
  609. ansible_test/_internal/commands/integration/cloud/httptester.py +3 -2
  610. ansible_test/_internal/commands/integration/cloud/nios.py +2 -1
  611. ansible_test/_internal/commands/integration/cloud/opennebula.py +1 -0
  612. ansible_test/_internal/commands/integration/cloud/openshift.py +1 -0
  613. ansible_test/_internal/commands/integration/cloud/scaleway.py +1 -0
  614. ansible_test/_internal/commands/integration/cloud/vcenter.py +1 -0
  615. ansible_test/_internal/commands/integration/cloud/vultr.py +1 -0
  616. ansible_test/_internal/commands/integration/coverage.py +8 -2
  617. ansible_test/_internal/commands/integration/filters.py +1 -0
  618. ansible_test/_internal/commands/integration/network.py +1 -0
  619. ansible_test/_internal/commands/integration/posix.py +1 -0
  620. ansible_test/_internal/commands/integration/windows.py +1 -0
  621. ansible_test/_internal/commands/sanity/__init__.py +19 -2
  622. ansible_test/_internal/commands/sanity/ansible_doc.py +1 -0
  623. ansible_test/_internal/commands/sanity/bin_symlinks.py +1 -0
  624. ansible_test/_internal/commands/sanity/compile.py +1 -0
  625. ansible_test/_internal/commands/sanity/ignores.py +1 -0
  626. ansible_test/_internal/commands/sanity/import.py +1 -0
  627. ansible_test/_internal/commands/sanity/integration_aliases.py +12 -0
  628. ansible_test/_internal/commands/sanity/pep8.py +1 -0
  629. ansible_test/_internal/commands/sanity/pslint.py +1 -0
  630. ansible_test/_internal/commands/sanity/pylint.py +25 -26
  631. ansible_test/_internal/commands/sanity/shellcheck.py +1 -0
  632. ansible_test/_internal/commands/sanity/validate_modules.py +1 -0
  633. ansible_test/_internal/commands/sanity/yamllint.py +1 -0
  634. ansible_test/_internal/commands/shell/__init__.py +44 -4
  635. ansible_test/_internal/commands/units/__init__.py +5 -1
  636. ansible_test/_internal/compat/__init__.py +1 -0
  637. ansible_test/_internal/compat/packaging.py +1 -0
  638. ansible_test/_internal/compat/yaml.py +1 -0
  639. ansible_test/_internal/completion.py +1 -0
  640. ansible_test/_internal/config.py +23 -13
  641. ansible_test/_internal/connections.py +1 -0
  642. ansible_test/_internal/constants.py +1 -0
  643. ansible_test/_internal/containers.py +1 -0
  644. ansible_test/_internal/content_config.py +1 -0
  645. ansible_test/_internal/core_ci.py +1 -0
  646. ansible_test/_internal/coverage_util.py +11 -10
  647. ansible_test/_internal/data.py +1 -0
  648. ansible_test/_internal/debugging.py +166 -0
  649. ansible_test/_internal/delegation.py +22 -13
  650. ansible_test/_internal/dev/__init__.py +1 -0
  651. ansible_test/_internal/dev/container_probe.py +1 -0
  652. ansible_test/_internal/diff.py +3 -2
  653. ansible_test/_internal/docker_util.py +2 -1
  654. ansible_test/_internal/encoding.py +1 -0
  655. ansible_test/_internal/executor.py +1 -0
  656. ansible_test/_internal/git.py +1 -0
  657. ansible_test/_internal/host_configs.py +1 -0
  658. ansible_test/_internal/host_profiles.py +260 -16
  659. ansible_test/_internal/http.py +1 -0
  660. ansible_test/_internal/init.py +1 -0
  661. ansible_test/_internal/inventory.py +39 -3
  662. ansible_test/_internal/io.py +1 -0
  663. ansible_test/_internal/metadata.py +95 -4
  664. ansible_test/_internal/payload.py +1 -0
  665. ansible_test/_internal/processes.py +80 -0
  666. ansible_test/_internal/provider/__init__.py +1 -0
  667. ansible_test/_internal/provider/layout/__init__.py +1 -0
  668. ansible_test/_internal/provider/layout/ansible.py +1 -0
  669. ansible_test/_internal/provider/layout/collection.py +1 -0
  670. ansible_test/_internal/provider/layout/unsupported.py +1 -0
  671. ansible_test/_internal/provider/source/__init__.py +1 -0
  672. ansible_test/_internal/provider/source/git.py +1 -0
  673. ansible_test/_internal/provider/source/installed.py +1 -0
  674. ansible_test/_internal/provider/source/unsupported.py +1 -0
  675. ansible_test/_internal/provider/source/unversioned.py +1 -0
  676. ansible_test/_internal/provisioning.py +11 -4
  677. ansible_test/_internal/pypi_proxy.py +6 -5
  678. ansible_test/_internal/python_requirements.py +28 -0
  679. ansible_test/_internal/ssh.py +2 -5
  680. ansible_test/_internal/target.py +9 -0
  681. ansible_test/_internal/test.py +3 -2
  682. ansible_test/_internal/thread.py +3 -1
  683. ansible_test/_internal/timeout.py +2 -1
  684. ansible_test/_internal/util.py +41 -12
  685. ansible_test/_internal/util_common.py +18 -5
  686. ansible_test/_internal/venv.py +1 -0
  687. ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +1 -0
  688. ansible_test/_util/controller/sanity/code-smell/changelog/sphinx.py +1 -0
  689. ansible_test/_util/controller/sanity/code-smell/changelog.py +1 -0
  690. ansible_test/_util/controller/sanity/code-smell/empty-init.py +1 -0
  691. ansible_test/_util/controller/sanity/code-smell/line-endings.py +1 -0
  692. ansible_test/_util/controller/sanity/code-smell/no-assert.py +1 -0
  693. ansible_test/_util/controller/sanity/code-smell/no-get-exception.py +1 -0
  694. ansible_test/_util/controller/sanity/code-smell/no-illegal-filenames.py +1 -0
  695. ansible_test/_util/controller/sanity/code-smell/no-smart-quotes.py +1 -0
  696. ansible_test/_util/controller/sanity/code-smell/replace-urlopen.py +1 -0
  697. ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +28 -1
  698. ansible_test/_util/controller/sanity/code-smell/shebang.py +1 -0
  699. ansible_test/_util/controller/sanity/code-smell/symlinks.py +1 -0
  700. ansible_test/_util/controller/sanity/code-smell/use-argspec-type-path.py +1 -0
  701. ansible_test/_util/controller/sanity/code-smell/use-compat-six.py +1 -0
  702. ansible_test/_util/controller/sanity/integration-aliases/yaml_to_json.py +2 -1
  703. ansible_test/_util/controller/sanity/pep8/current-ignore.txt +4 -0
  704. ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +8 -5
  705. ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +8 -5
  706. ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +8 -5
  707. ansible_test/_util/controller/sanity/pylint/config/collection.cfg +4 -5
  708. ansible_test/_util/controller/sanity/pylint/config/default.cfg +8 -7
  709. ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +541 -0
  710. ansible_test/_util/controller/sanity/pylint/plugins/deprecated_comment.py +137 -0
  711. ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +1 -0
  712. ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +1 -8
  713. ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +1 -8
  714. ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +55 -28
  715. ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +12 -5
  716. ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +13 -2
  717. ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -0
  718. ansible_test/_util/controller/sanity/yamllint/yamllinter.py +35 -17
  719. ansible_test/_util/controller/tools/collection_detail.py +1 -0
  720. ansible_test/_util/controller/tools/yaml_to_json.py +2 -1
  721. ansible_test/_util/target/injector/python.py +8 -0
  722. ansible_test/_util/target/pytest/plugins/ansible_forked.py +6 -1
  723. ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py +2 -1
  724. ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +1 -0
  725. ansible_test/_util/target/sanity/compile/compile.py +1 -0
  726. ansible_test/_util/target/sanity/import/importer.py +15 -16
  727. ansible_test/_util/target/setup/bootstrap.sh +9 -20
  728. ansible_test/_util/target/setup/probe_cgroups.py +1 -0
  729. ansible_test/_util/target/setup/quiet_pip.py +1 -0
  730. ansible_test/_util/target/setup/requirements.py +38 -36
  731. ansible_test/_util/target/tools/virtualenvcheck.py +2 -1
  732. ansible_test/_util/target/tools/yamlcheck.py +2 -1
  733. ansible/compat/selectors.py +0 -32
  734. ansible/errors/yaml_strings.py +0 -138
  735. ansible/executor/action_write_locks.py +0 -44
  736. ansible/executor/discovery/python_target.py +0 -47
  737. ansible/executor/powershell/module_powershell_wrapper.ps1 +0 -86
  738. ansible/executor/powershell/module_script_wrapper.ps1 +0 -22
  739. ansible/module_utils/compat/importlib.py +0 -26
  740. ansible/module_utils/compat/selectors.py +0 -32
  741. ansible/module_utils/pycompat24.py +0 -73
  742. ansible/parsing/yaml/constructor.py +0 -178
  743. ansible/template/native_helpers.py +0 -251
  744. ansible/template/template.py +0 -43
  745. ansible/template/vars.py +0 -77
  746. ansible/utils/native_jinja.py +0 -11
  747. ansible/vars/fact_cache.py +0 -71
  748. ansible_core-2.18.7.dist-info/RECORD +0 -992
  749. ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +0 -411
  750. {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/WHEEL +0 -0
  751. {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/entry_points.txt +0 -0
  752. {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/licenses/COPYING +0 -0
  753. {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/Apache-License.txt +0 -0
  754. {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/MIT-license.txt +0 -0
  755. {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/PSF-license.txt +0 -0
  756. {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
  757. {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/top_level.txt +0 -0
@@ -4,8 +4,10 @@
4
4
 
5
5
  from __future__ import annotations
6
6
 
7
+ import copy
7
8
  import json
8
9
  import sys
10
+ import typing as t
9
11
 
10
12
  # Used for determining if the system is running a new enough python version
11
13
  # and should only restrict on our documented minimum versions
@@ -24,6 +26,7 @@ if sys.version_info < _PY_MIN:
24
26
 
25
27
  import __main__
26
28
  import atexit
29
+ import dataclasses as _dataclasses
27
30
  import errno
28
31
  import grp
29
32
  import fcntl
@@ -50,6 +53,8 @@ try:
50
53
  except ImportError:
51
54
  HAS_SYSLOG = False
52
55
 
56
+ _UNSET = t.cast(t.Any, object())
57
+
53
58
  try:
54
59
  from systemd import journal, daemon as systemd_daemon
55
60
  # Makes sure that systemd.journal has method sendv()
@@ -70,8 +75,12 @@ except ImportError:
70
75
  # Python2 & 3 way to get NoneType
71
76
  NoneType = type(None)
72
77
 
73
- from ._text import to_native, to_bytes, to_text
74
- from ansible.module_utils.common.text.converters import (
78
+ from ._internal import _traceback, _errors, _debugging, _deprecator, _messages
79
+
80
+ from .common.text.converters import (
81
+ to_native,
82
+ to_bytes,
83
+ to_text,
75
84
  jsonify,
76
85
  container_to_bytes as json_dict_unicode_to_bytes,
77
86
  container_to_text as json_dict_bytes_to_unicode,
@@ -86,6 +95,8 @@ from ansible.module_utils.common.text.formatters import (
86
95
  SIZE_RANGES,
87
96
  )
88
97
 
98
+ from ansible.module_utils.common import json as _common_json
99
+
89
100
  import hashlib
90
101
 
91
102
 
@@ -110,6 +121,8 @@ def _get_available_hash_algorithms():
110
121
 
111
122
  AVAILABLE_HASH_ALGORITHMS = _get_available_hash_algorithms()
112
123
 
124
+ from ansible.module_utils.common import json as _json
125
+
113
126
  from ansible.module_utils.six.moves.collections_abc import (
114
127
  KeysView,
115
128
  Mapping, MutableMapping,
@@ -151,8 +164,9 @@ from ansible.module_utils.common._utils import get_all_subclasses as _get_all_su
151
164
  from ansible.module_utils.parsing.convert_bool import BOOLEANS, BOOLEANS_FALSE, BOOLEANS_TRUE, boolean
152
165
  from ansible.module_utils.common.warnings import (
153
166
  deprecate,
154
- get_deprecation_messages,
155
- get_warning_messages,
167
+ error_as_warning,
168
+ get_deprecations,
169
+ get_warnings,
156
170
  warn,
157
171
  )
158
172
 
@@ -168,7 +182,9 @@ imap = map
168
182
  # multiple AnsibleModules are created. Otherwise each AnsibleModule would
169
183
  # attempt to read from stdin. Other code should not use this directly as it
170
184
  # is an internal implementation detail
171
- _ANSIBLE_ARGS = None
185
+ _ANSIBLE_ARGS: bytes | None = None
186
+ _ANSIBLE_PROFILE: str | None = None
187
+ _PARSED_MODULE_ARGS: dict[str, t.Any] | None = None
172
188
 
173
189
 
174
190
  FILE_COMMON_ARGUMENTS = dict(
@@ -199,14 +215,14 @@ PERMS_RE = re.compile(r'^[rwxXstugo]*$')
199
215
  #
200
216
 
201
217
  def get_platform():
202
- '''
218
+ """
203
219
  **Deprecated** Use :py:func:`platform.system` directly.
204
220
 
205
221
  :returns: Name of the platform the module is running on in a native string
206
222
 
207
223
  Returns a native string that labels the platform ("Linux", "Solaris", etc). Currently, this is
208
224
  the result of calling :py:func:`platform.system`.
209
- '''
225
+ """
210
226
  return platform.system()
211
227
 
212
228
  # End deprecated functions
@@ -231,7 +247,7 @@ def get_all_subclasses(cls):
231
247
 
232
248
 
233
249
  def heuristic_log_sanitize(data, no_log_values=None):
234
- ''' Remove strings that look like passwords from log messages '''
250
+ """ Remove strings that look like passwords from log messages """
235
251
  # Currently filters:
236
252
  # user:pass@foo/whatever and http://username:pass@wherever/foo
237
253
  # This code has false positives and consumes parts of logs that are
@@ -296,7 +312,7 @@ def heuristic_log_sanitize(data, no_log_values=None):
296
312
 
297
313
 
298
314
  def _load_params():
299
- ''' read the modules parameters and store them globally.
315
+ """ read the modules parameters and store them globally.
300
316
 
301
317
  This function may be needed for certain very dynamic custom modules which
302
318
  want to process the parameters that are being handed the module. Since
@@ -305,42 +321,32 @@ def _load_params():
305
321
  will try not to break it gratuitously. It is certainly more future-proof
306
322
  to call this function and consume its outputs than to implement the logic
307
323
  inside it as a copy in your own code.
308
- '''
309
- global _ANSIBLE_ARGS
310
- if _ANSIBLE_ARGS is not None:
311
- buffer = _ANSIBLE_ARGS
312
- else:
313
- # debug overrides to read args from file or cmdline
324
+ """
325
+ global _ANSIBLE_ARGS, _ANSIBLE_PROFILE
314
326
 
315
- # Avoid tracebacks when locale is non-utf8
316
- # We control the args and we pass them as utf8
317
- if len(sys.argv) > 1:
318
- if os.path.isfile(sys.argv[1]):
319
- fd = open(sys.argv[1], 'rb')
320
- buffer = fd.read()
321
- fd.close()
322
- else:
323
- buffer = sys.argv[1].encode('utf-8', errors='surrogateescape')
324
- # default case, read from stdin
325
- else:
326
- buffer = sys.stdin.buffer.read()
327
- _ANSIBLE_ARGS = buffer
327
+ if _ANSIBLE_ARGS is None:
328
+ _ANSIBLE_ARGS, _ANSIBLE_PROFILE = _debugging.load_params()
328
329
 
329
- try:
330
- params = json.loads(buffer.decode('utf-8'))
331
- except ValueError:
332
- # This helper is used too early for fail_json to work.
333
- print('\n{"msg": "Error: Module unable to decode stdin/parameters as valid JSON. Unable to parse what parameters were passed", "failed": true}')
334
- sys.exit(1)
330
+ buffer = _ANSIBLE_ARGS
331
+ profile = _ANSIBLE_PROFILE
332
+
333
+ if not profile:
334
+ raise Exception("No serialization profile was specified.")
335
335
 
336
336
  try:
337
- return params['ANSIBLE_MODULE_ARGS']
338
- except KeyError:
339
- # This helper does not have access to fail_json so we have to print
340
- # json output on our own.
341
- print('\n{"msg": "Error: Module unable to locate ANSIBLE_MODULE_ARGS in JSON data from stdin. Unable to figure out what parameters were passed", '
342
- '"failed": true}')
343
- sys.exit(1)
337
+ decoder = _json.get_module_decoder(profile, _json.Direction.CONTROLLER_TO_MODULE)
338
+ params = json.loads(buffer.decode(), cls=decoder)
339
+ except Exception as ex:
340
+ raise Exception("Failed to decode JSON module parameters.") from ex
341
+
342
+ if (ansible_module_args := params.get('ANSIBLE_MODULE_ARGS', _UNSET)) is _UNSET:
343
+ raise Exception("ANSIBLE_MODULE_ARGS not provided.")
344
+
345
+ global _PARSED_MODULE_ARGS
346
+
347
+ _PARSED_MODULE_ARGS = copy.deepcopy(ansible_module_args) # AnsibleModule mutates the returned dict, so a copy is needed
348
+
349
+ return ansible_module_args
344
350
 
345
351
 
346
352
  def missing_required_lib(library, reason=None, url=None):
@@ -363,13 +369,13 @@ class AnsibleModule(object):
363
369
  required_one_of=None, add_file_common_args=False,
364
370
  supports_check_mode=False, required_if=None, required_by=None):
365
371
 
366
- '''
372
+ """
367
373
  Common code for quickly building an ansible module in Python
368
374
  (although you can write modules with anything that can return JSON).
369
375
 
370
376
  See :ref:`developing_modules_general` for a general introduction
371
377
  and :ref:`developing_program_flow_modules` for more detailed explanation.
372
- '''
378
+ """
373
379
 
374
380
  self._name = os.path.basename(__file__) # initialize name until we can parse from options
375
381
  self.argument_spec = argument_spec
@@ -394,7 +400,6 @@ class AnsibleModule(object):
394
400
  # run_command invocation
395
401
  self.run_command_environ_update = {}
396
402
  self._clean = {}
397
- self._string_conversion_action = ''
398
403
 
399
404
  self.aliases = {}
400
405
  self._legal_inputs = []
@@ -475,9 +480,11 @@ class AnsibleModule(object):
475
480
  if basedir is not None and not os.path.exists(basedir):
476
481
  try:
477
482
  os.makedirs(basedir, mode=0o700)
478
- except (OSError, IOError) as e:
479
- self.warn("Unable to use %s as temporary directory, "
480
- "failing back to system: %s" % (basedir, to_native(e)))
483
+ except OSError as ex:
484
+ self.error_as_warning(
485
+ msg=f"Unable to use {basedir!r} as temporary directory, falling back to system default.",
486
+ exception=ex,
487
+ )
481
488
  basedir = None
482
489
  else:
483
490
  self.warn("Module remote_tmp %s did not exist and was "
@@ -489,40 +496,80 @@ class AnsibleModule(object):
489
496
  basefile = "ansible-moduletmp-%s-" % time.time()
490
497
  try:
491
498
  tmpdir = tempfile.mkdtemp(prefix=basefile, dir=basedir)
492
- except (OSError, IOError) as e:
493
- self.fail_json(
494
- msg="Failed to create remote module tmp path at dir %s "
495
- "with prefix %s: %s" % (basedir, basefile, to_native(e))
496
- )
499
+ except OSError as ex:
500
+ raise Exception(
501
+ f"Failed to create remote module tmp path at dir {basedir!r} "
502
+ f"with prefix {basefile!r}.",
503
+ ) from ex
497
504
  if not self._keep_remote_files:
498
505
  atexit.register(shutil.rmtree, tmpdir)
499
506
  self._tmpdir = tmpdir
500
507
 
501
508
  return self._tmpdir
502
509
 
503
- def warn(self, warning):
504
- warn(warning)
505
- self.log('[WARNING] %s' % warning)
506
-
507
- def deprecate(self, msg, version=None, date=None, collection_name=None):
508
- if version is not None and date is not None:
509
- raise AssertionError("implementation error -- version and date must not both be set")
510
- deprecate(msg, version=version, date=date, collection_name=collection_name)
511
- # For compatibility, we accept that neither version nor date is set,
512
- # and treat that the same as if version would not have been set
513
- if date is not None:
514
- self.log('[DEPRECATION WARNING] %s %s' % (msg, date))
515
- else:
516
- self.log('[DEPRECATION WARNING] %s %s' % (msg, version))
510
+ def warn(
511
+ self,
512
+ warning: str,
513
+ *,
514
+ help_text: str | None = None,
515
+ ) -> None:
516
+ _skip_stackwalk = True
517
+
518
+ warn(
519
+ warning=warning,
520
+ help_text=help_text,
521
+ )
522
+
523
+ def error_as_warning(
524
+ self,
525
+ msg: str | None,
526
+ exception: BaseException,
527
+ *,
528
+ help_text: str | None = None,
529
+ ) -> None:
530
+ """Display an exception as a warning."""
531
+ _skip_stackwalk = True
532
+
533
+ error_as_warning(
534
+ msg=msg,
535
+ exception=exception,
536
+ help_text=help_text,
537
+ )
538
+
539
+ def deprecate(
540
+ self,
541
+ msg: str,
542
+ version: str | None = None,
543
+ date: str | None = None,
544
+ collection_name: str | None = None,
545
+ *,
546
+ deprecator: _messages.PluginInfo | None = None,
547
+ help_text: str | None = None,
548
+ ) -> None:
549
+ """
550
+ Record a deprecation warning to be returned with the module result.
551
+ Most callers do not need to provide `collection_name` or `deprecator` -- but provide only one if needed.
552
+ Specify `version` or `date`, but not both.
553
+ If `date` is a string, it must be in the form `YYYY-MM-DD`.
554
+ """
555
+ _skip_stackwalk = True
556
+
557
+ deprecate( # pylint: disable=ansible-deprecated-date-not-permitted,ansible-deprecated-unnecessary-collection-name
558
+ msg=msg,
559
+ version=version,
560
+ date=date,
561
+ deprecator=_deprecator.get_best_deprecator(deprecator=deprecator, collection_name=collection_name),
562
+ help_text=help_text,
563
+ )
517
564
 
518
565
  def load_file_common_arguments(self, params, path=None):
519
- '''
566
+ """
520
567
  many modules deal with files, this encapsulates common
521
568
  options that the file module accepts such that it is directly
522
569
  available to all modules and they can share code.
523
570
 
524
571
  Allows to overwrite the path/dest module argument by providing path.
525
- '''
572
+ """
526
573
 
527
574
  if path is None:
528
575
  path = params.get('path', params.get('dest', None))
@@ -613,11 +660,8 @@ class AnsibleModule(object):
613
660
  return context
614
661
  try:
615
662
  ret = selinux.lgetfilecon_raw(to_native(path, errors='surrogate_or_strict'))
616
- except OSError as e:
617
- if e.errno == errno.ENOENT:
618
- self.fail_json(path=path, msg='path %s does not exist' % path)
619
- else:
620
- self.fail_json(path=path, msg='failed to retrieve selinux context')
663
+ except OSError as ex:
664
+ self.fail_json(path=path, msg='Failed to retrieve selinux context.', exception=ex)
621
665
  if ret[0] == -1:
622
666
  return context
623
667
  # Limit split to 4 because the selevel, the last in the list,
@@ -635,12 +679,12 @@ class AnsibleModule(object):
635
679
  return (uid, gid)
636
680
 
637
681
  def find_mount_point(self, path):
638
- '''
682
+ """
639
683
  Takes a path and returns its mount point
640
684
 
641
685
  :param path: a string type with a filesystem path
642
686
  :returns: the path to the mount point as a text type
643
- '''
687
+ """
644
688
 
645
689
  b_path = os.path.realpath(to_bytes(os.path.expanduser(os.path.expandvars(path)), errors='surrogate_or_strict'))
646
690
  while not os.path.ismount(b_path):
@@ -654,9 +698,8 @@ class AnsibleModule(object):
654
698
  NFS or other 'special' fs mount point, otherwise the return will be (False, None).
655
699
  """
656
700
  try:
657
- f = open('/proc/mounts', 'r')
658
- mount_data = f.readlines()
659
- f.close()
701
+ with open('/proc/mounts', 'r') as f:
702
+ mount_data = f.readlines()
660
703
  except Exception:
661
704
  return (False, None)
662
705
 
@@ -758,9 +801,9 @@ class AnsibleModule(object):
758
801
  return True
759
802
  try:
760
803
  os.lchown(b_path, uid, -1)
761
- except (IOError, OSError) as e:
804
+ except OSError as ex:
762
805
  path = to_text(b_path)
763
- self.fail_json(path=path, msg='chown failed: %s' % (to_text(e)))
806
+ self.fail_json(path=path, msg='chown failed', exception=ex)
764
807
  changed = True
765
808
  return changed
766
809
 
@@ -880,8 +923,7 @@ class AnsibleModule(object):
880
923
  raise
881
924
  except Exception as e:
882
925
  path = to_text(b_path)
883
- self.fail_json(path=path, msg='chmod failed', details=to_native(e),
884
- exception=traceback.format_exc())
926
+ self.fail_json(path=path, msg='chmod failed', details=to_native(e))
885
927
 
886
928
  path_stat = os.lstat(b_path)
887
929
  new_mode = stat.S_IMODE(path_stat.st_mode)
@@ -929,8 +971,7 @@ class AnsibleModule(object):
929
971
  if rc != 0 or err:
930
972
  raise Exception("Error while setting attributes: %s" % (out + err))
931
973
  except Exception as e:
932
- self.fail_json(path=to_text(b_path), msg='chattr failed',
933
- details=to_native(e), exception=traceback.format_exc())
974
+ self.fail_json(path=to_text(b_path), msg='chattr failed', details=to_native(e))
934
975
  return changed
935
976
 
936
977
  def get_file_attributes(self, path, include_version=True):
@@ -1115,10 +1156,10 @@ class AnsibleModule(object):
1115
1156
  return self.set_fs_attributes_if_different(file_args, changed, diff, expand)
1116
1157
 
1117
1158
  def add_path_info(self, kwargs):
1118
- '''
1159
+ """
1119
1160
  for results that are files, supplement the info about the file
1120
1161
  in the return path with stats about the file path.
1121
- '''
1162
+ """
1122
1163
 
1123
1164
  path = kwargs.get('path', kwargs.get('dest', None))
1124
1165
  if path is None:
@@ -1155,10 +1196,10 @@ class AnsibleModule(object):
1155
1196
  return kwargs
1156
1197
 
1157
1198
  def _check_locale(self):
1158
- '''
1199
+ """
1159
1200
  Uses the locale module to test the currently set locale
1160
1201
  (per the LANG and LC_CTYPE environment settings)
1161
- '''
1202
+ """
1162
1203
  try:
1163
1204
  # setting the locale to '' uses the default locale
1164
1205
  # as it would be returned by locale.getdefaultlocale()
@@ -1175,8 +1216,7 @@ class AnsibleModule(object):
1175
1216
  os.environ['LC_ALL'] = best_locale
1176
1217
  os.environ['LC_MESSAGES'] = best_locale
1177
1218
  except Exception as e:
1178
- self.fail_json(msg="An unknown error was encountered while attempting to validate the locale: %s" %
1179
- to_native(e), exception=traceback.format_exc())
1219
+ self.fail_json(msg="An unknown error was encountered while attempting to validate the locale: %s" % to_native(e))
1180
1220
 
1181
1221
  def _set_internal_properties(self, argument_spec=None, module_parameters=None):
1182
1222
  if argument_spec is None:
@@ -1206,11 +1246,11 @@ class AnsibleModule(object):
1206
1246
  return safe_eval(value, locals, include_exceptions)
1207
1247
 
1208
1248
  def _load_params(self):
1209
- ''' read the input and set the params attribute.
1249
+ """ read the input and set the params attribute.
1210
1250
 
1211
1251
  This method is for backwards compatibility. The guts of the function
1212
1252
  were moved out in 2.1 so that custom modules could read the parameters.
1213
- '''
1253
+ """
1214
1254
  # debug overrides to read args from file or cmdline
1215
1255
  self.params = _load_params()
1216
1256
 
@@ -1226,7 +1266,6 @@ class AnsibleModule(object):
1226
1266
  msg='Failed to log to syslog (%s). To proceed anyway, '
1227
1267
  'disable syslog logging by setting no_target_syslog '
1228
1268
  'to True in your Ansible config.' % to_native(e),
1229
- exception=traceback.format_exc(),
1230
1269
  msg_to_log=msg,
1231
1270
  )
1232
1271
 
@@ -1290,14 +1329,14 @@ class AnsibleModule(object):
1290
1329
  else:
1291
1330
  journal.send(MESSAGE=u"%s %s" % (module, journal_msg),
1292
1331
  **dict(journal_args))
1293
- except IOError:
1332
+ except OSError:
1294
1333
  # fall back to syslog since logging to journal failed
1295
1334
  self._log_to_syslog(journal_msg)
1296
1335
  else:
1297
1336
  self._log_to_syslog(journal_msg)
1298
1337
 
1299
1338
  def _log_invocation(self):
1300
- ''' log that ansible ran the module '''
1339
+ """ log that ansible ran the module """
1301
1340
  # TODO: generalize a separate log function and make log_invocation use it
1302
1341
  # Sanitize possible password argument when logging.
1303
1342
  log_args = dict()
@@ -1350,7 +1389,7 @@ class AnsibleModule(object):
1350
1389
  return None
1351
1390
 
1352
1391
  def get_bin_path(self, arg, required=False, opt_dirs=None):
1353
- '''
1392
+ """
1354
1393
  Find system executable in PATH.
1355
1394
 
1356
1395
  :param arg: The executable to find.
@@ -1358,7 +1397,7 @@ class AnsibleModule(object):
1358
1397
  :param opt_dirs: optional list of directories to search in addition to ``PATH``
1359
1398
  :returns: if found return full path; otherwise return original arg, unless 'warning' then return None
1360
1399
  :raises: Sysexit: if arg is not found and required=True (via fail_json)
1361
- '''
1400
+ """
1362
1401
 
1363
1402
  bin_path = None
1364
1403
  try:
@@ -1370,7 +1409,7 @@ class AnsibleModule(object):
1370
1409
  return bin_path
1371
1410
 
1372
1411
  def boolean(self, arg):
1373
- '''Convert the argument to a boolean'''
1412
+ """Convert the argument to a boolean"""
1374
1413
  if arg is None:
1375
1414
  return arg
1376
1415
 
@@ -1380,8 +1419,15 @@ class AnsibleModule(object):
1380
1419
  self.fail_json(msg=to_native(e))
1381
1420
 
1382
1421
  def jsonify(self, data):
1422
+ # deprecated: description='deprecate AnsibleModule.jsonify()' core_version='2.23'
1423
+ # deprecate(
1424
+ # msg="The `AnsibleModule.jsonify' method is deprecated.",
1425
+ # version="2.27",
1426
+ # # help_text="", # DTFIX-FUTURE: fill in this help text
1427
+ # )
1428
+
1383
1429
  try:
1384
- return jsonify(data)
1430
+ return json.dumps(data, cls=_common_json._get_legacy_encoder())
1385
1431
  except UnicodeError as e:
1386
1432
  self.fail_json(msg=to_text(e))
1387
1433
 
@@ -1397,6 +1443,7 @@ class AnsibleModule(object):
1397
1443
  self.cleanup(path)
1398
1444
 
1399
1445
  def _return_formatted(self, kwargs):
1446
+ _skip_stackwalk = True
1400
1447
 
1401
1448
  self.add_path_info(kwargs)
1402
1449
 
@@ -1404,39 +1451,63 @@ class AnsibleModule(object):
1404
1451
  kwargs['invocation'] = {'module_args': self.params}
1405
1452
 
1406
1453
  if 'warnings' in kwargs:
1454
+ self.deprecate( # pylint: disable=ansible-deprecated-unnecessary-collection-name
1455
+ msg='Passing `warnings` to `exit_json` or `fail_json` is deprecated.',
1456
+ version='2.23',
1457
+ help_text='Use `AnsibleModule.warn` instead.',
1458
+ deprecator=_deprecator.ANSIBLE_CORE_DEPRECATOR,
1459
+ )
1460
+
1407
1461
  if isinstance(kwargs['warnings'], list):
1408
1462
  for w in kwargs['warnings']:
1409
1463
  self.warn(w)
1410
1464
  else:
1411
1465
  self.warn(kwargs['warnings'])
1412
1466
 
1413
- warnings = get_warning_messages()
1467
+ warnings = get_warnings()
1414
1468
  if warnings:
1415
1469
  kwargs['warnings'] = warnings
1416
1470
 
1417
1471
  if 'deprecations' in kwargs:
1472
+ self.deprecate( # pylint: disable=ansible-deprecated-unnecessary-collection-name
1473
+ msg='Passing `deprecations` to `exit_json` or `fail_json` is deprecated.',
1474
+ version='2.23',
1475
+ help_text='Use `AnsibleModule.deprecate` instead.',
1476
+ deprecator=_deprecator.ANSIBLE_CORE_DEPRECATOR,
1477
+ )
1478
+
1418
1479
  if isinstance(kwargs['deprecations'], list):
1419
1480
  for d in kwargs['deprecations']:
1420
- if isinstance(d, SEQUENCETYPE) and len(d) == 2:
1421
- self.deprecate(d[0], version=d[1])
1481
+ if isinstance(d, (KeysView, Sequence)) and len(d) == 2:
1482
+ self.deprecate( # pylint: disable=ansible-deprecated-unnecessary-collection-name,ansible-invalid-deprecated-version
1483
+ msg=d[0],
1484
+ version=d[1],
1485
+ deprecator=_deprecator.get_best_deprecator(),
1486
+ )
1422
1487
  elif isinstance(d, Mapping):
1423
- self.deprecate(d['msg'], version=d.get('version'), date=d.get('date'),
1424
- collection_name=d.get('collection_name'))
1488
+ self.deprecate( # pylint: disable=ansible-deprecated-date-not-permitted,ansible-deprecated-unnecessary-collection-name
1489
+ msg=d['msg'],
1490
+ version=d.get('version'),
1491
+ date=d.get('date'),
1492
+ deprecator=_deprecator.get_best_deprecator(collection_name=d.get('collection_name')),
1493
+ )
1425
1494
  else:
1426
- self.deprecate(d) # pylint: disable=ansible-deprecated-no-version
1495
+ self.deprecate( # pylint: disable=ansible-deprecated-unnecessary-collection-name,ansible-deprecated-no-version
1496
+ msg=d,
1497
+ deprecator=_deprecator.get_best_deprecator(),
1498
+ )
1427
1499
  else:
1428
- self.deprecate(kwargs['deprecations']) # pylint: disable=ansible-deprecated-no-version
1500
+ self.deprecate( # pylint: disable=ansible-deprecated-unnecessary-collection-name,ansible-deprecated-no-version
1501
+ msg=kwargs['deprecations'],
1502
+ deprecator=_deprecator.get_best_deprecator(),
1503
+ )
1429
1504
 
1430
- deprecations = get_deprecation_messages()
1505
+ deprecations = get_deprecations()
1431
1506
  if deprecations:
1432
1507
  kwargs['deprecations'] = deprecations
1433
1508
 
1434
1509
  # preserve bools/none from no_log
1435
- # TODO: once python version on target high enough, dict comprehensions
1436
- preserved = {}
1437
- for k, v in kwargs.items():
1438
- if v is None or isinstance(v, bool):
1439
- preserved[k] = v
1510
+ preserved = {k: v for k, v in kwargs.items() if v is None or isinstance(v, bool)}
1440
1511
 
1441
1512
  # strip no_log collisions
1442
1513
  kwargs = remove_values(kwargs, self.no_log_values)
@@ -1444,28 +1515,78 @@ class AnsibleModule(object):
1444
1515
  # return preserved
1445
1516
  kwargs.update(preserved)
1446
1517
 
1447
- print('\n%s' % self.jsonify(kwargs))
1518
+ encoder = _json.get_module_encoder(_ANSIBLE_PROFILE, _json.Direction.MODULE_TO_CONTROLLER)
1519
+ print('\n%s' % json.dumps(kwargs, cls=encoder))
1448
1520
 
1449
- def exit_json(self, **kwargs):
1450
- ''' return from the module, without error '''
1521
+ def exit_json(self, **kwargs) -> t.NoReturn:
1522
+ """ return from the module, without error """
1523
+ _skip_stackwalk = True
1451
1524
 
1452
1525
  self.do_cleanup_files()
1453
1526
  self._return_formatted(kwargs)
1454
1527
  sys.exit(0)
1455
1528
 
1456
- def fail_json(self, msg, **kwargs):
1457
- ''' return from the module, with an error message '''
1529
+ def fail_json(self, msg: str, *, exception: BaseException | str | None = _UNSET, **kwargs) -> t.NoReturn:
1530
+ """
1531
+ Return from the module with an error message and optional exception/traceback detail.
1532
+ A traceback will only be included in the result if error traceback capturing has been enabled.
1533
+
1534
+ When `exception` is an exception object, its message chain will be automatically combined with `msg` to create the final error message.
1535
+ The message chain includes the exception's message as well as messages from any __cause__ exceptions.
1536
+ The traceback from `exception` will be used for the formatted traceback.
1537
+
1538
+ When `exception` is a string, it will be used as the formatted traceback.
1539
+
1540
+ When `exception` is set to `None`, the current call stack will be used for the formatted traceback.
1541
+
1542
+ When `exception` is not specified, a formatted traceback will be retrieved from the current exception.
1543
+ If no exception is pending, the current call stack will be used instead.
1544
+ """
1545
+ _skip_stackwalk = True
1546
+
1547
+ msg = str(msg) # coerce to str instead of raising an error due to an invalid type
1458
1548
 
1459
- kwargs['failed'] = True
1460
- kwargs['msg'] = msg
1549
+ kwargs.update(
1550
+ failed=True,
1551
+ msg=msg,
1552
+ )
1461
1553
 
1462
- # Add traceback if debug or high verbosity and it is missing
1463
- # NOTE: Badly named as exception, it really always has been a traceback
1464
- if 'exception' not in kwargs and sys.exc_info()[2] and (self._debug or self._verbosity >= 3):
1465
- kwargs['exception'] = ''.join(traceback.format_tb(sys.exc_info()[2]))
1554
+ if isinstance(exception, BaseException):
1555
+ # Include a `_messages.Event` in the result.
1556
+ # The `msg` is included in the chain to ensure it is not lost when looking only at `exception` from the result.
1557
+
1558
+ kwargs.update(
1559
+ exception=_messages.ErrorSummary(
1560
+ event=_messages.Event(
1561
+ msg=msg,
1562
+ formatted_traceback=_traceback.maybe_capture_traceback(msg, _traceback.TracebackEvent.ERROR),
1563
+ chain=_messages.EventChain(
1564
+ msg_reason=_errors.MSG_REASON_DIRECT_CAUSE,
1565
+ traceback_reason="The above exception was the direct cause of the following error:",
1566
+ event=_errors.EventFactory.from_exception(exception, _traceback.is_traceback_enabled(_traceback.TracebackEvent.ERROR)),
1567
+ ),
1568
+ ),
1569
+ ),
1570
+ )
1571
+ elif _traceback.is_traceback_enabled(_traceback.TracebackEvent.ERROR):
1572
+ # Include only a formatted traceback string in the result.
1573
+ # The controller will combine this with `msg` to create an `_messages.ErrorSummary`.
1574
+
1575
+ formatted_traceback: str | None
1576
+
1577
+ if isinstance(exception, str):
1578
+ formatted_traceback = exception
1579
+ elif exception is _UNSET and (current_exception := t.cast(t.Optional[BaseException], sys.exc_info()[1])):
1580
+ formatted_traceback = _traceback.maybe_extract_traceback(current_exception, _traceback.TracebackEvent.ERROR)
1581
+ else:
1582
+ formatted_traceback = _traceback.maybe_capture_traceback(msg, _traceback.TracebackEvent.ERROR)
1583
+
1584
+ if formatted_traceback:
1585
+ kwargs.update(exception=formatted_traceback)
1466
1586
 
1467
1587
  self.do_cleanup_files()
1468
1588
  self._return_formatted(kwargs)
1589
+
1469
1590
  sys.exit(1)
1470
1591
 
1471
1592
  def fail_on_missing_params(self, required_params=None):
@@ -1477,7 +1598,7 @@ class AnsibleModule(object):
1477
1598
  self.fail_json(msg=to_native(e))
1478
1599
 
1479
1600
  def digest_from_file(self, filename, algorithm):
1480
- ''' Return hex digest of local file for a digest_method specified by name, or None if file is not present. '''
1601
+ """ Return hex digest of local file for a digest_method specified by name, or None if file is not present. """
1481
1602
  b_filename = to_bytes(filename, errors='surrogate_or_strict')
1482
1603
 
1483
1604
  if not os.path.exists(b_filename):
@@ -1505,7 +1626,7 @@ class AnsibleModule(object):
1505
1626
  return digest_method.hexdigest()
1506
1627
 
1507
1628
  def md5(self, filename):
1508
- ''' Return MD5 hex digest of local file using digest_from_file().
1629
+ """ Return MD5 hex digest of local file using digest_from_file().
1509
1630
 
1510
1631
  Do not use this function unless you have no other choice for:
1511
1632
  1) Optional backwards compatibility
@@ -1514,21 +1635,21 @@ class AnsibleModule(object):
1514
1635
  This function will not work on systems complying with FIPS-140-2.
1515
1636
 
1516
1637
  Most uses of this function can use the module.sha1 function instead.
1517
- '''
1638
+ """
1518
1639
  if 'md5' not in AVAILABLE_HASH_ALGORITHMS:
1519
1640
  raise ValueError('MD5 not available. Possibly running in FIPS mode')
1520
1641
  return self.digest_from_file(filename, 'md5')
1521
1642
 
1522
1643
  def sha1(self, filename):
1523
- ''' Return SHA1 hex digest of local file using digest_from_file(). '''
1644
+ """ Return SHA1 hex digest of local file using digest_from_file(). """
1524
1645
  return self.digest_from_file(filename, 'sha1')
1525
1646
 
1526
1647
  def sha256(self, filename):
1527
- ''' Return SHA-256 hex digest of local file using digest_from_file(). '''
1648
+ """ Return SHA-256 hex digest of local file using digest_from_file(). """
1528
1649
  return self.digest_from_file(filename, 'sha256')
1529
1650
 
1530
1651
  def backup_local(self, fn):
1531
- '''make a date-marked backup of the specified file, return True or False on success or failure'''
1652
+ """make a date-marked backup of the specified file, return True or False on success or failure"""
1532
1653
 
1533
1654
  backupdest = ''
1534
1655
  if os.path.exists(fn):
@@ -1536,10 +1657,11 @@ class AnsibleModule(object):
1536
1657
  ext = time.strftime("%Y-%m-%d@%H:%M:%S~", time.localtime(time.time()))
1537
1658
  backupdest = '%s.%s.%s' % (fn, os.getpid(), ext)
1538
1659
 
1539
- try:
1540
- self.preserved_copy(fn, backupdest)
1541
- except (shutil.Error, IOError) as e:
1542
- self.fail_json(msg='Could not make backup of %s to %s: %s' % (fn, backupdest, to_native(e)))
1660
+ if not self.check_mode:
1661
+ try:
1662
+ self.preserved_copy(fn, backupdest)
1663
+ except (shutil.Error, IOError) as ex:
1664
+ raise Exception(f'Could not make backup of {fn!r} to {backupdest!r}.') from ex
1543
1665
 
1544
1666
  return backupdest
1545
1667
 
@@ -1586,9 +1708,9 @@ class AnsibleModule(object):
1586
1708
  self.set_attributes_if_different(dest, current_attribs, True)
1587
1709
 
1588
1710
  def atomic_move(self, src, dest, unsafe_writes=False, keep_dest_attrs=True):
1589
- '''atomically move src to dest, copying attributes from dest, returns true on success
1711
+ """atomically move src to dest, copying attributes from dest, returns true on success
1590
1712
  it uses os.rename to ensure this as it is an atomic operation, rest of the function is
1591
- to work around limitations, corner cases and ensure selinux context is saved if possible'''
1713
+ to work around limitations, corner cases and ensure selinux context is saved if possible"""
1592
1714
  context = None
1593
1715
  dest_stat = None
1594
1716
  b_src = to_bytes(src, errors='surrogate_or_strict')
@@ -1613,29 +1735,25 @@ class AnsibleModule(object):
1613
1735
  try:
1614
1736
  # Optimistically try a rename, solves some corner cases and can avoid useless work, throws exception if not atomic.
1615
1737
  os.rename(b_src, b_dest)
1616
- except (IOError, OSError) as e:
1617
- if e.errno not in [errno.EPERM, errno.EXDEV, errno.EACCES, errno.ETXTBSY, errno.EBUSY]:
1738
+ except OSError as ex:
1739
+ if ex.errno in (errno.EPERM, errno.EXDEV, errno.EACCES, errno.ETXTBSY, errno.EBUSY):
1618
1740
  # only try workarounds for errno 18 (cross device), 1 (not permitted), 13 (permission denied)
1619
1741
  # and 26 (text file busy) which happens on vagrant synced folders and other 'exotic' non posix file systems
1620
- self.fail_json(msg='Could not replace file: %s to %s: %s' % (src, dest, to_native(e)), exception=traceback.format_exc())
1621
- else:
1622
1742
  # Use bytes here. In the shippable CI, this fails with
1623
1743
  # a UnicodeError with surrogateescape'd strings for an unknown
1624
1744
  # reason (doesn't happen in a local Ubuntu16.04 VM)
1625
1745
  b_dest_dir = os.path.dirname(b_dest)
1626
1746
  b_suffix = os.path.basename(b_dest)
1627
- error_msg = None
1628
1747
  tmp_dest_name = None
1629
1748
  try:
1630
1749
  tmp_dest_fd, tmp_dest_name = tempfile.mkstemp(prefix=b'.ansible_tmp', dir=b_dest_dir, suffix=b_suffix)
1631
- except (OSError, IOError) as e:
1632
- error_msg = 'The destination directory (%s) is not writable by the current user. Error was: %s' % (os.path.dirname(dest), to_native(e))
1633
- finally:
1634
- if error_msg:
1635
- if unsafe_writes:
1636
- self._unsafe_writes(b_src, b_dest)
1637
- else:
1638
- self.fail_json(msg=error_msg, exception=traceback.format_exc())
1750
+ except OSError as ex:
1751
+ if unsafe_writes:
1752
+ self._unsafe_writes(b_src, b_dest)
1753
+ else:
1754
+ raise Exception(
1755
+ f'The destination directory {os.path.dirname(dest)!r} is not writable by the current user.'
1756
+ ) from ex
1639
1757
 
1640
1758
  if tmp_dest_name:
1641
1759
  b_tmp_dest_name = to_bytes(tmp_dest_name, errors='surrogate_or_strict')
@@ -1664,24 +1782,27 @@ class AnsibleModule(object):
1664
1782
  if dest_stat and (tmp_stat.st_uid != dest_stat.st_uid or tmp_stat.st_gid != dest_stat.st_gid):
1665
1783
  os.chown(b_tmp_dest_name, dest_stat.st_uid, dest_stat.st_gid)
1666
1784
  os.utime(b_tmp_dest_name, times=(time.time(), time.time()))
1667
- except OSError as e:
1668
- if e.errno != errno.EPERM:
1785
+ except OSError as ex:
1786
+ if ex.errno != errno.EPERM:
1669
1787
  raise
1670
1788
  try:
1671
1789
  os.rename(b_tmp_dest_name, b_dest)
1672
- except (shutil.Error, OSError, IOError) as e:
1673
- if unsafe_writes and e.errno == errno.EBUSY:
1790
+ except (shutil.Error, OSError) as ex:
1791
+ if unsafe_writes and ex.errno == errno.EBUSY:
1674
1792
  self._unsafe_writes(b_tmp_dest_name, b_dest)
1675
1793
  else:
1676
- self.fail_json(msg='Unable to make %s into to %s, failed final rename from %s: %s' %
1677
- (src, dest, b_tmp_dest_name, to_native(e)), exception=traceback.format_exc())
1678
- except (shutil.Error, OSError, IOError) as e:
1794
+ raise Exception(
1795
+ f'Unable to make {src!r} into to {dest!r}, failed final rename from {to_text(b_tmp_dest_name)!r}.'
1796
+ ) from ex
1797
+ except (shutil.Error, OSError) as ex:
1679
1798
  if unsafe_writes:
1680
1799
  self._unsafe_writes(b_src, b_dest)
1681
1800
  else:
1682
- self.fail_json(msg='Failed to replace file: %s to %s: %s' % (src, dest, to_native(e)), exception=traceback.format_exc())
1801
+ raise Exception(f'Failed to replace {dest!r} with {src!r}.') from ex
1683
1802
  finally:
1684
1803
  self.cleanup(b_tmp_dest_name)
1804
+ else:
1805
+ raise Exception(f'Could not replace {dest!r} with {src!r}.') from ex
1685
1806
 
1686
1807
  if creating:
1687
1808
  # make sure the file has the correct permissions
@@ -1708,19 +1829,11 @@ class AnsibleModule(object):
1708
1829
  # sadly there are some situations where we cannot ensure atomicity, but only if
1709
1830
  # the user insists and we get the appropriate error we update the file unsafely
1710
1831
  try:
1711
- out_dest = in_src = None
1712
- try:
1713
- out_dest = open(dest, 'wb')
1714
- in_src = open(src, 'rb')
1715
- shutil.copyfileobj(in_src, out_dest)
1716
- finally: # assuring closed files in 2.4 compatible way
1717
- if out_dest:
1718
- out_dest.close()
1719
- if in_src:
1720
- in_src.close()
1721
- except (shutil.Error, OSError, IOError) as e:
1722
- self.fail_json(msg='Could not write data to file (%s) from (%s): %s' % (dest, src, to_native(e)),
1723
- exception=traceback.format_exc())
1832
+ with open(dest, 'wb') as out_dest:
1833
+ with open(src, 'rb') as in_src:
1834
+ shutil.copyfileobj(in_src, out_dest)
1835
+ except (shutil.Error, OSError) as ex:
1836
+ raise Exception(f'Could not write data to file {dest!r} from {src!r}.') from ex
1724
1837
 
1725
1838
  def _clean_args(self, args):
1726
1839
 
@@ -1756,7 +1869,7 @@ class AnsibleModule(object):
1756
1869
  def run_command(self, args, check_rc=False, close_fds=True, executable=None, data=None, binary_data=False, path_prefix=None, cwd=None,
1757
1870
  use_unsafe_shell=False, prompt_regex=None, environ_update=None, umask=None, encoding='utf-8', errors='surrogate_or_strict',
1758
1871
  expand_user_and_vars=True, pass_fds=None, before_communicate_callback=None, ignore_invalid_cwd=True, handle_exceptions=True):
1759
- '''
1872
+ """
1760
1873
  Execute a command, returns rc, stdout, and stderr.
1761
1874
 
1762
1875
  The mechanism of this method for reading stdout and stderr differs from
@@ -1787,18 +1900,18 @@ class AnsibleModule(object):
1787
1900
  the execution to hang (especially if no input data is specified)
1788
1901
  :kw environ_update: dictionary to *update* environ variables with
1789
1902
  :kw umask: Umask to be used when running the command. Default None
1790
- :kw encoding: Since we return native strings, on python3 we need to
1903
+ :kw encoding: Since we return strings, we need to
1791
1904
  know the encoding to use to transform from bytes to text. If you
1792
1905
  want to always get bytes back, use encoding=None. The default is
1793
1906
  "utf-8". This does not affect transformation of strings given as
1794
1907
  args.
1795
- :kw errors: Since we return native strings, on python3 we need to
1908
+ :kw errors: Since we return strings, we need to
1796
1909
  transform stdout and stderr from bytes to text. If the bytes are
1797
1910
  undecodable in the ``encoding`` specified, then use this error
1798
1911
  handler to deal with them. The default is ``surrogate_or_strict``
1799
1912
  which means that the bytes will be decoded using the
1800
1913
  surrogateescape error handler if available (available on all
1801
- python3 versions we support) otherwise a UnicodeError traceback
1914
+ Python versions we support) otherwise a UnicodeError traceback
1802
1915
  will be raised. This does not affect transformations of strings
1803
1916
  given as args.
1804
1917
  :kw expand_user_and_vars: When ``use_unsafe_shell=False`` this argument
@@ -1806,10 +1919,8 @@ class AnsibleModule(object):
1806
1919
  are expanded before running the command. When ``True`` a string such as
1807
1920
  ``$SHELL`` will be expanded regardless of escaping. When ``False`` and
1808
1921
  ``use_unsafe_shell=False`` no path or variable expansion will be done.
1809
- :kw pass_fds: When running on Python 3 this argument
1810
- dictates which file descriptors should be passed
1811
- to an underlying ``Popen`` constructor. On Python 2, this will
1812
- set ``close_fds`` to False.
1922
+ :kw pass_fds: This argument dictates which file descriptors should be passed
1923
+ to an underlying ``Popen`` constructor.
1813
1924
  :kw before_communicate_callback: This function will be called
1814
1925
  after ``Popen`` object will be created
1815
1926
  but before communicating to the process.
@@ -1820,12 +1931,11 @@ class AnsibleModule(object):
1820
1931
  :kw handle_exceptions: This flag indicates whether an exception will
1821
1932
  be handled inline and issue a failed_json or if the caller should
1822
1933
  handle it.
1823
- :returns: A 3-tuple of return code (integer), stdout (native string),
1824
- and stderr (native string). On python2, stdout and stderr are both
1825
- byte strings. On python3, stdout and stderr are text strings converted
1826
- according to the encoding and errors parameters. If you want byte
1827
- strings on python3, use encoding=None to turn decoding to text off.
1828
- '''
1934
+ :returns: A 3-tuple of return code (int), stdout (str), and stderr (str).
1935
+ stdout and stderr are text strings converted according to the encoding
1936
+ and errors parameters. If you want byte strings, use encoding=None
1937
+ to turn decoding to text off.
1938
+ """
1829
1939
  # used by clean args later on
1830
1940
  self._clean = None
1831
1941
 
@@ -2006,18 +2116,16 @@ class AnsibleModule(object):
2006
2116
  selector.close()
2007
2117
 
2008
2118
  rc = cmd.returncode
2009
- except (OSError, IOError) as e:
2010
- self.log("Error Executing CMD:%s Exception:%s" % (self._clean_args(args), to_native(e)))
2119
+ except OSError as ex:
2011
2120
  if handle_exceptions:
2012
- self.fail_json(rc=e.errno, stdout=b'', stderr=b'', msg=to_native(e), cmd=self._clean_args(args))
2121
+ self.fail_json(rc=ex.errno, stdout='', stderr='', msg="Error executing command.", cmd=self._clean_args(args), exception=ex)
2013
2122
  else:
2014
- raise e
2015
- except Exception as e:
2016
- self.log("Error Executing CMD:%s Exception:%s" % (self._clean_args(args), to_native(traceback.format_exc())))
2123
+ raise
2124
+ except Exception as ex:
2017
2125
  if handle_exceptions:
2018
- self.fail_json(rc=257, stdout=b'', stderr=b'', msg=to_native(e), exception=traceback.format_exc(), cmd=self._clean_args(args))
2126
+ self.fail_json(rc=257, stdout='', stderr='', msg="Error executing command.", cmd=self._clean_args(args), exception=ex)
2019
2127
  else:
2020
- raise e
2128
+ raise
2021
2129
 
2022
2130
  if rc != 0 and check_rc:
2023
2131
  msg = heuristic_log_sanitize(stderr.rstrip(), self.no_log_values)
@@ -2031,9 +2139,8 @@ class AnsibleModule(object):
2031
2139
 
2032
2140
  def append_to_file(self, filename, str):
2033
2141
  filename = os.path.expandvars(os.path.expanduser(filename))
2034
- fh = open(filename, 'a')
2035
- fh.write(str)
2036
- fh.close()
2142
+ with open(filename, 'a') as fh:
2143
+ fh.write(str)
2037
2144
 
2038
2145
  def bytes_to_human(self, size):
2039
2146
  return bytes_to_human(size)
@@ -2072,13 +2179,7 @@ def get_module_path():
2072
2179
 
2073
2180
  def __getattr__(importable_name):
2074
2181
  """Inject import-time deprecation warnings."""
2075
- if importable_name == 'get_exception':
2076
- from ansible.module_utils.pycompat24 import get_exception
2077
- importable = get_exception
2078
- elif importable_name in {'literal_eval', '_literal_eval'}:
2079
- from ast import literal_eval
2080
- importable = literal_eval
2081
- elif importable_name == 'datetime':
2182
+ if importable_name == 'datetime':
2082
2183
  import datetime
2083
2184
  importable = datetime
2084
2185
  elif importable_name == 'signal':
@@ -2095,7 +2196,7 @@ def __getattr__(importable_name):
2095
2196
  importable = repeat
2096
2197
  elif importable_name in {
2097
2198
  'PY2', 'PY3', 'b', 'binary_type', 'integer_types',
2098
- 'iteritems', 'string_types', 'test_type'
2199
+ 'iteritems', 'string_types', 'text_type',
2099
2200
  }:
2100
2201
  import importlib
2101
2202
  importable = getattr(