ansible-core 2.18.5rc1__py3-none-any.whl → 2.19.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.
Files changed (710) hide show
  1. ansible/_internal/__init__.py +53 -0
  2. ansible/_internal/_ansiballz.py +265 -0
  3. ansible/_internal/_collection_proxy.py +47 -0
  4. ansible/_internal/_datatag/__init__.py +0 -0
  5. ansible/_internal/_datatag/_tags.py +130 -0
  6. ansible/_internal/_datatag/_utils.py +19 -0
  7. ansible/_internal/_datatag/_wrappers.py +33 -0
  8. ansible/_internal/_errors/__init__.py +0 -0
  9. ansible/_internal/_errors/_captured.py +128 -0
  10. ansible/_internal/_errors/_handler.py +91 -0
  11. ansible/_internal/_errors/_utils.py +310 -0
  12. ansible/_internal/_json/__init__.py +203 -0
  13. ansible/_internal/_json/_legacy_encoder.py +34 -0
  14. ansible/_internal/_json/_profiles/__init__.py +0 -0
  15. ansible/_internal/_json/_profiles/_cache_persistence.py +55 -0
  16. ansible/_internal/_json/_profiles/_inventory_legacy.py +40 -0
  17. ansible/_internal/_json/_profiles/_legacy.py +197 -0
  18. ansible/_internal/_locking.py +21 -0
  19. ansible/_internal/_plugins/__init__.py +0 -0
  20. ansible/_internal/_plugins/_cache.py +57 -0
  21. ansible/_internal/_task.py +78 -0
  22. ansible/_internal/_templating/__init__.py +10 -0
  23. ansible/_internal/_templating/_access.py +86 -0
  24. ansible/_internal/_templating/_chain_templar.py +63 -0
  25. ansible/_internal/_templating/_datatag.py +95 -0
  26. ansible/_internal/_templating/_engine.py +588 -0
  27. ansible/_internal/_templating/_errors.py +28 -0
  28. ansible/_internal/_templating/_jinja_bits.py +1066 -0
  29. ansible/_internal/_templating/_jinja_common.py +332 -0
  30. ansible/_internal/_templating/_jinja_patches.py +44 -0
  31. ansible/_internal/_templating/_jinja_plugins.py +345 -0
  32. ansible/_internal/_templating/_lazy_containers.py +633 -0
  33. ansible/_internal/_templating/_marker_behaviors.py +103 -0
  34. ansible/_internal/_templating/_transform.py +63 -0
  35. ansible/_internal/_templating/_utils.py +107 -0
  36. ansible/_internal/_wrapt.py +1052 -0
  37. ansible/_internal/_yaml/__init__.py +0 -0
  38. ansible/_internal/_yaml/_constructor.py +240 -0
  39. ansible/_internal/_yaml/_dumper.py +62 -0
  40. ansible/_internal/_yaml/_errors.py +166 -0
  41. ansible/_internal/_yaml/_loader.py +66 -0
  42. ansible/_internal/ansible_collections/ansible/_protomatter/README.md +11 -0
  43. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/debug.py +36 -0
  44. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/apply_trust.py +19 -0
  45. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/dump_object.py +18 -0
  46. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/finalize.py +16 -0
  47. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/origin.py +18 -0
  48. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.py +24 -0
  49. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.yml +33 -0
  50. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/tag_names.py +16 -0
  51. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +17 -0
  52. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +49 -0
  53. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.py +21 -0
  54. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.yml +2 -0
  55. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.py +15 -0
  56. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.yml +19 -0
  57. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.py +18 -0
  58. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.yml +19 -0
  59. ansible/cli/__init__.py +159 -89
  60. ansible/cli/_ssh_askpass.py +47 -0
  61. ansible/cli/adhoc.py +14 -7
  62. ansible/cli/arguments/option_helpers.py +154 -7
  63. ansible/cli/config.py +43 -68
  64. ansible/cli/console.py +10 -8
  65. ansible/cli/doc.py +62 -53
  66. ansible/cli/galaxy.py +27 -20
  67. ansible/cli/inventory.py +28 -26
  68. ansible/cli/playbook.py +4 -12
  69. ansible/cli/pull.py +51 -11
  70. ansible/cli/scripts/ansible_connection_cli_stub.py +7 -7
  71. ansible/cli/vault.py +12 -11
  72. ansible/compat/__init__.py +2 -2
  73. ansible/config/base.yml +166 -112
  74. ansible/config/manager.py +52 -49
  75. ansible/constants.py +3 -4
  76. ansible/errors/__init__.py +277 -235
  77. ansible/executor/interpreter_discovery.py +28 -149
  78. ansible/executor/module_common.py +426 -493
  79. ansible/executor/play_iterator.py +22 -27
  80. ansible/executor/playbook_executor.py +11 -11
  81. ansible/executor/powershell/async_watchdog.ps1 +97 -102
  82. ansible/executor/powershell/async_wrapper.ps1 +202 -151
  83. ansible/executor/powershell/become_wrapper.ps1 +89 -144
  84. ansible/executor/powershell/bootstrap_wrapper.ps1 +24 -9
  85. ansible/executor/powershell/coverage_wrapper.ps1 +82 -135
  86. ansible/executor/powershell/exec_wrapper.ps1 +462 -196
  87. ansible/executor/powershell/module_manifest.py +417 -265
  88. ansible/executor/powershell/module_wrapper.ps1 +169 -186
  89. ansible/executor/powershell/psrp_fetch_file.ps1 +41 -0
  90. ansible/executor/powershell/psrp_put_file.ps1 +122 -0
  91. ansible/executor/powershell/winrm_fetch_file.ps1 +46 -0
  92. ansible/executor/powershell/winrm_put_file.ps1 +36 -0
  93. ansible/executor/process/worker.py +161 -96
  94. ansible/executor/stats.py +5 -5
  95. ansible/executor/task_executor.py +268 -258
  96. ansible/executor/task_queue_manager.py +124 -90
  97. ansible/executor/task_result.py +183 -78
  98. ansible/galaxy/__init__.py +2 -2
  99. ansible/galaxy/api.py +22 -18
  100. ansible/galaxy/collection/__init__.py +1 -1
  101. ansible/galaxy/collection/concrete_artifact_manager.py +8 -11
  102. ansible/galaxy/dependency_resolution/dataclasses.py +14 -4
  103. ansible/galaxy/dependency_resolution/providers.py +1 -1
  104. ansible/galaxy/dependency_resolution/reporters.py +81 -0
  105. ansible/galaxy/role.py +4 -8
  106. ansible/galaxy/token.py +28 -21
  107. ansible/inventory/data.py +47 -57
  108. ansible/inventory/group.py +44 -72
  109. ansible/inventory/helpers.py +9 -0
  110. ansible/inventory/host.py +32 -54
  111. ansible/inventory/manager.py +78 -34
  112. ansible/keyword_desc.yml +1 -1
  113. ansible/module_utils/_internal/__init__.py +55 -0
  114. ansible/module_utils/_internal/_ambient_context.py +58 -0
  115. ansible/module_utils/_internal/_ansiballz.py +133 -0
  116. ansible/module_utils/_internal/_concurrent/_daemon_threading.py +1 -0
  117. ansible/module_utils/_internal/_dataclass_annotation_patch.py +64 -0
  118. ansible/module_utils/_internal/_dataclass_validation.py +217 -0
  119. ansible/module_utils/_internal/_datatag/__init__.py +928 -0
  120. ansible/module_utils/_internal/_datatag/_tags.py +38 -0
  121. ansible/module_utils/_internal/_debugging.py +31 -0
  122. ansible/module_utils/_internal/_errors.py +30 -0
  123. ansible/module_utils/_internal/_json/__init__.py +63 -0
  124. ansible/module_utils/_internal/_json/_legacy_encoder.py +26 -0
  125. ansible/module_utils/_internal/_json/_profiles/__init__.py +410 -0
  126. ansible/module_utils/_internal/_json/_profiles/_fallback_to_str.py +73 -0
  127. ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +31 -0
  128. ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +35 -0
  129. ansible/module_utils/_internal/_json/_profiles/_module_modern_c2m.py +35 -0
  130. ansible/module_utils/_internal/_json/_profiles/_module_modern_m2c.py +33 -0
  131. ansible/module_utils/_internal/_json/_profiles/_tagless.py +50 -0
  132. ansible/module_utils/_internal/_patches/__init__.py +66 -0
  133. ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +55 -0
  134. ansible/module_utils/_internal/_patches/_socket_patch.py +34 -0
  135. ansible/module_utils/_internal/_patches/_sys_intern_patch.py +34 -0
  136. ansible/module_utils/_internal/_plugin_exec_context.py +49 -0
  137. ansible/module_utils/_internal/_testing.py +0 -0
  138. ansible/module_utils/_internal/_traceback.py +89 -0
  139. ansible/module_utils/ansible_release.py +2 -2
  140. ansible/module_utils/api.py +1 -2
  141. ansible/module_utils/basic.py +152 -120
  142. ansible/module_utils/common/_utils.py +24 -28
  143. ansible/module_utils/common/collections.py +1 -2
  144. ansible/module_utils/common/dict_transformations.py +2 -2
  145. ansible/module_utils/common/file.py +2 -2
  146. ansible/module_utils/common/json.py +90 -84
  147. ansible/module_utils/common/locale.py +2 -2
  148. ansible/module_utils/common/messages.py +108 -0
  149. ansible/module_utils/common/parameters.py +27 -24
  150. ansible/module_utils/common/process.py +2 -2
  151. ansible/module_utils/common/respawn.py +41 -19
  152. ansible/module_utils/common/sentinel.py +66 -0
  153. ansible/module_utils/common/sys_info.py +8 -8
  154. ansible/module_utils/common/text/converters.py +16 -37
  155. ansible/module_utils/common/validation.py +35 -24
  156. ansible/module_utils/common/warnings.py +86 -25
  157. ansible/module_utils/common/yaml.py +29 -3
  158. ansible/module_utils/compat/datetime.py +33 -21
  159. ansible/module_utils/compat/paramiko.py +21 -10
  160. ansible/module_utils/compat/typing.py +6 -5
  161. ansible/module_utils/connection.py +2 -2
  162. ansible/module_utils/csharp/Ansible.Basic.cs +14 -11
  163. ansible/module_utils/csharp/Ansible.Become.cs +1 -0
  164. ansible/module_utils/csharp/Ansible._Async.cs +517 -0
  165. ansible/module_utils/datatag.py +46 -0
  166. ansible/module_utils/distro/__init__.py +2 -2
  167. ansible/module_utils/facts/ansible_collector.py +4 -5
  168. ansible/module_utils/facts/collector.py +13 -14
  169. ansible/module_utils/facts/compat.py +4 -4
  170. ansible/module_utils/facts/default_collectors.py +1 -1
  171. ansible/module_utils/facts/hardware/aix.py +34 -0
  172. ansible/module_utils/facts/hardware/base.py +1 -1
  173. ansible/module_utils/facts/hardware/darwin.py +1 -3
  174. ansible/module_utils/facts/hardware/freebsd.py +2 -2
  175. ansible/module_utils/facts/hardware/linux.py +4 -4
  176. ansible/module_utils/facts/namespace.py +1 -1
  177. ansible/module_utils/facts/network/base.py +1 -1
  178. ansible/module_utils/facts/network/fc_wwn.py +1 -2
  179. ansible/module_utils/facts/network/iscsi.py +1 -2
  180. ansible/module_utils/facts/network/nvme.py +1 -2
  181. ansible/module_utils/facts/other/facter.py +1 -2
  182. ansible/module_utils/facts/other/ohai.py +2 -3
  183. ansible/module_utils/facts/system/apparmor.py +1 -2
  184. ansible/module_utils/facts/system/caps.py +1 -1
  185. ansible/module_utils/facts/system/chroot.py +1 -2
  186. ansible/module_utils/facts/system/cmdline.py +1 -2
  187. ansible/module_utils/facts/system/date_time.py +5 -3
  188. ansible/module_utils/facts/system/distribution.py +9 -8
  189. ansible/module_utils/facts/system/dns.py +1 -1
  190. ansible/module_utils/facts/system/env.py +1 -2
  191. ansible/module_utils/facts/system/fips.py +7 -20
  192. ansible/module_utils/facts/system/loadavg.py +1 -2
  193. ansible/module_utils/facts/system/local.py +1 -2
  194. ansible/module_utils/facts/system/lsb.py +1 -2
  195. ansible/module_utils/facts/system/pkg_mgr.py +1 -2
  196. ansible/module_utils/facts/system/platform.py +1 -2
  197. ansible/module_utils/facts/system/python.py +1 -2
  198. ansible/module_utils/facts/system/selinux.py +1 -1
  199. ansible/module_utils/facts/system/service_mgr.py +1 -2
  200. ansible/module_utils/facts/system/ssh_pub_keys.py +1 -1
  201. ansible/module_utils/facts/system/systemd.py +1 -1
  202. ansible/module_utils/facts/system/user.py +1 -2
  203. ansible/module_utils/facts/utils.py +3 -3
  204. ansible/module_utils/facts/virtual/base.py +1 -1
  205. ansible/module_utils/facts/virtual/sunos.py +3 -15
  206. ansible/module_utils/facts/virtual/sysctl.py +3 -16
  207. ansible/module_utils/json_utils.py +2 -2
  208. ansible/module_utils/parsing/convert_bool.py +1 -1
  209. ansible/module_utils/service.py +18 -21
  210. ansible/module_utils/splitter.py +7 -7
  211. ansible/module_utils/testing.py +31 -0
  212. ansible/module_utils/urls.py +60 -31
  213. ansible/modules/add_host.py +4 -4
  214. ansible/modules/apt.py +60 -46
  215. ansible/modules/apt_key.py +19 -12
  216. ansible/modules/apt_repository.py +19 -16
  217. ansible/modules/assemble.py +6 -6
  218. ansible/modules/assert.py +4 -4
  219. ansible/modules/async_status.py +10 -12
  220. ansible/modules/async_wrapper.py +8 -3
  221. ansible/modules/blockinfile.py +6 -7
  222. ansible/modules/command.py +10 -17
  223. ansible/modules/copy.py +57 -144
  224. ansible/modules/cron.py +20 -15
  225. ansible/modules/deb822_repository.py +8 -9
  226. ansible/modules/debconf.py +5 -5
  227. ansible/modules/debug.py +4 -4
  228. ansible/modules/dnf.py +8 -8
  229. ansible/modules/dnf5.py +39 -13
  230. ansible/modules/dpkg_selections.py +4 -4
  231. ansible/modules/expect.py +8 -10
  232. ansible/modules/fail.py +4 -4
  233. ansible/modules/fetch.py +4 -4
  234. ansible/modules/file.py +174 -133
  235. ansible/modules/find.py +19 -17
  236. ansible/modules/gather_facts.py +3 -3
  237. ansible/modules/get_url.py +59 -53
  238. ansible/modules/getent.py +7 -9
  239. ansible/modules/git.py +28 -25
  240. ansible/modules/group.py +6 -6
  241. ansible/modules/group_by.py +4 -4
  242. ansible/modules/hostname.py +13 -29
  243. ansible/modules/import_playbook.py +6 -6
  244. ansible/modules/import_role.py +6 -6
  245. ansible/modules/import_tasks.py +6 -6
  246. ansible/modules/include_role.py +6 -6
  247. ansible/modules/include_tasks.py +6 -6
  248. ansible/modules/include_vars.py +6 -6
  249. ansible/modules/iptables.py +86 -73
  250. ansible/modules/known_hosts.py +10 -10
  251. ansible/modules/lineinfile.py +5 -5
  252. ansible/modules/meta.py +4 -4
  253. ansible/modules/mount_facts.py +2 -2
  254. ansible/modules/package.py +4 -4
  255. ansible/modules/package_facts.py +22 -10
  256. ansible/modules/pause.py +6 -6
  257. ansible/modules/ping.py +6 -6
  258. ansible/modules/pip.py +10 -11
  259. ansible/modules/raw.py +4 -4
  260. ansible/modules/reboot.py +6 -6
  261. ansible/modules/replace.py +9 -13
  262. ansible/modules/rpm_key.py +7 -8
  263. ansible/modules/script.py +4 -4
  264. ansible/modules/service.py +7 -8
  265. ansible/modules/service_facts.py +87 -10
  266. ansible/modules/set_fact.py +5 -5
  267. ansible/modules/set_stats.py +4 -4
  268. ansible/modules/setup.py +2 -2
  269. ansible/modules/shell.py +6 -6
  270. ansible/modules/slurp.py +6 -6
  271. ansible/modules/stat.py +9 -23
  272. ansible/modules/subversion.py +15 -15
  273. ansible/modules/systemd.py +6 -6
  274. ansible/modules/systemd_service.py +6 -6
  275. ansible/modules/sysvinit.py +6 -6
  276. ansible/modules/tempfile.py +5 -6
  277. ansible/modules/template.py +6 -6
  278. ansible/modules/unarchive.py +32 -11
  279. ansible/modules/uri.py +33 -26
  280. ansible/modules/user.py +53 -34
  281. ansible/modules/validate_argument_spec.py +10 -7
  282. ansible/modules/wait_for.py +32 -27
  283. ansible/modules/wait_for_connection.py +6 -6
  284. ansible/modules/yum_repository.py +6 -6
  285. ansible/parsing/ajson.py +14 -32
  286. ansible/parsing/dataloader.py +99 -54
  287. ansible/parsing/mod_args.py +28 -44
  288. ansible/parsing/plugin_docs.py +21 -86
  289. ansible/parsing/quoting.py +1 -1
  290. ansible/parsing/splitter.py +27 -12
  291. ansible/parsing/utils/addresses.py +24 -24
  292. ansible/parsing/utils/jsonify.py +5 -1
  293. ansible/parsing/utils/yaml.py +32 -61
  294. ansible/parsing/vault/__init__.py +319 -87
  295. ansible/parsing/yaml/__init__.py +0 -18
  296. ansible/parsing/yaml/dumper.py +6 -120
  297. ansible/parsing/yaml/loader.py +6 -39
  298. ansible/parsing/yaml/objects.py +43 -335
  299. ansible/playbook/__init__.py +1 -1
  300. ansible/playbook/attribute.py +8 -3
  301. ansible/playbook/base.py +182 -132
  302. ansible/playbook/block.py +26 -24
  303. ansible/playbook/collectionsearch.py +1 -15
  304. ansible/playbook/conditional.py +3 -77
  305. ansible/playbook/handler.py +8 -2
  306. ansible/playbook/helpers.py +41 -53
  307. ansible/playbook/included_file.py +31 -27
  308. ansible/playbook/loop_control.py +2 -2
  309. ansible/playbook/play.py +85 -44
  310. ansible/playbook/play_context.py +12 -17
  311. ansible/playbook/playbook_include.py +14 -15
  312. ansible/playbook/role/__init__.py +24 -26
  313. ansible/playbook/role/definition.py +15 -17
  314. ansible/playbook/role/include.py +2 -4
  315. ansible/playbook/role/metadata.py +10 -11
  316. ansible/playbook/role_include.py +3 -3
  317. ansible/playbook/taggable.py +13 -8
  318. ansible/playbook/task.py +188 -118
  319. ansible/playbook/task_include.py +5 -5
  320. ansible/plugins/__init__.py +68 -21
  321. ansible/plugins/action/__init__.py +209 -176
  322. ansible/plugins/action/add_host.py +1 -1
  323. ansible/plugins/action/assemble.py +1 -1
  324. ansible/plugins/action/assert.py +54 -66
  325. ansible/plugins/action/copy.py +7 -11
  326. ansible/plugins/action/debug.py +37 -31
  327. ansible/plugins/action/dnf.py +3 -4
  328. ansible/plugins/action/fail.py +1 -1
  329. ansible/plugins/action/fetch.py +4 -5
  330. ansible/plugins/action/gather_facts.py +7 -6
  331. ansible/plugins/action/group_by.py +1 -1
  332. ansible/plugins/action/include_vars.py +10 -11
  333. ansible/plugins/action/package.py +3 -6
  334. ansible/plugins/action/pause.py +2 -2
  335. ansible/plugins/action/script.py +15 -8
  336. ansible/plugins/action/service.py +6 -11
  337. ansible/plugins/action/set_fact.py +3 -12
  338. ansible/plugins/action/set_stats.py +3 -8
  339. ansible/plugins/action/template.py +35 -59
  340. ansible/plugins/action/unarchive.py +1 -1
  341. ansible/plugins/action/validate_argument_spec.py +5 -5
  342. ansible/plugins/action/wait_for_connection.py +1 -1
  343. ansible/plugins/become/__init__.py +31 -8
  344. ansible/plugins/become/runas.py +71 -0
  345. ansible/plugins/become/su.py +13 -8
  346. ansible/plugins/become/sudo.py +19 -0
  347. ansible/plugins/cache/__init__.py +35 -44
  348. ansible/plugins/cache/base.py +8 -0
  349. ansible/plugins/cache/jsonfile.py +10 -16
  350. ansible/plugins/cache/memory.py +6 -12
  351. ansible/plugins/callback/__init__.py +284 -179
  352. ansible/plugins/callback/default.py +99 -92
  353. ansible/plugins/callback/junit.py +44 -39
  354. ansible/plugins/callback/minimal.py +28 -25
  355. ansible/plugins/callback/oneline.py +28 -21
  356. ansible/plugins/callback/tree.py +16 -11
  357. ansible/plugins/connection/__init__.py +47 -34
  358. ansible/plugins/connection/local.py +150 -54
  359. ansible/plugins/connection/paramiko_ssh.py +21 -18
  360. ansible/plugins/connection/psrp.py +76 -165
  361. ansible/plugins/connection/ssh.py +301 -78
  362. ansible/plugins/connection/winrm.py +58 -140
  363. ansible/plugins/doc_fragments/action_common_attributes.py +14 -14
  364. ansible/plugins/doc_fragments/action_core.py +6 -6
  365. ansible/plugins/doc_fragments/backup.py +2 -2
  366. ansible/plugins/doc_fragments/checksum_common.py +27 -0
  367. ansible/plugins/doc_fragments/constructed.py +6 -2
  368. ansible/plugins/doc_fragments/decrypt.py +2 -2
  369. ansible/plugins/doc_fragments/default_callback.py +2 -2
  370. ansible/plugins/doc_fragments/files.py +2 -2
  371. ansible/plugins/doc_fragments/inventory_cache.py +2 -2
  372. ansible/plugins/doc_fragments/result_format_callback.py +2 -2
  373. ansible/plugins/doc_fragments/return_common.py +2 -2
  374. ansible/plugins/doc_fragments/template_common.py +4 -4
  375. ansible/plugins/doc_fragments/url.py +17 -1
  376. ansible/plugins/doc_fragments/url_windows.py +2 -2
  377. ansible/plugins/doc_fragments/validate.py +2 -2
  378. ansible/plugins/doc_fragments/vars_plugin_staging.py +2 -2
  379. ansible/plugins/filter/__init__.py +6 -2
  380. ansible/plugins/filter/b64decode.yml +22 -0
  381. ansible/plugins/filter/b64encode.yml +22 -0
  382. ansible/plugins/filter/bool.yml +11 -4
  383. ansible/plugins/filter/core.py +225 -108
  384. ansible/plugins/filter/encryption.py +32 -32
  385. ansible/plugins/filter/flatten.yml +3 -2
  386. ansible/plugins/filter/human_to_bytes.yml +1 -1
  387. ansible/plugins/filter/mathstuff.py +30 -37
  388. ansible/plugins/filter/password_hash.yml +8 -0
  389. ansible/plugins/filter/regex_search.yml +1 -4
  390. ansible/plugins/filter/split.yml +1 -1
  391. ansible/plugins/filter/to_nice_yaml.yml +0 -4
  392. ansible/plugins/filter/to_yaml.yml +0 -4
  393. ansible/plugins/filter/unvault.yml +1 -1
  394. ansible/plugins/filter/urls.py +1 -1
  395. ansible/plugins/filter/urlsplit.py +8 -9
  396. ansible/plugins/filter/vault.yml +14 -9
  397. ansible/plugins/filter/win_basename.yml +6 -1
  398. ansible/plugins/filter/win_dirname.yml +5 -0
  399. ansible/plugins/inventory/__init__.py +97 -77
  400. ansible/plugins/inventory/advanced_host_list.py +7 -5
  401. ansible/plugins/inventory/auto.py +11 -4
  402. ansible/plugins/inventory/constructed.py +21 -24
  403. ansible/plugins/inventory/generator.py +16 -11
  404. ansible/plugins/inventory/host_list.py +7 -5
  405. ansible/plugins/inventory/ini.py +78 -44
  406. ansible/plugins/inventory/script.py +189 -119
  407. ansible/plugins/inventory/toml.py +16 -126
  408. ansible/plugins/inventory/yaml.py +10 -8
  409. ansible/plugins/list.py +3 -3
  410. ansible/plugins/loader.py +197 -82
  411. ansible/plugins/lookup/__init__.py +21 -4
  412. ansible/plugins/lookup/config.py +21 -35
  413. ansible/plugins/lookup/csvfile.py +3 -2
  414. ansible/plugins/lookup/dict.py +1 -6
  415. ansible/plugins/lookup/env.py +12 -9
  416. ansible/plugins/lookup/file.py +5 -8
  417. ansible/plugins/lookup/first_found.py +86 -55
  418. ansible/plugins/lookup/indexed_items.py +1 -10
  419. ansible/plugins/lookup/ini.py +14 -13
  420. ansible/plugins/lookup/items.py +1 -1
  421. ansible/plugins/lookup/lines.py +8 -1
  422. ansible/plugins/lookup/list.py +1 -1
  423. ansible/plugins/lookup/nested.py +2 -18
  424. ansible/plugins/lookup/password.py +5 -5
  425. ansible/plugins/lookup/pipe.py +5 -7
  426. ansible/plugins/lookup/sequence.py +18 -8
  427. ansible/plugins/lookup/subelements.py +1 -4
  428. ansible/plugins/lookup/template.py +42 -36
  429. ansible/plugins/lookup/together.py +0 -12
  430. ansible/plugins/lookup/unvault.py +1 -5
  431. ansible/plugins/lookup/url.py +2 -8
  432. ansible/plugins/lookup/vars.py +16 -24
  433. ansible/plugins/shell/__init__.py +2 -2
  434. ansible/plugins/shell/cmd.py +2 -2
  435. ansible/plugins/shell/powershell.py +39 -22
  436. ansible/plugins/shell/sh.py +3 -2
  437. ansible/plugins/strategy/__init__.py +159 -184
  438. ansible/plugins/strategy/debug.py +2 -2
  439. ansible/plugins/strategy/free.py +16 -31
  440. ansible/plugins/strategy/host_pinned.py +2 -2
  441. ansible/plugins/strategy/linear.py +41 -41
  442. ansible/plugins/terminal/__init__.py +4 -4
  443. ansible/plugins/test/__init__.py +7 -2
  444. ansible/plugins/test/core.py +55 -21
  445. ansible/plugins/test/files.py +1 -1
  446. ansible/plugins/test/mathstuff.py +3 -3
  447. ansible/plugins/test/uri.py +3 -3
  448. ansible/plugins/vars/host_group_vars.py +7 -14
  449. ansible/release.py +2 -2
  450. ansible/template/__init__.py +370 -944
  451. ansible/utils/__init__.py +0 -18
  452. ansible/utils/_ssh_agent.py +657 -0
  453. ansible/utils/collection_loader/__init__.py +52 -5
  454. ansible/utils/collection_loader/_collection_config.py +5 -6
  455. ansible/utils/collection_loader/_collection_finder.py +79 -93
  456. ansible/utils/collection_loader/_collection_meta.py +13 -8
  457. ansible/utils/display.py +433 -63
  458. ansible/utils/encrypt.py +27 -19
  459. ansible/utils/fqcn.py +2 -2
  460. ansible/utils/hashing.py +2 -2
  461. ansible/utils/helpers.py +2 -2
  462. ansible/utils/listify.py +8 -8
  463. ansible/utils/lock.py +2 -2
  464. ansible/utils/path.py +4 -4
  465. ansible/utils/plugin_docs.py +14 -13
  466. ansible/utils/sentinel.py +4 -62
  467. ansible/utils/singleton.py +2 -0
  468. ansible/utils/ssh_functions.py +1 -1
  469. ansible/utils/unsafe_proxy.py +23 -332
  470. ansible/utils/vars.py +51 -8
  471. ansible/utils/version.py +2 -2
  472. ansible/vars/clean.py +5 -5
  473. ansible/vars/hostvars.py +60 -90
  474. ansible/vars/manager.py +206 -282
  475. ansible/vars/reserved.py +8 -9
  476. ansible_core-2.19.0b2.dist-info/BSD-3-Clause.txt +28 -0
  477. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/METADATA +5 -4
  478. ansible_core-2.19.0b2.dist-info/RECORD +1072 -0
  479. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/WHEEL +1 -1
  480. ansible_test/_data/completion/docker.txt +7 -7
  481. ansible_test/_data/completion/remote.txt +6 -6
  482. ansible_test/_data/completion/windows.txt +1 -0
  483. ansible_test/_data/requirements/ansible.txt +2 -2
  484. ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
  485. ansible_test/_data/requirements/sanity.changelog.txt +1 -1
  486. ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
  487. ansible_test/_data/requirements/sanity.pylint.txt +4 -4
  488. ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
  489. ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
  490. ansible_test/_data/requirements/units.txt +1 -0
  491. ansible_test/_internal/__init__.py +1 -0
  492. ansible_test/_internal/ansible_util.py +2 -0
  493. ansible_test/_internal/become.py +1 -0
  494. ansible_test/_internal/bootstrap.py +1 -0
  495. ansible_test/_internal/cache.py +1 -0
  496. ansible_test/_internal/cgroup.py +1 -0
  497. ansible_test/_internal/ci/__init__.py +1 -0
  498. ansible_test/_internal/ci/azp.py +1 -0
  499. ansible_test/_internal/ci/local.py +1 -0
  500. ansible_test/_internal/classification/__init__.py +1 -0
  501. ansible_test/_internal/classification/common.py +1 -0
  502. ansible_test/_internal/classification/csharp.py +1 -0
  503. ansible_test/_internal/classification/powershell.py +1 -0
  504. ansible_test/_internal/classification/python.py +1 -0
  505. ansible_test/_internal/cli/__init__.py +1 -0
  506. ansible_test/_internal/cli/actions.py +1 -0
  507. ansible_test/_internal/cli/argparsing/__init__.py +1 -0
  508. ansible_test/_internal/cli/argparsing/actions.py +1 -0
  509. ansible_test/_internal/cli/argparsing/argcompletion.py +1 -0
  510. ansible_test/_internal/cli/argparsing/parsers.py +1 -0
  511. ansible_test/_internal/cli/commands/__init__.py +11 -0
  512. ansible_test/_internal/cli/commands/coverage/__init__.py +1 -0
  513. ansible_test/_internal/cli/commands/coverage/analyze/__init__.py +1 -0
  514. ansible_test/_internal/cli/commands/coverage/analyze/targets/__init__.py +1 -0
  515. ansible_test/_internal/cli/commands/coverage/analyze/targets/combine.py +1 -0
  516. ansible_test/_internal/cli/commands/coverage/analyze/targets/expand.py +1 -0
  517. ansible_test/_internal/cli/commands/coverage/analyze/targets/filter.py +1 -0
  518. ansible_test/_internal/cli/commands/coverage/analyze/targets/generate.py +1 -0
  519. ansible_test/_internal/cli/commands/coverage/analyze/targets/missing.py +1 -0
  520. ansible_test/_internal/cli/commands/coverage/combine.py +1 -0
  521. ansible_test/_internal/cli/commands/coverage/erase.py +1 -0
  522. ansible_test/_internal/cli/commands/coverage/html.py +1 -0
  523. ansible_test/_internal/cli/commands/coverage/report.py +1 -0
  524. ansible_test/_internal/cli/commands/coverage/xml.py +1 -0
  525. ansible_test/_internal/cli/commands/env.py +1 -0
  526. ansible_test/_internal/cli/commands/integration/__init__.py +1 -0
  527. ansible_test/_internal/cli/commands/integration/network.py +1 -0
  528. ansible_test/_internal/cli/commands/integration/posix.py +1 -0
  529. ansible_test/_internal/cli/commands/integration/windows.py +1 -0
  530. ansible_test/_internal/cli/commands/sanity.py +9 -0
  531. ansible_test/_internal/cli/commands/shell.py +1 -0
  532. ansible_test/_internal/cli/commands/units.py +1 -0
  533. ansible_test/_internal/cli/compat.py +1 -0
  534. ansible_test/_internal/cli/completers.py +1 -0
  535. ansible_test/_internal/cli/converters.py +1 -0
  536. ansible_test/_internal/cli/environments.py +1 -0
  537. ansible_test/_internal/cli/epilog.py +1 -0
  538. ansible_test/_internal/cli/parsers/__init__.py +1 -0
  539. ansible_test/_internal/cli/parsers/base_argument_parsers.py +1 -0
  540. ansible_test/_internal/cli/parsers/helpers.py +1 -0
  541. ansible_test/_internal/cli/parsers/host_config_parsers.py +1 -0
  542. ansible_test/_internal/cli/parsers/key_value_parsers.py +1 -0
  543. ansible_test/_internal/cli/parsers/value_parsers.py +1 -0
  544. ansible_test/_internal/commands/__init__.py +1 -0
  545. ansible_test/_internal/commands/coverage/__init__.py +2 -1
  546. ansible_test/_internal/commands/coverage/analyze/__init__.py +1 -0
  547. ansible_test/_internal/commands/coverage/analyze/targets/__init__.py +1 -0
  548. ansible_test/_internal/commands/coverage/analyze/targets/combine.py +1 -0
  549. ansible_test/_internal/commands/coverage/analyze/targets/expand.py +1 -0
  550. ansible_test/_internal/commands/coverage/analyze/targets/filter.py +1 -0
  551. ansible_test/_internal/commands/coverage/analyze/targets/generate.py +1 -0
  552. ansible_test/_internal/commands/coverage/analyze/targets/missing.py +1 -0
  553. ansible_test/_internal/commands/coverage/combine.py +2 -1
  554. ansible_test/_internal/commands/coverage/erase.py +1 -0
  555. ansible_test/_internal/commands/coverage/html.py +1 -0
  556. ansible_test/_internal/commands/coverage/report.py +1 -0
  557. ansible_test/_internal/commands/coverage/xml.py +1 -0
  558. ansible_test/_internal/commands/env/__init__.py +2 -0
  559. ansible_test/_internal/commands/integration/__init__.py +4 -0
  560. ansible_test/_internal/commands/integration/cloud/__init__.py +1 -0
  561. ansible_test/_internal/commands/integration/cloud/acme.py +2 -1
  562. ansible_test/_internal/commands/integration/cloud/aws.py +1 -0
  563. ansible_test/_internal/commands/integration/cloud/azure.py +1 -0
  564. ansible_test/_internal/commands/integration/cloud/cs.py +1 -0
  565. ansible_test/_internal/commands/integration/cloud/digitalocean.py +1 -0
  566. ansible_test/_internal/commands/integration/cloud/galaxy.py +3 -2
  567. ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -0
  568. ansible_test/_internal/commands/integration/cloud/httptester.py +2 -1
  569. ansible_test/_internal/commands/integration/cloud/nios.py +2 -1
  570. ansible_test/_internal/commands/integration/cloud/opennebula.py +1 -0
  571. ansible_test/_internal/commands/integration/cloud/openshift.py +1 -0
  572. ansible_test/_internal/commands/integration/cloud/scaleway.py +1 -0
  573. ansible_test/_internal/commands/integration/cloud/vcenter.py +1 -0
  574. ansible_test/_internal/commands/integration/cloud/vultr.py +1 -0
  575. ansible_test/_internal/commands/integration/coverage.py +1 -0
  576. ansible_test/_internal/commands/integration/filters.py +1 -0
  577. ansible_test/_internal/commands/integration/network.py +1 -0
  578. ansible_test/_internal/commands/integration/posix.py +1 -0
  579. ansible_test/_internal/commands/integration/windows.py +1 -0
  580. ansible_test/_internal/commands/sanity/__init__.py +16 -1
  581. ansible_test/_internal/commands/sanity/ansible_doc.py +1 -0
  582. ansible_test/_internal/commands/sanity/bin_symlinks.py +1 -0
  583. ansible_test/_internal/commands/sanity/compile.py +1 -0
  584. ansible_test/_internal/commands/sanity/ignores.py +1 -0
  585. ansible_test/_internal/commands/sanity/import.py +1 -0
  586. ansible_test/_internal/commands/sanity/integration_aliases.py +1 -0
  587. ansible_test/_internal/commands/sanity/pep8.py +1 -0
  588. ansible_test/_internal/commands/sanity/pslint.py +1 -0
  589. ansible_test/_internal/commands/sanity/pylint.py +24 -26
  590. ansible_test/_internal/commands/sanity/shellcheck.py +1 -0
  591. ansible_test/_internal/commands/sanity/validate_modules.py +1 -0
  592. ansible_test/_internal/commands/sanity/yamllint.py +1 -0
  593. ansible_test/_internal/commands/shell/__init__.py +1 -0
  594. ansible_test/_internal/commands/units/__init__.py +1 -0
  595. ansible_test/_internal/compat/__init__.py +1 -0
  596. ansible_test/_internal/compat/packaging.py +1 -0
  597. ansible_test/_internal/compat/yaml.py +1 -0
  598. ansible_test/_internal/completion.py +1 -0
  599. ansible_test/_internal/config.py +2 -0
  600. ansible_test/_internal/connections.py +1 -0
  601. ansible_test/_internal/constants.py +1 -0
  602. ansible_test/_internal/containers.py +1 -0
  603. ansible_test/_internal/content_config.py +1 -0
  604. ansible_test/_internal/core_ci.py +1 -0
  605. ansible_test/_internal/coverage_util.py +11 -10
  606. ansible_test/_internal/data.py +1 -0
  607. ansible_test/_internal/delegation.py +1 -0
  608. ansible_test/_internal/dev/__init__.py +1 -0
  609. ansible_test/_internal/dev/container_probe.py +1 -0
  610. ansible_test/_internal/diff.py +3 -2
  611. ansible_test/_internal/docker_util.py +2 -1
  612. ansible_test/_internal/encoding.py +1 -0
  613. ansible_test/_internal/executor.py +1 -0
  614. ansible_test/_internal/git.py +1 -0
  615. ansible_test/_internal/host_configs.py +1 -0
  616. ansible_test/_internal/host_profiles.py +1 -0
  617. ansible_test/_internal/http.py +1 -0
  618. ansible_test/_internal/init.py +1 -0
  619. ansible_test/_internal/inventory.py +35 -3
  620. ansible_test/_internal/io.py +1 -0
  621. ansible_test/_internal/metadata.py +1 -0
  622. ansible_test/_internal/payload.py +1 -0
  623. ansible_test/_internal/provider/__init__.py +1 -0
  624. ansible_test/_internal/provider/layout/__init__.py +1 -0
  625. ansible_test/_internal/provider/layout/ansible.py +1 -0
  626. ansible_test/_internal/provider/layout/collection.py +1 -0
  627. ansible_test/_internal/provider/layout/unsupported.py +1 -0
  628. ansible_test/_internal/provider/source/__init__.py +1 -0
  629. ansible_test/_internal/provider/source/git.py +1 -0
  630. ansible_test/_internal/provider/source/installed.py +1 -0
  631. ansible_test/_internal/provider/source/unsupported.py +1 -0
  632. ansible_test/_internal/provider/source/unversioned.py +1 -0
  633. ansible_test/_internal/provisioning.py +1 -0
  634. ansible_test/_internal/pypi_proxy.py +6 -5
  635. ansible_test/_internal/python_requirements.py +1 -0
  636. ansible_test/_internal/ssh.py +1 -0
  637. ansible_test/_internal/target.py +1 -0
  638. ansible_test/_internal/test.py +3 -2
  639. ansible_test/_internal/thread.py +1 -0
  640. ansible_test/_internal/timeout.py +1 -0
  641. ansible_test/_internal/util.py +1 -0
  642. ansible_test/_internal/util_common.py +5 -2
  643. ansible_test/_internal/venv.py +1 -0
  644. ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +1 -0
  645. ansible_test/_util/controller/sanity/code-smell/changelog/sphinx.py +1 -0
  646. ansible_test/_util/controller/sanity/code-smell/changelog.py +1 -0
  647. ansible_test/_util/controller/sanity/code-smell/empty-init.py +1 -0
  648. ansible_test/_util/controller/sanity/code-smell/line-endings.py +1 -0
  649. ansible_test/_util/controller/sanity/code-smell/no-assert.py +1 -0
  650. ansible_test/_util/controller/sanity/code-smell/no-get-exception.py +1 -0
  651. ansible_test/_util/controller/sanity/code-smell/no-illegal-filenames.py +1 -0
  652. ansible_test/_util/controller/sanity/code-smell/no-smart-quotes.py +1 -0
  653. ansible_test/_util/controller/sanity/code-smell/replace-urlopen.py +1 -0
  654. ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +28 -1
  655. ansible_test/_util/controller/sanity/code-smell/shebang.py +1 -0
  656. ansible_test/_util/controller/sanity/code-smell/symlinks.py +1 -0
  657. ansible_test/_util/controller/sanity/code-smell/use-argspec-type-path.py +1 -0
  658. ansible_test/_util/controller/sanity/code-smell/use-compat-six.py +1 -0
  659. ansible_test/_util/controller/sanity/integration-aliases/yaml_to_json.py +2 -1
  660. ansible_test/_util/controller/sanity/pep8/current-ignore.txt +4 -0
  661. ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +7 -5
  662. ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +7 -5
  663. ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +7 -5
  664. ansible_test/_util/controller/sanity/pylint/config/collection.cfg +3 -5
  665. ansible_test/_util/controller/sanity/pylint/config/default.cfg +7 -7
  666. ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -13
  667. ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +1 -0
  668. ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +1 -8
  669. ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +1 -8
  670. ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +55 -28
  671. ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +12 -5
  672. ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +13 -2
  673. ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -0
  674. ansible_test/_util/controller/sanity/yamllint/yamllinter.py +35 -17
  675. ansible_test/_util/controller/tools/collection_detail.py +1 -0
  676. ansible_test/_util/controller/tools/yaml_to_json.py +2 -1
  677. ansible_test/_util/target/pytest/plugins/ansible_forked.py +6 -1
  678. ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py +2 -1
  679. ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +1 -0
  680. ansible_test/_util/target/sanity/compile/compile.py +1 -0
  681. ansible_test/_util/target/sanity/import/importer.py +15 -16
  682. ansible_test/_util/target/setup/bootstrap.sh +9 -20
  683. ansible_test/_util/target/setup/probe_cgroups.py +1 -0
  684. ansible_test/_util/target/setup/quiet_pip.py +1 -0
  685. ansible_test/_util/target/setup/requirements.py +35 -27
  686. ansible_test/_util/target/tools/virtualenvcheck.py +2 -1
  687. ansible_test/_util/target/tools/yamlcheck.py +2 -1
  688. ansible/compat/selectors.py +0 -32
  689. ansible/errors/yaml_strings.py +0 -138
  690. ansible/executor/action_write_locks.py +0 -44
  691. ansible/executor/discovery/python_target.py +0 -47
  692. ansible/executor/powershell/module_powershell_wrapper.ps1 +0 -86
  693. ansible/executor/powershell/module_script_wrapper.ps1 +0 -22
  694. ansible/module_utils/compat/importlib.py +0 -26
  695. ansible/module_utils/compat/selectors.py +0 -32
  696. ansible/module_utils/pycompat24.py +0 -73
  697. ansible/parsing/yaml/constructor.py +0 -178
  698. ansible/template/native_helpers.py +0 -251
  699. ansible/template/template.py +0 -43
  700. ansible/template/vars.py +0 -77
  701. ansible/utils/native_jinja.py +0 -11
  702. ansible/vars/fact_cache.py +0 -71
  703. ansible_core-2.18.5rc1.dist-info/RECORD +0 -992
  704. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/Apache-License.txt +0 -0
  705. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/COPYING +0 -0
  706. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/MIT-license.txt +0 -0
  707. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/PSF-license.txt +0 -0
  708. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/entry_points.txt +0 -0
  709. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/simplified_bsd.txt +0 -0
  710. {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/top_level.txt +0 -0
@@ -6,10 +6,52 @@
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
- # FIXME: decide what of this we want to actually be public/toplevel, put other stuff on a utility class?
10
- from ._collection_config import AnsibleCollectionConfig
11
- from ._collection_finder import AnsibleCollectionRef
12
- from ansible.module_utils.common.text.converters import to_text
9
+ import typing as t
10
+
11
+
12
+ @t.runtime_checkable
13
+ class _EncryptedStringProtocol(t.Protocol):
14
+ """Protocol representing an `EncryptedString`, since it cannot be imported here."""
15
+
16
+ def _decrypt(self) -> str: ...
17
+
18
+
19
+ def _to_text(value: str | bytes | _EncryptedStringProtocol | None, strict: bool = False) -> str | None:
20
+ """Internal implementation to keep collection loader standalone."""
21
+ # FUTURE: remove this method when _to_bytes is removed
22
+
23
+ if value is None:
24
+ return None
25
+
26
+ if isinstance(value, str):
27
+ return value
28
+
29
+ if isinstance(value, bytes):
30
+ return value.decode(errors='strict' if strict else 'surrogateescape')
31
+
32
+ if isinstance(value, _EncryptedStringProtocol):
33
+ return value._decrypt()
34
+
35
+ raise TypeError(f'unsupported type {type(value)}')
36
+
37
+
38
+ def _to_bytes(value: str | bytes | _EncryptedStringProtocol | None, strict: bool = False) -> bytes | None:
39
+ """Internal implementation to keep collection loader standalone."""
40
+ # FUTURE: remove this method and rely on automatic str -> bytes conversions of filesystem methods instead
41
+
42
+ if value is None:
43
+ return None
44
+
45
+ if isinstance(value, bytes):
46
+ return value
47
+
48
+ if isinstance(value, str):
49
+ return value.encode(errors='strict' if strict else 'surrogateescape')
50
+
51
+ if isinstance(value, _EncryptedStringProtocol):
52
+ return value._decrypt().encode(errors='strict' if strict else 'surrogateescape')
53
+
54
+ raise TypeError(f'unsupported type {type(value)}')
13
55
 
14
56
 
15
57
  def resource_from_fqcr(ref):
@@ -21,5 +63,10 @@ def resource_from_fqcr(ref):
21
63
  :param ref: collection reference to parse
22
64
  :return: the resource as a unicode string
23
65
  """
24
- ref = to_text(ref, errors='strict')
66
+ ref = _to_text(ref, strict=True)
25
67
  return ref.split(u'.')[-1]
68
+
69
+
70
+ # FIXME: decide what of this we want to actually be public/toplevel, put other stuff on a utility class?
71
+ from ._collection_config import AnsibleCollectionConfig
72
+ from ._collection_finder import AnsibleCollectionRef
@@ -6,8 +6,7 @@
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
- from ansible.module_utils.common.text.converters import to_text
10
- from ansible.module_utils.six import add_metaclass
9
+ from . import _to_text
11
10
 
12
11
 
13
12
  class _EventSource:
@@ -61,7 +60,7 @@ class _AnsibleCollectionConfig(type):
61
60
  @property
62
61
  def collection_paths(cls):
63
62
  cls._require_finder()
64
- return [to_text(p) for p in cls._collection_finder._n_collection_paths]
63
+ return [_to_text(p) for p in cls._collection_finder._n_collection_paths]
65
64
 
66
65
  @property
67
66
  def default_collection(cls):
@@ -84,7 +83,7 @@ class _AnsibleCollectionConfig(type):
84
83
  @property
85
84
  def playbook_paths(cls):
86
85
  cls._require_finder()
87
- return [to_text(p) for p in cls._collection_finder._n_playbook_paths]
86
+ return [_to_text(p) for p in cls._collection_finder._n_playbook_paths]
88
87
 
89
88
  @playbook_paths.setter
90
89
  def playbook_paths(cls, value):
@@ -97,6 +96,6 @@ class _AnsibleCollectionConfig(type):
97
96
 
98
97
 
99
98
  # concrete class of our metaclass type that defines the class properties we want
100
- @add_metaclass(_AnsibleCollectionConfig)
101
- class AnsibleCollectionConfig(object):
99
+
100
+ class AnsibleCollectionConfig(object, metaclass=_AnsibleCollectionConfig):
102
101
  pass
@@ -9,28 +9,22 @@ from __future__ import annotations
9
9
  import itertools
10
10
  import os
11
11
  import os.path
12
+ import pathlib
12
13
  import re
13
14
  import sys
14
- from keyword import iskeyword
15
15
 
16
+ from contextlib import contextmanager
17
+ from importlib import import_module, reload as reload_module
18
+ from importlib.machinery import FileFinder
19
+ from importlib.util import find_spec, spec_from_loader
20
+ from keyword import iskeyword
21
+ from types import ModuleType
16
22
 
17
23
  # DO NOT add new non-stdlib import deps here, this loader is used by external tools (eg ansible-test import sanity)
18
24
  # that only allow stdlib and module_utils
19
- from ansible.module_utils.common.text.converters import to_native, to_text, to_bytes
25
+ from . import _to_bytes, _to_text
20
26
  from ._collection_config import AnsibleCollectionConfig
21
27
 
22
- from contextlib import contextmanager
23
- from types import ModuleType
24
-
25
- try:
26
- from importlib import import_module
27
- except ImportError:
28
- def import_module(name): # type: ignore[misc]
29
- __import__(name)
30
- return sys.modules[name]
31
-
32
- from importlib import reload as reload_module
33
-
34
28
  try:
35
29
  try:
36
30
  # Available on Python >= 3.11
@@ -47,31 +41,12 @@ except ImportError:
47
41
  # deprecated: description='TraversableResources fallback' python_version='3.8'
48
42
  TraversableResources = object # type: ignore[assignment,misc]
49
43
 
50
- try:
51
- from importlib.util import find_spec, spec_from_loader
52
- except ImportError:
53
- pass
54
-
55
- try:
56
- from importlib.machinery import FileFinder
57
- except ImportError:
58
- HAS_FILE_FINDER = False
59
- else:
60
- HAS_FILE_FINDER = True
61
-
62
- try:
63
- import pathlib
64
- except ImportError:
65
- pass
66
-
67
44
  # NB: this supports import sanity test providing a different impl
68
45
  try:
69
46
  from ._collection_meta import _meta_yml_to_dict
70
47
  except ImportError:
71
48
  _meta_yml_to_dict = None
72
49
 
73
- is_python_identifier = str.isidentifier # type: ignore[attr-defined]
74
-
75
50
  PB_EXTENSIONS = ('.yml', '.yaml')
76
51
  SYNTHETIC_PACKAGE_NAME = '<ansible_synthetic_collection_package>'
77
52
 
@@ -111,7 +86,7 @@ class _AnsibleNSTraversable:
111
86
  self._paths = [pathlib.Path(p) for p in paths]
112
87
 
113
88
  def __repr__(self):
114
- return "_AnsibleNSTraversable('%s')" % "', '".join(map(to_text, self._paths))
89
+ return "_AnsibleNSTraversable('%s')" % "', '".join(map(_to_text, self._paths))
115
90
 
116
91
  def iterdir(self):
117
92
  return itertools.chain.from_iterable(p.iterdir() for p in self._paths if p.is_dir())
@@ -213,7 +188,7 @@ class _AnsibleTraversableResources(TraversableResources):
213
188
  class _AnsibleCollectionFinder:
214
189
  def __init__(self, paths=None, scan_sys_paths=True):
215
190
  # TODO: accept metadata loader override
216
- self._ansible_pkg_path = to_native(os.path.dirname(to_bytes(sys.modules['ansible'].__file__)))
191
+ self._ansible_pkg_path = _to_text(os.path.dirname(_to_bytes(sys.modules['ansible'].__file__)))
217
192
 
218
193
  if isinstance(paths, str):
219
194
  paths = [paths]
@@ -221,7 +196,7 @@ class _AnsibleCollectionFinder:
221
196
  paths = []
222
197
 
223
198
  # expand any placeholders in configured paths
224
- paths = [os.path.expanduser(to_native(p, errors='surrogate_or_strict')) for p in paths]
199
+ paths = [os.path.expanduser(_to_text(p)) for p in paths]
225
200
 
226
201
  # add syspaths if needed
227
202
  if scan_sys_paths:
@@ -235,7 +210,7 @@ class _AnsibleCollectionFinder:
235
210
  if os.path.basename(p) == 'ansible_collections':
236
211
  p = os.path.dirname(p)
237
212
 
238
- if p not in good_paths and os.path.isdir(to_bytes(os.path.join(p, 'ansible_collections'), errors='surrogate_or_strict')):
213
+ if p not in good_paths and os.path.isdir(_to_bytes(os.path.join(p, 'ansible_collections'))):
239
214
  good_paths.append(p)
240
215
 
241
216
  self._n_configured_paths = good_paths
@@ -244,6 +219,14 @@ class _AnsibleCollectionFinder:
244
219
 
245
220
  self._n_playbook_paths = []
246
221
 
222
+ @classmethod
223
+ def _find_existing_finder(cls) -> _AnsibleCollectionFinder | None:
224
+ for finder in sys.meta_path:
225
+ if isinstance(finder, _AnsibleCollectionFinder):
226
+ return finder
227
+
228
+ return None
229
+
247
230
  @classmethod
248
231
  def _remove(cls):
249
232
  for mps in sys.meta_path:
@@ -273,7 +256,7 @@ class _AnsibleCollectionFinder:
273
256
  AnsibleCollectionConfig.collection_finder = self
274
257
 
275
258
  def _ansible_collection_path_hook(self, path):
276
- path = to_native(path)
259
+ path = _to_text(path)
277
260
  interesting_paths = self._n_cached_collection_qualified_paths
278
261
  if not interesting_paths:
279
262
  interesting_paths = []
@@ -307,7 +290,7 @@ class _AnsibleCollectionFinder:
307
290
  added_paths = set()
308
291
 
309
292
  # de-dupe
310
- self._n_playbook_paths = [os.path.join(to_native(p), 'collections') for p in playbook_paths if not (p in added_paths or added_paths.add(p))]
293
+ self._n_playbook_paths = [os.path.join(_to_text(p), 'collections') for p in playbook_paths if not (p in added_paths or added_paths.add(p))]
311
294
  self._n_cached_collection_paths = None
312
295
  # HACK: playbook CLI sets this relatively late, so we've already loaded some packages whose paths might depend on this. Fix those up.
313
296
  # NB: this should NOT be used for late additions; ideally we'd fix the playbook dir setup earlier in Ansible init
@@ -384,7 +367,7 @@ class _AnsibleCollectionFinder:
384
367
  class _AnsiblePathHookFinder:
385
368
  def __init__(self, collection_finder, pathctx):
386
369
  # when called from a path_hook, find_module doesn't usually get the path arg, so this provides our context
387
- self._pathctx = to_native(pathctx)
370
+ self._pathctx = _to_text(pathctx)
388
371
  self._collection_finder = collection_finder
389
372
  # cache the native FileFinder (take advantage of its filesystem cache for future find/load requests)
390
373
  self._file_finder = None
@@ -434,7 +417,7 @@ class _AnsiblePathHookFinder:
434
417
 
435
418
  if finder is None:
436
419
  return None
437
- elif HAS_FILE_FINDER and isinstance(finder, FileFinder):
420
+ elif isinstance(finder, FileFinder):
438
421
  # this codepath is erroneously used under some cases in py3,
439
422
  # and the find_module method on FileFinder does not accept the path arg
440
423
  # see https://github.com/pypa/setuptools/pull/2918
@@ -480,7 +463,7 @@ class _AnsibleCollectionPkgLoaderBase:
480
463
 
481
464
  self._validate_args()
482
465
 
483
- self._candidate_paths = self._get_candidate_paths([to_native(p) for p in path_list])
466
+ self._candidate_paths = self._get_candidate_paths([_to_text(p) for p in path_list])
484
467
  self._subpackage_search_paths = self._get_subpackage_search_paths(self._candidate_paths)
485
468
 
486
469
  self._validate_final()
@@ -497,7 +480,7 @@ class _AnsibleCollectionPkgLoaderBase:
497
480
  # allow subclasses to customize finding paths
498
481
  def _get_subpackage_search_paths(self, candidate_paths):
499
482
  # filter candidate paths for existence (NB: silently ignoring package init code and same-named modules)
500
- return [p for p in candidate_paths if os.path.isdir(to_bytes(p))]
483
+ return [p for p in candidate_paths if os.path.isdir(_to_bytes(p))]
501
484
 
502
485
  # allow subclasses to customize state validation/manipulation before we return the loader instance
503
486
  def _validate_final(self):
@@ -529,20 +512,20 @@ class _AnsibleCollectionPkgLoaderBase:
529
512
  @staticmethod
530
513
  def _module_file_from_path(leaf_name, path):
531
514
  has_code = True
532
- package_path = os.path.join(to_native(path), to_native(leaf_name))
515
+ package_path = os.path.join(_to_text(path), _to_text(leaf_name))
533
516
  module_path = None
534
517
 
535
518
  # if the submodule is a package, assemble valid submodule paths, but stop looking for a module
536
- if os.path.isdir(to_bytes(package_path)):
519
+ if os.path.isdir(_to_bytes(package_path)):
537
520
  # is there a package init?
538
521
  module_path = os.path.join(package_path, '__init__.py')
539
- if not os.path.isfile(to_bytes(module_path)):
522
+ if not os.path.isfile(_to_bytes(module_path)):
540
523
  module_path = os.path.join(package_path, '__synthetic__')
541
524
  has_code = False
542
525
  else:
543
526
  module_path = package_path + '.py'
544
527
  package_path = None
545
- if not os.path.isfile(to_bytes(module_path)):
528
+ if not os.path.isfile(_to_bytes(module_path)):
546
529
  raise ImportError('{0} not found at {1}'.format(leaf_name, path))
547
530
 
548
531
  return module_path, has_code, package_path
@@ -624,7 +607,7 @@ class _AnsibleCollectionPkgLoaderBase:
624
607
  candidate_paths = [path]
625
608
 
626
609
  for p in candidate_paths:
627
- b_path = to_bytes(p)
610
+ b_path = _to_bytes(p)
628
611
  if os.path.isfile(b_path):
629
612
  with open(b_path, 'rb') as fd:
630
613
  return fd.read()
@@ -734,10 +717,10 @@ class _AnsibleCollectionPkgLoader(_AnsibleCollectionPkgLoaderBase):
734
717
  # ansible.builtin is a synthetic collection, get its routing config from the Ansible distro
735
718
  ansible_pkg_path = os.path.dirname(import_module('ansible').__file__)
736
719
  metadata_path = os.path.join(ansible_pkg_path, 'config/ansible_builtin_runtime.yml')
737
- with open(to_bytes(metadata_path), 'rb') as fd:
720
+ with open(_to_bytes(metadata_path), 'rb') as fd:
738
721
  raw_routing = fd.read()
739
722
  else:
740
- b_routing_meta_path = to_bytes(os.path.join(module.__path__[0], 'meta/runtime.yml'))
723
+ b_routing_meta_path = _to_bytes(os.path.join(module.__path__[0], 'meta/runtime.yml'))
741
724
  if os.path.isfile(b_routing_meta_path):
742
725
  with open(b_routing_meta_path, 'rb') as fd:
743
726
  raw_routing = fd.read()
@@ -748,7 +731,7 @@ class _AnsibleCollectionPkgLoader(_AnsibleCollectionPkgLoaderBase):
748
731
  routing_dict = _meta_yml_to_dict(raw_routing, (collection_name, 'runtime.yml'))
749
732
  module._collection_meta = self._canonicalize_meta(routing_dict)
750
733
  except Exception as ex:
751
- raise ValueError('error parsing collection metadata: {0}'.format(to_native(ex)))
734
+ raise ValueError(f'error parsing collection metadata: {ex}')
752
735
 
753
736
  AnsibleCollectionConfig.on_collection_load.fire(collection_name=collection_name, collection_path=os.path.dirname(module.__file__))
754
737
 
@@ -906,14 +889,14 @@ class _AnsibleInternalRedirectLoader:
906
889
 
907
890
  class AnsibleCollectionRef:
908
891
  # FUTURE: introspect plugin loaders to get these dynamically?
909
- VALID_REF_TYPES = frozenset(to_text(r) for r in ['action', 'become', 'cache', 'callback', 'cliconf', 'connection',
910
- 'doc_fragments', 'filter', 'httpapi', 'inventory', 'lookup',
911
- 'module_utils', 'modules', 'netconf', 'role', 'shell', 'strategy',
912
- 'terminal', 'test', 'vars', 'playbook'])
892
+ VALID_REF_TYPES = frozenset(_to_text(r) for r in ['action', 'become', 'cache', 'callback', 'cliconf', 'connection',
893
+ 'doc_fragments', 'filter', 'httpapi', 'inventory', 'lookup',
894
+ 'module_utils', 'modules', 'netconf', 'role', 'shell', 'strategy',
895
+ 'terminal', 'test', 'vars', 'playbook'])
913
896
 
914
897
  # FIXME: tighten this up to match Python identifier reqs, etc
915
- VALID_SUBDIRS_RE = re.compile(to_text(r'^\w+(\.\w+)*$'))
916
- VALID_FQCR_RE = re.compile(to_text(r'^\w+(\.\w+){2,}$')) # can have 0-N included subdirs as well
898
+ VALID_SUBDIRS_RE = re.compile(_to_text(r'^\w+(\.\w+)*$'))
899
+ VALID_FQCR_RE = re.compile(_to_text(r'^\w+(\.\w+){2,}$')) # can have 0-N included subdirs as well
917
900
 
918
901
  def __init__(self, collection_name, subdirs, resource, ref_type):
919
902
  """
@@ -923,14 +906,14 @@ class AnsibleCollectionRef:
923
906
  :param resource: the name of the resource being references (eg, 'mymodule', 'someaction', 'a_role')
924
907
  :param ref_type: the type of the reference, eg 'module', 'role', 'doc_fragment'
925
908
  """
926
- collection_name = to_text(collection_name, errors='strict')
909
+ collection_name = _to_text(collection_name, strict=True)
927
910
  if subdirs is not None:
928
- subdirs = to_text(subdirs, errors='strict')
929
- resource = to_text(resource, errors='strict')
930
- ref_type = to_text(ref_type, errors='strict')
911
+ subdirs = _to_text(subdirs, strict=True)
912
+ resource = _to_text(resource, strict=True)
913
+ ref_type = _to_text(ref_type, strict=True)
931
914
 
932
915
  if not self.is_valid_collection_name(collection_name):
933
- raise ValueError('invalid collection name (must be of the form namespace.collection): {0}'.format(to_native(collection_name)))
916
+ raise ValueError('invalid collection name (must be of the form namespace.collection): {0}'.format(_to_text(collection_name)))
934
917
 
935
918
  if ref_type not in self.VALID_REF_TYPES:
936
919
  raise ValueError('invalid collection ref_type: {0}'.format(ref_type))
@@ -938,7 +921,7 @@ class AnsibleCollectionRef:
938
921
  self.collection = collection_name
939
922
  if subdirs:
940
923
  if not re.match(self.VALID_SUBDIRS_RE, subdirs):
941
- raise ValueError('invalid subdirs entry: {0} (must be empty/None or of the form subdir1.subdir2)'.format(to_native(subdirs)))
924
+ raise ValueError('invalid subdirs entry: {0} (must be empty/None or of the form subdir1.subdir2)'.format(_to_text(subdirs)))
942
925
  self.subdirs = subdirs
943
926
  else:
944
927
  self.subdirs = u''
@@ -949,7 +932,7 @@ class AnsibleCollectionRef:
949
932
  package_components = [u'ansible_collections', self.collection]
950
933
  fqcr_components = [self.collection]
951
934
 
952
- self.n_python_collection_package_name = to_native('.'.join(package_components))
935
+ self.n_python_collection_package_name = _to_text('.'.join(package_components))
953
936
 
954
937
  if self.ref_type == u'role':
955
938
  package_components.append(u'roles')
@@ -969,7 +952,7 @@ class AnsibleCollectionRef:
969
952
 
970
953
  fqcr_components.append(self.resource)
971
954
 
972
- self.n_python_package_name = to_native('.'.join(package_components))
955
+ self.n_python_package_name = _to_text('.'.join(package_components))
973
956
  self._fqcr = u'.'.join(fqcr_components)
974
957
 
975
958
  def __repr__(self):
@@ -994,10 +977,10 @@ class AnsibleCollectionRef:
994
977
  # ns.coll.subdir1.resource -> ansible_collections.ns.coll.plugins.subdir1.(plugintype).resource
995
978
  # ns.coll.rolename -> ansible_collections.ns.coll.roles.rolename
996
979
  if not AnsibleCollectionRef.is_valid_fqcr(ref):
997
- raise ValueError('{0} is not a valid collection reference'.format(to_native(ref)))
980
+ raise ValueError('{0} is not a valid collection reference'.format(_to_text(ref)))
998
981
 
999
- ref = to_text(ref, errors='strict')
1000
- ref_type = to_text(ref_type, errors='strict')
982
+ ref = _to_text(ref, strict=True)
983
+ ref_type = _to_text(ref_type, strict=True)
1001
984
  ext = ''
1002
985
 
1003
986
  if ref_type == u'playbook' and ref.endswith(PB_EXTENSIONS):
@@ -1042,15 +1025,18 @@ class AnsibleCollectionRef:
1042
1025
  :param legacy_plugin_dir_name: PluginLoader dir name (eg, 'action_plugins', 'library')
1043
1026
  :return: the corresponding plugin ref_type (eg, 'action', 'role')
1044
1027
  """
1045
- legacy_plugin_dir_name = to_text(legacy_plugin_dir_name)
1028
+ if legacy_plugin_dir_name is None:
1029
+ plugin_type = None
1030
+ else:
1031
+ legacy_plugin_dir_name = _to_text(legacy_plugin_dir_name)
1046
1032
 
1047
- plugin_type = legacy_plugin_dir_name.removesuffix(u'_plugins')
1033
+ plugin_type = legacy_plugin_dir_name.removesuffix(u'_plugins')
1048
1034
 
1049
1035
  if plugin_type == u'library':
1050
1036
  plugin_type = u'modules'
1051
1037
 
1052
1038
  if plugin_type not in AnsibleCollectionRef.VALID_REF_TYPES:
1053
- raise ValueError('{0} cannot be mapped to a valid collection ref type'.format(to_native(legacy_plugin_dir_name)))
1039
+ raise ValueError(f'{legacy_plugin_dir_name!r} cannot be mapped to a valid collection ref type')
1054
1040
 
1055
1041
  return plugin_type
1056
1042
 
@@ -1063,7 +1049,7 @@ class AnsibleCollectionRef:
1063
1049
  :return: True if the collection ref passed is well-formed, False otherwise
1064
1050
  """
1065
1051
 
1066
- ref = to_text(ref)
1052
+ ref = _to_text(ref)
1067
1053
 
1068
1054
  if not ref_type:
1069
1055
  return bool(re.match(AnsibleCollectionRef.VALID_FQCR_RE, ref))
@@ -1078,20 +1064,20 @@ class AnsibleCollectionRef:
1078
1064
  :return: True if the collection name passed is well-formed, False otherwise
1079
1065
  """
1080
1066
 
1081
- collection_name = to_text(collection_name)
1067
+ collection_name = _to_text(collection_name)
1082
1068
 
1083
1069
  if collection_name.count(u'.') != 1:
1084
1070
  return False
1085
1071
 
1086
1072
  return all(
1087
1073
  # NOTE: keywords and identifiers are different in different Pythons
1088
- not iskeyword(ns_or_name) and is_python_identifier(ns_or_name)
1074
+ not iskeyword(ns_or_name) and ns_or_name.isidentifier()
1089
1075
  for ns_or_name in collection_name.split(u'.')
1090
1076
  )
1091
1077
 
1092
1078
 
1093
1079
  def _get_collection_path(collection_name):
1094
- collection_name = to_native(collection_name)
1080
+ collection_name = _to_text(collection_name)
1095
1081
  if not collection_name or not isinstance(collection_name, str) or len(collection_name.split('.')) != 2:
1096
1082
  raise ValueError('collection_name must be a non-empty string of the form namespace.collection')
1097
1083
  try:
@@ -1099,7 +1085,7 @@ def _get_collection_path(collection_name):
1099
1085
  except ImportError:
1100
1086
  raise ValueError('unable to locate collection {0}'.format(collection_name))
1101
1087
 
1102
- return to_native(os.path.dirname(to_bytes(collection_pkg.__file__)))
1088
+ return _to_text(os.path.dirname(_to_bytes(collection_pkg.__file__)))
1103
1089
 
1104
1090
 
1105
1091
  def _get_collection_playbook_path(playbook):
@@ -1117,17 +1103,17 @@ def _get_collection_playbook_path(playbook):
1117
1103
  cpath = os.path.join(sys.modules[acr.n_python_collection_package_name].__file__.replace('__synthetic__', 'playbooks'))
1118
1104
 
1119
1105
  if acr.subdirs:
1120
- paths = [to_native(x) for x in acr.subdirs.split(u'.')]
1106
+ paths = [_to_text(x) for x in acr.subdirs.split(u'.')]
1121
1107
  paths.insert(0, cpath)
1122
1108
  cpath = os.path.join(*paths)
1123
1109
 
1124
- path = os.path.join(cpath, to_native(acr.resource))
1125
- if os.path.exists(to_bytes(path)):
1110
+ path = os.path.join(cpath, _to_text(acr.resource))
1111
+ if os.path.exists(_to_bytes(path)):
1126
1112
  return acr.resource, path, acr.collection
1127
1113
  elif not acr.resource.endswith(PB_EXTENSIONS):
1128
1114
  for ext in PB_EXTENSIONS:
1129
- path = os.path.join(cpath, to_native(acr.resource + ext))
1130
- if os.path.exists(to_bytes(path)):
1115
+ path = os.path.join(cpath, _to_text(acr.resource + ext))
1116
+ if os.path.exists(_to_bytes(path)):
1131
1117
  return acr.resource, path, acr.collection
1132
1118
  return None
1133
1119
 
@@ -1162,8 +1148,8 @@ def _get_collection_resource_path(name, ref_type, collection_list=None):
1162
1148
 
1163
1149
  if pkg is not None:
1164
1150
  # the package is now loaded, get the collection's package and ask where it lives
1165
- path = os.path.dirname(to_bytes(sys.modules[acr.n_python_package_name].__file__, errors='surrogate_or_strict'))
1166
- return resource, to_text(path, errors='surrogate_or_strict'), collection_name
1151
+ path = os.path.dirname(_to_bytes(sys.modules[acr.n_python_package_name].__file__))
1152
+ return resource, _to_text(path), collection_name
1167
1153
 
1168
1154
  except (IOError, ModuleNotFoundError) as e:
1169
1155
  continue
@@ -1184,7 +1170,7 @@ def _get_collection_name_from_path(path):
1184
1170
  """
1185
1171
 
1186
1172
  # ensure we compare full paths since pkg path will be abspath
1187
- path = to_native(os.path.abspath(to_bytes(path)))
1173
+ path = _to_text(os.path.abspath(_to_bytes(path)))
1188
1174
 
1189
1175
  path_parts = path.split('/')
1190
1176
  if path_parts.count('ansible_collections') != 1:
@@ -1200,7 +1186,7 @@ def _get_collection_name_from_path(path):
1200
1186
 
1201
1187
  try:
1202
1188
  # we've got a name for it, now see if the path prefix matches what the loader sees
1203
- imported_pkg_path = to_native(os.path.dirname(to_bytes(import_module('ansible_collections.' + candidate_collection_name).__file__)))
1189
+ imported_pkg_path = _to_text(os.path.dirname(_to_bytes(import_module('ansible_collections.' + candidate_collection_name).__file__)))
1204
1190
  except ImportError:
1205
1191
  return None
1206
1192
 
@@ -1209,7 +1195,7 @@ def _get_collection_name_from_path(path):
1209
1195
 
1210
1196
  original_path_prefix = os.path.join('/', *path_parts[0:ac_pos + 3])
1211
1197
 
1212
- imported_pkg_path = to_native(os.path.abspath(to_bytes(imported_pkg_path)))
1198
+ imported_pkg_path = _to_text(os.path.abspath(_to_bytes(imported_pkg_path)))
1213
1199
  if original_path_prefix != imported_pkg_path:
1214
1200
  return None
1215
1201
 
@@ -1251,10 +1237,10 @@ def _iter_modules_impl(paths, prefix=''):
1251
1237
  if not prefix:
1252
1238
  prefix = ''
1253
1239
  else:
1254
- prefix = to_native(prefix)
1240
+ prefix = _to_text(prefix)
1255
1241
  # yield (module_loader, name, ispkg) for each module/pkg under path
1256
1242
  # TODO: implement ignore/silent catch for unreadable?
1257
- for b_path in map(to_bytes, paths):
1243
+ for b_path in map(_to_bytes, paths):
1258
1244
  if not os.path.isdir(b_path):
1259
1245
  continue
1260
1246
  for b_basename in sorted(os.listdir(b_path)):
@@ -1266,22 +1252,22 @@ def _iter_modules_impl(paths, prefix=''):
1266
1252
  continue
1267
1253
 
1268
1254
  # TODO: proper string handling?
1269
- yield prefix + to_native(b_basename), True
1255
+ yield prefix + _to_text(b_basename), True
1270
1256
  else:
1271
1257
  # FIXME: match builtin ordering for package/dir/file, support compiled?
1272
1258
  if b_basename.endswith(b'.py') and b_basename != b'__init__.py':
1273
- yield prefix + to_native(os.path.splitext(b_basename)[0]), False
1259
+ yield prefix + _to_text(os.path.splitext(b_basename)[0]), False
1274
1260
 
1275
1261
 
1276
1262
  def _get_collection_metadata(collection_name):
1277
- collection_name = to_native(collection_name)
1263
+ collection_name = _to_text(collection_name)
1278
1264
  if not collection_name or not isinstance(collection_name, str) or len(collection_name.split('.')) != 2:
1279
1265
  raise ValueError('collection_name must be a non-empty string of the form namespace.collection')
1280
1266
 
1281
1267
  try:
1282
1268
  collection_pkg = import_module('ansible_collections.' + collection_name)
1283
- except ImportError:
1284
- raise ValueError('unable to locate collection {0}'.format(collection_name))
1269
+ except ImportError as ex:
1270
+ raise ValueError('unable to locate collection {0}'.format(collection_name)) from ex
1285
1271
 
1286
1272
  _collection_meta = getattr(collection_pkg, '_collection_meta', None)
1287
1273
 
@@ -6,15 +6,10 @@
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
- try:
10
- from collections.abc import Mapping
11
- except ImportError:
12
- from collections import Mapping # type: ignore[no-redef,attr-defined] # pylint: disable=ansible-bad-import-from
9
+ from collections.abc import Mapping
13
10
 
14
- from ansible.module_utils.common.yaml import yaml_load
15
11
 
16
-
17
- def _meta_yml_to_dict(yaml_string_data, content_id):
12
+ def _meta_yml_to_dict(yaml_string_data: bytes | str, content_id):
18
13
  """
19
14
  Converts string YAML dictionary to a Python dictionary. This function may be monkeypatched to another implementation
20
15
  by some tools (eg the import sanity test).
@@ -23,7 +18,17 @@ def _meta_yml_to_dict(yaml_string_data, content_id):
23
18
  :return: a Python dictionary representing the YAML dictionary content
24
19
  """
25
20
  # NB: content_id is passed in, but not used by this implementation
26
- routing_dict = yaml_load(yaml_string_data)
21
+
22
+ # Import the `yaml` module only when needed, as it is not available for the module/module_utils import sanity tests.
23
+ # This also avoids use of shared YAML infrastructure to eliminate any Ansible dependencies outside the collection loader itself.
24
+ import yaml
25
+
26
+ try:
27
+ from yaml import CSafeLoader as SafeLoader
28
+ except (ImportError, AttributeError):
29
+ from yaml import SafeLoader # type: ignore[assignment]
30
+
31
+ routing_dict = yaml.load(yaml_string_data, Loader=SafeLoader)
27
32
  if not routing_dict:
28
33
  routing_dict = {}
29
34
  if not isinstance(routing_dict, Mapping):