ansible-core 2.15.4rc1__py3-none-any.whl → 2.16.0b2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (427) hide show
  1. ansible/cli/__init__.py +3 -3
  2. ansible/cli/adhoc.py +1 -1
  3. ansible/cli/arguments/option_helpers.py +15 -5
  4. ansible/cli/config.py +2 -2
  5. ansible/cli/console.py +21 -17
  6. ansible/cli/doc.py +8 -9
  7. ansible/cli/galaxy.py +60 -27
  8. ansible/cli/inventory.py +1 -1
  9. ansible/cli/playbook.py +1 -1
  10. ansible/cli/pull.py +2 -2
  11. ansible/cli/scripts/ansible_connection_cli_stub.py +1 -1
  12. ansible/cli/vault.py +11 -6
  13. ansible/collections/__init__.py +0 -29
  14. ansible/collections/list.py +23 -44
  15. ansible/config/ansible_builtin_runtime.yml +8 -4
  16. ansible/config/base.yml +34 -22
  17. ansible/config/manager.py +1 -1
  18. ansible/constants.py +3 -5
  19. ansible/errors/__init__.py +1 -1
  20. ansible/executor/interpreter_discovery.py +1 -1
  21. ansible/executor/module_common.py +39 -32
  22. ansible/executor/play_iterator.py +0 -15
  23. ansible/executor/playbook_executor.py +3 -3
  24. ansible/executor/powershell/module_manifest.py +1 -1
  25. ansible/executor/powershell/module_wrapper.ps1 +4 -1
  26. ansible/executor/process/worker.py +22 -7
  27. ansible/executor/task_executor.py +39 -40
  28. ansible/executor/task_queue_manager.py +8 -11
  29. ansible/galaxy/__init__.py +1 -1
  30. ansible/galaxy/api.py +8 -11
  31. ansible/galaxy/collection/__init__.py +17 -4
  32. ansible/galaxy/collection/concrete_artifact_manager.py +7 -2
  33. ansible/galaxy/collection/galaxy_api_proxy.py +1 -1
  34. ansible/galaxy/data/container/README.md +3 -5
  35. ansible/galaxy/dependency_resolution/__init__.py +1 -6
  36. ansible/galaxy/dependency_resolution/dataclasses.py +22 -1
  37. ansible/galaxy/dependency_resolution/providers.py +61 -69
  38. ansible/galaxy/role.py +31 -13
  39. ansible/galaxy/token.py +2 -2
  40. ansible/inventory/group.py +1 -1
  41. ansible/inventory/manager.py +1 -1
  42. ansible/module_utils/ansible_release.py +2 -2
  43. ansible/module_utils/basic.py +11 -41
  44. ansible/module_utils/common/file.py +0 -100
  45. ansible/module_utils/common/json.py +1 -1
  46. ansible/module_utils/common/locale.py +1 -1
  47. ansible/module_utils/common/text/converters.py +2 -2
  48. ansible/module_utils/common/validation.py +1 -1
  49. ansible/module_utils/compat/_selectors2.py +4 -4
  50. ansible/module_utils/compat/datetime.py +40 -0
  51. ansible/module_utils/compat/selinux.py +1 -1
  52. ansible/module_utils/compat/typing.py +1 -1
  53. ansible/module_utils/connection.py +1 -1
  54. ansible/module_utils/facts/hardware/linux.py +2 -2
  55. ansible/module_utils/facts/hardware/openbsd.py +1 -1
  56. ansible/module_utils/facts/network/linux.py +3 -3
  57. ansible/module_utils/facts/other/facter.py +8 -15
  58. ansible/module_utils/facts/sysctl.py +1 -1
  59. ansible/module_utils/facts/system/date_time.py +2 -2
  60. ansible/module_utils/facts/system/distribution.py +1 -1
  61. ansible/module_utils/facts/system/local.py +6 -2
  62. ansible/module_utils/facts/system/pkg_mgr.py +6 -1
  63. ansible/module_utils/facts/system/service_mgr.py +4 -2
  64. ansible/module_utils/parsing/convert_bool.py +1 -1
  65. ansible/module_utils/service.py +9 -6
  66. ansible/module_utils/urls.py +40 -22
  67. ansible/modules/add_host.py +2 -2
  68. ansible/modules/apt.py +48 -31
  69. ansible/modules/apt_key.py +4 -4
  70. ansible/modules/apt_repository.py +5 -5
  71. ansible/modules/assemble.py +7 -7
  72. ansible/modules/assert.py +1 -1
  73. ansible/modules/async_status.py +11 -7
  74. ansible/modules/async_wrapper.py +1 -1
  75. ansible/modules/blockinfile.py +60 -17
  76. ansible/modules/command.py +37 -15
  77. ansible/modules/copy.py +35 -30
  78. ansible/modules/cron.py +14 -14
  79. ansible/modules/deb822_repository.py +4 -3
  80. ansible/modules/debconf.py +35 -14
  81. ansible/modules/debug.py +1 -1
  82. ansible/modules/dnf.py +29 -27
  83. ansible/modules/dnf5.py +22 -22
  84. ansible/modules/dpkg_selections.py +9 -2
  85. ansible/modules/expect.py +4 -4
  86. ansible/modules/fetch.py +7 -7
  87. ansible/modules/file.py +30 -30
  88. ansible/modules/find.py +82 -22
  89. ansible/modules/gather_facts.py +6 -2
  90. ansible/modules/get_url.py +29 -29
  91. ansible/modules/getent.py +4 -4
  92. ansible/modules/git.py +27 -27
  93. ansible/modules/group.py +5 -12
  94. ansible/modules/hostname.py +21 -2
  95. ansible/modules/include_role.py +5 -5
  96. ansible/modules/include_tasks.py +2 -2
  97. ansible/modules/include_vars.py +5 -5
  98. ansible/modules/iptables.py +70 -65
  99. ansible/modules/known_hosts.py +7 -7
  100. ansible/modules/lineinfile.py +33 -33
  101. ansible/modules/meta.py +13 -13
  102. ansible/modules/package.py +8 -8
  103. ansible/modules/package_facts.py +3 -3
  104. ansible/modules/pause.py +2 -2
  105. ansible/modules/ping.py +5 -5
  106. ansible/modules/pip.py +80 -46
  107. ansible/modules/reboot.py +8 -4
  108. ansible/modules/replace.py +20 -15
  109. ansible/modules/rpm_key.py +2 -2
  110. ansible/modules/script.py +16 -10
  111. ansible/modules/service.py +26 -98
  112. ansible/modules/service_facts.py +36 -12
  113. ansible/modules/set_fact.py +2 -2
  114. ansible/modules/set_stats.py +2 -2
  115. ansible/modules/setup.py +18 -18
  116. ansible/modules/shell.py +3 -3
  117. ansible/modules/stat.py +9 -30
  118. ansible/modules/subversion.py +9 -9
  119. ansible/modules/systemd.py +20 -19
  120. ansible/modules/systemd_service.py +20 -19
  121. ansible/modules/sysvinit.py +26 -21
  122. ansible/modules/tempfile.py +5 -4
  123. ansible/modules/template.py +60 -6
  124. ansible/modules/unarchive.py +21 -18
  125. ansible/modules/uri.py +39 -39
  126. ansible/modules/user.py +81 -53
  127. ansible/modules/wait_for.py +22 -21
  128. ansible/modules/wait_for_connection.py +4 -4
  129. ansible/modules/yum.py +38 -38
  130. ansible/modules/yum_repository.py +58 -80
  131. ansible/parsing/dataloader.py +27 -27
  132. ansible/parsing/mod_args.py +1 -1
  133. ansible/parsing/plugin_docs.py +3 -3
  134. ansible/parsing/splitter.py +14 -16
  135. ansible/parsing/utils/yaml.py +1 -1
  136. ansible/parsing/vault/__init__.py +8 -6
  137. ansible/parsing/yaml/constructor.py +1 -1
  138. ansible/parsing/yaml/objects.py +1 -1
  139. ansible/playbook/__init__.py +1 -1
  140. ansible/playbook/base.py +2 -2
  141. ansible/playbook/block.py +0 -1
  142. ansible/playbook/conditional.py +40 -114
  143. ansible/playbook/helpers.py +5 -28
  144. ansible/playbook/included_file.py +8 -7
  145. ansible/playbook/play.py +1 -1
  146. ansible/playbook/play_context.py +2 -2
  147. ansible/playbook/playbook_include.py +2 -2
  148. ansible/playbook/role/__init__.py +1 -1
  149. ansible/playbook/role/include.py +1 -1
  150. ansible/playbook/role/metadata.py +1 -1
  151. ansible/playbook/role_include.py +1 -1
  152. ansible/playbook/task.py +2 -2
  153. ansible/playbook/task_include.py +1 -24
  154. ansible/plugins/__init__.py +13 -5
  155. ansible/plugins/action/__init__.py +17 -43
  156. ansible/plugins/action/add_host.py +2 -3
  157. ansible/plugins/action/assemble.py +1 -1
  158. ansible/plugins/action/assert.py +2 -1
  159. ansible/plugins/action/copy.py +2 -2
  160. ansible/plugins/action/debug.py +2 -1
  161. ansible/plugins/action/fail.py +1 -0
  162. ansible/plugins/action/fetch.py +3 -1
  163. ansible/plugins/action/gather_facts.py +37 -13
  164. ansible/plugins/action/group_by.py +1 -0
  165. ansible/plugins/action/include_vars.py +3 -2
  166. ansible/plugins/action/normal.py +3 -3
  167. ansible/plugins/action/pause.py +1 -1
  168. ansible/plugins/action/reboot.py +21 -16
  169. ansible/plugins/action/script.py +23 -8
  170. ansible/plugins/action/set_fact.py +1 -0
  171. ansible/plugins/action/set_stats.py +1 -0
  172. ansible/plugins/action/shell.py +6 -0
  173. ansible/plugins/action/template.py +1 -1
  174. ansible/plugins/action/unarchive.py +1 -1
  175. ansible/plugins/action/uri.py +1 -1
  176. ansible/plugins/action/validate_argument_spec.py +1 -0
  177. ansible/plugins/action/wait_for_connection.py +4 -4
  178. ansible/plugins/become/__init__.py +1 -1
  179. ansible/plugins/become/su.py +1 -1
  180. ansible/plugins/cache/__init__.py +1 -1
  181. ansible/plugins/callback/junit.py +1 -1
  182. ansible/plugins/callback/oneline.py +1 -1
  183. ansible/plugins/callback/tree.py +1 -1
  184. ansible/plugins/cliconf/__init__.py +2 -2
  185. ansible/plugins/connection/__init__.py +65 -37
  186. ansible/plugins/connection/local.py +9 -8
  187. ansible/plugins/connection/paramiko_ssh.py +34 -28
  188. ansible/plugins/connection/psrp.py +56 -43
  189. ansible/plugins/connection/ssh.py +67 -43
  190. ansible/plugins/connection/winrm.py +77 -30
  191. ansible/plugins/doc_fragments/constructed.py +4 -4
  192. ansible/plugins/doc_fragments/files.py +12 -12
  193. ansible/plugins/doc_fragments/inventory_cache.py +0 -6
  194. ansible/plugins/doc_fragments/result_format_callback.py +5 -5
  195. ansible/plugins/doc_fragments/shell_common.py +2 -2
  196. ansible/plugins/doc_fragments/shell_windows.py +1 -1
  197. ansible/plugins/doc_fragments/template_common.py +6 -6
  198. ansible/plugins/doc_fragments/url.py +10 -10
  199. ansible/plugins/doc_fragments/url_windows.py +15 -15
  200. ansible/plugins/doc_fragments/vars_plugin_staging.py +4 -4
  201. ansible/plugins/filter/b64decode.yml +1 -1
  202. ansible/plugins/filter/b64encode.yml +2 -2
  203. ansible/plugins/filter/bool.yml +5 -5
  204. ansible/plugins/filter/combine.yml +1 -1
  205. ansible/plugins/filter/commonpath.yml +2 -1
  206. ansible/plugins/filter/core.py +6 -8
  207. ansible/plugins/filter/dict2items.yml +11 -1
  208. ansible/plugins/filter/difference.yml +1 -0
  209. ansible/plugins/filter/encryption.py +1 -1
  210. ansible/plugins/filter/extract.yml +1 -1
  211. ansible/plugins/filter/flatten.yml +1 -1
  212. ansible/plugins/filter/from_yaml.yml +1 -1
  213. ansible/plugins/filter/from_yaml_all.yml +2 -2
  214. ansible/plugins/filter/hash.yml +1 -1
  215. ansible/plugins/filter/human_readable.yml +1 -1
  216. ansible/plugins/filter/human_to_bytes.yml +2 -2
  217. ansible/plugins/filter/intersect.yml +1 -0
  218. ansible/plugins/filter/mandatory.yml +7 -0
  219. ansible/plugins/filter/mathstuff.py +15 -17
  220. ansible/plugins/filter/normpath.yml +1 -1
  221. ansible/plugins/filter/path_join.yml +8 -1
  222. ansible/plugins/filter/realpath.yml +3 -2
  223. ansible/plugins/filter/regex_findall.yml +8 -2
  224. ansible/plugins/filter/regex_replace.yml +9 -3
  225. ansible/plugins/filter/regex_search.yml +8 -2
  226. ansible/plugins/filter/relpath.yml +2 -2
  227. ansible/plugins/filter/root.yml +1 -1
  228. ansible/plugins/filter/splitext.yml +1 -1
  229. ansible/plugins/filter/subelements.yml +2 -2
  230. ansible/plugins/filter/symmetric_difference.yml +1 -0
  231. ansible/plugins/filter/ternary.yml +5 -5
  232. ansible/plugins/filter/to_json.yml +7 -7
  233. ansible/plugins/filter/to_nice_json.yml +5 -5
  234. ansible/plugins/filter/to_yaml.yml +2 -2
  235. ansible/plugins/filter/type_debug.yml +1 -1
  236. ansible/plugins/filter/union.yml +1 -0
  237. ansible/plugins/filter/unvault.yml +2 -2
  238. ansible/plugins/filter/urldecode.yml +13 -32
  239. ansible/plugins/filter/urlsplit.py +1 -1
  240. ansible/plugins/filter/vault.yml +1 -1
  241. ansible/plugins/filter/zip.yml +1 -1
  242. ansible/plugins/filter/zip_longest.yml +1 -1
  243. ansible/plugins/inventory/__init__.py +1 -1
  244. ansible/plugins/inventory/advanced_host_list.py +1 -1
  245. ansible/plugins/inventory/constructed.py +2 -2
  246. ansible/plugins/inventory/host_list.py +1 -1
  247. ansible/plugins/inventory/ini.py +6 -3
  248. ansible/plugins/inventory/script.py +8 -2
  249. ansible/plugins/inventory/toml.py +1 -1
  250. ansible/plugins/inventory/yaml.py +1 -1
  251. ansible/plugins/list.py +21 -17
  252. ansible/plugins/loader.py +66 -88
  253. ansible/plugins/lookup/__init__.py +1 -1
  254. ansible/plugins/lookup/config.py +16 -6
  255. ansible/plugins/lookup/csvfile.py +7 -4
  256. ansible/plugins/lookup/env.py +1 -1
  257. ansible/plugins/lookup/file.py +5 -2
  258. ansible/plugins/lookup/fileglob.py +5 -2
  259. ansible/plugins/lookup/first_found.py +20 -14
  260. ansible/plugins/lookup/ini.py +6 -3
  261. ansible/plugins/lookup/lines.py +2 -1
  262. ansible/plugins/lookup/password.py +7 -7
  263. ansible/plugins/lookup/pipe.py +1 -0
  264. ansible/plugins/lookup/random_choice.py +2 -2
  265. ansible/plugins/lookup/sequence.py +1 -1
  266. ansible/plugins/lookup/subelements.py +2 -2
  267. ansible/plugins/lookup/template.py +4 -1
  268. ansible/plugins/lookup/unvault.py +4 -1
  269. ansible/plugins/lookup/url.py +6 -6
  270. ansible/plugins/lookup/varnames.py +1 -1
  271. ansible/plugins/netconf/__init__.py +3 -3
  272. ansible/plugins/shell/__init__.py +1 -1
  273. ansible/plugins/shell/cmd.py +7 -7
  274. ansible/plugins/shell/powershell.py +1 -1
  275. ansible/plugins/strategy/__init__.py +8 -10
  276. ansible/plugins/strategy/free.py +1 -1
  277. ansible/plugins/strategy/linear.py +3 -3
  278. ansible/plugins/terminal/__init__.py +2 -2
  279. ansible/plugins/test/abs.yml +1 -1
  280. ansible/plugins/test/all.yml +1 -1
  281. ansible/plugins/test/any.yml +1 -1
  282. ansible/plugins/test/change.yml +2 -2
  283. ansible/plugins/test/changed.yml +2 -2
  284. ansible/plugins/test/contains.yml +1 -1
  285. ansible/plugins/test/core.py +1 -1
  286. ansible/plugins/test/directory.yml +1 -1
  287. ansible/plugins/test/exists.yml +3 -2
  288. ansible/plugins/test/failed.yml +2 -2
  289. ansible/plugins/test/failure.yml +2 -2
  290. ansible/plugins/test/falsy.yml +2 -2
  291. ansible/plugins/test/file.yml +1 -1
  292. ansible/plugins/test/finished.yml +2 -2
  293. ansible/plugins/test/is_abs.yml +1 -1
  294. ansible/plugins/test/is_dir.yml +1 -1
  295. ansible/plugins/test/is_file.yml +1 -1
  296. ansible/plugins/test/is_link.yml +1 -1
  297. ansible/plugins/test/is_mount.yml +1 -1
  298. ansible/plugins/test/is_same_file.yml +1 -1
  299. ansible/plugins/test/isnan.yml +1 -1
  300. ansible/plugins/test/issubset.yml +1 -2
  301. ansible/plugins/test/issuperset.yml +1 -2
  302. ansible/plugins/test/link.yml +1 -1
  303. ansible/plugins/test/link_exists.yml +1 -1
  304. ansible/plugins/test/match.yml +2 -2
  305. ansible/plugins/test/mount.yml +1 -1
  306. ansible/plugins/test/nan.yml +1 -1
  307. ansible/plugins/test/reachable.yml +2 -2
  308. ansible/plugins/test/regex.yml +1 -1
  309. ansible/plugins/test/same_file.yml +1 -1
  310. ansible/plugins/test/search.yml +2 -2
  311. ansible/plugins/test/skip.yml +3 -3
  312. ansible/plugins/test/skipped.yml +3 -3
  313. ansible/plugins/test/started.yml +2 -2
  314. ansible/plugins/test/subset.yml +1 -2
  315. ansible/plugins/test/succeeded.yml +2 -2
  316. ansible/plugins/test/success.yml +2 -2
  317. ansible/plugins/test/successful.yml +2 -2
  318. ansible/plugins/test/superset.yml +1 -2
  319. ansible/plugins/test/truthy.yml +3 -3
  320. ansible/plugins/test/unreachable.yml +2 -2
  321. ansible/plugins/test/uri.yml +1 -1
  322. ansible/plugins/test/url.yml +1 -1
  323. ansible/plugins/test/urn.yml +1 -1
  324. ansible/plugins/test/vault_encrypted.yml +1 -1
  325. ansible/plugins/test/version.yml +7 -7
  326. ansible/plugins/test/version_compare.yml +7 -7
  327. ansible/plugins/vars/host_group_vars.py +1 -1
  328. ansible/release.py +2 -2
  329. ansible/template/__init__.py +24 -26
  330. ansible/template/native_helpers.py +1 -1
  331. ansible/template/vars.py +1 -1
  332. ansible/utils/_junit_xml.py +1 -1
  333. ansible/utils/cmd_functions.py +1 -1
  334. ansible/utils/collection_loader/_collection_finder.py +12 -1
  335. ansible/utils/display.py +113 -62
  336. ansible/utils/encrypt.py +11 -14
  337. ansible/utils/hashing.py +1 -1
  338. ansible/utils/jsonrpc.py +1 -1
  339. ansible/utils/path.py +1 -1
  340. ansible/utils/plugin_docs.py +1 -1
  341. ansible/utils/py3compat.py +1 -1
  342. ansible/utils/shlex.py +2 -10
  343. ansible/utils/ssh_functions.py +5 -4
  344. ansible/utils/unicode.py +1 -1
  345. ansible/utils/unsafe_proxy.py +1 -1
  346. ansible/utils/vars.py +4 -29
  347. ansible/vars/hostvars.py +1 -2
  348. ansible/vars/manager.py +13 -9
  349. ansible/vars/plugins.py +2 -2
  350. {ansible_core-2.15.4rc1.dist-info → ansible_core-2.16.0b2.dist-info}/COPYING +4 -5
  351. {ansible_core-2.15.4rc1.dist-info → ansible_core-2.16.0b2.dist-info}/METADATA +2 -4
  352. {ansible_core-2.15.4rc1.dist-info → ansible_core-2.16.0b2.dist-info}/RECORD +424 -425
  353. ansible_test/_data/completion/docker.txt +9 -9
  354. ansible_test/_data/completion/remote.txt +4 -7
  355. ansible_test/_data/completion/windows.txt +0 -2
  356. ansible_test/_data/requirements/ansible-test.txt +2 -1
  357. ansible_test/_data/requirements/ansible.txt +0 -3
  358. ansible_test/_data/requirements/constraints.txt +0 -2
  359. ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -5
  360. ansible_test/_data/requirements/sanity.changelog.in +1 -2
  361. ansible_test/_data/requirements/sanity.changelog.txt +4 -6
  362. ansible_test/_data/requirements/sanity.import.plugin.txt +2 -4
  363. ansible_test/_data/requirements/sanity.import.txt +1 -3
  364. ansible_test/_data/requirements/sanity.integration-aliases.txt +1 -3
  365. ansible_test/_data/requirements/sanity.mypy.txt +12 -12
  366. ansible_test/_data/requirements/sanity.pep8.txt +1 -1
  367. ansible_test/_data/requirements/sanity.pylint.txt +6 -12
  368. ansible_test/_data/requirements/sanity.runtime-metadata.txt +1 -3
  369. ansible_test/_data/requirements/sanity.validate-modules.in +1 -1
  370. ansible_test/_data/requirements/sanity.validate-modules.txt +3 -5
  371. ansible_test/_data/requirements/sanity.yamllint.txt +3 -5
  372. ansible_test/_data/requirements/units.txt +0 -1
  373. ansible_test/_internal/ci/azp.py +4 -4
  374. ansible_test/_internal/cli/environments.py +0 -13
  375. ansible_test/_internal/commands/coverage/analyze/targets/__init__.py +4 -4
  376. ansible_test/_internal/commands/coverage/combine.py +1 -1
  377. ansible_test/_internal/commands/integration/cloud/acme.py +6 -8
  378. ansible_test/_internal/commands/integration/cloud/cs.py +4 -9
  379. ansible_test/_internal/commands/integration/cloud/galaxy.py +103 -96
  380. ansible_test/_internal/commands/integration/cloud/httptester.py +0 -3
  381. ansible_test/_internal/commands/integration/cloud/nios.py +7 -9
  382. ansible_test/_internal/commands/integration/cloud/openshift.py +2 -7
  383. ansible_test/_internal/commands/integration/cloud/vcenter.py +11 -95
  384. ansible_test/_internal/commands/sanity/__init__.py +10 -0
  385. ansible_test/_internal/commands/sanity/import.py +8 -2
  386. ansible_test/_internal/commands/sanity/pylint.py +27 -1
  387. ansible_test/_internal/commands/units/__init__.py +2 -1
  388. ansible_test/_internal/config.py +0 -7
  389. ansible_test/_internal/containers.py +11 -56
  390. ansible_test/_internal/core_ci.py +0 -7
  391. ansible_test/_internal/coverage_util.py +8 -3
  392. ansible_test/_internal/delegation.py +0 -1
  393. ansible_test/_internal/diff.py +1 -1
  394. ansible_test/_internal/docker_util.py +9 -2
  395. ansible_test/_internal/host_profiles.py +6 -6
  396. ansible_test/_internal/http.py +1 -1
  397. ansible_test/_internal/junit_xml.py +1 -1
  398. ansible_test/_internal/pypi_proxy.py +1 -1
  399. ansible_test/_internal/python_requirements.py +3 -8
  400. ansible_test/_internal/util.py +1 -6
  401. ansible_test/_util/controller/sanity/code-smell/no-get-exception.json +4 -0
  402. ansible_test/_util/controller/sanity/code-smell/replace-urlopen.json +4 -0
  403. ansible_test/_util/controller/sanity/code-smell/use-compat-six.json +4 -0
  404. ansible_test/_util/controller/sanity/mypy/ansible-core.ini +3 -0
  405. ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +2 -0
  406. ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +0 -1
  407. ansible_test/_util/controller/sanity/pylint/config/collection.cfg +1 -0
  408. ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +172 -10
  409. ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +13 -2
  410. ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +7 -1
  411. ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +6 -6
  412. ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +1 -1
  413. ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -1
  414. ansible_test/_util/controller/sanity/yamllint/yamllinter.py +3 -3
  415. ansible_test/_util/controller/tools/collection_detail.py +2 -2
  416. ansible_test/_util/target/common/constants.py +2 -2
  417. ansible_test/_util/target/pytest/plugins/ansible_forked.py +103 -0
  418. ansible_test/_util/target/sanity/import/importer.py +0 -8
  419. ansible_test/_util/target/setup/bootstrap.sh +36 -16
  420. ansible_test/_util/target/setup/quiet_pip.py +0 -4
  421. ansible/modules/_include.py +0 -80
  422. ansible_test/_internal/commands/integration/cloud/foreman.py +0 -102
  423. ansible_test/_util/target/setup/ConfigureRemotingForAnsible.ps1 +0 -435
  424. {ansible_core-2.15.4rc1.data → ansible_core-2.16.0b2.data}/scripts/ansible-test +0 -0
  425. {ansible_core-2.15.4rc1.dist-info → ansible_core-2.16.0b2.dist-info}/WHEEL +0 -0
  426. {ansible_core-2.15.4rc1.dist-info → ansible_core-2.16.0b2.dist-info}/entry_points.txt +0 -0
  427. {ansible_core-2.15.4rc1.dist-info → ansible_core-2.16.0b2.dist-info}/top_level.txt +0 -0
