ansible-core 2.18.7rc1__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.7rc1.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.7rc1.dist-info/RECORD +0 -992
  749. ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +0 -411
  750. {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/WHEEL +0 -0
  751. {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/entry_points.txt +0 -0
  752. {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/COPYING +0 -0
  753. {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/Apache-License.txt +0 -0
  754. {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/MIT-license.txt +0 -0
  755. {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/PSF-license.txt +0 -0
  756. {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
  757. {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,541 @@
1
+ """Ansible-specific pylint plugin for checking deprecation calls."""
2
+
3
+ # (c) 2018, Matt Martz <matt@sivel.net>
4
+ # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
5
+
6
+ from __future__ import annotations
7
+
8
+ import dataclasses
9
+ import datetime
10
+ import functools
11
+ import pathlib
12
+ import re
13
+
14
+ import astroid
15
+ import astroid.context
16
+ import astroid.typing
17
+
18
+ import pylint.lint
19
+ import pylint.checkers
20
+ import pylint.checkers.utils
21
+
22
+ import ansible.release
23
+
24
+ from ansible.module_utils._internal._deprecator import INDETERMINATE_DEPRECATOR, _path_as_collection_plugininfo
25
+ from ansible.module_utils.compat.version import StrictVersion
26
+ from ansible.utils.version import SemanticVersion
27
+
28
+
29
+ @dataclasses.dataclass(frozen=True, kw_only=True)
30
+ class DeprecationCallArgs:
31
+ """Arguments passed to a deprecation function."""
32
+
33
+ msg: object = None
34
+ version: object = None
35
+ date: object = None
36
+ collection_name: object = None
37
+ deprecator: object = None
38
+ help_text: object = None # only on Display.deprecated, warnings.deprecate and deprecate_value
39
+ obj: object = None # only on Display.deprecated and warnings.deprecate
40
+ removed: object = None # only on Display.deprecated
41
+ value: object = None # only on deprecate_value
42
+
43
+ def all_args_dynamic(self) -> bool:
44
+ """True if all args are dynamic or None, otherwise False."""
45
+ return all(arg is None or isinstance(arg, astroid.NodeNG) for arg in dataclasses.asdict(self).values())
46
+
47
+
48
+ class AnsibleDeprecatedChecker(pylint.checkers.BaseChecker):
49
+ """Checks for deprecated calls to ensure proper usage."""
50
+
51
+ name = 'deprecated-calls'
52
+ msgs = {
53
+ 'E9501': (
54
+ "Deprecated version %r found in call to %r",
55
+ "ansible-deprecated-version",
56
+ None,
57
+ ),
58
+ 'E9502': (
59
+ "Found %r call without a version or date",
60
+ "ansible-deprecated-no-version",
61
+ None,
62
+ ),
63
+ 'E9503': (
64
+ "Invalid deprecated version %r found in call to %r",
65
+ "ansible-invalid-deprecated-version",
66
+ None,
67
+ ),
68
+ 'E9504': (
69
+ "Deprecated version %r found in call to %r",
70
+ "collection-deprecated-version",
71
+ None,
72
+ ),
73
+ 'E9505': (
74
+ "Invalid deprecated version %r found in call to %r",
75
+ "collection-invalid-deprecated-version",
76
+ None,
77
+ ),
78
+ 'E9506': (
79
+ "No collection_name or deprecator found in call to %r",
80
+ "ansible-deprecated-no-collection-name",
81
+ None,
82
+ ),
83
+ 'E9507': (
84
+ "Wrong collection_name %r found in call to %r",
85
+ "wrong-collection-deprecated",
86
+ None,
87
+ ),
88
+ 'E9508': (
89
+ "Expired date %r found in call to %r",
90
+ "ansible-expired-deprecated-date",
91
+ None,
92
+ ),
93
+ 'E9509': (
94
+ "Invalid date %r found in call to %r",
95
+ "ansible-invalid-deprecated-date",
96
+ None,
97
+ ),
98
+ 'E9510': (
99
+ "Both version and date found in call to %r",
100
+ "ansible-deprecated-both-version-and-date",
101
+ None,
102
+ ),
103
+ 'E9511': (
104
+ "Removal version %r must be a major release, not a minor or patch release, see https://semver.org/",
105
+ "removal-version-must-be-major",
106
+ None,
107
+ ),
108
+ 'E9512': (
109
+ "Passing date is not permitted in call to %r for ansible-core, use a version instead",
110
+ "ansible-deprecated-date-not-permitted",
111
+ None,
112
+ ),
113
+ 'E9513': (
114
+ "Unnecessary %r found in call to %r",
115
+ "ansible-deprecated-unnecessary-collection-name",
116
+ None,
117
+ ),
118
+ 'E9514': (
119
+ "Passing collection_name not permitted in call to %r for ansible-core, use deprecator instead",
120
+ "ansible-deprecated-collection-name-not-permitted",
121
+ None,
122
+ ),
123
+ 'E9515': (
124
+ "Both collection_name and deprecator found in call to %r",
125
+ "ansible-deprecated-both-collection-name-and-deprecator",
126
+ None,
127
+ ),
128
+ }
129
+
130
+ options = (
131
+ (
132
+ 'collection-name',
133
+ dict(
134
+ default=None,
135
+ type='string',
136
+ metavar='<name>',
137
+ help="The name of the collection to check.",
138
+ ),
139
+ ),
140
+ (
141
+ 'collection-version',
142
+ dict(
143
+ default=None,
144
+ type='string',
145
+ metavar='<version>',
146
+ help="The version of the collection to check.",
147
+ ),
148
+ ),
149
+ (
150
+ 'collection-path',
151
+ dict(
152
+ default=None,
153
+ type='string',
154
+ metavar='<path>',
155
+ help="The path of the collection to check.",
156
+ ),
157
+ ),
158
+ )
159
+
160
+ ANSIBLE_VERSION = StrictVersion(re.match('[0-9.]*[0-9]', ansible.release.__version__)[0])
161
+ """The current ansible-core X.Y.Z version."""
162
+
163
+ DEPRECATION_MODULE_FUNCTIONS: dict[tuple[str, str], tuple[str, ...]] = {
164
+ ('ansible.module_utils.common.warnings', 'deprecate'): ('msg', 'version', 'date', 'collection_name'),
165
+ ('ansible.module_utils.datatag', 'deprecate_value'): ('value', 'msg'),
166
+ ('ansible.module_utils.basic', 'AnsibleModule.deprecate'): ('msg', 'version', 'date', 'collection_name'),
167
+ ('ansible.utils.display', 'Display.deprecated'): ('msg', 'version', 'removed', 'date', 'collection_name'),
168
+ }
169
+ """Mapping of deprecation module+function and their positional arguments."""
170
+
171
+ DEPRECATION_MODULES = frozenset(key[0] for key in DEPRECATION_MODULE_FUNCTIONS)
172
+ """Modules which contain deprecation functions."""
173
+
174
+ DEPRECATION_FUNCTIONS = {'.'.join(key): value for key, value in DEPRECATION_MODULE_FUNCTIONS.items()}
175
+ """Mapping of deprecation functions and their positional arguments."""
176
+
177
+ def __init__(self, *args, **kwargs) -> None:
178
+ super().__init__(*args, **kwargs)
179
+
180
+ self.module_cache: dict[str, astroid.Module] = {}
181
+
182
+ @functools.cached_property
183
+ def collection_name(self) -> str | None:
184
+ """Return the collection name, or None if ansible-core is being tested."""
185
+ return self.linter.config.collection_name or None
186
+
187
+ @functools.cached_property
188
+ def collection_path(self) -> pathlib.Path:
189
+ """Return the collection path. Not valid when ansible-core is being tested."""
190
+ return pathlib.Path(self.linter.config.collection_path)
191
+
192
+ @functools.cached_property
193
+ def collection_version(self) -> SemanticVersion | None:
194
+ """Return the collection version, or None if ansible-core is being tested."""
195
+ if not self.linter.config.collection_version:
196
+ return None
197
+
198
+ sem_ver = SemanticVersion(self.linter.config.collection_version)
199
+ sem_ver.prerelease = () # ignore pre-release for version comparison to catch issues before the final release is cut
200
+
201
+ return sem_ver
202
+
203
+ @functools.cached_property
204
+ def is_ansible_core(self) -> bool:
205
+ """True if ansible-core is being tested."""
206
+ return not self.collection_name
207
+
208
+ @functools.cached_property
209
+ def today_utc(self) -> datetime.date:
210
+ """Today's date in UTC."""
211
+ return datetime.datetime.now(tz=datetime.timezone.utc).date()
212
+
213
+ def is_deprecator_required(self) -> bool | None:
214
+ """Determine is a `collection_name` or `deprecator` is required (True), unnecessary (False) or optional (None)."""
215
+ if self.is_ansible_core:
216
+ return False # in ansible-core, never provide the deprecator -- if it really is needed, disable the sanity test inline for that line of code
217
+
218
+ plugin_info = _path_as_collection_plugininfo(self.linter.current_file)
219
+
220
+ if plugin_info is INDETERMINATE_DEPRECATOR:
221
+ return True # deprecator cannot be detected, caller must provide deprecator
222
+
223
+ # deprecation: description='deprecate collection_name/deprecator now that detection is widely available' core_version='2.23'
224
+ # When this deprecation triggers, change the return type here to False.
225
+ # At that point, callers should be able to omit the collection_name/deprecator in all but a few cases (inline ignores can be used for those cases)
226
+ return None
227
+
228
+ @pylint.checkers.utils.only_required_for_messages(*(msgs.keys()))
229
+ def visit_call(self, node: astroid.Call) -> None:
230
+ """Visit a call node."""
231
+ if inferred := self.infer(node.func):
232
+ name = self.get_fully_qualified_name(inferred)
233
+
234
+ if args := self.DEPRECATION_FUNCTIONS.get(name):
235
+ self.check_call(node, name, args)
236
+
237
+ def infer(self, node: astroid.NodeNG) -> astroid.NodeNG | None:
238
+ """Return the inferred node from the given node, or `None` if it cannot be unambiguously inferred."""
239
+ names: list[str] = []
240
+ target: astroid.NodeNG | None = node
241
+ inferred: astroid.typing.InferenceResult | None = None
242
+
243
+ while target:
244
+ if inferred := astroid.util.safe_infer(target):
245
+ break
246
+
247
+ if isinstance(target, astroid.Call):
248
+ inferred = self.infer(target.func)
249
+ break
250
+
251
+ if isinstance(target, astroid.FunctionDef):
252
+ inferred = target
253
+ break
254
+
255
+ if isinstance(target, astroid.Name):
256
+ target = self.infer_name(target)
257
+ elif isinstance(target, astroid.AssignName) and isinstance(target.parent, astroid.Assign):
258
+ target = target.parent.value
259
+ elif isinstance(target, astroid.Attribute):
260
+ names.append(target.attrname)
261
+ target = target.expr
262
+ else:
263
+ break
264
+
265
+ for name in reversed(names):
266
+ if isinstance(inferred, astroid.Instance):
267
+ try:
268
+ attr = next(iter(inferred.getattr(name)), None)
269
+ except astroid.AttributeInferenceError:
270
+ break
271
+
272
+ if isinstance(attr, astroid.AssignAttr):
273
+ inferred = self.get_ansible_module(attr)
274
+ continue
275
+
276
+ if isinstance(attr, astroid.FunctionDef):
277
+ inferred = attr
278
+ continue
279
+
280
+ if not isinstance(inferred, (astroid.Module, astroid.ClassDef)):
281
+ inferred = None
282
+ break
283
+
284
+ try:
285
+ inferred = inferred[name]
286
+ except KeyError:
287
+ inferred = None
288
+ else:
289
+ inferred = self.infer(inferred)
290
+
291
+ if isinstance(inferred, astroid.FunctionDef) and isinstance(inferred.parent, astroid.ClassDef):
292
+ inferred = astroid.BoundMethod(inferred, inferred.parent)
293
+
294
+ return inferred
295
+
296
+ def infer_name(self, node: astroid.Name) -> astroid.NodeNG | None:
297
+ """Infer the node referenced by the given name, or `None` if it cannot be unambiguously inferred."""
298
+ scope = node.scope()
299
+ inferred: astroid.NodeNG | None = None
300
+ name = node.name
301
+
302
+ while scope:
303
+ try:
304
+ assignment = scope[name]
305
+ except KeyError:
306
+ scope = scope.parent.scope() if scope.parent else None
307
+ continue
308
+
309
+ if isinstance(assignment, astroid.AssignName) and isinstance(assignment.parent, astroid.Assign):
310
+ inferred = assignment.parent.value
311
+ elif (
312
+ isinstance(scope, astroid.FunctionDef)
313
+ and isinstance(assignment, astroid.AssignName)
314
+ and isinstance(assignment.parent, astroid.Arguments)
315
+ and assignment.parent.annotations
316
+ ):
317
+ idx, _node = assignment.parent.find_argname(name)
318
+
319
+ if idx is not None:
320
+ try:
321
+ annotation = assignment.parent.annotations[idx]
322
+ except IndexError:
323
+ pass
324
+ else:
325
+ if isinstance(annotation, astroid.Name):
326
+ name = annotation.name
327
+ continue
328
+ elif isinstance(assignment, astroid.ClassDef):
329
+ inferred = assignment
330
+ elif isinstance(assignment, astroid.ImportFrom):
331
+ if module := self.get_module(assignment):
332
+ name = assignment.real_name(name)
333
+ scope = module.scope()
334
+ continue
335
+
336
+ break
337
+
338
+ return inferred
339
+
340
+ def get_module(self, node: astroid.ImportFrom) -> astroid.Module | None:
341
+ """Import the requested module if possible and cache the result."""
342
+ module_name = pylint.checkers.utils.get_import_name(node, node.modname)
343
+
344
+ if module_name not in self.DEPRECATION_MODULES:
345
+ return None # avoid unnecessary import overhead
346
+
347
+ if module := self.module_cache.get(module_name):
348
+ return module
349
+
350
+ module = node.do_import_module()
351
+
352
+ if module.name != module_name:
353
+ raise RuntimeError(f'Attempted to import {module_name!r} but found {module.name!r} instead.')
354
+
355
+ self.module_cache[module_name] = module
356
+
357
+ return module
358
+
359
+ @staticmethod
360
+ def get_fully_qualified_name(node: astroid.NodeNG) -> str | None:
361
+ """Return the fully qualified name of the given inferred node."""
362
+ parent = node.parent
363
+ parts: tuple[str, ...] | None
364
+
365
+ if isinstance(node, astroid.FunctionDef) and isinstance(parent, astroid.Module):
366
+ parts = (parent.name, node.name)
367
+ elif isinstance(node, astroid.BoundMethod) and isinstance(parent, astroid.ClassDef) and isinstance(parent.parent, astroid.Module):
368
+ parts = (parent.parent.name, parent.name, node.name)
369
+ else:
370
+ parts = None
371
+
372
+ return '.'.join(parts) if parts else None
373
+
374
+ def check_call(self, node: astroid.Call, name: str, args: tuple[str, ...]) -> None:
375
+ """Check the given deprecation call node for valid arguments."""
376
+ call_args = self.get_deprecation_call_args(node, args)
377
+
378
+ self.check_collection_name(node, name, call_args)
379
+
380
+ if not call_args.version and not call_args.date:
381
+ self.add_message('ansible-deprecated-no-version', node=node, args=(name,))
382
+ return
383
+
384
+ if call_args.date and self.is_ansible_core:
385
+ self.add_message('ansible-deprecated-date-not-permitted', node=node, args=(name,))
386
+ return
387
+
388
+ if call_args.all_args_dynamic():
389
+ # assume collection maintainers know what they're doing if all args are dynamic
390
+ return
391
+
392
+ if call_args.version and call_args.date:
393
+ self.add_message('ansible-deprecated-both-version-and-date', node=node, args=(name,))
394
+ return
395
+
396
+ if call_args.date:
397
+ self.check_date(node, name, call_args)
398
+
399
+ if call_args.version:
400
+ self.check_version(node, name, call_args)
401
+
402
+ @staticmethod
403
+ def get_deprecation_call_args(node: astroid.Call, args: tuple[str, ...]) -> DeprecationCallArgs:
404
+ """Get the deprecation call arguments from the given node."""
405
+ fields: dict[str, object] = {}
406
+
407
+ for idx, arg in enumerate(node.args):
408
+ field = args[idx]
409
+ fields[field] = arg
410
+
411
+ for keyword in node.keywords:
412
+ if keyword.arg is not None:
413
+ fields[keyword.arg] = keyword.value
414
+
415
+ for key, value in fields.items():
416
+ if isinstance(value, astroid.Const):
417
+ fields[key] = value.value
418
+
419
+ return DeprecationCallArgs(**fields)
420
+
421
+ def check_collection_name(self, node: astroid.Call, name: str, args: DeprecationCallArgs) -> None:
422
+ """Check the collection name provided to the given call node."""
423
+ deprecator_requirement = self.is_deprecator_required()
424
+
425
+ if self.is_ansible_core and args.collection_name:
426
+ self.add_message('ansible-deprecated-collection-name-not-permitted', node=node, args=(name,))
427
+ return
428
+
429
+ if args.collection_name and args.deprecator:
430
+ self.add_message('ansible-deprecated-both-collection-name-and-deprecator', node=node, args=(name,))
431
+
432
+ if deprecator_requirement is True:
433
+ if not args.collection_name and not args.deprecator:
434
+ self.add_message('ansible-deprecated-no-collection-name', node=node, args=(name,))
435
+ return
436
+ elif deprecator_requirement is False:
437
+ if args.collection_name:
438
+ self.add_message('ansible-deprecated-unnecessary-collection-name', node=node, args=('collection_name', name,))
439
+ return
440
+
441
+ if args.deprecator:
442
+ self.add_message('ansible-deprecated-unnecessary-collection-name', node=node, args=('deprecator', name,))
443
+ return
444
+ else:
445
+ # collection_name may be needed for backward compat with 2.18 and earlier, since it is only detected in 2.19 and later
446
+
447
+ if args.deprecator:
448
+ # Unlike collection_name, which is needed for backward compat, deprecator is generally not needed by collections.
449
+ # For the very rare cases where this is needed by collections, an inline pylint ignore can be used to silence it.
450
+ self.add_message('ansible-deprecated-unnecessary-collection-name', node=node, args=('deprecator', name,))
451
+ return
452
+
453
+ if args.all_args_dynamic():
454
+ # assume collection maintainers know what they're doing if all args are dynamic
455
+ return
456
+
457
+ expected_collection_name = 'ansible.builtin' if self.is_ansible_core else self.collection_name
458
+
459
+ if args.collection_name and args.collection_name != expected_collection_name:
460
+ self.add_message('wrong-collection-deprecated', node=node, args=(args.collection_name, name))
461
+
462
+ def check_version(self, node: astroid.Call, name: str, args: DeprecationCallArgs) -> None:
463
+ """Check the version provided to the given call node."""
464
+ if self.collection_name:
465
+ self.check_collection_version(node, name, args)
466
+ else:
467
+ self.check_core_version(node, name, args)
468
+
469
+ def check_core_version(self, node: astroid.Call, name: str, args: DeprecationCallArgs) -> None:
470
+ """Check the core version provided to the given call node."""
471
+ try:
472
+ if not isinstance(args.version, str) or not args.version:
473
+ raise ValueError()
474
+
475
+ strict_version = StrictVersion(args.version)
476
+ except ValueError:
477
+ self.add_message('ansible-invalid-deprecated-version', node=node, args=(args.version, name))
478
+ return
479
+
480
+ if self.ANSIBLE_VERSION >= strict_version:
481
+ self.add_message('ansible-deprecated-version', node=node, args=(args.version, name))
482
+
483
+ def check_collection_version(self, node: astroid.Call, name: str, args: DeprecationCallArgs) -> None:
484
+ """Check the collection version provided to the given call node."""
485
+ try:
486
+ if not isinstance(args.version, str) or not args.version:
487
+ raise ValueError()
488
+
489
+ semantic_version = SemanticVersion(args.version)
490
+ except ValueError:
491
+ self.add_message('collection-invalid-deprecated-version', node=node, args=(args.version, name))
492
+ return
493
+
494
+ if self.collection_version >= semantic_version:
495
+ self.add_message('collection-deprecated-version', node=node, args=(args.version, name))
496
+
497
+ if semantic_version.major != 0 and (semantic_version.minor != 0 or semantic_version.patch != 0):
498
+ self.add_message('removal-version-must-be-major', node=node, args=(args.version,))
499
+
500
+ def check_date(self, node: astroid.Call, name: str, args: DeprecationCallArgs) -> None:
501
+ """Check the date provided to the given call node."""
502
+ try:
503
+ date_parsed = self.parse_isodate(args.date)
504
+ except (ValueError, TypeError):
505
+ self.add_message('ansible-invalid-deprecated-date', node=node, args=(args.date, name))
506
+ else:
507
+ if date_parsed < self.today_utc:
508
+ self.add_message('ansible-expired-deprecated-date', node=node, args=(args.date, name))
509
+
510
+ @staticmethod
511
+ def parse_isodate(value: object) -> datetime.date:
512
+ """Parse an ISO 8601 date string."""
513
+ if isinstance(value, str):
514
+ return datetime.date.fromisoformat(value)
515
+
516
+ raise TypeError(type(value))
517
+
518
+ def get_ansible_module(self, node: astroid.AssignAttr) -> astroid.Instance | None:
519
+ """Infer an AnsibleModule instance node from the given assignment."""
520
+ if isinstance(node.parent, astroid.Assign) and isinstance(node.parent.type_annotation, astroid.Name):
521
+ inferred = self.infer_name(node.parent.type_annotation)
522
+ elif isinstance(node.parent, astroid.Assign) and isinstance(node.parent.parent, astroid.FunctionDef) and isinstance(node.parent.value, astroid.Name):
523
+ inferred = self.infer_name(node.parent.value)
524
+ elif isinstance(node.parent, astroid.AnnAssign) and isinstance(node.parent.annotation, astroid.Name):
525
+ inferred = self.infer_name(node.parent.annotation)
526
+ else:
527
+ inferred = None
528
+
529
+ if isinstance(inferred, astroid.ClassDef) and inferred.name == 'AnsibleModule':
530
+ return inferred.instantiate_class()
531
+
532
+ return None
533
+
534
+ def register(self) -> None:
535
+ """Register this plugin."""
536
+ self.linter.register_checker(self)
537
+
538
+
539
+ def register(linter: pylint.lint.PyLinter) -> None:
540
+ """Required method to auto-register this checker."""
541
+ AnsibleDeprecatedChecker(linter).register()
@@ -0,0 +1,137 @@
1
+ """Ansible-specific pylint plugin for checking deprecation comments."""
2
+
3
+ # (c) 2018, Matt Martz <matt@sivel.net>
4
+ # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
5
+
6
+ from __future__ import annotations
7
+
8
+ import shlex
9
+ import tokenize
10
+
11
+ import pylint.checkers
12
+ import pylint.lint
13
+
14
+ import ansible.release
15
+
16
+ from ansible.module_utils.compat.version import LooseVersion
17
+
18
+
19
+ class AnsibleDeprecatedCommentChecker(pylint.checkers.BaseTokenChecker):
20
+ """Checks for ``# deprecated:`` comments to ensure that the ``version`` has not passed or met the time for removal."""
21
+
22
+ name = 'deprecated-comment'
23
+ msgs = {
24
+ 'E9601': (
25
+ "Deprecated core version (%r) found: %s",
26
+ "ansible-deprecated-version-comment",
27
+ None,
28
+ ),
29
+ 'E9602': (
30
+ "Deprecated comment contains invalid keys %r",
31
+ "ansible-deprecated-version-comment-invalid-key",
32
+ None,
33
+ ),
34
+ 'E9603': (
35
+ "Deprecated comment missing version",
36
+ "ansible-deprecated-version-comment-missing-version",
37
+ None,
38
+ ),
39
+ 'E9604': (
40
+ "Deprecated python version (%r) found: %s",
41
+ "ansible-deprecated-python-version-comment",
42
+ None,
43
+ ),
44
+ 'E9605': (
45
+ "Deprecated comment contains invalid version %r: %s",
46
+ "ansible-deprecated-version-comment-invalid-version",
47
+ None,
48
+ ),
49
+ }
50
+
51
+ ANSIBLE_VERSION = LooseVersion('.'.join(ansible.release.__version__.split('.')[:3]))
52
+ """The current ansible-core X.Y.Z version."""
53
+
54
+ def process_tokens(self, tokens: list[tokenize.TokenInfo]) -> None:
55
+ for token in tokens:
56
+ if token.type == tokenize.COMMENT:
57
+ self._process_comment(token)
58
+
59
+ def _deprecated_string_to_dict(self, token: tokenize.TokenInfo, string: str) -> dict[str, str]:
60
+ valid_keys = {'description', 'core_version', 'python_version'}
61
+ data = dict.fromkeys(valid_keys)
62
+ for opt in shlex.split(string):
63
+ if '=' not in opt:
64
+ data[opt] = None
65
+ continue
66
+ key, _sep, value = opt.partition('=')
67
+ data[key] = value
68
+ if not any((data['core_version'], data['python_version'])):
69
+ self.add_message(
70
+ 'ansible-deprecated-version-comment-missing-version',
71
+ line=token.start[0],
72
+ col_offset=token.start[1],
73
+ )
74
+ bad = set(data).difference(valid_keys)
75
+ if bad:
76
+ self.add_message(
77
+ 'ansible-deprecated-version-comment-invalid-key',
78
+ line=token.start[0],
79
+ col_offset=token.start[1],
80
+ args=(','.join(bad),),
81
+ )
82
+ return data
83
+
84
+ def _process_python_version(self, token: tokenize.TokenInfo, data: dict[str, str]) -> None:
85
+ check_version = '.'.join(map(str, self.linter.config.py_version)) # minimum supported Python version provided by ansible-test
86
+
87
+ try:
88
+ if LooseVersion(check_version) > LooseVersion(data['python_version']):
89
+ self.add_message(
90
+ 'ansible-deprecated-python-version-comment',
91
+ line=token.start[0],
92
+ col_offset=token.start[1],
93
+ args=(
94
+ data['python_version'],
95
+ data['description'] or 'description not provided',
96
+ ),
97
+ )
98
+ except (ValueError, TypeError) as exc:
99
+ self.add_message(
100
+ 'ansible-deprecated-version-comment-invalid-version',
101
+ line=token.start[0],
102
+ col_offset=token.start[1],
103
+ args=(data['python_version'], exc),
104
+ )
105
+
106
+ def _process_core_version(self, token: tokenize.TokenInfo, data: dict[str, str]) -> None:
107
+ try:
108
+ if self.ANSIBLE_VERSION >= LooseVersion(data['core_version']):
109
+ self.add_message(
110
+ 'ansible-deprecated-version-comment',
111
+ line=token.start[0],
112
+ col_offset=token.start[1],
113
+ args=(
114
+ data['core_version'],
115
+ data['description'] or 'description not provided',
116
+ ),
117
+ )
118
+ except (ValueError, TypeError) as exc:
119
+ self.add_message(
120
+ 'ansible-deprecated-version-comment-invalid-version',
121
+ line=token.start[0],
122
+ col_offset=token.start[1],
123
+ args=(data['core_version'], exc),
124
+ )
125
+
126
+ def _process_comment(self, token: tokenize.TokenInfo) -> None:
127
+ if token.string.startswith('# deprecated:'):
128
+ data = self._deprecated_string_to_dict(token, token.string[13:].strip())
129
+ if data['core_version']:
130
+ self._process_core_version(token, data)
131
+ if data['python_version']:
132
+ self._process_python_version(token, data)
133
+
134
+
135
+ def register(linter: pylint.lint.PyLinter) -> None:
136
+ """Required method to auto-register this checker."""
137
+ linter.register_checker(AnsibleDeprecatedCommentChecker(linter))
@@ -1,4 +1,5 @@
1
1
  """Temporary plugin to prevent stdout noise pollution from finalization of abandoned generators."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import sys