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.
- ansible/_internal/__init__.py +53 -0
- ansible/_internal/_ansiballz.py +265 -0
- ansible/_internal/_collection_proxy.py +47 -0
- ansible/_internal/_datatag/__init__.py +0 -0
- ansible/_internal/_datatag/_tags.py +130 -0
- ansible/_internal/_datatag/_utils.py +19 -0
- ansible/_internal/_datatag/_wrappers.py +33 -0
- ansible/_internal/_errors/__init__.py +0 -0
- ansible/_internal/_errors/_captured.py +128 -0
- ansible/_internal/_errors/_handler.py +91 -0
- ansible/_internal/_errors/_utils.py +310 -0
- ansible/_internal/_json/__init__.py +203 -0
- ansible/_internal/_json/_legacy_encoder.py +34 -0
- ansible/_internal/_json/_profiles/__init__.py +0 -0
- ansible/_internal/_json/_profiles/_cache_persistence.py +55 -0
- ansible/_internal/_json/_profiles/_inventory_legacy.py +40 -0
- ansible/_internal/_json/_profiles/_legacy.py +197 -0
- ansible/_internal/_locking.py +21 -0
- ansible/_internal/_plugins/__init__.py +0 -0
- ansible/_internal/_plugins/_cache.py +57 -0
- ansible/_internal/_task.py +78 -0
- ansible/_internal/_templating/__init__.py +10 -0
- ansible/_internal/_templating/_access.py +86 -0
- ansible/_internal/_templating/_chain_templar.py +63 -0
- ansible/_internal/_templating/_datatag.py +95 -0
- ansible/_internal/_templating/_engine.py +588 -0
- ansible/_internal/_templating/_errors.py +28 -0
- ansible/_internal/_templating/_jinja_bits.py +1066 -0
- ansible/_internal/_templating/_jinja_common.py +332 -0
- ansible/_internal/_templating/_jinja_patches.py +44 -0
- ansible/_internal/_templating/_jinja_plugins.py +345 -0
- ansible/_internal/_templating/_lazy_containers.py +633 -0
- ansible/_internal/_templating/_marker_behaviors.py +103 -0
- ansible/_internal/_templating/_transform.py +63 -0
- ansible/_internal/_templating/_utils.py +107 -0
- ansible/_internal/_wrapt.py +1052 -0
- ansible/_internal/_yaml/__init__.py +0 -0
- ansible/_internal/_yaml/_constructor.py +240 -0
- ansible/_internal/_yaml/_dumper.py +62 -0
- ansible/_internal/_yaml/_errors.py +166 -0
- ansible/_internal/_yaml/_loader.py +66 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/README.md +11 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/debug.py +36 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/apply_trust.py +19 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/dump_object.py +18 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/finalize.py +16 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/origin.py +18 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.py +24 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.yml +33 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/tag_names.py +16 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +17 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +49 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.py +21 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.yml +2 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.py +15 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.yml +19 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.py +18 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.yml +19 -0
- ansible/cli/__init__.py +159 -89
- ansible/cli/_ssh_askpass.py +47 -0
- ansible/cli/adhoc.py +14 -7
- ansible/cli/arguments/option_helpers.py +154 -7
- ansible/cli/config.py +43 -68
- ansible/cli/console.py +10 -8
- ansible/cli/doc.py +62 -53
- ansible/cli/galaxy.py +27 -20
- ansible/cli/inventory.py +28 -26
- ansible/cli/playbook.py +4 -12
- ansible/cli/pull.py +51 -11
- ansible/cli/scripts/ansible_connection_cli_stub.py +7 -7
- ansible/cli/vault.py +12 -11
- ansible/compat/__init__.py +2 -2
- ansible/config/base.yml +166 -112
- ansible/config/manager.py +52 -49
- ansible/constants.py +3 -4
- ansible/errors/__init__.py +277 -235
- ansible/executor/interpreter_discovery.py +28 -149
- ansible/executor/module_common.py +426 -493
- ansible/executor/play_iterator.py +22 -27
- ansible/executor/playbook_executor.py +11 -11
- ansible/executor/powershell/async_watchdog.ps1 +97 -102
- ansible/executor/powershell/async_wrapper.ps1 +202 -151
- ansible/executor/powershell/become_wrapper.ps1 +89 -144
- ansible/executor/powershell/bootstrap_wrapper.ps1 +24 -9
- ansible/executor/powershell/coverage_wrapper.ps1 +82 -135
- ansible/executor/powershell/exec_wrapper.ps1 +462 -196
- ansible/executor/powershell/module_manifest.py +417 -265
- ansible/executor/powershell/module_wrapper.ps1 +169 -186
- ansible/executor/powershell/psrp_fetch_file.ps1 +41 -0
- ansible/executor/powershell/psrp_put_file.ps1 +122 -0
- ansible/executor/powershell/winrm_fetch_file.ps1 +46 -0
- ansible/executor/powershell/winrm_put_file.ps1 +36 -0
- ansible/executor/process/worker.py +161 -96
- ansible/executor/stats.py +5 -5
- ansible/executor/task_executor.py +268 -258
- ansible/executor/task_queue_manager.py +124 -90
- ansible/executor/task_result.py +183 -78
- ansible/galaxy/__init__.py +2 -2
- ansible/galaxy/api.py +22 -18
- ansible/galaxy/collection/__init__.py +1 -1
- ansible/galaxy/collection/concrete_artifact_manager.py +8 -11
- ansible/galaxy/dependency_resolution/dataclasses.py +14 -4
- ansible/galaxy/dependency_resolution/providers.py +1 -1
- ansible/galaxy/dependency_resolution/reporters.py +81 -0
- ansible/galaxy/role.py +4 -8
- ansible/galaxy/token.py +28 -21
- ansible/inventory/data.py +47 -57
- ansible/inventory/group.py +44 -72
- ansible/inventory/helpers.py +9 -0
- ansible/inventory/host.py +32 -54
- ansible/inventory/manager.py +78 -34
- ansible/keyword_desc.yml +1 -1
- ansible/module_utils/_internal/__init__.py +55 -0
- ansible/module_utils/_internal/_ambient_context.py +58 -0
- ansible/module_utils/_internal/_ansiballz.py +133 -0
- ansible/module_utils/_internal/_concurrent/_daemon_threading.py +1 -0
- ansible/module_utils/_internal/_dataclass_annotation_patch.py +64 -0
- ansible/module_utils/_internal/_dataclass_validation.py +217 -0
- ansible/module_utils/_internal/_datatag/__init__.py +928 -0
- ansible/module_utils/_internal/_datatag/_tags.py +38 -0
- ansible/module_utils/_internal/_debugging.py +31 -0
- ansible/module_utils/_internal/_errors.py +30 -0
- ansible/module_utils/_internal/_json/__init__.py +63 -0
- ansible/module_utils/_internal/_json/_legacy_encoder.py +26 -0
- ansible/module_utils/_internal/_json/_profiles/__init__.py +410 -0
- ansible/module_utils/_internal/_json/_profiles/_fallback_to_str.py +73 -0
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +31 -0
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +35 -0
- ansible/module_utils/_internal/_json/_profiles/_module_modern_c2m.py +35 -0
- ansible/module_utils/_internal/_json/_profiles/_module_modern_m2c.py +33 -0
- ansible/module_utils/_internal/_json/_profiles/_tagless.py +50 -0
- ansible/module_utils/_internal/_patches/__init__.py +66 -0
- ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +55 -0
- ansible/module_utils/_internal/_patches/_socket_patch.py +34 -0
- ansible/module_utils/_internal/_patches/_sys_intern_patch.py +34 -0
- ansible/module_utils/_internal/_plugin_exec_context.py +49 -0
- ansible/module_utils/_internal/_testing.py +0 -0
- ansible/module_utils/_internal/_traceback.py +89 -0
- ansible/module_utils/ansible_release.py +2 -2
- ansible/module_utils/api.py +1 -2
- ansible/module_utils/basic.py +152 -120
- ansible/module_utils/common/_utils.py +24 -28
- ansible/module_utils/common/collections.py +1 -2
- ansible/module_utils/common/dict_transformations.py +2 -2
- ansible/module_utils/common/file.py +2 -2
- ansible/module_utils/common/json.py +90 -84
- ansible/module_utils/common/locale.py +2 -2
- ansible/module_utils/common/messages.py +108 -0
- ansible/module_utils/common/parameters.py +27 -24
- ansible/module_utils/common/process.py +2 -2
- ansible/module_utils/common/respawn.py +41 -19
- ansible/module_utils/common/sentinel.py +66 -0
- ansible/module_utils/common/sys_info.py +8 -8
- ansible/module_utils/common/text/converters.py +16 -37
- ansible/module_utils/common/validation.py +35 -24
- ansible/module_utils/common/warnings.py +86 -25
- ansible/module_utils/common/yaml.py +29 -3
- ansible/module_utils/compat/datetime.py +33 -21
- ansible/module_utils/compat/paramiko.py +21 -10
- ansible/module_utils/compat/typing.py +6 -5
- ansible/module_utils/connection.py +2 -2
- ansible/module_utils/csharp/Ansible.Basic.cs +14 -11
- ansible/module_utils/csharp/Ansible.Become.cs +1 -0
- ansible/module_utils/csharp/Ansible._Async.cs +517 -0
- ansible/module_utils/datatag.py +46 -0
- ansible/module_utils/distro/__init__.py +2 -2
- ansible/module_utils/facts/ansible_collector.py +4 -5
- ansible/module_utils/facts/collector.py +13 -14
- ansible/module_utils/facts/compat.py +4 -4
- ansible/module_utils/facts/default_collectors.py +1 -1
- ansible/module_utils/facts/hardware/aix.py +34 -0
- ansible/module_utils/facts/hardware/base.py +1 -1
- ansible/module_utils/facts/hardware/darwin.py +1 -3
- ansible/module_utils/facts/hardware/freebsd.py +2 -2
- ansible/module_utils/facts/hardware/linux.py +4 -4
- ansible/module_utils/facts/namespace.py +1 -1
- ansible/module_utils/facts/network/base.py +1 -1
- ansible/module_utils/facts/network/fc_wwn.py +1 -2
- ansible/module_utils/facts/network/iscsi.py +1 -2
- ansible/module_utils/facts/network/nvme.py +1 -2
- ansible/module_utils/facts/other/facter.py +1 -2
- ansible/module_utils/facts/other/ohai.py +2 -3
- ansible/module_utils/facts/system/apparmor.py +1 -2
- ansible/module_utils/facts/system/caps.py +1 -1
- ansible/module_utils/facts/system/chroot.py +1 -2
- ansible/module_utils/facts/system/cmdline.py +1 -2
- ansible/module_utils/facts/system/date_time.py +5 -3
- ansible/module_utils/facts/system/distribution.py +9 -8
- ansible/module_utils/facts/system/dns.py +1 -1
- ansible/module_utils/facts/system/env.py +1 -2
- ansible/module_utils/facts/system/fips.py +7 -20
- ansible/module_utils/facts/system/loadavg.py +1 -2
- ansible/module_utils/facts/system/local.py +1 -2
- ansible/module_utils/facts/system/lsb.py +1 -2
- ansible/module_utils/facts/system/pkg_mgr.py +1 -2
- ansible/module_utils/facts/system/platform.py +1 -2
- ansible/module_utils/facts/system/python.py +1 -2
- ansible/module_utils/facts/system/selinux.py +1 -1
- ansible/module_utils/facts/system/service_mgr.py +1 -2
- ansible/module_utils/facts/system/ssh_pub_keys.py +1 -1
- ansible/module_utils/facts/system/systemd.py +1 -1
- ansible/module_utils/facts/system/user.py +1 -2
- ansible/module_utils/facts/utils.py +3 -3
- ansible/module_utils/facts/virtual/base.py +1 -1
- ansible/module_utils/facts/virtual/sunos.py +3 -15
- ansible/module_utils/facts/virtual/sysctl.py +3 -16
- ansible/module_utils/json_utils.py +2 -2
- ansible/module_utils/parsing/convert_bool.py +1 -1
- ansible/module_utils/service.py +18 -21
- ansible/module_utils/splitter.py +7 -7
- ansible/module_utils/testing.py +31 -0
- ansible/module_utils/urls.py +60 -31
- ansible/modules/add_host.py +4 -4
- ansible/modules/apt.py +60 -46
- ansible/modules/apt_key.py +19 -12
- ansible/modules/apt_repository.py +19 -16
- ansible/modules/assemble.py +6 -6
- ansible/modules/assert.py +4 -4
- ansible/modules/async_status.py +10 -12
- ansible/modules/async_wrapper.py +8 -3
- ansible/modules/blockinfile.py +6 -7
- ansible/modules/command.py +10 -17
- ansible/modules/copy.py +57 -144
- ansible/modules/cron.py +20 -15
- ansible/modules/deb822_repository.py +8 -9
- ansible/modules/debconf.py +5 -5
- ansible/modules/debug.py +4 -4
- ansible/modules/dnf.py +8 -8
- ansible/modules/dnf5.py +39 -13
- ansible/modules/dpkg_selections.py +4 -4
- ansible/modules/expect.py +8 -10
- ansible/modules/fail.py +4 -4
- ansible/modules/fetch.py +4 -4
- ansible/modules/file.py +174 -133
- ansible/modules/find.py +19 -17
- ansible/modules/gather_facts.py +3 -3
- ansible/modules/get_url.py +59 -53
- ansible/modules/getent.py +7 -9
- ansible/modules/git.py +28 -25
- ansible/modules/group.py +6 -6
- ansible/modules/group_by.py +4 -4
- ansible/modules/hostname.py +13 -29
- ansible/modules/import_playbook.py +6 -6
- ansible/modules/import_role.py +6 -6
- ansible/modules/import_tasks.py +6 -6
- ansible/modules/include_role.py +6 -6
- ansible/modules/include_tasks.py +6 -6
- ansible/modules/include_vars.py +6 -6
- ansible/modules/iptables.py +86 -73
- ansible/modules/known_hosts.py +10 -10
- ansible/modules/lineinfile.py +5 -5
- ansible/modules/meta.py +4 -4
- ansible/modules/mount_facts.py +2 -2
- ansible/modules/package.py +4 -4
- ansible/modules/package_facts.py +22 -10
- ansible/modules/pause.py +6 -6
- ansible/modules/ping.py +6 -6
- ansible/modules/pip.py +10 -11
- ansible/modules/raw.py +4 -4
- ansible/modules/reboot.py +6 -6
- ansible/modules/replace.py +9 -13
- ansible/modules/rpm_key.py +7 -8
- ansible/modules/script.py +4 -4
- ansible/modules/service.py +7 -8
- ansible/modules/service_facts.py +87 -10
- ansible/modules/set_fact.py +5 -5
- ansible/modules/set_stats.py +4 -4
- ansible/modules/setup.py +2 -2
- ansible/modules/shell.py +6 -6
- ansible/modules/slurp.py +6 -6
- ansible/modules/stat.py +9 -23
- ansible/modules/subversion.py +15 -15
- ansible/modules/systemd.py +6 -6
- ansible/modules/systemd_service.py +6 -6
- ansible/modules/sysvinit.py +6 -6
- ansible/modules/tempfile.py +5 -6
- ansible/modules/template.py +6 -6
- ansible/modules/unarchive.py +32 -11
- ansible/modules/uri.py +33 -26
- ansible/modules/user.py +53 -34
- ansible/modules/validate_argument_spec.py +10 -7
- ansible/modules/wait_for.py +32 -27
- ansible/modules/wait_for_connection.py +6 -6
- ansible/modules/yum_repository.py +6 -6
- ansible/parsing/ajson.py +14 -32
- ansible/parsing/dataloader.py +99 -54
- ansible/parsing/mod_args.py +28 -44
- ansible/parsing/plugin_docs.py +21 -86
- ansible/parsing/quoting.py +1 -1
- ansible/parsing/splitter.py +27 -12
- ansible/parsing/utils/addresses.py +24 -24
- ansible/parsing/utils/jsonify.py +5 -1
- ansible/parsing/utils/yaml.py +32 -61
- ansible/parsing/vault/__init__.py +319 -87
- ansible/parsing/yaml/__init__.py +0 -18
- ansible/parsing/yaml/dumper.py +6 -120
- ansible/parsing/yaml/loader.py +6 -39
- ansible/parsing/yaml/objects.py +43 -335
- ansible/playbook/__init__.py +1 -1
- ansible/playbook/attribute.py +8 -3
- ansible/playbook/base.py +182 -132
- ansible/playbook/block.py +26 -24
- ansible/playbook/collectionsearch.py +1 -15
- ansible/playbook/conditional.py +3 -77
- ansible/playbook/handler.py +8 -2
- ansible/playbook/helpers.py +41 -53
- ansible/playbook/included_file.py +31 -27
- ansible/playbook/loop_control.py +2 -2
- ansible/playbook/play.py +85 -44
- ansible/playbook/play_context.py +12 -17
- ansible/playbook/playbook_include.py +14 -15
- ansible/playbook/role/__init__.py +24 -26
- ansible/playbook/role/definition.py +15 -17
- ansible/playbook/role/include.py +2 -4
- ansible/playbook/role/metadata.py +10 -11
- ansible/playbook/role_include.py +3 -3
- ansible/playbook/taggable.py +13 -8
- ansible/playbook/task.py +188 -118
- ansible/playbook/task_include.py +5 -5
- ansible/plugins/__init__.py +68 -21
- ansible/plugins/action/__init__.py +209 -176
- ansible/plugins/action/add_host.py +1 -1
- ansible/plugins/action/assemble.py +1 -1
- ansible/plugins/action/assert.py +54 -66
- ansible/plugins/action/copy.py +7 -11
- ansible/plugins/action/debug.py +37 -31
- ansible/plugins/action/dnf.py +3 -4
- ansible/plugins/action/fail.py +1 -1
- ansible/plugins/action/fetch.py +4 -5
- ansible/plugins/action/gather_facts.py +7 -6
- ansible/plugins/action/group_by.py +1 -1
- ansible/plugins/action/include_vars.py +10 -11
- ansible/plugins/action/package.py +3 -6
- ansible/plugins/action/pause.py +2 -2
- ansible/plugins/action/script.py +15 -8
- ansible/plugins/action/service.py +6 -11
- ansible/plugins/action/set_fact.py +3 -12
- ansible/plugins/action/set_stats.py +3 -8
- ansible/plugins/action/template.py +35 -59
- ansible/plugins/action/unarchive.py +1 -1
- ansible/plugins/action/validate_argument_spec.py +5 -5
- ansible/plugins/action/wait_for_connection.py +1 -1
- ansible/plugins/become/__init__.py +31 -8
- ansible/plugins/become/runas.py +71 -0
- ansible/plugins/become/su.py +13 -8
- ansible/plugins/become/sudo.py +19 -0
- ansible/plugins/cache/__init__.py +35 -44
- ansible/plugins/cache/base.py +8 -0
- ansible/plugins/cache/jsonfile.py +10 -16
- ansible/plugins/cache/memory.py +6 -12
- ansible/plugins/callback/__init__.py +284 -179
- ansible/plugins/callback/default.py +99 -92
- ansible/plugins/callback/junit.py +44 -39
- ansible/plugins/callback/minimal.py +28 -25
- ansible/plugins/callback/oneline.py +28 -21
- ansible/plugins/callback/tree.py +16 -11
- ansible/plugins/connection/__init__.py +47 -34
- ansible/plugins/connection/local.py +150 -54
- ansible/plugins/connection/paramiko_ssh.py +21 -18
- ansible/plugins/connection/psrp.py +76 -165
- ansible/plugins/connection/ssh.py +301 -78
- ansible/plugins/connection/winrm.py +58 -140
- ansible/plugins/doc_fragments/action_common_attributes.py +14 -14
- ansible/plugins/doc_fragments/action_core.py +6 -6
- ansible/plugins/doc_fragments/backup.py +2 -2
- ansible/plugins/doc_fragments/checksum_common.py +27 -0
- ansible/plugins/doc_fragments/constructed.py +6 -2
- ansible/plugins/doc_fragments/decrypt.py +2 -2
- ansible/plugins/doc_fragments/default_callback.py +2 -2
- ansible/plugins/doc_fragments/files.py +2 -2
- ansible/plugins/doc_fragments/inventory_cache.py +2 -2
- ansible/plugins/doc_fragments/result_format_callback.py +2 -2
- ansible/plugins/doc_fragments/return_common.py +2 -2
- ansible/plugins/doc_fragments/template_common.py +4 -4
- ansible/plugins/doc_fragments/url.py +17 -1
- ansible/plugins/doc_fragments/url_windows.py +2 -2
- ansible/plugins/doc_fragments/validate.py +2 -2
- ansible/plugins/doc_fragments/vars_plugin_staging.py +2 -2
- ansible/plugins/filter/__init__.py +6 -2
- ansible/plugins/filter/b64decode.yml +22 -0
- ansible/plugins/filter/b64encode.yml +22 -0
- ansible/plugins/filter/bool.yml +11 -4
- ansible/plugins/filter/core.py +225 -108
- ansible/plugins/filter/encryption.py +32 -32
- ansible/plugins/filter/flatten.yml +3 -2
- ansible/plugins/filter/human_to_bytes.yml +1 -1
- ansible/plugins/filter/mathstuff.py +30 -37
- ansible/plugins/filter/password_hash.yml +8 -0
- ansible/plugins/filter/regex_search.yml +1 -4
- ansible/plugins/filter/split.yml +1 -1
- ansible/plugins/filter/to_nice_yaml.yml +0 -4
- ansible/plugins/filter/to_yaml.yml +0 -4
- ansible/plugins/filter/unvault.yml +1 -1
- ansible/plugins/filter/urls.py +1 -1
- ansible/plugins/filter/urlsplit.py +8 -9
- ansible/plugins/filter/vault.yml +14 -9
- ansible/plugins/filter/win_basename.yml +6 -1
- ansible/plugins/filter/win_dirname.yml +5 -0
- ansible/plugins/inventory/__init__.py +97 -77
- ansible/plugins/inventory/advanced_host_list.py +7 -5
- ansible/plugins/inventory/auto.py +11 -4
- ansible/plugins/inventory/constructed.py +21 -24
- ansible/plugins/inventory/generator.py +16 -11
- ansible/plugins/inventory/host_list.py +7 -5
- ansible/plugins/inventory/ini.py +78 -44
- ansible/plugins/inventory/script.py +189 -119
- ansible/plugins/inventory/toml.py +16 -126
- ansible/plugins/inventory/yaml.py +10 -8
- ansible/plugins/list.py +3 -3
- ansible/plugins/loader.py +197 -82
- ansible/plugins/lookup/__init__.py +21 -4
- ansible/plugins/lookup/config.py +21 -35
- ansible/plugins/lookup/csvfile.py +3 -2
- ansible/plugins/lookup/dict.py +1 -6
- ansible/plugins/lookup/env.py +12 -9
- ansible/plugins/lookup/file.py +5 -8
- ansible/plugins/lookup/first_found.py +86 -55
- ansible/plugins/lookup/indexed_items.py +1 -10
- ansible/plugins/lookup/ini.py +14 -13
- ansible/plugins/lookup/items.py +1 -1
- ansible/plugins/lookup/lines.py +8 -1
- ansible/plugins/lookup/list.py +1 -1
- ansible/plugins/lookup/nested.py +2 -18
- ansible/plugins/lookup/password.py +5 -5
- ansible/plugins/lookup/pipe.py +5 -7
- ansible/plugins/lookup/sequence.py +18 -8
- ansible/plugins/lookup/subelements.py +1 -4
- ansible/plugins/lookup/template.py +42 -36
- ansible/plugins/lookup/together.py +0 -12
- ansible/plugins/lookup/unvault.py +1 -5
- ansible/plugins/lookup/url.py +2 -8
- ansible/plugins/lookup/vars.py +16 -24
- ansible/plugins/shell/__init__.py +2 -2
- ansible/plugins/shell/cmd.py +2 -2
- ansible/plugins/shell/powershell.py +39 -22
- ansible/plugins/shell/sh.py +3 -2
- ansible/plugins/strategy/__init__.py +159 -184
- ansible/plugins/strategy/debug.py +2 -2
- ansible/plugins/strategy/free.py +16 -31
- ansible/plugins/strategy/host_pinned.py +2 -2
- ansible/plugins/strategy/linear.py +41 -41
- ansible/plugins/terminal/__init__.py +4 -4
- ansible/plugins/test/__init__.py +7 -2
- ansible/plugins/test/core.py +55 -21
- ansible/plugins/test/files.py +1 -1
- ansible/plugins/test/mathstuff.py +3 -3
- ansible/plugins/test/uri.py +3 -3
- ansible/plugins/vars/host_group_vars.py +7 -14
- ansible/release.py +2 -2
- ansible/template/__init__.py +370 -944
- ansible/utils/__init__.py +0 -18
- ansible/utils/_ssh_agent.py +657 -0
- ansible/utils/collection_loader/__init__.py +52 -5
- ansible/utils/collection_loader/_collection_config.py +5 -6
- ansible/utils/collection_loader/_collection_finder.py +79 -93
- ansible/utils/collection_loader/_collection_meta.py +13 -8
- ansible/utils/display.py +433 -63
- ansible/utils/encrypt.py +27 -19
- ansible/utils/fqcn.py +2 -2
- ansible/utils/hashing.py +2 -2
- ansible/utils/helpers.py +2 -2
- ansible/utils/listify.py +8 -8
- ansible/utils/lock.py +2 -2
- ansible/utils/path.py +4 -4
- ansible/utils/plugin_docs.py +14 -13
- ansible/utils/sentinel.py +4 -62
- ansible/utils/singleton.py +2 -0
- ansible/utils/ssh_functions.py +1 -1
- ansible/utils/unsafe_proxy.py +23 -332
- ansible/utils/vars.py +51 -8
- ansible/utils/version.py +2 -2
- ansible/vars/clean.py +5 -5
- ansible/vars/hostvars.py +60 -90
- ansible/vars/manager.py +206 -282
- ansible/vars/reserved.py +8 -9
- ansible_core-2.19.0b2.dist-info/BSD-3-Clause.txt +28 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/METADATA +5 -4
- ansible_core-2.19.0b2.dist-info/RECORD +1072 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/WHEEL +1 -1
- ansible_test/_data/completion/docker.txt +7 -7
- ansible_test/_data/completion/remote.txt +6 -6
- ansible_test/_data/completion/windows.txt +1 -0
- ansible_test/_data/requirements/ansible.txt +2 -2
- ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
- ansible_test/_data/requirements/sanity.changelog.txt +1 -1
- ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
- ansible_test/_data/requirements/sanity.pylint.txt +4 -4
- ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
- ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
- ansible_test/_data/requirements/units.txt +1 -0
- ansible_test/_internal/__init__.py +1 -0
- ansible_test/_internal/ansible_util.py +2 -0
- ansible_test/_internal/become.py +1 -0
- ansible_test/_internal/bootstrap.py +1 -0
- ansible_test/_internal/cache.py +1 -0
- ansible_test/_internal/cgroup.py +1 -0
- ansible_test/_internal/ci/__init__.py +1 -0
- ansible_test/_internal/ci/azp.py +1 -0
- ansible_test/_internal/ci/local.py +1 -0
- ansible_test/_internal/classification/__init__.py +1 -0
- ansible_test/_internal/classification/common.py +1 -0
- ansible_test/_internal/classification/csharp.py +1 -0
- ansible_test/_internal/classification/powershell.py +1 -0
- ansible_test/_internal/classification/python.py +1 -0
- ansible_test/_internal/cli/__init__.py +1 -0
- ansible_test/_internal/cli/actions.py +1 -0
- ansible_test/_internal/cli/argparsing/__init__.py +1 -0
- ansible_test/_internal/cli/argparsing/actions.py +1 -0
- ansible_test/_internal/cli/argparsing/argcompletion.py +1 -0
- ansible_test/_internal/cli/argparsing/parsers.py +1 -0
- ansible_test/_internal/cli/commands/__init__.py +11 -0
- ansible_test/_internal/cli/commands/coverage/__init__.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/__init__.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/__init__.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/combine.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/expand.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/filter.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/generate.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/missing.py +1 -0
- ansible_test/_internal/cli/commands/coverage/combine.py +1 -0
- ansible_test/_internal/cli/commands/coverage/erase.py +1 -0
- ansible_test/_internal/cli/commands/coverage/html.py +1 -0
- ansible_test/_internal/cli/commands/coverage/report.py +1 -0
- ansible_test/_internal/cli/commands/coverage/xml.py +1 -0
- ansible_test/_internal/cli/commands/env.py +1 -0
- ansible_test/_internal/cli/commands/integration/__init__.py +1 -0
- ansible_test/_internal/cli/commands/integration/network.py +1 -0
- ansible_test/_internal/cli/commands/integration/posix.py +1 -0
- ansible_test/_internal/cli/commands/integration/windows.py +1 -0
- ansible_test/_internal/cli/commands/sanity.py +9 -0
- ansible_test/_internal/cli/commands/shell.py +1 -0
- ansible_test/_internal/cli/commands/units.py +1 -0
- ansible_test/_internal/cli/compat.py +1 -0
- ansible_test/_internal/cli/completers.py +1 -0
- ansible_test/_internal/cli/converters.py +1 -0
- ansible_test/_internal/cli/environments.py +1 -0
- ansible_test/_internal/cli/epilog.py +1 -0
- ansible_test/_internal/cli/parsers/__init__.py +1 -0
- ansible_test/_internal/cli/parsers/base_argument_parsers.py +1 -0
- ansible_test/_internal/cli/parsers/helpers.py +1 -0
- ansible_test/_internal/cli/parsers/host_config_parsers.py +1 -0
- ansible_test/_internal/cli/parsers/key_value_parsers.py +1 -0
- ansible_test/_internal/cli/parsers/value_parsers.py +1 -0
- ansible_test/_internal/commands/__init__.py +1 -0
- ansible_test/_internal/commands/coverage/__init__.py +2 -1
- ansible_test/_internal/commands/coverage/analyze/__init__.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/__init__.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/combine.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/expand.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/filter.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/generate.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/missing.py +1 -0
- ansible_test/_internal/commands/coverage/combine.py +2 -1
- ansible_test/_internal/commands/coverage/erase.py +1 -0
- ansible_test/_internal/commands/coverage/html.py +1 -0
- ansible_test/_internal/commands/coverage/report.py +1 -0
- ansible_test/_internal/commands/coverage/xml.py +1 -0
- ansible_test/_internal/commands/env/__init__.py +2 -0
- ansible_test/_internal/commands/integration/__init__.py +4 -0
- ansible_test/_internal/commands/integration/cloud/__init__.py +1 -0
- ansible_test/_internal/commands/integration/cloud/acme.py +2 -1
- ansible_test/_internal/commands/integration/cloud/aws.py +1 -0
- ansible_test/_internal/commands/integration/cloud/azure.py +1 -0
- ansible_test/_internal/commands/integration/cloud/cs.py +1 -0
- ansible_test/_internal/commands/integration/cloud/digitalocean.py +1 -0
- ansible_test/_internal/commands/integration/cloud/galaxy.py +3 -2
- ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -0
- ansible_test/_internal/commands/integration/cloud/httptester.py +2 -1
- ansible_test/_internal/commands/integration/cloud/nios.py +2 -1
- ansible_test/_internal/commands/integration/cloud/opennebula.py +1 -0
- ansible_test/_internal/commands/integration/cloud/openshift.py +1 -0
- ansible_test/_internal/commands/integration/cloud/scaleway.py +1 -0
- ansible_test/_internal/commands/integration/cloud/vcenter.py +1 -0
- ansible_test/_internal/commands/integration/cloud/vultr.py +1 -0
- ansible_test/_internal/commands/integration/coverage.py +1 -0
- ansible_test/_internal/commands/integration/filters.py +1 -0
- ansible_test/_internal/commands/integration/network.py +1 -0
- ansible_test/_internal/commands/integration/posix.py +1 -0
- ansible_test/_internal/commands/integration/windows.py +1 -0
- ansible_test/_internal/commands/sanity/__init__.py +16 -1
- ansible_test/_internal/commands/sanity/ansible_doc.py +1 -0
- ansible_test/_internal/commands/sanity/bin_symlinks.py +1 -0
- ansible_test/_internal/commands/sanity/compile.py +1 -0
- ansible_test/_internal/commands/sanity/ignores.py +1 -0
- ansible_test/_internal/commands/sanity/import.py +1 -0
- ansible_test/_internal/commands/sanity/integration_aliases.py +1 -0
- ansible_test/_internal/commands/sanity/pep8.py +1 -0
- ansible_test/_internal/commands/sanity/pslint.py +1 -0
- ansible_test/_internal/commands/sanity/pylint.py +24 -26
- ansible_test/_internal/commands/sanity/shellcheck.py +1 -0
- ansible_test/_internal/commands/sanity/validate_modules.py +1 -0
- ansible_test/_internal/commands/sanity/yamllint.py +1 -0
- ansible_test/_internal/commands/shell/__init__.py +1 -0
- ansible_test/_internal/commands/units/__init__.py +1 -0
- ansible_test/_internal/compat/__init__.py +1 -0
- ansible_test/_internal/compat/packaging.py +1 -0
- ansible_test/_internal/compat/yaml.py +1 -0
- ansible_test/_internal/completion.py +1 -0
- ansible_test/_internal/config.py +2 -0
- ansible_test/_internal/connections.py +1 -0
- ansible_test/_internal/constants.py +1 -0
- ansible_test/_internal/containers.py +1 -0
- ansible_test/_internal/content_config.py +1 -0
- ansible_test/_internal/core_ci.py +1 -0
- ansible_test/_internal/coverage_util.py +11 -10
- ansible_test/_internal/data.py +1 -0
- ansible_test/_internal/delegation.py +1 -0
- ansible_test/_internal/dev/__init__.py +1 -0
- ansible_test/_internal/dev/container_probe.py +1 -0
- ansible_test/_internal/diff.py +3 -2
- ansible_test/_internal/docker_util.py +2 -1
- ansible_test/_internal/encoding.py +1 -0
- ansible_test/_internal/executor.py +1 -0
- ansible_test/_internal/git.py +1 -0
- ansible_test/_internal/host_configs.py +1 -0
- ansible_test/_internal/host_profiles.py +1 -0
- ansible_test/_internal/http.py +1 -0
- ansible_test/_internal/init.py +1 -0
- ansible_test/_internal/inventory.py +35 -3
- ansible_test/_internal/io.py +1 -0
- ansible_test/_internal/metadata.py +1 -0
- ansible_test/_internal/payload.py +1 -0
- ansible_test/_internal/provider/__init__.py +1 -0
- ansible_test/_internal/provider/layout/__init__.py +1 -0
- ansible_test/_internal/provider/layout/ansible.py +1 -0
- ansible_test/_internal/provider/layout/collection.py +1 -0
- ansible_test/_internal/provider/layout/unsupported.py +1 -0
- ansible_test/_internal/provider/source/__init__.py +1 -0
- ansible_test/_internal/provider/source/git.py +1 -0
- ansible_test/_internal/provider/source/installed.py +1 -0
- ansible_test/_internal/provider/source/unsupported.py +1 -0
- ansible_test/_internal/provider/source/unversioned.py +1 -0
- ansible_test/_internal/provisioning.py +1 -0
- ansible_test/_internal/pypi_proxy.py +6 -5
- ansible_test/_internal/python_requirements.py +1 -0
- ansible_test/_internal/ssh.py +1 -0
- ansible_test/_internal/target.py +1 -0
- ansible_test/_internal/test.py +3 -2
- ansible_test/_internal/thread.py +1 -0
- ansible_test/_internal/timeout.py +1 -0
- ansible_test/_internal/util.py +1 -0
- ansible_test/_internal/util_common.py +5 -2
- ansible_test/_internal/venv.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/changelog/sphinx.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/changelog.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/empty-init.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/line-endings.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-assert.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-get-exception.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-illegal-filenames.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-smart-quotes.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/replace-urlopen.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +28 -1
- ansible_test/_util/controller/sanity/code-smell/shebang.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/symlinks.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/use-argspec-type-path.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/use-compat-six.py +1 -0
- ansible_test/_util/controller/sanity/integration-aliases/yaml_to_json.py +2 -1
- ansible_test/_util/controller/sanity/pep8/current-ignore.txt +4 -0
- ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +7 -5
- ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +7 -5
- ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +7 -5
- ansible_test/_util/controller/sanity/pylint/config/collection.cfg +3 -5
- ansible_test/_util/controller/sanity/pylint/config/default.cfg +7 -7
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -13
- ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +1 -0
- ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +1 -8
- ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +1 -8
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +55 -28
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +12 -5
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +13 -2
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -0
- ansible_test/_util/controller/sanity/yamllint/yamllinter.py +35 -17
- ansible_test/_util/controller/tools/collection_detail.py +1 -0
- ansible_test/_util/controller/tools/yaml_to_json.py +2 -1
- ansible_test/_util/target/pytest/plugins/ansible_forked.py +6 -1
- ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py +2 -1
- ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +1 -0
- ansible_test/_util/target/sanity/compile/compile.py +1 -0
- ansible_test/_util/target/sanity/import/importer.py +15 -16
- ansible_test/_util/target/setup/bootstrap.sh +9 -20
- ansible_test/_util/target/setup/probe_cgroups.py +1 -0
- ansible_test/_util/target/setup/quiet_pip.py +1 -0
- ansible_test/_util/target/setup/requirements.py +35 -27
- ansible_test/_util/target/tools/virtualenvcheck.py +2 -1
- ansible_test/_util/target/tools/yamlcheck.py +2 -1
- ansible/compat/selectors.py +0 -32
- ansible/errors/yaml_strings.py +0 -138
- ansible/executor/action_write_locks.py +0 -44
- ansible/executor/discovery/python_target.py +0 -47
- ansible/executor/powershell/module_powershell_wrapper.ps1 +0 -86
- ansible/executor/powershell/module_script_wrapper.ps1 +0 -22
- ansible/module_utils/compat/importlib.py +0 -26
- ansible/module_utils/compat/selectors.py +0 -32
- ansible/module_utils/pycompat24.py +0 -73
- ansible/parsing/yaml/constructor.py +0 -178
- ansible/template/native_helpers.py +0 -251
- ansible/template/template.py +0 -43
- ansible/template/vars.py +0 -77
- ansible/utils/native_jinja.py +0 -11
- ansible/vars/fact_cache.py +0 -71
- ansible_core-2.18.5rc1.dist-info/RECORD +0 -992
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/Apache-License.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/COPYING +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/MIT-license.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/PSF-license.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/simplified_bsd.txt +0 -0
- {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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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 =
|
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
|
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 [
|
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 [
|
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
|
-
|
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
|
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(
|
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 =
|
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(
|
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(
|
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 =
|
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(
|
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 =
|
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
|
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([
|
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(
|
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(
|
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(
|
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(
|
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(
|
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 =
|
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(
|
720
|
+
with open(_to_bytes(metadata_path), 'rb') as fd:
|
738
721
|
raw_routing = fd.read()
|
739
722
|
else:
|
740
|
-
b_routing_meta_path =
|
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: {
|
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(
|
910
|
-
|
911
|
-
|
912
|
-
|
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(
|
916
|
-
VALID_FQCR_RE = re.compile(
|
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 =
|
909
|
+
collection_name = _to_text(collection_name, strict=True)
|
927
910
|
if subdirs is not None:
|
928
|
-
subdirs =
|
929
|
-
resource =
|
930
|
-
ref_type =
|
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(
|
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(
|
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 =
|
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 =
|
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(
|
980
|
+
raise ValueError('{0} is not a valid collection reference'.format(_to_text(ref)))
|
998
981
|
|
999
|
-
ref =
|
1000
|
-
ref_type =
|
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
|
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
|
-
|
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('{
|
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 =
|
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 =
|
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
|
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 =
|
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
|
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 = [
|
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,
|
1125
|
-
if os.path.exists(
|
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,
|
1130
|
-
if os.path.exists(
|
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(
|
1166
|
-
return resource,
|
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 =
|
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 =
|
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 =
|
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 =
|
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(
|
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 +
|
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 +
|
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 =
|
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
|
-
|
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
|
-
|
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):
|