@@ -5,14 +5,31 @@
5
5
  from __future__ import annotations
6
6
 
7
7
  import datetime
8
+ import functools
9
+ import json
8
10
  import re
11
+ import shlex
9
12
  import typing as t
13
+ from tokenize import COMMENT, TokenInfo
10
14
 
11
15
  import astroid
12
16
 
13
- from pylint.interfaces import IAstroidChecker
14
- from pylint.checkers import BaseChecker
15
- from pylint.checkers.utils import check_messages
17
+ # support pylint 2.x and 3.x -- remove when supporting only 3.x
18
+ try:
19
+ from pylint.interfaces import IAstroidChecker, ITokenChecker
20
+ except ImportError:
21
+ class IAstroidChecker:
22
+ """Backwards compatibility for 2.x / 3.x support."""
23
+
24
+ class ITokenChecker:
25
+ """Backwards compatibility for 2.x / 3.x support."""
26
+
27
+ try:
28
+ from pylint.checkers.utils import check_messages
29
+ except ImportError:
30
+ from pylint.checkers.utils import only_required_for_messages as check_messages
31
+
32
+ from pylint.checkers import BaseChecker, BaseTokenChecker
16
33
 
17
34
  from ansible.module_utils.compat.version import LooseVersion
18
35
  from ansible.module_utils.six import string_types
