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
@@ -28,7 +28,7 @@ from multiprocessing.queues import Queue
28
28
 
29
29
  from ansible.errors import AnsibleConnectionFailure, AnsibleError
30
30
  from ansible.executor.task_executor import TaskExecutor
31
- from ansible.module_utils._text import to_text
31
+ from ansible.module_utils.common.text.converters import to_text
32
32
  from ansible.utils.display import Display
33
33
  from ansible.utils.multiprocessing import context as multiprocessing_context
34
34
 
@@ -194,12 +194,27 @@ class WorkerProcess(multiprocessing_context.Process): # type: ignore[name-defin
194
194
 
195
195
  # put the result on the result queue
196
196
  display.debug("sending task result for task %s" % self._task._uuid)
197
- self._final_q.send_task_result(
198
- self._host.name,
199
- self._task._uuid,
200
- executor_result,
201
- task_fields=self._task.dump_attrs(),
202
- )
197
+ try:
198
+ self._final_q.send_task_result(
199
+ self._host.name,
200
+ self._task._uuid,
201
+ executor_result,
202
+ task_fields=self._task.dump_attrs(),
203
+ )
204
+ except Exception as e:
205
+ display.debug(f'failed to send task result ({e}), sending surrogate result')
206
+ self._final_q.send_task_result(
207
+ self._host.name,
208
+ self._task._uuid,
209
+ # Overriding the task result, to represent the failure
210
+ {
211
+ 'failed': True,
212
+ 'msg': f'{e}',
213
+ 'exception': traceback.format_exc(),
214
+ },
215
+ # The failure pickling may have been caused by the task attrs, omit for safety
216
+ {},
217
+ )
203
218
  display.debug("done sending task result for task %s" % self._task._uuid)
204
219
 
205
220
  except AnsibleConnectionFailure:
@@ -20,7 +20,7 @@ from ansible.executor.task_result import TaskResult
20
20
  from ansible.executor.module_common import get_action_args_with_defaults
21
21
  from ansible.module_utils.parsing.convert_bool import boolean
22
22
  from ansible.module_utils.six import binary_type
23
- from ansible.module_utils._text import to_text, to_native
23
+ from ansible.module_utils.common.text.converters import to_text, to_native
24
24
  from ansible.module_utils.connection import write_to_file_descriptor
25
25
  from ansible.playbook.conditional import Conditional
26
26
  from ansible.playbook.task import Task
@@ -224,14 +224,11 @@ class TaskExecutor:
224
224
  items = None
225
225
  if self._task.loop_with:
226
226
  if self._task.loop_with in self._shared_loader_obj.lookup_loader:
227
- fail = True
228
- if self._task.loop_with == 'first_found':
229
- # first_found loops are special. If the item is undefined then we want to fall through to the next value rather than failing.
230
- fail = False
231
227
 
228
+ # TODO: hardcoded so it fails for non first_found lookups, but thhis shoudl be generalized for those that don't do their own templating
229
+ # lookup prop/attribute?
230
+ fail = bool(self._task.loop_with != 'first_found')
232
231
  loop_terms = listify_lookup_plugin_terms(terms=self._task.loop, templar=templar, fail_on_undefined=fail, convert_bare=False)
233
- if not fail:
234
- loop_terms = [t for t in loop_terms if not templar.is_template(t)]
235
232
 
236
233
  # get lookup
237
234
  mylookup = self._shared_loader_obj.lookup_loader.get(self._task.loop_with, loader=self._loader, templar=templar)
@@ -514,7 +511,7 @@ class TaskExecutor:
514
511
 
515
512
  # if this task is a TaskInclude, we just return now with a success code so the
516
513
  # main thread can expand the task list for the given host
517
- if self._task.action in C._ACTION_ALL_INCLUDE_TASKS:
514
+ if self._task.action in C._ACTION_INCLUDE_TASKS:
518
515
  include_args = self._task.args.copy()
519
516
  include_file = include_args.pop('_raw_params', None)
520
517
  if not include_file:
@@ -598,24 +595,14 @@ class TaskExecutor:
598
595
  # feed back into pc to ensure plugins not using get_option can get correct value
