ansible-core 2.18.7rc1__py3-none-any.whl → 2.19.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ansible-core might be problematic. Click here for more details.
- ansible/_internal/__init__.py +53 -0
- ansible/_internal/_ansiballz/__init__.py +0 -0
- ansible/_internal/_ansiballz/_builder.py +101 -0
- ansible/_internal/_ansiballz/_wrapper.py +262 -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/_alarm_timeout.py +66 -0
- ansible/_internal/_errors/_captured.py +123 -0
- ansible/_internal/_errors/_error_factory.py +89 -0
- ansible/_internal/_errors/_error_utils.py +240 -0
- ansible/_internal/_errors/_handler.py +91 -0
- ansible/_internal/_errors/_task_timeout.py +28 -0
- ansible/_internal/_event_formatting.py +127 -0
- ansible/_internal/_json/__init__.py +214 -0
- ansible/_internal/_json/_legacy_encoder.py +34 -0
- ansible/_internal/_json/_profiles/__init__.py +0 -0
- ansible/_internal/_json/_profiles/_cache_persistence.py +57 -0
- ansible/_internal/_json/_profiles/_inventory_legacy.py +40 -0
- ansible/_internal/_json/_profiles/_legacy.py +189 -0
- ansible/_internal/_locking.py +21 -0
- ansible/_internal/_plugins/__init__.py +0 -0
- ansible/_internal/_plugins/_cache.py +57 -0
- ansible/_internal/_ssh/__init__.py +0 -0
- ansible/_internal/_ssh/_agent_launch.py +91 -0
- ansible/_internal/_ssh/_ssh_agent.py +619 -0
- ansible/_internal/_task.py +78 -0
- ansible/_internal/_templating/__init__.py +12 -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 +592 -0
- ansible/_internal/_templating/_errors.py +28 -0
- ansible/_internal/_templating/_jinja_bits.py +1106 -0
- ansible/_internal/_templating/_jinja_common.py +323 -0
- ansible/_internal/_templating/_jinja_patches.py +44 -0
- ansible/_internal/_templating/_jinja_plugins.py +375 -0
- ansible/_internal/_templating/_lazy_containers.py +633 -0
- ansible/_internal/_templating/_marker_behaviors.py +103 -0
- ansible/_internal/_templating/_template_vars.py +72 -0
- ansible/_internal/_templating/_transform.py +70 -0
- ansible/_internal/_templating/_utils.py +108 -0
- ansible/_internal/_testing.py +26 -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 +70 -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 +27 -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 +93 -104
- ansible/cli/_ssh_askpass.py +54 -0
- ansible/cli/adhoc.py +20 -10
- ansible/cli/arguments/option_helpers.py +163 -10
- ansible/cli/config.py +43 -68
- ansible/cli/console.py +13 -11
- ansible/cli/doc.py +134 -77
- ansible/cli/galaxy.py +27 -20
- ansible/cli/inventory.py +28 -28
- ansible/cli/playbook.py +4 -12
- ansible/cli/pull.py +6 -3
- ansible/cli/scripts/ansible_connection_cli_stub.py +7 -7
- ansible/cli/vault.py +12 -11
- ansible/compat/__init__.py +2 -2
- ansible/compat/importlib_resources.py +9 -12
- ansible/config/base.yml +218 -133
- ansible/config/manager.py +220 -159
- ansible/constants.py +2 -65
- ansible/errors/__init__.py +350 -256
- ansible/executor/interpreter_discovery.py +28 -149
- ansible/executor/module_common.py +480 -514
- 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 +204 -153
- ansible/executor/powershell/become_wrapper.ps1 +107 -144
- ansible/executor/powershell/bootstrap_wrapper.ps1 +46 -9
- ansible/executor/powershell/coverage_wrapper.ps1 +91 -135
- ansible/executor/powershell/exec_wrapper.ps1 +675 -196
- ansible/executor/powershell/module_manifest.py +469 -265
- ansible/executor/powershell/module_wrapper.ps1 +195 -186
- ansible/executor/powershell/powershell_expand_user.ps1 +20 -0
- ansible/executor/powershell/powershell_mkdtemp.ps1 +17 -0
- 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 +139 -149
- ansible/executor/stats.py +5 -5
- ansible/executor/task_executor.py +270 -297
- ansible/executor/task_queue_manager.py +135 -137
- ansible/executor/task_result.py +182 -79
- ansible/galaxy/__init__.py +2 -2
- ansible/galaxy/api.py +26 -25
- ansible/galaxy/collection/__init__.py +6 -14
- ansible/galaxy/collection/concrete_artifact_manager.py +12 -21
- ansible/galaxy/dependency_resolution/dataclasses.py +14 -4
- ansible/galaxy/dependency_resolution/providers.py +4 -4
- ansible/galaxy/dependency_resolution/reporters.py +81 -0
- ansible/galaxy/role.py +6 -10
- ansible/galaxy/token.py +28 -21
- ansible/inventory/data.py +47 -57
- ansible/inventory/group.py +50 -73
- ansible/inventory/helpers.py +9 -0
- ansible/inventory/host.py +37 -54
- ansible/inventory/manager.py +79 -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/__init__.py +0 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/__init__.py +0 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/_coverage.py +45 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/_pydevd.py +62 -0
- ansible/module_utils/_internal/_ansiballz/_loader.py +81 -0
- ansible/module_utils/_internal/_ansiballz/_respawn.py +32 -0
- ansible/module_utils/_internal/_ansiballz/_respawn_wrapper.py +23 -0
- ansible/module_utils/_internal/_concurrent/_daemon_threading.py +1 -0
- ansible/module_utils/_internal/_dataclass_validation.py +217 -0
- ansible/module_utils/_internal/_datatag/__init__.py +961 -0
- ansible/module_utils/_internal/_datatag/_tags.py +16 -0
- ansible/module_utils/_internal/_debugging.py +31 -0
- ansible/module_utils/_internal/_deprecator.py +157 -0
- ansible/module_utils/_internal/_errors.py +101 -0
- ansible/module_utils/_internal/_event_utils.py +61 -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 +428 -0
- ansible/module_utils/_internal/_json/_profiles/_fallback_to_str.py +73 -0
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +33 -0
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +37 -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 +52 -0
- ansible/module_utils/_internal/_messages.py +130 -0
- ansible/module_utils/_internal/_patches/__init__.py +66 -0
- ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +53 -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_info.py +38 -0
- ansible/module_utils/_internal/_stack.py +22 -0
- ansible/module_utils/_internal/_testing.py +0 -0
- ansible/module_utils/_internal/_text_utils.py +6 -0
- ansible/module_utils/_internal/_traceback.py +92 -0
- ansible/module_utils/_internal/_validation.py +14 -0
- ansible/module_utils/ansible_release.py +2 -2
- ansible/module_utils/api.py +1 -2
- ansible/module_utils/basic.py +303 -202
- ansible/module_utils/common/_utils.py +24 -28
- ansible/module_utils/common/arg_spec.py +8 -3
- ansible/module_utils/common/collections.py +7 -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/parameters.py +27 -24
- ansible/module_utils/common/process.py +2 -3
- ansible/module_utils/common/respawn.py +11 -33
- 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 +143 -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 +10 -13
- ansible/module_utils/csharp/Ansible.Basic.cs +15 -12
- ansible/module_utils/csharp/Ansible.Become.cs +1 -0
- ansible/module_utils/csharp/Ansible.Privilege.cs +2 -2
- ansible/module_utils/csharp/Ansible._Async.cs +517 -0
- ansible/module_utils/datatag.py +49 -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 +2 -2
- 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 +5 -5
- 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 +2 -3
- ansible/module_utils/facts/other/ohai.py +2 -3
- ansible/module_utils/facts/sysctl.py +4 -6
- ansible/module_utils/facts/system/apparmor.py +1 -2
- ansible/module_utils/facts/system/caps.py +3 -3
- 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 +27 -13
- 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 +2 -3
- 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/linux.py +3 -3
- 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 +7 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.CommandUtil.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.WebRequest.psm1 +1 -1
- ansible/module_utils/service.py +21 -31
- ansible/module_utils/splitter.py +7 -7
- ansible/module_utils/testing.py +31 -0
- ansible/module_utils/urls.py +64 -35
- ansible/modules/add_host.py +4 -4
- ansible/modules/apt.py +69 -49
- ansible/modules/apt_key.py +19 -12
- ansible/modules/apt_repository.py +32 -51
- ansible/modules/assemble.py +16 -14
- ansible/modules/assert.py +4 -4
- ansible/modules/async_status.py +24 -24
- ansible/modules/async_wrapper.py +20 -25
- ansible/modules/blockinfile.py +6 -7
- ansible/modules/command.py +13 -20
- ansible/modules/copy.py +60 -147
- ansible/modules/cron.py +24 -21
- 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 +13 -15
- ansible/modules/fail.py +4 -4
- ansible/modules/fetch.py +4 -4
- ansible/modules/file.py +184 -144
- ansible/modules/find.py +22 -20
- ansible/modules/gather_facts.py +3 -3
- ansible/modules/get_url.py +77 -54
- ansible/modules/getent.py +7 -9
- ansible/modules/git.py +38 -38
- ansible/modules/group.py +6 -6
- ansible/modules/group_by.py +4 -4
- ansible/modules/hostname.py +15 -32
- 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 +22 -24
- ansible/modules/lineinfile.py +5 -5
- ansible/modules/meta.py +4 -4
- ansible/modules/mount_facts.py +2 -2
- ansible/modules/package.py +10 -4
- ansible/modules/package_facts.py +22 -10
- ansible/modules/pause.py +6 -6
- ansible/modules/ping.py +6 -6
- ansible/modules/pip.py +21 -26
- ansible/modules/raw.py +6 -6
- ansible/modules/reboot.py +6 -6
- ansible/modules/replace.py +10 -14
- ansible/modules/rpm_key.py +7 -8
- ansible/modules/script.py +4 -4
- ansible/modules/service.py +10 -17
- 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 +16 -19
- ansible/modules/stat.py +15 -31
- ansible/modules/subversion.py +15 -15
- ansible/modules/systemd.py +7 -7
- ansible/modules/systemd_service.py +7 -7
- ansible/modules/sysvinit.py +9 -9
- ansible/modules/tempfile.py +5 -6
- ansible/modules/template.py +6 -6
- ansible/modules/unarchive.py +38 -17
- ansible/modules/uri.py +33 -26
- ansible/modules/user.py +45 -32
- ansible/modules/validate_argument_spec.py +10 -7
- ansible/modules/wait_for.py +70 -60
- ansible/modules/wait_for_connection.py +6 -6
- ansible/modules/yum_repository.py +10 -9
- ansible/parsing/ajson.py +17 -37
- ansible/parsing/dataloader.py +99 -54
- ansible/parsing/mod_args.py +62 -60
- 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 +327 -99
- 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 +187 -134
- 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 +32 -26
- ansible/playbook/loop_control.py +2 -2
- ansible/playbook/play.py +85 -44
- ansible/playbook/play_context.py +14 -17
- ansible/playbook/playbook_include.py +27 -62
- ansible/playbook/role/__init__.py +64 -49
- 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 +28 -12
- ansible/playbook/task.py +192 -121
- ansible/playbook/task_include.py +5 -5
- ansible/plugins/__init__.py +58 -26
- ansible/plugins/action/__init__.py +188 -186
- ansible/plugins/action/add_host.py +2 -2
- ansible/plugins/action/assemble.py +11 -18
- ansible/plugins/action/assert.py +55 -67
- ansible/plugins/action/async_status.py +7 -2
- ansible/plugins/action/copy.py +14 -17
- 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 +7 -8
- ansible/plugins/action/gather_facts.py +13 -14
- ansible/plugins/action/group_by.py +1 -1
- ansible/plugins/action/include_vars.py +10 -11
- ansible/plugins/action/package.py +8 -14
- ansible/plugins/action/pause.py +2 -2
- ansible/plugins/action/script.py +27 -38
- ansible/plugins/action/service.py +9 -18
- ansible/plugins/action/set_fact.py +3 -12
- ansible/plugins/action/set_stats.py +3 -8
- ansible/plugins/action/template.py +47 -67
- ansible/plugins/action/unarchive.py +6 -16
- ansible/plugins/action/uri.py +9 -20
- 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 +52 -63
- 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 +294 -201
- ansible/plugins/callback/default.py +99 -95
- ansible/plugins/callback/junit.py +44 -43
- ansible/plugins/callback/minimal.py +28 -25
- ansible/plugins/callback/oneline.py +34 -21
- ansible/plugins/callback/tree.py +27 -16
- ansible/plugins/connection/__init__.py +47 -34
- ansible/plugins/connection/local.py +156 -60
- ansible/plugins/connection/paramiko_ssh.py +34 -24
- ansible/plugins/connection/psrp.py +76 -165
- ansible/plugins/connection/ssh.py +326 -86
- ansible/plugins/connection/winrm.py +62 -141
- 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 +8 -4
- 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 +245 -120
- ansible/plugins/filter/encryption.py +42 -34
- 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/pow.yml +1 -1
- ansible/plugins/filter/regex_search.yml +1 -4
- ansible/plugins/filter/root.yml +1 -1
- ansible/plugins/filter/split.yml +1 -1
- ansible/plugins/filter/strftime.yml +3 -3
- ansible/plugins/filter/to_nice_yaml.yml +0 -4
- ansible/plugins/filter/to_uuid.yml +1 -1
- 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 +107 -86
- 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 +190 -120
- ansible/plugins/inventory/toml.py +16 -126
- ansible/plugins/inventory/yaml.py +10 -8
- ansible/plugins/list.py +72 -19
- ansible/plugins/loader.py +383 -198
- ansible/plugins/lookup/__init__.py +21 -4
- ansible/plugins/lookup/config.py +21 -35
- ansible/plugins/lookup/csvfile.py +19 -73
- 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 +87 -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 +47 -36
- ansible/plugins/lookup/together.py +0 -12
- ansible/plugins/lookup/unvault.py +1 -5
- ansible/plugins/lookup/url.py +4 -10
- ansible/plugins/lookup/vars.py +16 -24
- ansible/plugins/shell/__init__.py +58 -4
- ansible/plugins/shell/cmd.py +2 -2
- ansible/plugins/shell/powershell.py +106 -31
- ansible/plugins/shell/sh.py +13 -7
- ansible/plugins/strategy/__init__.py +168 -193
- 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 +75 -35
- ansible/plugins/test/files.py +1 -1
- ansible/plugins/test/finished.yml +1 -1
- ansible/plugins/test/mathstuff.py +3 -3
- ansible/plugins/test/uri.py +5 -8
- ansible/plugins/vars/host_group_vars.py +7 -14
- ansible/release.py +2 -2
- ansible/template/__init__.py +353 -943
- ansible/utils/__init__.py +0 -18
- ansible/utils/collection_loader/__init__.py +54 -5
- ansible/utils/collection_loader/_collection_config.py +5 -6
- ansible/utils/collection_loader/_collection_finder.py +82 -96
- ansible/utils/collection_loader/_collection_meta.py +15 -8
- ansible/utils/display.py +485 -73
- ansible/utils/encrypt.py +27 -19
- ansible/utils/fqcn.py +2 -2
- ansible/utils/galaxy.py +2 -2
- ansible/utils/hashing.py +8 -10
- ansible/utils/helpers.py +2 -2
- ansible/utils/listify.py +10 -8
- ansible/utils/lock.py +2 -2
- ansible/utils/path.py +10 -12
- ansible/utils/plugin_docs.py +16 -14
- ansible/utils/py3compat.py +2 -7
- ansible/utils/sentinel.py +4 -62
- ansible/utils/singleton.py +2 -0
- ansible/utils/ssh_functions.py +6 -2
- ansible/utils/unsafe_proxy.py +23 -332
- ansible/utils/vars.py +55 -8
- ansible/utils/version.py +2 -2
- ansible/vars/clean.py +5 -5
- ansible/vars/hostvars.py +60 -90
- ansible/vars/manager.py +220 -285
- ansible/vars/plugins.py +4 -4
- ansible/vars/reserved.py +13 -12
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/METADATA +4 -3
- ansible_core-2.19.0.dist-info/RECORD +1097 -0
- ansible_core-2.19.0.dist-info/licenses/licenses/BSD-3-Clause.txt +28 -0
- 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 +2 -2
- ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
- ansible_test/_data/requirements/sanity.pep8.txt +1 -1
- ansible_test/_data/requirements/sanity.pylint.txt +5 -5
- 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 +6 -0
- ansible_test/_internal/ansible_util.py +3 -1
- 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 -5
- 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 +52 -5
- 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 +3 -2
- 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 +22 -5
- 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 +3 -2
- 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 +8 -2
- 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 +19 -2
- 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 +12 -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 +25 -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 +44 -4
- ansible_test/_internal/commands/units/__init__.py +5 -1
- 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 +23 -13
- 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/debugging.py +166 -0
- ansible_test/_internal/delegation.py +22 -13
- 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 +260 -16
- ansible_test/_internal/http.py +1 -0
- ansible_test/_internal/init.py +1 -0
- ansible_test/_internal/inventory.py +39 -3
- ansible_test/_internal/io.py +1 -0
- ansible_test/_internal/metadata.py +95 -4
- ansible_test/_internal/payload.py +1 -0
- ansible_test/_internal/processes.py +80 -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 +11 -4
- ansible_test/_internal/pypi_proxy.py +6 -5
- ansible_test/_internal/python_requirements.py +28 -0
- ansible_test/_internal/ssh.py +2 -5
- ansible_test/_internal/target.py +9 -0
- ansible_test/_internal/test.py +3 -2
- ansible_test/_internal/thread.py +3 -1
- ansible_test/_internal/timeout.py +2 -1
- ansible_test/_internal/util.py +41 -12
- ansible_test/_internal/util_common.py +18 -5
- 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 +8 -5
- ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +8 -5
- ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +8 -5
- ansible_test/_util/controller/sanity/pylint/config/collection.cfg +4 -5
- ansible_test/_util/controller/sanity/pylint/config/default.cfg +8 -7
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +541 -0
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_comment.py +137 -0
- 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/injector/python.py +8 -0
- 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 +38 -36
- 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.7rc1.dist-info/RECORD +0 -992
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +0 -411
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/WHEEL +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.18.7rc1.dist-info → ansible_core-2.19.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import datetime
|
|
4
|
+
import functools
|
|
5
|
+
import json
|
|
6
|
+
import typing as t
|
|
7
|
+
|
|
8
|
+
from ansible.module_utils import _internal
|
|
9
|
+
from ansible.module_utils._internal import _messages
|
|
10
|
+
from ansible.module_utils._internal._datatag import (
|
|
11
|
+
AnsibleSerializable,
|
|
12
|
+
AnsibleSerializableWrapper,
|
|
13
|
+
AnsibleTaggedObject,
|
|
14
|
+
Tripwire,
|
|
15
|
+
_AnsibleTaggedBytes,
|
|
16
|
+
_AnsibleTaggedDate,
|
|
17
|
+
_AnsibleTaggedDateTime,
|
|
18
|
+
_AnsibleTaggedDict,
|
|
19
|
+
_AnsibleTaggedFloat,
|
|
20
|
+
_AnsibleTaggedInt,
|
|
21
|
+
_AnsibleTaggedList,
|
|
22
|
+
_AnsibleTaggedSet,
|
|
23
|
+
_AnsibleTaggedStr,
|
|
24
|
+
_AnsibleTaggedTime,
|
|
25
|
+
_AnsibleTaggedTuple,
|
|
26
|
+
AnsibleTagHelper,
|
|
27
|
+
_tags,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# transformations to "final" JSON representations can only use:
|
|
31
|
+
# str, float, int, bool, None, dict, list
|
|
32
|
+
# NOT SUPPORTED: tuple, set -- the representation of these in JSON varies by profile (can raise an error, may be converted to list, etc.)
|
|
33
|
+
# This means that any special handling required on JSON types that are not wrapped/tagged must be done in a pre-pass before serialization.
|
|
34
|
+
# The final type map cannot contain any JSON types other than tuple or set.
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
_NoneType: t.Final[type] = type(None)
|
|
38
|
+
|
|
39
|
+
_json_subclassable_scalar_types: t.Final[tuple[type, ...]] = (str, float, int)
|
|
40
|
+
"""Scalar types understood by JSONEncoder which can also be subclassed."""
|
|
41
|
+
|
|
42
|
+
_json_scalar_types: t.Final[tuple[type, ...]] = (str, float, int, bool, _NoneType)
|
|
43
|
+
"""Scalar types understood by JSONEncoder."""
|
|
44
|
+
|
|
45
|
+
_json_container_types: t.Final[tuple[type, ...]] = (dict, list, tuple)
|
|
46
|
+
"""Container types understood by JSONEncoder."""
|
|
47
|
+
|
|
48
|
+
_json_types: t.Final[tuple[type, ...]] = _json_scalar_types + _json_container_types
|
|
49
|
+
"""Types understood by JSONEncoder."""
|
|
50
|
+
|
|
51
|
+
_intercept_containers = frozenset(
|
|
52
|
+
{
|
|
53
|
+
dict,
|
|
54
|
+
list,
|
|
55
|
+
tuple,
|
|
56
|
+
_AnsibleTaggedDict,
|
|
57
|
+
_AnsibleTaggedList,
|
|
58
|
+
_AnsibleTaggedTuple,
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
"""Container types to intercept in support of scalar interception."""
|
|
62
|
+
|
|
63
|
+
_common_module_types: frozenset[type[AnsibleSerializable]] = frozenset(
|
|
64
|
+
{
|
|
65
|
+
_AnsibleTaggedBytes,
|
|
66
|
+
_AnsibleTaggedDate,
|
|
67
|
+
_AnsibleTaggedDateTime,
|
|
68
|
+
_AnsibleTaggedDict,
|
|
69
|
+
_AnsibleTaggedFloat,
|
|
70
|
+
_AnsibleTaggedInt,
|
|
71
|
+
_AnsibleTaggedList,
|
|
72
|
+
_AnsibleTaggedSet,
|
|
73
|
+
_AnsibleTaggedStr,
|
|
74
|
+
_AnsibleTaggedTime,
|
|
75
|
+
_AnsibleTaggedTuple,
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
"""
|
|
79
|
+
Types that must be supported for all Ansible module serialization profiles.
|
|
80
|
+
|
|
81
|
+
For module-to-controller, all types should support full fidelity serialization.
|
|
82
|
+
This allows infrastructure and library code to use these features even when a module does not.
|
|
83
|
+
|
|
84
|
+
For controller-to-module, type behavior is profile dependent.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
_common_module_response_types: frozenset[type[AnsibleSerializable]] = frozenset(
|
|
88
|
+
{
|
|
89
|
+
_messages.PluginInfo,
|
|
90
|
+
_messages.PluginType,
|
|
91
|
+
_messages.Event,
|
|
92
|
+
_messages.EventChain,
|
|
93
|
+
_messages.ErrorSummary,
|
|
94
|
+
_messages.WarningSummary,
|
|
95
|
+
_messages.DeprecationSummary,
|
|
96
|
+
_tags.Deprecated,
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
"""Types that must be supported for all Ansible module-to-controller serialization profiles."""
|
|
100
|
+
|
|
101
|
+
_T_encoder = t.TypeVar('_T_encoder', bound="AnsibleProfileJSONEncoder")
|
|
102
|
+
_T_decoder = t.TypeVar('_T_decoder', bound="AnsibleProfileJSONDecoder")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class _JSONSerializationProfile(t.Generic[_T_encoder, _T_decoder]):
|
|
106
|
+
serialize_map: t.ClassVar[dict[type, t.Callable]]
|
|
107
|
+
"""
|
|
108
|
+
Each concrete non-JSON type must be included in this mapping to support serialization.
|
|
109
|
+
Including a JSON type in the mapping allows for overriding or disabling of serialization of that type.
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
deserialize_map: t.ClassVar[dict[str, t.Callable]]
|
|
113
|
+
"""A mapping of type keys to type dispatchers for deserialization."""
|
|
114
|
+
|
|
115
|
+
allowed_ansible_serializable_types: t.ClassVar[frozenset[type[AnsibleSerializable]]] = frozenset()
|
|
116
|
+
"""Each concrete AnsibleSerialiable derived type must be included in this set to support serialization."""
|
|
117
|
+
|
|
118
|
+
_common_discard_tags: t.ClassVar[dict[type, t.Callable]]
|
|
119
|
+
"""
|
|
120
|
+
Serialize map for tagged types to have their tags discarded.
|
|
121
|
+
This is generated by __init_subclass__ and should not be manually updated.
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
_allowed_type_keys: t.ClassVar[frozenset[str]]
|
|
125
|
+
"""
|
|
126
|
+
The set of type keys allowed during deserialization.
|
|
127
|
+
This is generated by __init_subclass__ and should not be manually updated.
|
|
128
|
+
"""
|
|
129
|
+
|
|
130
|
+
_unwrapped_json_types: t.ClassVar[frozenset[type]]
|
|
131
|
+
"""
|
|
132
|
+
The set of types that do not need to be wrapped during serialization.
|
|
133
|
+
This is generated by __init_subclass__ and should not be manually updated.
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
profile_name: t.ClassVar[str]
|
|
137
|
+
"""
|
|
138
|
+
The user-facing name of the profile, derived from the module name in which the profile resides.
|
|
139
|
+
Used to load the profile dynamically at runtime.
|
|
140
|
+
This is generated by __init_subclass__ and should not be manually updated.
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
encode_strings_as_utf8: t.ClassVar[bool] = False
|
|
144
|
+
r"""
|
|
145
|
+
When enabled, JSON encoding will result in UTF8 strings being emitted.
|
|
146
|
+
Otherwise, non-ASCII strings will be escaped with `\uXXXX` escape sequences.`
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
@classmethod
|
|
150
|
+
def pre_serialize(cls, encoder: _T_encoder, o: t.Any) -> t.Any:
|
|
151
|
+
return o
|
|
152
|
+
|
|
153
|
+
@classmethod
|
|
154
|
+
def post_deserialize(cls, decoder: _T_decoder, o: t.Any) -> t.Any:
|
|
155
|
+
return o
|
|
156
|
+
|
|
157
|
+
@classmethod
|
|
158
|
+
def cannot_serialize_error(cls, target: t.Any, /) -> t.NoReturn:
|
|
159
|
+
raise TypeError(f'Object of type {type(target).__name__!r} is not JSON serializable by the {cls.profile_name!r} profile.')
|
|
160
|
+
|
|
161
|
+
@classmethod
|
|
162
|
+
def cannot_deserialize_error(cls, target_type_name: str, /) -> t.NoReturn:
|
|
163
|
+
raise TypeError(f'Object of type {target_type_name!r} is not JSON deserializable by the {cls.profile_name!r} profile.')
|
|
164
|
+
|
|
165
|
+
@classmethod
|
|
166
|
+
def unsupported_target_type_error(cls, target_type_name: str, _value: dict) -> t.NoReturn:
|
|
167
|
+
cls.cannot_deserialize_error(target_type_name)
|
|
168
|
+
|
|
169
|
+
@classmethod
|
|
170
|
+
def discard_tags(cls, value: AnsibleTaggedObject) -> object:
|
|
171
|
+
return value._native_copy()
|
|
172
|
+
|
|
173
|
+
@classmethod
|
|
174
|
+
def deserialize_serializable(cls, value: dict[str, t.Any]) -> object:
|
|
175
|
+
type_key = value[AnsibleSerializable._TYPE_KEY]
|
|
176
|
+
|
|
177
|
+
if type_key not in cls._allowed_type_keys:
|
|
178
|
+
cls.cannot_deserialize_error(type_key)
|
|
179
|
+
|
|
180
|
+
return AnsibleSerializable._deserialize(value)
|
|
181
|
+
|
|
182
|
+
@classmethod
|
|
183
|
+
def serialize_as_list(cls, value: t.Iterable) -> list:
|
|
184
|
+
# DTFIX-FUTURE: once we have separate control/data channels for module-to-controller (and back), warn about this conversion
|
|
185
|
+
return AnsibleTagHelper.tag_copy(value, (item for item in value), value_type=list)
|
|
186
|
+
|
|
187
|
+
@classmethod
|
|
188
|
+
def serialize_as_isoformat(cls, value: datetime.date | datetime.time | datetime.datetime) -> str:
|
|
189
|
+
return value.isoformat()
|
|
190
|
+
|
|
191
|
+
@classmethod
|
|
192
|
+
def serialize_serializable_object(cls, value: AnsibleSerializable) -> t.Any:
|
|
193
|
+
return value._serialize()
|
|
194
|
+
|
|
195
|
+
@classmethod
|
|
196
|
+
def post_init(cls) -> None:
|
|
197
|
+
pass
|
|
198
|
+
|
|
199
|
+
@classmethod
|
|
200
|
+
def maybe_wrap(cls, o: t.Any) -> t.Any:
|
|
201
|
+
if type(o) in cls._unwrapped_json_types:
|
|
202
|
+
return o
|
|
203
|
+
|
|
204
|
+
return _WrappedValue(o)
|
|
205
|
+
|
|
206
|
+
@classmethod
|
|
207
|
+
def handle_key(cls, k: t.Any) -> t.Any:
|
|
208
|
+
"""Validation/conversion hook before a dict key is serialized. The default implementation only accepts str-typed keys."""
|
|
209
|
+
# NOTE: Since JSON requires string keys, there is no support for preserving tags on dictionary keys during serialization.
|
|
210
|
+
|
|
211
|
+
if not isinstance(k, str): # DTFIX-FUTURE: optimize this to use all known str-derived types in type map / allowed types
|
|
212
|
+
raise TypeError(f'Key of type {type(k).__name__!r} is not JSON serializable by the {cls.profile_name!r} profile.')
|
|
213
|
+
|
|
214
|
+
return k
|
|
215
|
+
|
|
216
|
+
@classmethod
|
|
217
|
+
def _handle_key_str_fallback(cls, k: t.Any) -> t.Any:
|
|
218
|
+
"""Legacy implementations should use this key handler for backward compatibility with stdlib JSON key conversion quirks."""
|
|
219
|
+
# DTFIX-FUTURE: optimized exact-type table lookup first
|
|
220
|
+
|
|
221
|
+
if isinstance(k, str):
|
|
222
|
+
return k
|
|
223
|
+
|
|
224
|
+
if k is None or isinstance(k, (int, float)):
|
|
225
|
+
return json.dumps(k)
|
|
226
|
+
|
|
227
|
+
raise TypeError(f'Key of type {type(k).__name__!r} is not JSON serializable by the {cls.profile_name!r} profile.')
|
|
228
|
+
|
|
229
|
+
@classmethod
|
|
230
|
+
def default(cls, o: t.Any) -> t.Any:
|
|
231
|
+
# Preserve the built-in JSON encoder support for subclasses of scalar types.
|
|
232
|
+
|
|
233
|
+
if isinstance(o, _json_subclassable_scalar_types):
|
|
234
|
+
return o
|
|
235
|
+
|
|
236
|
+
# Preserve the built-in JSON encoder support for subclasses of dict and list.
|
|
237
|
+
# Additionally, add universal support for mappings and sequences/sets by converting them to dict and list, respectively.
|
|
238
|
+
|
|
239
|
+
if _internal.is_intermediate_mapping(o):
|
|
240
|
+
return {cls.handle_key(k): cls.maybe_wrap(v) for k, v in o.items()}
|
|
241
|
+
|
|
242
|
+
if _internal.is_intermediate_iterable(o):
|
|
243
|
+
return [cls.maybe_wrap(v) for v in o]
|
|
244
|
+
|
|
245
|
+
return cls.last_chance(o)
|
|
246
|
+
|
|
247
|
+
@classmethod
|
|
248
|
+
def last_chance(cls, o: t.Any) -> t.Any:
|
|
249
|
+
if isinstance(o, Tripwire):
|
|
250
|
+
o.trip()
|
|
251
|
+
|
|
252
|
+
cls.cannot_serialize_error(o)
|
|
253
|
+
|
|
254
|
+
def __init_subclass__(cls, **kwargs) -> None:
|
|
255
|
+
cls.deserialize_map = {}
|
|
256
|
+
cls._common_discard_tags = {obj: cls.discard_tags for obj in _common_module_types if issubclass(obj, AnsibleTaggedObject)}
|
|
257
|
+
|
|
258
|
+
cls.post_init()
|
|
259
|
+
|
|
260
|
+
cls.profile_name = cls.__module__.rsplit('.', maxsplit=1)[-1].lstrip('_')
|
|
261
|
+
|
|
262
|
+
wrapper_types = set(obj for obj in cls.serialize_map.values() if isinstance(obj, type) and issubclass(obj, AnsibleSerializableWrapper))
|
|
263
|
+
|
|
264
|
+
cls.allowed_ansible_serializable_types |= wrapper_types
|
|
265
|
+
|
|
266
|
+
# no current need to preserve tags on controller-only types or custom behavior for anything in `allowed_serializable_types`
|
|
267
|
+
cls.serialize_map.update({obj: cls.serialize_serializable_object for obj in cls.allowed_ansible_serializable_types})
|
|
268
|
+
cls.serialize_map.update({obj: func for obj, func in _internal.get_controller_serialize_map().items() if obj not in cls.serialize_map})
|
|
269
|
+
|
|
270
|
+
cls.deserialize_map[AnsibleSerializable._TYPE_KEY] = cls.deserialize_serializable # always recognize tagged types
|
|
271
|
+
|
|
272
|
+
cls._allowed_type_keys = frozenset(obj._type_key for obj in cls.allowed_ansible_serializable_types)
|
|
273
|
+
|
|
274
|
+
cls._unwrapped_json_types = frozenset(
|
|
275
|
+
{obj for obj in cls.serialize_map if not issubclass(obj, _json_types)} # custom types that do not extend JSON-native types
|
|
276
|
+
| {obj for obj in _json_scalar_types if obj not in cls.serialize_map} # JSON-native scalars lacking custom handling
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
class _WrappedValue:
|
|
281
|
+
__slots__ = ('wrapped',)
|
|
282
|
+
|
|
283
|
+
def __init__(self, wrapped: t.Any) -> None:
|
|
284
|
+
self.wrapped = wrapped
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
class AnsibleProfileJSONEncoder(json.JSONEncoder):
|
|
288
|
+
"""Profile based JSON encoder capable of handling Ansible internal types."""
|
|
289
|
+
|
|
290
|
+
_wrap_container_types = (list, set, tuple, dict)
|
|
291
|
+
_profile: type[_JSONSerializationProfile]
|
|
292
|
+
|
|
293
|
+
profile_name: str
|
|
294
|
+
|
|
295
|
+
def __init__(self, **kwargs):
|
|
296
|
+
self._wrap_types = self._wrap_container_types + (AnsibleSerializable,)
|
|
297
|
+
|
|
298
|
+
if self._profile.encode_strings_as_utf8:
|
|
299
|
+
kwargs.update(ensure_ascii=False)
|
|
300
|
+
|
|
301
|
+
super().__init__(**kwargs)
|
|
302
|
+
|
|
303
|
+
def __init_subclass__(cls, **kwargs) -> None:
|
|
304
|
+
cls.profile_name = cls._profile.profile_name
|
|
305
|
+
|
|
306
|
+
def encode(self, o):
|
|
307
|
+
o = self._profile.maybe_wrap(self._profile.pre_serialize(self, o))
|
|
308
|
+
|
|
309
|
+
return super().encode(o)
|
|
310
|
+
|
|
311
|
+
def default(self, o: t.Any) -> t.Any:
|
|
312
|
+
o_type = type(o)
|
|
313
|
+
|
|
314
|
+
if o_type is _WrappedValue: # pylint: disable=unidiomatic-typecheck
|
|
315
|
+
o = o.wrapped
|
|
316
|
+
o_type = type(o)
|
|
317
|
+
|
|
318
|
+
if mapped_callable := self._profile.serialize_map.get(o_type):
|
|
319
|
+
return self._profile.maybe_wrap(mapped_callable(o))
|
|
320
|
+
|
|
321
|
+
# This is our last chance to intercept the values in containers, so they must be wrapped here.
|
|
322
|
+
# Only containers natively understood by the built-in JSONEncoder are recognized, since any other container types must be present in serialize_map.
|
|
323
|
+
|
|
324
|
+
if o_type is dict: # pylint: disable=unidiomatic-typecheck
|
|
325
|
+
return {self._profile.handle_key(k): self._profile.maybe_wrap(v) for k, v in o.items()}
|
|
326
|
+
|
|
327
|
+
if o_type is list or o_type is tuple: # pylint: disable=unidiomatic-typecheck
|
|
328
|
+
return [self._profile.maybe_wrap(v) for v in o] # JSONEncoder converts tuple to a list, so just make it a list now
|
|
329
|
+
|
|
330
|
+
# Any value here is a type not explicitly handled by this encoder.
|
|
331
|
+
# The profile default handler is responsible for generating an error or converting the value to a supported type.
|
|
332
|
+
|
|
333
|
+
return self._profile.default(o)
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
class AnsibleProfileJSONDecoder(json.JSONDecoder):
|
|
337
|
+
"""Profile based JSON decoder capable of handling Ansible internal types."""
|
|
338
|
+
|
|
339
|
+
_profile: type[_JSONSerializationProfile]
|
|
340
|
+
|
|
341
|
+
profile_name: str
|
|
342
|
+
|
|
343
|
+
def __init__(self, **kwargs):
|
|
344
|
+
kwargs.update(object_hook=self.object_hook)
|
|
345
|
+
|
|
346
|
+
super().__init__(**kwargs)
|
|
347
|
+
|
|
348
|
+
def __init_subclass__(cls, **kwargs) -> None:
|
|
349
|
+
cls.profile_name = cls._profile.profile_name
|
|
350
|
+
|
|
351
|
+
def raw_decode(self, s: str, idx: int = 0) -> tuple[t.Any, int]:
|
|
352
|
+
obj, end = super().raw_decode(s, idx)
|
|
353
|
+
|
|
354
|
+
if _string_encoding_check_enabled():
|
|
355
|
+
try:
|
|
356
|
+
_recursively_check_string_encoding(obj)
|
|
357
|
+
except UnicodeEncodeError as ex:
|
|
358
|
+
raise _create_encoding_check_error() from ex
|
|
359
|
+
|
|
360
|
+
obj = self._profile.post_deserialize(self, obj)
|
|
361
|
+
|
|
362
|
+
return obj, end
|
|
363
|
+
|
|
364
|
+
def object_hook(self, pairs: dict[str, object]) -> object:
|
|
365
|
+
if _string_encoding_check_enabled():
|
|
366
|
+
try:
|
|
367
|
+
for key, value in pairs.items():
|
|
368
|
+
key.encode()
|
|
369
|
+
_recursively_check_string_encoding(value)
|
|
370
|
+
except UnicodeEncodeError as ex:
|
|
371
|
+
raise _create_encoding_check_error() from ex
|
|
372
|
+
|
|
373
|
+
for mapped_key, mapped_callable in self._profile.deserialize_map.items():
|
|
374
|
+
if mapped_key in pairs:
|
|
375
|
+
return mapped_callable(pairs)
|
|
376
|
+
|
|
377
|
+
return pairs
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
_check_encoding_setting = 'MODULE_STRICT_UTF8_RESPONSE'
|
|
381
|
+
r"""
|
|
382
|
+
The setting to control whether strings are checked to verify they can be encoded as valid UTF8.
|
|
383
|
+
This is currently only used during deserialization, to prevent string values from entering the controller which will later fail to be encoded as bytes.
|
|
384
|
+
|
|
385
|
+
The encoding failure can occur when the string represents one of two kinds of values:
|
|
386
|
+
1) It was created through decoding bytes with the `surrogateescape` error handler, and that handler is not being used when encoding.
|
|
387
|
+
2) It represents an invalid UTF8 value, such as `"\ud8f3"` in a JSON payload. This cannot be encoded, even using the `surrogateescape` error handler.
|
|
388
|
+
|
|
389
|
+
Although this becomes an error during deserialization, there are other opportunities for these values to become strings within Ansible.
|
|
390
|
+
Future code changes should further restrict bytes to string conversions to eliminate use of `surrogateescape` where appropriate.
|
|
391
|
+
Additional warnings at other boundaries may be needed to give users an opportunity to resolve the issues before they become errors.
|
|
392
|
+
"""
|
|
393
|
+
# DTFIX-FUTURE: add strict UTF8 string encoding checking to serialization profiles (to match the checks performed during deserialization)
|
|
394
|
+
# DTFIX3: the surrogateescape note above isn't quite right, for encoding use surrogatepass, which does work
|
|
395
|
+
# DTFIX-FUTURE: this config setting should probably be deprecated
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def _create_encoding_check_error() -> Exception:
|
|
399
|
+
"""
|
|
400
|
+
Return an AnsibleError for use when a UTF8 string encoding check has failed.
|
|
401
|
+
These checks are only performed in the controller context, but since this is module_utils code, dynamic loading of the `errors` module is required.
|
|
402
|
+
"""
|
|
403
|
+
errors = _internal.import_controller_module('ansible.errors') # bypass AnsiballZ import scanning
|
|
404
|
+
|
|
405
|
+
return errors.AnsibleRuntimeError(
|
|
406
|
+
message='Refusing to deserialize an invalid UTF8 string value.',
|
|
407
|
+
help_text=f'This check can be disabled with the `{_check_encoding_setting}` setting.',
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
@functools.lru_cache
|
|
412
|
+
def _string_encoding_check_enabled() -> bool:
|
|
413
|
+
"""Return True if JSON deserialization should verify strings can be encoded as valid UTF8."""
|
|
414
|
+
if constants := _internal.import_controller_module('ansible.constants'): # bypass AnsiballZ import scanning
|
|
415
|
+
return constants.config.get_config_value(_check_encoding_setting) # covers all profile-based deserializers, not just modules
|
|
416
|
+
|
|
417
|
+
return False
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def _recursively_check_string_encoding(value: t.Any) -> None:
|
|
421
|
+
"""Recursively check the given object to ensure all strings can be encoded as valid UTF8."""
|
|
422
|
+
value_type = type(value)
|
|
423
|
+
|
|
424
|
+
if value_type is str:
|
|
425
|
+
value.encode()
|
|
426
|
+
elif value_type is list: # dict is handled by the JSON deserializer
|
|
427
|
+
for item in value:
|
|
428
|
+
_recursively_check_string_encoding(item)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Lossy best-effort serialization for Ansible variables; used primarily for callback JSON display.
|
|
3
|
+
Any type which is not supported by JSON will be converted to a string.
|
|
4
|
+
The string representation of any type that is not native to JSON is subject to change and should not be considered stable.
|
|
5
|
+
The decoder provides no special behavior.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations as _annotations
|
|
9
|
+
|
|
10
|
+
import datetime as _datetime
|
|
11
|
+
import typing as _t
|
|
12
|
+
|
|
13
|
+
from json import dumps as _dumps
|
|
14
|
+
|
|
15
|
+
from ... import _datatag
|
|
16
|
+
from .. import _profiles
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class _Profile(_profiles._JSONSerializationProfile["Encoder", "Decoder"]):
|
|
20
|
+
serialize_map: _t.ClassVar[dict[type, _t.Callable]]
|
|
21
|
+
|
|
22
|
+
@classmethod
|
|
23
|
+
def post_init(cls) -> None:
|
|
24
|
+
cls.serialize_map = {
|
|
25
|
+
bytes: cls.serialize_bytes_as_str,
|
|
26
|
+
set: cls.serialize_as_list,
|
|
27
|
+
tuple: cls.serialize_as_list,
|
|
28
|
+
_datetime.date: cls.serialize_as_isoformat,
|
|
29
|
+
_datetime.time: cls.serialize_as_isoformat,
|
|
30
|
+
_datetime.datetime: cls.serialize_as_isoformat,
|
|
31
|
+
_datatag._AnsibleTaggedDate: cls.discard_tags,
|
|
32
|
+
_datatag._AnsibleTaggedTime: cls.discard_tags,
|
|
33
|
+
_datatag._AnsibleTaggedDateTime: cls.discard_tags,
|
|
34
|
+
_datatag._AnsibleTaggedStr: cls.discard_tags,
|
|
35
|
+
_datatag._AnsibleTaggedInt: cls.discard_tags,
|
|
36
|
+
_datatag._AnsibleTaggedFloat: cls.discard_tags,
|
|
37
|
+
_datatag._AnsibleTaggedSet: cls.discard_tags,
|
|
38
|
+
_datatag._AnsibleTaggedList: cls.discard_tags,
|
|
39
|
+
_datatag._AnsibleTaggedTuple: cls.discard_tags,
|
|
40
|
+
_datatag._AnsibleTaggedDict: cls.discard_tags,
|
|
41
|
+
_datatag._AnsibleTaggedBytes: cls.discard_tags,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
def serialize_bytes_as_str(cls, value: bytes) -> str:
|
|
46
|
+
return value.decode(errors='surrogateescape')
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def handle_key(cls, k: _t.Any) -> _t.Any:
|
|
50
|
+
while mapped_callable := cls.serialize_map.get(type(k)):
|
|
51
|
+
k = mapped_callable(k)
|
|
52
|
+
|
|
53
|
+
k = cls.default(k)
|
|
54
|
+
|
|
55
|
+
if not isinstance(k, str):
|
|
56
|
+
k = _dumps(k, cls=Encoder)
|
|
57
|
+
|
|
58
|
+
return k
|
|
59
|
+
|
|
60
|
+
@classmethod
|
|
61
|
+
def last_chance(cls, o: _t.Any) -> _t.Any:
|
|
62
|
+
try:
|
|
63
|
+
return str(o)
|
|
64
|
+
except Exception as ex:
|
|
65
|
+
return str(ex)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class Encoder(_profiles.AnsibleProfileJSONEncoder):
|
|
69
|
+
_profile = _Profile
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class Decoder(_profiles.AnsibleProfileJSONDecoder):
|
|
73
|
+
_profile = _Profile
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Legacy wire format for controller to module communication."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations as _annotations
|
|
4
|
+
|
|
5
|
+
import datetime as _datetime
|
|
6
|
+
|
|
7
|
+
from .. import _profiles
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class _Profile(_profiles._JSONSerializationProfile["Encoder", "Decoder"]):
|
|
11
|
+
@classmethod
|
|
12
|
+
def post_init(cls) -> None:
|
|
13
|
+
cls.serialize_map = {}
|
|
14
|
+
cls.serialize_map.update(cls._common_discard_tags)
|
|
15
|
+
cls.serialize_map.update(
|
|
16
|
+
{
|
|
17
|
+
set: cls.serialize_as_list, # legacy _json_encode_fallback behavior
|
|
18
|
+
tuple: cls.serialize_as_list, # JSONEncoder built-in behavior
|
|
19
|
+
_datetime.date: cls.serialize_as_isoformat,
|
|
20
|
+
_datetime.time: cls.serialize_as_isoformat, # always failed pre-2.18, so okay to include for consistency
|
|
21
|
+
_datetime.datetime: cls.serialize_as_isoformat,
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
cls.handle_key = cls._handle_key_str_fallback # type: ignore[method-assign] # legacy stdlib-compatible key behavior
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Encoder(_profiles.AnsibleProfileJSONEncoder):
|
|
29
|
+
_profile = _Profile
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Decoder(_profiles.AnsibleProfileJSONDecoder):
|
|
33
|
+
_profile = _Profile
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Legacy wire format for module to controller communication."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations as _annotations
|
|
4
|
+
|
|
5
|
+
import datetime as _datetime
|
|
6
|
+
|
|
7
|
+
from .. import _profiles
|
|
8
|
+
from ansible.module_utils.common.text.converters import to_text as _to_text
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class _Profile(_profiles._JSONSerializationProfile["Encoder", "Decoder"]):
|
|
12
|
+
@classmethod
|
|
13
|
+
def bytes_to_text(cls, value: bytes) -> str:
|
|
14
|
+
return _to_text(value, errors='surrogateescape')
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
def post_init(cls) -> None:
|
|
18
|
+
cls.allowed_ansible_serializable_types = _profiles._common_module_types | _profiles._common_module_response_types
|
|
19
|
+
|
|
20
|
+
cls.serialize_map = {
|
|
21
|
+
bytes: cls.bytes_to_text, # legacy behavior from jsonify and container_to_text
|
|
22
|
+
set: cls.serialize_as_list, # legacy _json_encode_fallback behavior
|
|
23
|
+
tuple: cls.serialize_as_list, # JSONEncoder built-in behavior
|
|
24
|
+
_datetime.date: cls.serialize_as_isoformat, # legacy parameters.py does this before serialization
|
|
25
|
+
_datetime.time: cls.serialize_as_isoformat, # always failed pre-2.18, so okay to include for consistency
|
|
26
|
+
_datetime.datetime: cls.serialize_as_isoformat, # legacy _json_encode_fallback behavior *and* legacy parameters.py does this before serialization
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
cls.handle_key = cls._handle_key_str_fallback # type: ignore[method-assign] # legacy stdlib-compatible key behavior
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Encoder(_profiles.AnsibleProfileJSONEncoder):
|
|
33
|
+
_profile = _Profile
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Decoder(_profiles.AnsibleProfileJSONDecoder):
|
|
37
|
+
_profile = _Profile
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Data tagging aware wire format for controller to module communication."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations as _annotations
|
|
4
|
+
|
|
5
|
+
import datetime as _datetime
|
|
6
|
+
|
|
7
|
+
from ... import _datatag
|
|
8
|
+
from .. import _profiles
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class _Profile(_profiles._JSONSerializationProfile["Encoder", "Decoder"]):
|
|
12
|
+
encode_strings_as_utf8 = True
|
|
13
|
+
|
|
14
|
+
@classmethod
|
|
15
|
+
def post_init(cls) -> None:
|
|
16
|
+
cls.serialize_map = {}
|
|
17
|
+
cls.serialize_map.update(cls._common_discard_tags)
|
|
18
|
+
cls.serialize_map.update(
|
|
19
|
+
{
|
|
20
|
+
# The bytes type is not supported, use str instead (future module profiles may support a bytes wrapper distinct from `bytes`).
|
|
21
|
+
set: cls.serialize_as_list, # legacy _json_encode_fallback behavior
|
|
22
|
+
tuple: cls.serialize_as_list, # JSONEncoder built-in behavior
|
|
23
|
+
_datetime.date: _datatag.AnsibleSerializableDate,
|
|
24
|
+
_datetime.time: _datatag.AnsibleSerializableTime,
|
|
25
|
+
_datetime.datetime: _datatag.AnsibleSerializableDateTime,
|
|
26
|
+
}
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Encoder(_profiles.AnsibleProfileJSONEncoder):
|
|
31
|
+
_profile = _Profile
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class Decoder(_profiles.AnsibleProfileJSONDecoder):
|
|
35
|
+
_profile = _Profile
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Data tagging aware wire format for module to controller communication."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations as _annotations
|
|
4
|
+
|
|
5
|
+
import datetime as _datetime
|
|
6
|
+
|
|
7
|
+
from ... import _datatag
|
|
8
|
+
from .. import _profiles
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class _Profile(_profiles._JSONSerializationProfile["Encoder", "Decoder"]):
|
|
12
|
+
encode_strings_as_utf8 = True
|
|
13
|
+
|
|
14
|
+
@classmethod
|
|
15
|
+
def post_init(cls) -> None:
|
|
16
|
+
cls.allowed_ansible_serializable_types = _profiles._common_module_types | _profiles._common_module_response_types
|
|
17
|
+
|
|
18
|
+
cls.serialize_map = {
|
|
19
|
+
# The bytes type is not supported, use str instead (future module profiles may support a bytes wrapper distinct from `bytes`).
|
|
20
|
+
set: cls.serialize_as_list, # legacy _json_encode_fallback behavior
|
|
21
|
+
tuple: cls.serialize_as_list, # JSONEncoder built-in behavior
|
|
22
|
+
_datetime.date: _datatag.AnsibleSerializableDate,
|
|
23
|
+
_datetime.time: _datatag.AnsibleSerializableTime,
|
|
24
|
+
_datetime.datetime: _datatag.AnsibleSerializableDateTime,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Encoder(_profiles.AnsibleProfileJSONEncoder):
|
|
29
|
+
_profile = _Profile
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Decoder(_profiles.AnsibleProfileJSONDecoder):
|
|
33
|
+
_profile = _Profile
|