@@ -95,7 +112,7 @@ ANSIBLE_VERSION = LooseVersion('.'.join(ansible_version_raw.split('.')[:3]))
95
112
 
96
113
 
97
114
  def _get_expr_name(node):
98
- """Funciton to get either ``attrname`` or ``name`` from ``node.func.expr``
115
+ """Function to get either ``attrname`` or ``name`` from ``node.func.expr``
99
116
 
100
117
  Created specifically for the case of ``display.deprecated`` or ``self._display.deprecated``
101
118
  """
@@ -106,6 +123,17 @@ def _get_expr_name(node):
106
123
  return node.func.expr.name
107
124
 
108
125
 
126
+ def _get_func_name(node):
127
+ """Function to get either ``attrname`` or ``name`` from ``node.func``
128
+
129
+ Created specifically for the case of ``from ansible.module_utils.common.warnings import deprecate``
130
+ """
131
+ try:
132
+ return node.func.attrname
133
+ except AttributeError:
134
+ return node.func.name
135
+
136
+
109
137
  def parse_isodate(value):
110
138
  """Parse an ISO 8601 date string."""
111
139
  msg = 'Expected ISO 8601 date string (YYYY-MM-DD)'
@@ -118,7 +146,7 @@ def parse_isodate(value):
118
146
  try:
119
147
  return datetime.datetime.strptime(value, '%Y-%m-%d').date()
120
148
  except ValueError:
121
- raise ValueError(msg)
149
+ raise ValueError(msg) from None
122
150
 
123
151
 
124
152
  class AnsibleDeprecatedChecker(BaseChecker):
@@ -160,6 +188,8 @@ class AnsibleDeprecatedChecker(BaseChecker):
160
188
  self.add_message('ansible-deprecated-date', node=node, args=(date,))
161
189
 
162
190
  def _check_version(self, node, version, collection_name):
191
+ if collection_name is None:
192
+ collection_name = 'ansible.builtin'
163
193
  if not isinstance(version, (str, float)):
164
194
  if collection_name == 'ansible.builtin':
165
195
  symbol = 'ansible-invalid-deprecated-version'
@@ -197,14 +227,14 @@ class AnsibleDeprecatedChecker(BaseChecker):
197
227
  @property
198
228
  def collection_name(self) -> t.Optional[str]:
199
229
  """Return the collection name, or None if ansible-core is being tested."""
200
- return self.config.collection_name
230
+ return self.linter.config.collection_name
201
231
 
202
232
  @property
203
233
  def collection_version(self) -> t.Optional[SemanticVersion]:
204
234
  """Return the collection version, or None if ansible-core is being tested."""
205
- if self.config.collection_version is None:
235
+ if self.linter.config.collection_version is None:
206
236
  return None
207
- sem_ver = SemanticVersion(self.config.collection_version)
237
+ sem_ver = SemanticVersion(self.linter.config.collection_version)
208
238
  # Ignore pre-release for version comparison to catch issues before the final release is cut.
209
239
  sem_ver.prerelease = ()
210
240
  return sem_ver
@@ -216,8 +246,9 @@ class AnsibleDeprecatedChecker(BaseChecker):
216
246
  date = None
217
247
  collection_name = None
218
248
  try:
219
- if (node.func.attrname == 'deprecated' and 'display' in _get_expr_name(node) or
220
- node.func.attrname == 'deprecate' and _get_expr_name(node)):
249
+ funcname = _get_func_name(node)
250
+ if (funcname == 'deprecated' and 'display' in _get_expr_name(node) or
251
+ funcname == 'deprecate'):
221
252
  if node.keywords:
222
253
  for keyword in node.keywords:
223
254
  if len(node.keywords) == 1 and keyword.arg is None:
@@ -263,6 +294,137 @@ class AnsibleDeprecatedChecker(BaseChecker):
263
294
  pass
264
295
 
265
296
 
297
+ class AnsibleDeprecatedCommentChecker(BaseTokenChecker):
298
+ """Checks for ``# deprecated:`` comments to ensure that the ``version``
299
+ has not passed or met the time for removal
300
+ """
301
+
302
+ __implements__ = (ITokenChecker,)
303
+
304
+ name = 'deprecated-comment'
305
+ msgs = {
306
+ 'E9601': ("Deprecated core version (%r) found: %s",
307
+ "ansible-deprecated-version-comment",
308
+ "Used when a '# deprecated:' comment specifies a version "
309
+ "less than or equal to the current version of Ansible",
310
+ {'minversion': (2, 6)}),
311
+ 'E9602': ("Deprecated comment contains invalid keys %r",
312
+ "ansible-deprecated-version-comment-invalid-key",
313
+ "Used when a '#deprecated:' comment specifies invalid data",
314
+ {'minversion': (2, 6)}),
315
+ 'E9603': ("Deprecated comment missing version",
316
+ "ansible-deprecated-version-comment-missing-version",
317
+ "Used when a '#deprecated:' comment specifies invalid data",
318
+ {'minversion': (2, 6)}),
319
+ 'E9604': ("Deprecated python version (%r) found: %s",
320
+ "ansible-deprecated-python-version-comment",
321
+ "Used when a '#deprecated:' comment specifies a python version "
322
+ "less than or equal to the minimum python version",
323
+ {'minversion': (2, 6)}),
324
+ 'E9605': ("Deprecated comment contains invalid version %r: %s",
325
+ "ansible-deprecated-version-comment-invalid-version",
326
+ "Used when a '#deprecated:' comment specifies an invalid version",
327
+ {'minversion': (2, 6)}),
328
+ }
329
+
330
+ options = (
331
+ ('min-python-version-db', {
332
+ 'default': None,
333
+ 'type': 'string',
334
+ 'metavar': '<path>',
335
+ 'help': 'The path to the DB mapping paths to minimum Python versions.',
336
+ }),
337
+ )
338
+
339
+ def process_tokens(self, tokens: list[TokenInfo]) -> None:
340
+ for token in tokens:
341
+ if token.type == COMMENT:
342
+ self._process_comment(token)
343
+
344
+ def _deprecated_string_to_dict(self, token: TokenInfo, string: str) -> dict[str, str]:
345
+ valid_keys = {'description', 'core_version', 'python_version'}
346
+ data = dict.fromkeys(valid_keys)
347
+ for opt in shlex.split(string):
348
+ if '=' not in opt:
349
+ data[opt] = None
350
+ continue
351
+ key, _sep, value = opt.partition('=')
352
+ data[key] = value
353
+ if not any((data['core_version'], data['python_version'])):
354
+ self.add_message(
355
+ 'ansible-deprecated-version-comment-missing-version',
356
+ line=token.start[0],
357
+ col_offset=token.start[1],
358
+ )
359
+ bad = set(data).difference(valid_keys)
360
+ if bad:
361
+ self.add_message(
362
+ 'ansible-deprecated-version-comment-invalid-key',
363
+ line=token.start[0],
364
+ col_offset=token.start[1],
365
+ args=(','.join(bad),)
366
+ )
367
+ return data
368
+
369
+ @functools.cached_property
370
+ def _min_python_version_db(self) -> dict[str, str]:
371
+ """A dictionary of absolute file paths and their minimum required Python version."""
372
+ with open(self.linter.config.min_python_version_db) as db_file:
373
+ return json.load(db_file)
374
+
375
+ def _process_python_version(self, token: TokenInfo, data: dict[str, str]) -> None:
376
+ current_file = self.linter.current_file
377
+ check_version = self._min_python_version_db[current_file]
378
+
379
+ try:
380
+ if LooseVersion(data['python_version']) < LooseVersion(check_version):
381
+ self.add_message(
382
+ 'ansible-deprecated-python-version-comment',
383
+ line=token.start[0],
384
+ col_offset=token.start[1],
385
+ args=(
386
+ data['python_version'],
387
+ data['description'] or 'description not provided',
388
+ ),
389
+ )
390
+ except (ValueError, TypeError) as exc:
391
+ self.add_message(
392
+ 'ansible-deprecated-version-comment-invalid-version',
393
+ line=token.start[0],
394
+ col_offset=token.start[1],
395
+ args=(data['python_version'], exc)
396
+ )
397
+
398
+ def _process_core_version(self, token: TokenInfo, data: dict[str, str]) -> None:
399
+ try:
400
+ if ANSIBLE_VERSION >= LooseVersion(data['core_version']):
401
+ self.add_message(
402
+ 'ansible-deprecated-version-comment',
403
+ line=token.start[0],
404
+ col_offset=token.start[1],
405
+ args=(
406
+ data['core_version'],
407
+ data['description'] or 'description not provided',
408
+ )
409
+ )
410
+ except (ValueError, TypeError) as exc:
411
+ self.add_message(
412
+ 'ansible-deprecated-version-comment-invalid-version',
413
+ line=token.start[0],
414
+ col_offset=token.start[1],
415
+ args=(data['core_version'], exc)
416
+ )
417
+
418
+ def _process_comment(self, token: TokenInfo) -> None:
419
+ if token.string.startswith('# deprecated:'):
420
+ data = self._deprecated_string_to_dict(token, token.string[13:].strip())
421
+ if data['core_version']:
422
+ self._process_core_version(token, data)
423
+ if data['python_version']:
424
+ self._process_python_version(token, data)
425
+
426
+
266
427
  def register(linter):
267
428
  """required method to auto register this checker """
268
429
  linter.register_checker(AnsibleDeprecatedChecker(linter))
430
+ linter.register_checker(AnsibleDeprecatedCommentChecker(linter))
@@ -5,10 +5,21 @@
5
5
  from __future__ import annotations
6
6
 
7
7
  import astroid
8
- from pylint.interfaces import IAstroidChecker
8
+
9
+ # support pylint 2.x and 3.x -- remove when supporting only 3.x
10
+ try:
11
+ from pylint.interfaces import IAstroidChecker
12
+ except ImportError:
13
+ class IAstroidChecker:
14
+ """Backwards compatibility for 2.x / 3.x support."""
15
+
16
+ try:
17
+ from pylint.checkers.utils import check_messages
18
+ except ImportError:
19
+ from pylint.checkers.utils import only_required_for_messages as check_messages
20
+
9
21
  from pylint.checkers import BaseChecker
10
22
  from pylint.checkers import utils
11
- from pylint.checkers.utils import check_messages
12
23
 
13
24
  MSGS = {
14
25
  'E9305': ("disabled", # kept for backwards compatibility with inline ignores, remove after 2.14 is EOL
@@ -6,8 +6,14 @@ import typing as t
6
6
 
7
7
  import astroid
8
8
 
9
+ # support pylint 2.x and 3.x -- remove when supporting only 3.x
10
+ try:
11
+ from pylint.interfaces import IAstroidChecker
12
+ except ImportError:
13
+ class IAstroidChecker:
14
+ """Backwards compatibility for 2.x / 3.x support."""
15
+
9
16
  from pylint.checkers import BaseChecker
10
- from pylint.interfaces import IAstroidChecker
11
17
 
12
18
  ANSIBLE_TEST_MODULES_PATH = os.environ['ANSIBLE_TEST_MODULES_PATH']
13
19
  ANSIBLE_TEST_MODULE_UTILS_PATH = os.environ['ANSIBLE_TEST_MODULE_UTILS_PATH']
@@ -808,22 +808,22 @@ class ModuleValidator(Validator):
808
808
  continue
809
809
 
810
810
  if grandchild.id == 'DOCUMENTATION':
811
- docs['DOCUMENTATION']['value'] = child.value.s
811
+ docs['DOCUMENTATION']['value'] = child.value.value
812
812
  docs['DOCUMENTATION']['lineno'] = child.lineno
813
813
  docs['DOCUMENTATION']['end_lineno'] = (
814
- child.lineno + len(child.value.s.splitlines())
814
+ child.lineno + len(child.value.value.splitlines())
815
815
  )
816
816
  elif grandchild.id == 'EXAMPLES':
817
- docs['EXAMPLES']['value'] = child.value.s
817
+ docs['EXAMPLES']['value'] = child.value.value
818
818
  docs['EXAMPLES']['lineno'] = child.lineno
819
819
  docs['EXAMPLES']['end_lineno'] = (
820
- child.lineno + len(child.value.s.splitlines())
820
+ child.lineno + len(child.value.value.splitlines())
821
821
  )
822
822
  elif grandchild.id == 'RETURN':
823
- docs['RETURN']['value'] = child.value.s
823
+ docs['RETURN']['value'] = child.value.value
824
824
  docs['RETURN']['lineno'] = child.lineno
825
825
  docs['RETURN']['end_lineno'] = (
826
- child.lineno + len(child.value.s.splitlines())
826
+ child.lineno + len(child.value.value.splitlines())
827
827
  )
828
828
 
829
829
  return docs
@@ -29,7 +29,7 @@ from contextlib import contextmanager
29
29
  from ansible.executor.powershell.module_manifest import PSModuleDepFinder
30
30
  from ansible.module_utils.basic import FILE_COMMON_ARGUMENTS, AnsibleModule
31
31
  from ansible.module_utils.six import reraise
32
- from ansible.module_utils._text import to_bytes, to_text
32
+ from ansible.module_utils.common.text.converters import to_bytes, to_text
33
33
 
34
34
  from .utils import CaptureStd, find_executable, get_module_name_from_filename
35
35
 
@@ -28,7 +28,7 @@ from io import BytesIO, TextIOWrapper
28
28
  import yaml
29
29
  import yaml.reader
30
30
 
31
- from ansible.module_utils._text import to_text
31
+ from ansible.module_utils.common.text.converters import to_text
32
32
  from ansible.module_utils.basic import AnsibleModule
33
33
  from ansible.module_utils.common.yaml import SafeLoader
34
34
  from ansible.module_utils.six import string_types
@@ -181,15 +181,15 @@ class YamlChecker:
181
181
  if doc_types and target.id not in doc_types:
182
182
  continue
183
183
 
184
- fmt_match = fmt_re.match(statement.value.s.lstrip())
184
+ fmt_match = fmt_re.match(statement.value.value.lstrip())
185
185
  fmt = 'yaml'
186
186
  if fmt_match:
187
187
  fmt = fmt_match.group(1)
188
188
 
189
189
  docs[target.id] = dict(
190
- yaml=statement.value.s,
190
+ yaml=statement.value.value,
191
191
  lineno=statement.lineno,
192
- end_lineno=statement.lineno + len(statement.value.s.splitlines()),
192
+ end_lineno=statement.lineno + len(statement.value.value.splitlines()),
193
193
  fmt=fmt.lower(),
194
194
  )
195
195
 
@@ -50,7 +50,7 @@ def read_manifest_json(collection_path):
50
50
  )
51
51
  validate_version(result['version'])
52
52
  except Exception as ex: # pylint: disable=broad-except
53
- raise Exception('{0}: {1}'.format(os.path.basename(manifest_path), ex))
53
+ raise Exception('{0}: {1}'.format(os.path.basename(manifest_path), ex)) from None
54
54
 
55
55
  return result
56
56
 
@@ -71,7 +71,7 @@ def read_galaxy_yml(collection_path):
71
71
  )
72
72
  validate_version(result['version'])
73
73
  except Exception as ex: # pylint: disable=broad-except
74
- raise Exception('{0}: {1}'.format(os.path.basename(galaxy_path), ex))
74
+ raise Exception('{0}: {1}'.format(os.path.basename(galaxy_path), ex)) from None
75
75
 
76
76
  return result
77
77
 
@@ -7,14 +7,14 @@ __metaclass__ = type
7
7
 
8
8
  REMOTE_ONLY_PYTHON_VERSIONS = (
9
9
  '2.7',
10
- '3.5',
11
10
  '3.6',
12
11
  '3.7',
13
12
  '3.8',
13
+ '3.9',
14
14
  )
15
15
 
16
16
  CONTROLLER_PYTHON_VERSIONS = (
17
- '3.9',
18
17
  '3.10',
19
18
  '3.11',
19
+ '3.12',
20
20
  )
@@ -0,0 +1,103 @@
1
+ """Run each test in its own fork. PYTEST_DONT_REWRITE"""
2
+ # MIT License (see licenses/MIT-license.txt or https://opensource.org/licenses/MIT)
3
+ # Based on code originally from:
4
+ # https://github.com/pytest-dev/pytest-forked
5
+ # https://github.com/pytest-dev/py
6
+ # TIP: Disable pytest-xdist when debugging internal errors in this plugin.
7
+ from __future__ import absolute_import, division, print_function
8
+
9
+ __metaclass__ = type
10
+
11
+ import os
12
+ import pickle
13
+ import tempfile
14
+ import warnings
15
+
16
+ from pytest import Item, hookimpl
17
+
18
+ try:
19
+ from pytest import TestReport
20
+ except ImportError:
21
+ from _pytest.runner import TestReport # Backwards compatibility with pytest < 7. Remove once Python 2.7 is not supported.
22
+
23
+ from _pytest.runner import runtestprotocol
24
+
25
+
26
+ @hookimpl(tryfirst=True)
27
+ def pytest_runtest_protocol(item, nextitem): # type: (Item, Item | None) -> object | None
28
+ """Entry point for enabling this plugin."""
29
+ # This is needed because pytest-xdist creates an OS thread (using execnet).
30
+ # See: https://github.com/pytest-dev/execnet/blob/d6aa1a56773c2e887515d63e50b1d08338cb78a7/execnet/gateway_base.py#L51
31
+ warnings.filterwarnings("ignore", "^This process .* is multi-threaded, use of .* may lead to deadlocks in the child.$", DeprecationWarning)
32
+
33
+ item_hook = item.ihook
34
+ item_hook.pytest_runtest_logstart(nodeid=item.nodeid, location=item.location)
35
+
36
+ reports = run_item(item, nextitem)
37
+
38
+ for report in reports:
39
+ item_hook.pytest_runtest_logreport(report=report)
40
+
41
+ item_hook.pytest_runtest_logfinish(nodeid=item.nodeid, location=item.location)
42
+
43
+ return True
44
+
45
+
46
+ def run_item(item, nextitem): # type: (Item, Item | None) -> list[TestReport]
47
+ """Run the item in a child process and return a list of reports."""
48
+ with tempfile.NamedTemporaryFile() as temp_file:
49
+ pid = os.fork()
50
+
51
+ if not pid:
52
+ temp_file.delete = False
53
+ run_child(item, nextitem, temp_file.name)
54
+
55
+ return run_parent(item, pid, temp_file.name)
56
+
57
+
58
+ def run_child(item, nextitem, result_path): # type: (Item, Item | None, str) -> None
59
+ """Run the item, record the result and exit. Called in the child process."""
60
+ with warnings.catch_warnings(record=True) as captured_warnings:
61
+ reports = runtestprotocol(item, nextitem=nextitem, log=False)
62
+
63
+ with open(result_path, "wb") as result_file:
64
+ pickle.dump((reports, captured_warnings), result_file)
65
+
66
+ os._exit(0) # noqa
67
+
68
+
69
+ def run_parent(item, pid, result_path): # type: (Item, int, str) -> list[TestReport]
70
+ """Wait for the child process to exit and return the test reports. Called in the parent process."""
71
+ exit_code = waitstatus_to_exitcode(os.waitpid(pid, 0)[1])
72
+
73
+ if exit_code:
74
+ reason = "Test CRASHED with exit code {}.".format(exit_code)
75
+ report = TestReport(item.nodeid, item.location, {x: 1 for x in item.keywords}, "failed", reason, "call", user_properties=item.user_properties)
76
+
77
+ if item.get_closest_marker("xfail"):
78
+ report.outcome = "skipped"
79
+ report.wasxfail = reason
80
+
81
+ reports = [report]
82
+ else:
83
+ with open(result_path, "rb") as result_file:
84
+ reports, captured_warnings = pickle.load(result_file) # type: list[TestReport], list[warnings.WarningMessage]
85
+
86
+ for warning in captured_warnings:
87
+ warnings.warn_explicit(warning.message, warning.category, warning.filename, warning.lineno)
88
+
89
+ return reports
90
+
91
+
92
+ def waitstatus_to_exitcode(status): # type: (int) -> int
93
+ """Convert a wait status to an exit code."""
94
+ # This function was added in Python 3.9.
95
+ # See: https://docs.python.org/3/library/os.html#os.waitstatus_to_exitcode
96
+
97
+ if os.WIFEXITED(status):
98
+ return os.WEXITSTATUS(status)
99
+
100
+ if os.WIFSIGNALED(status):
101
+ return -os.WTERMSIG(status)
102
+
103
+ raise ValueError(status)
@@ -552,14 +552,6 @@ def main():
552
552
  "Python 2 is no longer supported by the Python core team. Support for it is now deprecated in cryptography,"
553
553
  " and will be removed in the next release.")
554
554
 
555
- if sys.version_info[:2] == (3, 5):
556
- warnings.filterwarnings(
557
- "ignore",
558
- "Python 3.5 support will be dropped in the next release ofcryptography. Please upgrade your Python.")
559
- warnings.filterwarnings(
560
- "ignore",
561
- "Python 3.5 support will be dropped in the next release of cryptography. Please upgrade your Python.")
562
-
563
555
  try:
564
556
  yield
565
557
  finally:
@@ -53,7 +53,7 @@ install_pip() {
53
53
  pip_bootstrap_url="https://ci-files.testing.ansible.com/ansible-test/get-pip-20.3.4.py"
54
54
  ;;
55
55
  *)
56
- pip_bootstrap_url="https://ci-files.testing.ansible.com/ansible-test/get-pip-21.3.1.py"
56
+ pip_bootstrap_url="https://ci-files.testing.ansible.com/ansible-test/get-pip-23.1.2.py"
57
57
  ;;
58
58
  esac
59
59
 
@@ -163,8 +163,6 @@ bootstrap_remote_freebsd()
163
163
  # Declare platform/python version combinations which do not have supporting OS packages available.
164
164
  # For these combinations ansible-test will use pip to install the requirements instead.
165
165
  case "${platform_version}/${python_version}" in
166
- "12.4/3.9")
167
- ;;
168
166
  *)
169
167
  jinja2_pkg="" # not available
170
168
  cryptography_pkg="" # not available
@@ -261,7 +259,7 @@ bootstrap_remote_rhel_8()
261
259
  if [ "${python_version}" = "3.6" ]; then
262
260
  py_pkg_prefix="python3"
263
261
  else
264
- py_pkg_prefix="python${python_package_version}"
262
+ py_pkg_prefix="python${python_version}"
265
263
  fi
266
264
 
267
265
  packages="
@@ -269,6 +267,14 @@ bootstrap_remote_rhel_8()
269
267
  ${py_pkg_prefix}-devel
270
268
  "
271
269
 
270
+ # pip isn't included in the Python devel package under Python 3.11
271
+ if [ "${python_version}" != "3.6" ]; then
272
+ packages="
273
+ ${packages}
274
+ ${py_pkg_prefix}-pip
275
+ "
276
+ fi
277
+
272
278
  # Jinja2 is not installed with an OS package since the provided version is too old.
273
279
  # Instead, ansible-test will install it using pip.
274
280
  if [ "${controller}" ]; then
@@ -278,9 +284,19 @@ bootstrap_remote_rhel_8()
278
284
  "
279
285
  fi
280
286
 
287
+ # Python 3.11 isn't a module like the earlier versions
288
+ if [ "${python_version}" = "3.6" ]; then
289
+ while true; do
290
+ # shellcheck disable=SC2086
291
+ yum module install -q -y "python${python_package_version}" \
292
+ && break
293
+ echo "Failed to install packages. Sleeping before trying again..."
294
+ sleep 10
295
+ done
296
+ fi
297
+
281
298
  while true; do
282
299
  # shellcheck disable=SC2086
283
- yum module install -q -y "python${python_package_version}" && \
284
300
  yum install -q -y ${packages} \
285
301
  && break
286
302
  echo "Failed to install packages. Sleeping before trying again..."
@@ -292,22 +308,34 @@ bootstrap_remote_rhel_8()
292
308
 
293
309
  bootstrap_remote_rhel_9()
294
310
  {
295
- py_pkg_prefix="python3"
311
+ if [ "${python_version}" = "3.9" ]; then
312
+ py_pkg_prefix="python3"
313
+ else
314
+ py_pkg_prefix="python${python_version}"
315
+ fi
296
316
 
297
317
  packages="
298
318
  gcc
299
319
  ${py_pkg_prefix}-devel
300
320
  "
301
321
 
322
+ # pip is not included in the Python devel package under Python 3.11
323
+ if [ "${python_version}" != "3.9" ]; then
324
+ packages="
325
+ ${packages}
326
+ ${py_pkg_prefix}-pip
327
+ "
328
+ fi
329
+
302
330
  # Jinja2 is not installed with an OS package since the provided version is too old.
303
331
  # Instead, ansible-test will install it using pip.
332
+ # packaging and resolvelib are missing for Python 3.11 (and possible later) so we just
333
+ # skip them and let ansible-test install them from PyPI.
304
334
  if [ "${controller}" ]; then
305
335
  packages="
306
336
  ${packages}
307
337
  ${py_pkg_prefix}-cryptography
308
- ${py_pkg_prefix}-packaging
309
338
  ${py_pkg_prefix}-pyyaml
310
- ${py_pkg_prefix}-resolvelib
311
339
  "
312
340
  fi
313
341
 
@@ -387,14 +415,6 @@ bootstrap_remote_ubuntu()
387
415
  echo "Failed to install packages. Sleeping before trying again..."
388
416
  sleep 10
389
417
  done
390
-
391
- if [ "${controller}" ]; then
392
- if [ "${platform_version}/${python_version}" = "20.04/3.9" ]; then
393
- # Install pyyaml using pip so libyaml support is available on Python 3.9.
394
- # The OS package install (which is installed by default) only has a .so file for Python 3.8.
395
- pip_install "--upgrade pyyaml"
396
- fi
397
- fi
398
418
  }
399
419
 
400
420
  bootstrap_docker()
@@ -27,10 +27,6 @@ WARNING_MESSAGE_FILTERS = (
27
27
  # pip 21.0 will drop support for Python 2.7 in January 2021.
28
28
  # More details about Python 2 support in pip, can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support
29
29
  'DEPRECATION: Python 2.7 reached the end of its life ',
30
-
31
- # DEPRECATION: Python 3.5 reached the end of its life on September 13th, 2020. Please upgrade your Python as Python 3.5 is no longer maintained.
32
- # pip 21.0 will drop support for Python 3.5 in January 2021. pip 21.0 will remove support for this functionality.
33
- 'DEPRECATION: Python 3.5 reached the end of its life ',
34
30
  )
35
31
 
36
32