599
596
  self._connection._play_context = self._play_context.set_task_and_variable_override(task=self._task, variables=vars_copy, templar=templar)
600
597
 
601
- # for persistent connections, initialize socket path and start connection manager
602
- if any(((self._connection.supports_persistence and C.USE_PERSISTENT_CONNECTIONS), self._connection.force_persistence)):
603
- self._play_context.timeout = self._connection.get_option('persistent_command_timeout')
604
- display.vvvv('attempting to start connection', host=self._play_context.remote_addr)
605
- display.vvvv('using connection plugin %s' % self._connection.transport, host=self._play_context.remote_addr)
606
-
607
- options = self._connection.get_options()
608
- socket_path = start_connection(self._play_context, options, self._task._uuid)
609
- display.vvvv('local domain socket path is %s' % socket_path, host=self._play_context.remote_addr)
610
- setattr(self._connection, '_socket_path', socket_path)
611
-
598
+ # TODO: eventually remove this block as this should be a 'consequence' of 'forced_local' modules, right now rely on remote_is_local connection
612
599
  # special handling for python interpreter for network_os, default to ansible python unless overridden
613
600
  if 'ansible_python_interpreter' not in cvars and 'ansible_network_os' in cvars and getattr(self._connection, '_remote_is_local', False):
614
601
  # this also avoids 'python discovery'
615
602
  cvars['ansible_python_interpreter'] = sys.executable
616
603
 
617
604
  # get handler
618
- self._handler, module_context = self._get_action_handler_with_module_context(connection=self._connection, templar=templar)
605
+ self._handler, module_context = self._get_action_handler_with_module_context(templar=templar)
619
606
 
620
607
  if module_context is not None:
621
608
  module_defaults_fqcn = module_context.resolved_fqcn
@@ -633,17 +620,11 @@ class TaskExecutor:
633
620
  if omit_token is not None:
634
621
  self._task.args = remove_omit(self._task.args, omit_token)
635
622
 
636
- # Read some values from the task, so that we can modify them if need be
637
- if self._task.until:
638
- retries = self._task.retries
639
- if retries is None:
640
- retries = 3
641
- elif retries <= 0:
642
- retries = 1
643
- else:
644
- retries += 1
645
- else:
646
- retries = 1
623
+ retries = 1 # includes the default actual run + retries set by user/default
624
+ if self._task.retries is not None:
625
+ retries += max(0, self._task.retries)
626
+ elif self._task.until:
627
+ retries += 3 # the default is not set in FA because we need to differentiate "unset" value
647
628
 
648
629
  delay = self._task.delay
649
630
  if delay < 0:
@@ -749,7 +730,7 @@ class TaskExecutor:
749
730
  result['failed'] = False
750
731
 
751
732
  # Make attempts and retries available early to allow their use in changed/failed_when
752
- if self._task.until:
733
+ if retries > 1:
753
734
  result['attempts'] = attempt
754
735
 
755
736
  # set the changed property if it was missing.
@@ -781,7 +762,7 @@ class TaskExecutor:
781
762
 
782
763
  if retries > 1:
783
764
  cond = Conditional(loader=self._loader)
784
- cond.when = self._task.until
765
+ cond.when = self._task.until or [not result['failed']]
785
766
  if cond.evaluate_conditional(templar, vars_copy):
786
767
  break
787
768
  else:
@@ -800,7 +781,7 @@ class TaskExecutor:
800
781
  )
801
782
  )
802
783
  time.sleep(delay)
803
- self._handler = self._get_action_handler(connection=self._connection, templar=templar)
784
+ self._handler = self._get_action_handler(templar=templar)
804
785
  else:
805
786
  if retries > 1:
806
787
  # we ran out of attempts, so mark the result as failed
@@ -1118,13 +1099,13 @@ class TaskExecutor:
1118
1099
 
1119
1100
  return varnames
1120
1101
 
1121
- def _get_action_handler(self, connection, templar):
1102
+ def _get_action_handler(self, templar):
1122
1103
  '''
1123
1104
  Returns the correct action plugin to handle the requestion task action
1124
1105
  '''
1125
- return self._get_action_handler_with_module_context(connection, templar)[0]
1106
+ return self._get_action_handler_with_module_context(templar)[0]
1126
1107
 
1127
- def _get_action_handler_with_module_context(self, connection, templar):
1108
+ def _get_action_handler_with_module_context(self, templar):
1128
1109
  '''
1129
1110
  Returns the correct action plugin to handle the requestion task action and the module context
1130
1111
  '''
@@ -1161,10 +1142,29 @@ class TaskExecutor:
1161
1142
  handler_name = 'ansible.legacy.normal'
1162
1143
  collections = None # until then, we don't want the task's collection list to be consulted; use the builtin
1163
1144
 
1145
+ # networking/psersistent connections handling
1146
+ if any(((self._connection.supports_persistence and C.USE_PERSISTENT_CONNECTIONS), self._connection.force_persistence)):
1147
+
1148
+ # check handler in case we dont need to do all the work to setup persistent connection
1149
+ handler_class = self._shared_loader_obj.action_loader.get(handler_name, class_only=True)
1150
+ if getattr(handler_class, '_requires_connection', True):
1151
+ # for persistent connections, initialize socket path and start connection manager
1152
+ self._play_context.timeout = self._connection.get_option('persistent_command_timeout')
1153
+ display.vvvv('attempting to start connection', host=self._play_context.remote_addr)
1154
+ display.vvvv('using connection plugin %s' % self._connection.transport, host=self._play_context.remote_addr)
1155
+
1156
+ options = self._connection.get_options()
1157
+ socket_path = start_connection(self._play_context, options, self._task._uuid)
1158
+ display.vvvv('local domain socket path is %s' % socket_path, host=self._play_context.remote_addr)
1159
+ setattr(self._connection, '_socket_path', socket_path)
1160
+ else:
1161
+ # TODO: set self._connection to dummy/noop connection, using local for now
1162
+ self._connection = self._get_connection({}, templar, 'local')
1163
+
1164
1164
  handler = self._shared_loader_obj.action_loader.get(
1165
1165
  handler_name,
1166
1166
  task=self._task,
1167
- connection=connection,
1167
+ connection=self._connection,
1168
1168
  play_context=self._play_context,
1169
1169
  loader=self._loader,
1170
1170
  templar=templar,
@@ -1240,8 +1240,7 @@ def start_connection(play_context, options, task_uuid):
1240
1240
  else:
1241
1241
  try:
1242
1242
  result = json.loads(to_text(stderr, errors='surrogate_then_replace'))
1243
- except getattr(json.decoder, 'JSONDecodeError', ValueError):
1244
- # JSONDecodeError only available on Python 3.5+
1243
+ except json.decoder.JSONDecodeError:
1245
1244
  result = {'error': to_text(stderr, errors='surrogate_then_replace')}
1246
1245
 
1247
1246
  if 'messages' in result:
@@ -34,7 +34,7 @@ from ansible.executor.play_iterator import PlayIterator
34
34
  from ansible.executor.stats import AggregateStats
35
35
  from ansible.executor.task_result import TaskResult
36
36
  from ansible.module_utils.six import string_types
37
- from ansible.module_utils._text import to_text, to_native
37
+ from ansible.module_utils.common.text.converters import to_text, to_native
38
38
  from ansible.playbook.play_context import PlayContext
39
39
  from ansible.playbook.task import Task
40
40
  from ansible.plugins.loader import callback_loader, strategy_loader, module_loader
@@ -61,7 +61,8 @@ class CallbackSend:
61
61
 
62
62
 
63
63
  class DisplaySend:
64
- def __init__(self, *args, **kwargs):
64
+ def __init__(self, method, *args, **kwargs):
65
+ self.method = method
65
66
  self.args = args
66
67
  self.kwargs = kwargs
67
68
 
@@ -76,15 +77,14 @@ class PromptSend:
76
77
  complete_input: t.Iterable[bytes] = None
77
78
 
78
79
 
79
- class FinalQueue(multiprocessing.queues.Queue):
80
+ class FinalQueue(multiprocessing.queues.SimpleQueue):
80
81
  def __init__(self, *args, **kwargs):
81
82
  kwargs['ctx'] = multiprocessing_context
82
- super(FinalQueue, self).__init__(*args, **kwargs)
83
+ super().__init__(*args, **kwargs)
83
84
 
84
85
  def send_callback(self, method_name, *args, **kwargs):
85
86
  self.put(
86
87
  CallbackSend(method_name, *args, **kwargs),
87
- block=False
88
88
  )
89
89
 
90
90
  def send_task_result(self, *args, **kwargs):
@@ -94,19 +94,16 @@ class FinalQueue(multiprocessing.queues.Queue):
94
94
  tr = TaskResult(*args, **kwargs)
95
95
  self.put(
96
96
  tr,
97
- block=False
98
97
  )
99
98
 
100
- def send_display(self, *args, **kwargs):
99
+ def send_display(self, method, *args, **kwargs):
101
100
  self.put(
102
- DisplaySend(*args, **kwargs),
103
- block=False
101
+ DisplaySend(method, *args, **kwargs),
104
102
  )
105
103
 
106
104
  def send_prompt(self, **kwargs):
107
105
  self.put(
108
106
  PromptSend(**kwargs),
109
- block=False
110
107
  )
111
108
 
112
109
 
@@ -235,7 +232,7 @@ class TaskQueueManager:
235
232
  callback_name = cnames[0]
236
233
  else:
237
234
  # fallback to 'old loader name'
238
- (callback_name, _) = os.path.splitext(os.path.basename(callback_plugin._original_path))
235
+ (callback_name, ext) = os.path.splitext(os.path.basename(callback_plugin._original_path))
239
236
 
240
237
  display.vvvvv("Attempting to use '%s' callback." % (callback_name))
241
238
  if callback_type == 'stdout':
@@ -27,7 +27,7 @@ import os
27
27
 
28
28
  import ansible.constants as C
29
29
  from ansible import context
30
- from ansible.module_utils._text import to_bytes
30
+ from ansible.module_utils.common.text.converters import to_bytes
31
31
  from ansible.module_utils.common.yaml import yaml_load
32
32
 
33
33
  # default_readme_template
ansible/galaxy/api.py CHANGED
@@ -11,7 +11,6 @@ import functools
11
11
  import hashlib
12
12
  import json
13
13
  import os
14
- import socket
15
14
  import stat
16
15
  import tarfile
17
16
  import time
@@ -28,7 +27,7 @@ from ansible.galaxy.user_agent import user_agent
28
27
  from ansible.module_utils.api import retry_with_delays_and_condition
29
28
  from ansible.module_utils.api import generate_jittered_backoff
30
29
  from ansible.module_utils.six import string_types
31
- from ansible.module_utils._text import to_bytes, to_native, to_text
30
+ from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
32
31
  from ansible.module_utils.urls import open_url, prepare_multipart
33
32
  from ansible.utils.display import Display
34
33
  from ansible.utils.hashing import secure_hash_s
@@ -66,7 +65,7 @@ def should_retry_error(exception):
66
65
 
67
66
  # Handle common URL related errors such as TimeoutError, and BadStatusLine
68
67
  # Note: socket.timeout is only required for Py3.9
69
- if isinstance(orig_exc, (TimeoutError, BadStatusLine, IncompleteRead, socket.timeout)):
68
+ if isinstance(orig_exc, (TimeoutError, BadStatusLine, IncompleteRead)):
70
69
  return True
71
70
 
72
71
  return False
@@ -360,7 +359,8 @@ class GalaxyAPI:
360
359
  valid = False
361
360
  if cache_key in server_cache:
362
361
  expires = datetime.datetime.strptime(server_cache[cache_key]['expires'], iso_datetime_format)
363
- valid = datetime.datetime.utcnow() < expires
362
+ expires = expires.replace(tzinfo=datetime.timezone.utc)
363
+ valid = datetime.datetime.now(datetime.timezone.utc) < expires
364
364
 
365
365
  is_paginated_url = 'page' in query or 'offset' in query
366
366
  if valid and not is_paginated_url:
@@ -385,7 +385,7 @@ class GalaxyAPI:
385
385
 
386
386
  elif not is_paginated_url:
387
387
  # The cache entry had expired or does not exist, start a new blank entry to be filled later.
388
- expires = datetime.datetime.utcnow()
388
+ expires = datetime.datetime.now(datetime.timezone.utc)
389
389
  expires += datetime.timedelta(days=1)
390
390
  server_cache[cache_key] = {
391
391
  'expires': expires.strftime(iso_datetime_format),
@@ -923,10 +923,7 @@ class GalaxyAPI:
923
923
  data = self._call_galaxy(n_collection_url, error_context_msg=error_context_msg, cache=True)
924
924
  self._set_cache()
925
925
 
926
- try:
927
- signatures = data["signatures"]
928
- except KeyError:
926
+ signatures = [signature_info["signature"] for signature_info in data.get("signatures") or []]
927
+ if not signatures:
929
928
  display.vvvv(f"Server {self.api_server} has not signed {namespace}.{name}:{version}")
930
- return []
931
- else:
932
- return [signature_info["signature"] for signature_info in signatures]
929
+ return signatures
@@ -124,7 +124,7 @@ from ansible.galaxy.dependency_resolution.dataclasses import (
124
124
  )
125
125
  from ansible.galaxy.dependency_resolution.versioning import meets_requirements
126
126
  from ansible.plugins.loader import get_all_plugin_loaders
127
- from ansible.module_utils._text import to_bytes, to_native, to_text
127
+ from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
128
128
  from ansible.module_utils.common.collections import is_sequence
129
129
  from ansible.module_utils.common.yaml import yaml_dump
130
130
  from ansible.utils.collection_loader import AnsibleCollectionRef
@@ -1325,6 +1325,8 @@ def _build_collection_tar(
1325
1325
 
1326
1326
  if os.path.islink(b_src_path):
1327
1327
  b_link_target = os.path.realpath(b_src_path)
1328
+ if not os.path.exists(b_link_target):
1329
+ raise AnsibleError(f"Failed to find the target path '{to_native(b_link_target)}' for the symlink '{to_native(b_src_path)}'.")
1328
1330
  if _is_child_path(b_link_target, b_collection_path):
1329
1331
  b_rel_path = os.path.relpath(b_link_target, start=os.path.dirname(b_src_path))
1330
1332
 
@@ -1420,6 +1422,10 @@ def find_existing_collections(path_filter, artifacts_manager, namespace_filter=N
1420
1422
 
1421
1423
  if path_filter and not is_sequence(path_filter):
1422
1424
  path_filter = [path_filter]
1425
+ if namespace_filter and not is_sequence(namespace_filter):
1426
+ namespace_filter = [namespace_filter]
1427
+ if collection_filter and not is_sequence(collection_filter):
1428
+ collection_filter = [collection_filter]
1423
1429
 
1424
1430
  paths = set()
1425
1431
  for path in files('ansible_collections').glob('*/*/'):
@@ -1441,9 +1447,9 @@ def find_existing_collections(path_filter, artifacts_manager, namespace_filter=N
1441
1447
  for path in paths:
1442
1448
  namespace = path.parent.name
1443
1449
  name = path.name
1444
- if namespace_filter and namespace != namespace_filter:
1450
+ if namespace_filter and namespace not in namespace_filter:
1445
1451
  continue
1446
- if collection_filter and name != collection_filter:
1452
+ if collection_filter and name not in collection_filter:
1447
1453
  continue
1448
1454
 
1449
1455
  if dedupe:
@@ -1811,10 +1817,15 @@ def _resolve_depenency_map(
1811
1817
  elif not req.specifier.contains(RESOLVELIB_VERSION.vstring):
1812
1818
  raise AnsibleError(f"ansible-galaxy requires {req.name}{req.specifier}")
1813
1819
 
1820
+ pre_release_hint = '' if allow_pre_release else (
1821
+ 'Hint: Pre-releases hosted on Galaxy or Automation Hub are not '
1822
+ 'installed by default unless a specific version is requested. '
1823
+ 'To enable pre-releases globally, use --pre.'
1824
+ )
1825
+
1814
1826
  collection_dep_resolver = build_collection_dependency_resolver(
1815
1827
  galaxy_apis=galaxy_apis,
1816
1828
  concrete_artifacts_manager=concrete_artifacts_manager,
1817
- user_requirements=requested_requirements,
1818
1829
  preferred_candidates=preferred_candidates,
1819
1830
  with_deps=not no_deps,
1820
1831
  with_pre_releases=allow_pre_release,
@@ -1846,6 +1857,7 @@ def _resolve_depenency_map(
1846
1857
  ),
1847
1858
  conflict_causes,
1848
1859
  ))
1860
+ error_msg_lines.append(pre_release_hint)
1849
1861
  raise AnsibleError('\n'.join(error_msg_lines)) from dep_exc
1850
1862
  except CollectionDependencyInconsistentCandidate as dep_exc:
1851
1863
  parents = [
@@ -1872,6 +1884,7 @@ def _resolve_depenency_map(
1872
1884
  error_msg_lines.append(
1873
1885
  '* {req.fqcn!s}:{req.ver!s}'.format(req=req)
1874
1886
  )
1887
+ error_msg_lines.append(pre_release_hint)
1875
1888
 
1876
1889
  raise AnsibleError('\n'.join(error_msg_lines)) from dep_exc
1877
1890
  except ValueError as exc:
@@ -30,7 +30,7 @@ from ansible.galaxy import get_collections_galaxy_meta_info
30
30
  from ansible.galaxy.api import should_retry_error
31
31
  from ansible.galaxy.dependency_resolution.dataclasses import _GALAXY_YAML
32
32
  from ansible.galaxy.user_agent import user_agent
33
- from ansible.module_utils._text import to_bytes, to_native, to_text
33
+ from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
34
34
  from ansible.module_utils.api import retry_with_delays_and_condition
35
35
  from ansible.module_utils.api import generate_jittered_backoff
36
36
  from ansible.module_utils.common.process import get_bin_path
@@ -140,7 +140,7 @@ class ConcreteArtifactsManager:
140
140
  url, sha256_hash, token = self._galaxy_collection_cache[collection]
141
141
  except KeyError as key_err:
142
142
  raise RuntimeError(
143
- 'The is no known source for {coll!s}'.
143
+ 'There is no known source for {coll!s}'.
144
144
  format(coll=collection),
145
145
  ) from key_err
146
146
 
@@ -702,6 +702,11 @@ def _get_meta_from_installed_dir(
702
702
  def _get_meta_from_tar(
703
703
  b_path, # type: bytes
704
704
  ): # type: (...) -> dict[str, t.Union[str, list[str], dict[str, str], None, t.Type[Sentinel]]]
705
+ if not os.path.exists(b_path):
706
+ raise AnsibleError(
707
+ f"Unable to find collection artifact file at '{to_native(b_path)}'."
708
+ )
709
+
705
710
  if not tarfile.is_tarfile(b_path):
706
711
  raise AnsibleError(
707
712
  "Collection artifact at '{path!s}' is not a valid tar file.".
@@ -18,7 +18,7 @@ if t.TYPE_CHECKING:
18
18
  )
19
19
 
20
20
  from ansible.galaxy.api import GalaxyAPI, GalaxyError
21
- from ansible.module_utils._text import to_text
21
+ from ansible.module_utils.common.text.converters import to_text
22
22
  from ansible.utils.display import Display
23
23
 
24
24
 
@@ -3,7 +3,7 @@
3
3
  Adds a <SERVICE_NAME> service to your [Ansible Container](https://github.com/ansible/ansible-container) project. Run the following commands
4
4
  to install the service:
5
5
 
6
- ```
6
+ ```shell
7
7
  # Set the working directory to your Ansible Container project root
8
8
  $ cd myproject
9
9
 
@@ -15,7 +15,8 @@ $ ansible-container install <USERNAME.ROLE_NAME>
15
15
 
16
16
  - [Ansible Container](https://github.com/ansible/ansible-container)
17
17
  - An existing Ansible Container project. To create a project, simply run the following:
18
- ```
18
+
19
+ ```shell
19
20
  # Create an empty project directory
20
21
  $ mkdir myproject
21
22
 
@@ -28,7 +29,6 @@ $ ansible-container install <USERNAME.ROLE_NAME>
28
29
 
29
30
  - Continue listing any prerequisites here...
30
31
 
31
-
32
32
  ## Role Variables
33
33
 
34
34
  A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set
@@ -45,5 +45,3 @@ BSD
45
45
  ## Author Information
46
46
 
47
47
  An optional section for the role authors to include contact information, or a website (HTML is not allowed).
48
-
49
-
@@ -13,10 +13,7 @@ if t.TYPE_CHECKING:
13
13
  from ansible.galaxy.collection.concrete_artifact_manager import (
14
14
  ConcreteArtifactsManager,
15
15
  )
16
- from ansible.galaxy.dependency_resolution.dataclasses import (
17
- Candidate,
18
- Requirement,
19
- )
16
+ from ansible.galaxy.dependency_resolution.dataclasses import Candidate
20
17
 
21
18
  from ansible.galaxy.collection.galaxy_api_proxy import MultiGalaxyAPIProxy
22
19
  from ansible.galaxy.dependency_resolution.providers import CollectionDependencyProvider
@@ -27,7 +24,6 @@ from ansible.galaxy.dependency_resolution.resolvers import CollectionDependencyR
27
24
  def build_collection_dependency_resolver(
28
25
  galaxy_apis, # type: t.Iterable[GalaxyAPI]
29
26
  concrete_artifacts_manager, # type: ConcreteArtifactsManager
30
- user_requirements, # type: t.Iterable[Requirement]
31
27
  preferred_candidates=None, # type: t.Iterable[Candidate]
32
28
  with_deps=True, # type: bool
33
29
  with_pre_releases=False, # type: bool
@@ -44,7 +40,6 @@ def build_collection_dependency_resolver(
44
40
  CollectionDependencyProvider(
45
41
  apis=MultiGalaxyAPIProxy(galaxy_apis, concrete_artifacts_manager, offline=offline),
46
42
  concrete_artifacts_manager=concrete_artifacts_manager,
47
- user_requirements=user_requirements,
48
43
  preferred_candidates=preferred_candidates,
49
44
  with_deps=with_deps,
50
45
  with_pre_releases=with_pre_releases,
@@ -30,7 +30,7 @@ if t.TYPE_CHECKING:
30
30
  from ansible.errors import AnsibleError, AnsibleAssertionError
31
31
  from ansible.galaxy.api import GalaxyAPI
32
32
  from ansible.galaxy.collection import HAS_PACKAGING, PkgReq
33
- from ansible.module_utils._text import to_bytes, to_native, to_text
33
+ from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
34
34
  from ansible.module_utils.common.arg_spec import ArgumentSpecValidator
35
35
  from ansible.utils.collection_loader import AnsibleCollectionRef
36
36
  from ansible.utils.display import Display
@@ -564,6 +564,27 @@ class _ComputedReqKindsMixin:
564
564
  def is_online_index_pointer(self):
565
565
  return not self.is_concrete_artifact
566
566
 
567
+ @property
568
+ def is_pinned(self):
569
+ """Indicate if the version set is considered pinned.
570
+
571
+ This essentially computes whether the version field of the current
572
+ requirement explicitly requests a specific version and not an allowed
573
+ version range.
574
+
575
+ It is then used to help the resolvelib-based dependency resolver judge
576
+ whether it's acceptable to consider a pre-release candidate version
577
+ despite pre-release installs not being requested by the end-user
578
+ explicitly.
579
+
580
+ See https://github.com/ansible/ansible/pull/81606 for extra context.
581
+ """
582
+ version_string = self.ver[0]
583
+ return version_string.isdigit() or not (
584
+ version_string == '*' or
585
+ version_string.startswith(('<', '>', '!='))
586
+ )
587
+
567
588
  @property
568
589
  def source_info(self):
569
590
  return self._source_info