ansible-core 2.18.7__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.7.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.7.dist-info/RECORD +0 -992
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +0 -411
- {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/WHEEL +0 -0
- {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.18.7.dist-info → ansible_core-2.19.0.dist-info}/top_level.txt +0 -0
ansible/utils/display.py
CHANGED
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
|
+
import contextlib
|
|
21
|
+
import dataclasses
|
|
22
|
+
|
|
20
23
|
try:
|
|
21
24
|
import curses
|
|
22
25
|
except ImportError:
|
|
@@ -37,7 +40,6 @@ import secrets
|
|
|
37
40
|
import subprocess
|
|
38
41
|
import sys
|
|
39
42
|
import termios
|
|
40
|
-
import textwrap
|
|
41
43
|
import threading
|
|
42
44
|
import time
|
|
43
45
|
import tty
|
|
@@ -47,13 +49,19 @@ from functools import wraps
|
|
|
47
49
|
from struct import unpack, pack
|
|
48
50
|
|
|
49
51
|
from ansible import constants as C
|
|
50
|
-
from ansible.
|
|
52
|
+
from ansible.constants import config
|
|
53
|
+
from ansible.errors import AnsibleAssertionError, AnsiblePromptInterrupt, AnsiblePromptNoninteractive, AnsibleError
|
|
54
|
+
from ansible._internal._errors import _error_utils, _error_factory
|
|
55
|
+
from ansible._internal import _event_formatting
|
|
56
|
+
from ansible.module_utils._internal import _ambient_context, _deprecator, _messages
|
|
51
57
|
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
|
58
|
+
from ansible.module_utils.datatag import deprecator_from_collection_name
|
|
59
|
+
from ansible._internal._datatag._tags import TrustedAsTemplate
|
|
52
60
|
from ansible.module_utils.six import text_type
|
|
61
|
+
from ansible.module_utils._internal import _traceback, _errors
|
|
53
62
|
from ansible.utils.color import stringc
|
|
54
63
|
from ansible.utils.multiprocessing import context as multiprocessing_context
|
|
55
64
|
from ansible.utils.singleton import Singleton
|
|
56
|
-
from ansible.utils.unsafe_proxy import wrap_var
|
|
57
65
|
|
|
58
66
|
if t.TYPE_CHECKING:
|
|
59
67
|
# avoid circular import at runtime
|
|
@@ -73,6 +81,25 @@ MOVE_TO_BOL = b'\r'
|
|
|
73
81
|
CLEAR_TO_EOL = b'\x1b[K'
|
|
74
82
|
|
|
75
83
|
|
|
84
|
+
def _is_controller_traceback_enabled(event: _traceback.TracebackEvent) -> bool:
|
|
85
|
+
"""Controller utility function to determine if traceback collection is enabled for the specified event."""
|
|
86
|
+
flag_values: set[str] = set(value for value in C.config.get_config_value('DISPLAY_TRACEBACK'))
|
|
87
|
+
|
|
88
|
+
if 'always' in flag_values:
|
|
89
|
+
return True
|
|
90
|
+
|
|
91
|
+
if 'never' in flag_values:
|
|
92
|
+
return False
|
|
93
|
+
|
|
94
|
+
if _traceback.TracebackEvent.DEPRECATED_VALUE.name.lower() in flag_values:
|
|
95
|
+
flag_values.add(_traceback.TracebackEvent.DEPRECATED.name.lower()) # DEPRECATED_VALUE implies DEPRECATED
|
|
96
|
+
|
|
97
|
+
return event.name.lower() in flag_values
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
_traceback._is_traceback_enabled = _is_controller_traceback_enabled
|
|
101
|
+
|
|
102
|
+
|
|
76
103
|
def get_text_width(text: str) -> int:
|
|
77
104
|
"""Function that utilizes ``wcswidth`` or ``wcwidth`` to determine the
|
|
78
105
|
number of columns used to display a text string.
|
|
@@ -189,10 +216,22 @@ b_COW_PATHS = (
|
|
|
189
216
|
|
|
190
217
|
|
|
191
218
|
def _synchronize_textiowrapper(tio: t.TextIO, lock: threading.RLock):
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
219
|
+
"""
|
|
220
|
+
This decorator ensures that the supplied RLock is held before invoking the wrapped methods.
|
|
221
|
+
It is intended to prevent background threads from holding the Python stdout/stderr buffer lock on a file object during a fork.
|
|
222
|
+
Since background threads are abandoned in child forks, locks they hold are orphaned in a locked state.
|
|
223
|
+
Attempts to acquire an orphaned lock in this state will block forever, effectively hanging the child process on stdout/stderr writes.
|
|
224
|
+
The shared lock is permanently disabled immediately after a fork.
|
|
225
|
+
This prevents hangs in early post-fork code (e.g., stdio writes from pydevd, coverage, etc.) before user code has resumed and released the lock.
|
|
226
|
+
"""
|
|
227
|
+
|
|
195
228
|
def _wrap_with_lock(f, lock):
|
|
229
|
+
def disable_lock():
|
|
230
|
+
nonlocal lock
|
|
231
|
+
lock = contextlib.nullcontext()
|
|
232
|
+
|
|
233
|
+
os.register_at_fork(after_in_child=disable_lock)
|
|
234
|
+
|
|
196
235
|
@wraps(f)
|
|
197
236
|
def locking_wrapper(*args, **kwargs):
|
|
198
237
|
with lock:
|
|
@@ -281,9 +320,9 @@ class Display(metaclass=Singleton):
|
|
|
281
320
|
self.log_verbosity = max(verbosity, C.LOG_VERBOSITY)
|
|
282
321
|
|
|
283
322
|
# list of all deprecation messages to prevent duplicate display
|
|
284
|
-
self._deprecations:
|
|
285
|
-
self._warns:
|
|
286
|
-
self._errors:
|
|
323
|
+
self._deprecations: set[str] = set()
|
|
324
|
+
self._warns: set[str] = set()
|
|
325
|
+
self._errors: set[str] = set()
|
|
287
326
|
|
|
288
327
|
self.b_cowsay: bytes | None = None
|
|
289
328
|
self.noncow = C.ANSIBLE_COW_SELECTION
|
|
@@ -322,12 +361,9 @@ class Display(metaclass=Singleton):
|
|
|
322
361
|
self.setup_curses = False
|
|
323
362
|
|
|
324
363
|
def _replacing_warning_handler(self, exception: UnicodeError) -> tuple[str | bytes, int]:
|
|
325
|
-
#
|
|
326
|
-
#
|
|
327
|
-
self.
|
|
328
|
-
'Non UTF-8 encoded data replaced with "?" while displaying text to stdout/stderr, this is temporary and will become an error',
|
|
329
|
-
version='2.18',
|
|
330
|
-
)
|
|
364
|
+
# This can't be removed as long as we have the possibility of encountering un-renderable strings
|
|
365
|
+
# created with `surrogateescape`; the alternative of having display methods hard fail is untenable.
|
|
366
|
+
self.warning('Non UTF-8 encoded data replaced with "?" while displaying text to stdout/stderr.')
|
|
331
367
|
return '?', exception.end
|
|
332
368
|
|
|
333
369
|
def set_queue(self, queue: FinalQueue) -> None:
|
|
@@ -412,6 +448,10 @@ class Display(metaclass=Singleton):
|
|
|
412
448
|
if not isinstance(msg, str):
|
|
413
449
|
raise TypeError(f'Display message must be str, not: {msg.__class__.__name__}')
|
|
414
450
|
|
|
451
|
+
# Convert Windows newlines to Unix newlines.
|
|
452
|
+
# Some environments, such as Azure Pipelines, render `\r` as an additional `\n`.
|
|
453
|
+
msg = msg.replace('\r\n', '\n')
|
|
454
|
+
|
|
415
455
|
nocolor = msg
|
|
416
456
|
|
|
417
457
|
if not log_only:
|
|
@@ -445,7 +485,7 @@ class Display(metaclass=Singleton):
|
|
|
445
485
|
# final flush at shutdown.
|
|
446
486
|
# try:
|
|
447
487
|
# fileobj.flush()
|
|
448
|
-
# except
|
|
488
|
+
# except OSError as e:
|
|
449
489
|
# # Ignore EPIPE in case fileobj has been prematurely closed, eg.
|
|
450
490
|
# # when piping to "head -n1"
|
|
451
491
|
# if e.errno != errno.EPIPE:
|
|
@@ -535,41 +575,107 @@ class Display(metaclass=Singleton):
|
|
|
535
575
|
date: str | None = None,
|
|
536
576
|
collection_name: str | None = None,
|
|
537
577
|
) -> str:
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
578
|
+
"""Return a deprecation message and help text for non-display purposes (e.g., exception messages)."""
|
|
579
|
+
self.deprecated(
|
|
580
|
+
msg="The `get_deprecation_message` method is deprecated.",
|
|
581
|
+
help_text="Use the `deprecated` method instead.",
|
|
582
|
+
version="2.23",
|
|
583
|
+
)
|
|
542
584
|
|
|
543
|
-
|
|
544
|
-
|
|
585
|
+
msg = self._get_deprecation_message_with_plugin_info(
|
|
586
|
+
msg=msg,
|
|
587
|
+
version=version,
|
|
588
|
+
removed=removed,
|
|
589
|
+
date=date,
|
|
590
|
+
deprecator=deprecator_from_collection_name(collection_name),
|
|
591
|
+
)
|
|
592
|
+
|
|
593
|
+
if removed:
|
|
594
|
+
msg = f'[DEPRECATED]: {msg}'
|
|
595
|
+
else:
|
|
596
|
+
msg = f'[DEPRECATION WARNING]: {msg}'
|
|
597
|
+
|
|
598
|
+
return msg
|
|
599
|
+
|
|
600
|
+
def _get_deprecation_message_with_plugin_info(
|
|
601
|
+
self,
|
|
602
|
+
*,
|
|
603
|
+
msg: str,
|
|
604
|
+
version: str | None,
|
|
605
|
+
removed: bool = False,
|
|
606
|
+
date: str | None,
|
|
607
|
+
deprecator: _messages.PluginInfo | None,
|
|
608
|
+
) -> str:
|
|
609
|
+
"""Internal use only. Return a deprecation message and help text for display."""
|
|
610
|
+
# DTFIX-FUTURE: the logic for omitting date/version doesn't apply to the payload, so it shows up in vars in some cases when it should not
|
|
545
611
|
|
|
546
612
|
if removed:
|
|
547
|
-
header = '[DEPRECATED]: {0}'.format(msg)
|
|
548
613
|
removal_fragment = 'This feature was removed'
|
|
549
|
-
help_text = 'Please update your playbooks.'
|
|
550
614
|
else:
|
|
551
|
-
header = '[DEPRECATION WARNING]: {0}'.format(msg)
|
|
552
615
|
removal_fragment = 'This feature will be removed'
|
|
553
|
-
# FUTURE: make this a standalone warning so it only shows up once?
|
|
554
|
-
help_text = 'Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.'
|
|
555
616
|
|
|
556
|
-
if
|
|
557
|
-
|
|
617
|
+
if not deprecator or not deprecator.type:
|
|
618
|
+
# indeterminate has no resolved_name or type
|
|
619
|
+
# collections have a resolved_name but no type
|
|
620
|
+
collection = deprecator.resolved_name if deprecator else None
|
|
621
|
+
plugin_fragment = ''
|
|
622
|
+
elif deprecator.resolved_name == 'ansible.builtin':
|
|
623
|
+
# core deprecations from base classes (the API) have no plugin name, only 'ansible.builtin'
|
|
624
|
+
plugin_type_name = str(deprecator.type) if deprecator.type is _messages.PluginType.MODULE else f'{deprecator.type} plugin'
|
|
625
|
+
|
|
626
|
+
collection = deprecator.resolved_name
|
|
627
|
+
plugin_fragment = f'the {plugin_type_name} API'
|
|
558
628
|
else:
|
|
559
|
-
|
|
629
|
+
parts = deprecator.resolved_name.split('.')
|
|
630
|
+
plugin_name = parts[-1]
|
|
631
|
+
plugin_type_name = str(deprecator.type) if deprecator.type is _messages.PluginType.MODULE else f'{deprecator.type} plugin'
|
|
632
|
+
|
|
633
|
+
collection = '.'.join(parts[:2]) if len(parts) > 2 else None
|
|
634
|
+
plugin_fragment = f'{plugin_type_name} {plugin_name!r}'
|
|
560
635
|
|
|
561
|
-
if
|
|
562
|
-
|
|
636
|
+
if collection and plugin_fragment:
|
|
637
|
+
plugin_fragment += ' in'
|
|
638
|
+
|
|
639
|
+
if collection == 'ansible.builtin':
|
|
640
|
+
collection_fragment = 'ansible-core'
|
|
641
|
+
elif collection:
|
|
642
|
+
collection_fragment = f'collection {collection!r}'
|
|
643
|
+
else:
|
|
644
|
+
collection_fragment = ''
|
|
645
|
+
|
|
646
|
+
if not collection:
|
|
647
|
+
when_fragment = 'in the future' if not removed else ''
|
|
648
|
+
elif date:
|
|
649
|
+
when_fragment = f'in a release after {date}'
|
|
563
650
|
elif version:
|
|
564
|
-
|
|
651
|
+
when_fragment = f'version {version}'
|
|
565
652
|
else:
|
|
566
|
-
|
|
653
|
+
when_fragment = 'in a future release' if not removed else ''
|
|
567
654
|
|
|
568
|
-
|
|
655
|
+
if plugin_fragment or collection_fragment:
|
|
656
|
+
from_fragment = 'from'
|
|
657
|
+
else:
|
|
658
|
+
from_fragment = ''
|
|
569
659
|
|
|
570
|
-
|
|
660
|
+
deprecation_msg = ' '.join(f for f in [removal_fragment, from_fragment, plugin_fragment, collection_fragment, when_fragment] if f) + '.'
|
|
661
|
+
|
|
662
|
+
return _join_sentences(msg, deprecation_msg)
|
|
663
|
+
|
|
664
|
+
@staticmethod
|
|
665
|
+
def _deduplicate(msg: str, messages: set[str]) -> bool:
|
|
666
|
+
"""
|
|
667
|
+
Return True if the given message was previously seen, otherwise record the message as seen and return False.
|
|
668
|
+
This is done very late (at display-time) to avoid loss of attribution of messages to individual tasks.
|
|
669
|
+
Duplicates included in task results will always be visible to registered variables and callbacks.
|
|
670
|
+
"""
|
|
671
|
+
|
|
672
|
+
if msg in messages:
|
|
673
|
+
return True
|
|
674
|
+
|
|
675
|
+
messages.add(msg)
|
|
676
|
+
|
|
677
|
+
return False
|
|
571
678
|
|
|
572
|
-
@_proxy
|
|
573
679
|
def deprecated(
|
|
574
680
|
self,
|
|
575
681
|
msg: str,
|
|
@@ -577,35 +683,155 @@ class Display(metaclass=Singleton):
|
|
|
577
683
|
removed: bool = False,
|
|
578
684
|
date: str | None = None,
|
|
579
685
|
collection_name: str | None = None,
|
|
686
|
+
*,
|
|
687
|
+
deprecator: _messages.PluginInfo | None = None,
|
|
688
|
+
help_text: str | None = None,
|
|
689
|
+
obj: t.Any = None,
|
|
580
690
|
) -> None:
|
|
581
|
-
|
|
582
|
-
|
|
691
|
+
"""
|
|
692
|
+
Display a deprecation warning message, if enabled.
|
|
693
|
+
Most callers do not need to provide `collection_name` or `deprecator` -- but provide only one if needed.
|
|
694
|
+
Specify `version` or `date`, but not both.
|
|
695
|
+
If `date` is a string, it must be in the form `YYYY-MM-DD`.
|
|
696
|
+
"""
|
|
697
|
+
# DTFIX3: are there any deprecation calls where the feature is switching from enabled to disabled, rather than being removed entirely?
|
|
698
|
+
# DTFIX3: are there deprecated features which should going through deferred deprecation instead?
|
|
699
|
+
|
|
700
|
+
_skip_stackwalk = True
|
|
701
|
+
|
|
702
|
+
self._deprecated_with_plugin_info(
|
|
703
|
+
msg=msg,
|
|
704
|
+
version=version,
|
|
705
|
+
removed=removed,
|
|
706
|
+
date=date,
|
|
707
|
+
help_text=help_text,
|
|
708
|
+
obj=obj,
|
|
709
|
+
deprecator=_deprecator.get_best_deprecator(deprecator=deprecator, collection_name=collection_name),
|
|
710
|
+
formatted_traceback=_traceback.maybe_capture_traceback(msg, _traceback.TracebackEvent.DEPRECATED),
|
|
711
|
+
)
|
|
583
712
|
|
|
584
|
-
|
|
713
|
+
def _deprecated_with_plugin_info(
|
|
714
|
+
self,
|
|
715
|
+
*,
|
|
716
|
+
msg: str,
|
|
717
|
+
version: str | None,
|
|
718
|
+
removed: bool = False,
|
|
719
|
+
date: str | None,
|
|
720
|
+
help_text: str | None,
|
|
721
|
+
obj: t.Any,
|
|
722
|
+
deprecator: _messages.PluginInfo | None,
|
|
723
|
+
formatted_traceback: str | None = None,
|
|
724
|
+
) -> None:
|
|
725
|
+
"""
|
|
726
|
+
This is the internal pre-proxy half of the `deprecated` implementation.
|
|
727
|
+
Any logic that must occur on workers needs to be implemented here.
|
|
728
|
+
"""
|
|
729
|
+
_skip_stackwalk = True
|
|
585
730
|
|
|
586
731
|
if removed:
|
|
587
|
-
|
|
732
|
+
formatted_msg = self._get_deprecation_message_with_plugin_info(
|
|
733
|
+
msg=msg,
|
|
734
|
+
version=version,
|
|
735
|
+
removed=removed,
|
|
736
|
+
date=date,
|
|
737
|
+
deprecator=deprecator,
|
|
738
|
+
)
|
|
588
739
|
|
|
589
|
-
|
|
590
|
-
message_text = "\n".join(wrapped) + "\n"
|
|
740
|
+
raise AnsibleError(formatted_msg)
|
|
591
741
|
|
|
592
|
-
if
|
|
593
|
-
|
|
594
|
-
|
|
742
|
+
if source_context := _error_utils.SourceContext.from_value(obj):
|
|
743
|
+
formatted_source_context = str(source_context)
|
|
744
|
+
else:
|
|
745
|
+
formatted_source_context = None
|
|
746
|
+
|
|
747
|
+
deprecation = _messages.DeprecationSummary(
|
|
748
|
+
event=_messages.Event(
|
|
749
|
+
msg=msg,
|
|
750
|
+
formatted_source_context=formatted_source_context,
|
|
751
|
+
help_text=help_text,
|
|
752
|
+
formatted_traceback=formatted_traceback,
|
|
753
|
+
),
|
|
754
|
+
version=version,
|
|
755
|
+
date=date,
|
|
756
|
+
deprecator=deprecator,
|
|
757
|
+
)
|
|
758
|
+
|
|
759
|
+
if warning_ctx := _DeferredWarningContext.current(optional=True):
|
|
760
|
+
warning_ctx.capture(deprecation)
|
|
761
|
+
return
|
|
762
|
+
|
|
763
|
+
self._deprecated(deprecation)
|
|
595
764
|
|
|
596
765
|
@_proxy
|
|
597
|
-
def
|
|
766
|
+
def _deprecated(self, warning: _messages.DeprecationSummary) -> None:
|
|
767
|
+
"""Internal implementation detail, use `deprecated` instead."""
|
|
768
|
+
|
|
769
|
+
# This is the post-proxy half of the `deprecated` implementation.
|
|
770
|
+
# Any logic that must occur in the primary controller process needs to be implemented here.
|
|
771
|
+
|
|
772
|
+
if not _DeferredWarningContext.deprecation_warnings_enabled():
|
|
773
|
+
return
|
|
774
|
+
|
|
775
|
+
self.warning('Deprecation warnings can be disabled by setting `deprecation_warnings=False` in ansible.cfg.')
|
|
776
|
+
|
|
777
|
+
msg = _format_message(warning, _traceback.is_traceback_enabled(_traceback.TracebackEvent.DEPRECATED))
|
|
778
|
+
msg = f'[DEPRECATION WARNING]: {msg}'
|
|
779
|
+
|
|
780
|
+
if self._deduplicate(msg, self._deprecations):
|
|
781
|
+
return
|
|
782
|
+
|
|
783
|
+
self.display(msg, color=C.config.get_config_value('COLOR_DEPRECATE'), stderr=True)
|
|
784
|
+
|
|
785
|
+
def warning(
|
|
786
|
+
self,
|
|
787
|
+
msg: str,
|
|
788
|
+
formatted: bool = False,
|
|
789
|
+
*,
|
|
790
|
+
help_text: str | None = None,
|
|
791
|
+
obj: t.Any = None
|
|
792
|
+
) -> None:
|
|
793
|
+
"""Display a warning message."""
|
|
794
|
+
_skip_stackwalk = True
|
|
795
|
+
|
|
796
|
+
# deprecated: description='The formatted argument has no effect.' core_version='2.23'
|
|
797
|
+
|
|
798
|
+
# This is the pre-proxy half of the `warning` implementation.
|
|
799
|
+
# Any logic that must occur on workers needs to be implemented here.
|
|
598
800
|
|
|
599
|
-
if
|
|
600
|
-
|
|
601
|
-
wrapped = textwrap.wrap(new_msg, self.columns)
|
|
602
|
-
new_msg = "\n".join(wrapped) + "\n"
|
|
801
|
+
if source_context := _error_utils.SourceContext.from_value(obj):
|
|
802
|
+
formatted_source_context = str(source_context)
|
|
603
803
|
else:
|
|
604
|
-
|
|
804
|
+
formatted_source_context = None
|
|
805
|
+
|
|
806
|
+
warning = _messages.WarningSummary(
|
|
807
|
+
event=_messages.Event(
|
|
808
|
+
msg=msg,
|
|
809
|
+
help_text=help_text,
|
|
810
|
+
formatted_source_context=formatted_source_context,
|
|
811
|
+
formatted_traceback=_traceback.maybe_capture_traceback(msg, _traceback.TracebackEvent.WARNING),
|
|
812
|
+
),
|
|
813
|
+
)
|
|
814
|
+
|
|
815
|
+
if warning_ctx := _DeferredWarningContext.current(optional=True):
|
|
816
|
+
warning_ctx.capture(warning)
|
|
817
|
+
return
|
|
818
|
+
|
|
819
|
+
self._warning(warning)
|
|
820
|
+
|
|
821
|
+
@_proxy
|
|
822
|
+
def _warning(self, warning: _messages.WarningSummary) -> None:
|
|
823
|
+
"""Internal implementation detail, use `warning` instead."""
|
|
824
|
+
|
|
825
|
+
# This is the post-proxy half of the `warning` implementation.
|
|
826
|
+
# Any logic that must occur in the primary controller process needs to be implemented here.
|
|
827
|
+
|
|
828
|
+
msg = _format_message(warning, _traceback.is_traceback_enabled(_traceback.TracebackEvent.WARNING))
|
|
829
|
+
msg = f"[WARNING]: {msg}"
|
|
830
|
+
|
|
831
|
+
if self._deduplicate(msg, self._warns):
|
|
832
|
+
return
|
|
605
833
|
|
|
606
|
-
|
|
607
|
-
self.display(new_msg, color=C.COLOR_WARN, stderr=True, caplevel=-2)
|
|
608
|
-
self._warns[new_msg] = 1
|
|
834
|
+
self.display(msg, color=C.config.get_config_value('COLOR_WARN'), stderr=True, caplevel=-2)
|
|
609
835
|
|
|
610
836
|
@_proxy
|
|
611
837
|
def system_warning(self, msg: str) -> None:
|
|
@@ -614,9 +840,9 @@ class Display(metaclass=Singleton):
|
|
|
614
840
|
|
|
615
841
|
@_proxy
|
|
616
842
|
def banner(self, msg: str, color: str | None = None, cows: bool = True) -> None:
|
|
617
|
-
|
|
843
|
+
"""
|
|
618
844
|
Prints a header-looking line with cowsay or stars with length depending on terminal width (3 minimum)
|
|
619
|
-
|
|
845
|
+
"""
|
|
620
846
|
msg = to_text(msg)
|
|
621
847
|
|
|
622
848
|
if self.b_cowsay and cows:
|
|
@@ -654,17 +880,85 @@ class Display(metaclass=Singleton):
|
|
|
654
880
|
(out, err) = cmd.communicate()
|
|
655
881
|
self.display(u"%s\n" % to_text(out), color=color)
|
|
656
882
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
883
|
+
def error_as_warning(
|
|
884
|
+
self,
|
|
885
|
+
msg: str | None,
|
|
886
|
+
exception: BaseException,
|
|
887
|
+
*,
|
|
888
|
+
help_text: str | None = None,
|
|
889
|
+
obj: t.Any = None,
|
|
890
|
+
) -> None:
|
|
891
|
+
"""Display an exception as a warning."""
|
|
892
|
+
_skip_stackwalk = True
|
|
893
|
+
|
|
894
|
+
event = _error_factory.ControllerEventFactory.from_exception(exception, _traceback.is_traceback_enabled(_traceback.TracebackEvent.WARNING))
|
|
895
|
+
|
|
896
|
+
if msg:
|
|
897
|
+
if source_context := _error_utils.SourceContext.from_value(obj):
|
|
898
|
+
formatted_source_context = str(source_context)
|
|
899
|
+
else:
|
|
900
|
+
formatted_source_context = None
|
|
901
|
+
|
|
902
|
+
event = _messages.Event(
|
|
903
|
+
msg=msg,
|
|
904
|
+
help_text=help_text,
|
|
905
|
+
formatted_source_context=formatted_source_context,
|
|
906
|
+
formatted_traceback=_traceback.maybe_capture_traceback(msg, _traceback.TracebackEvent.WARNING),
|
|
907
|
+
chain=_messages.EventChain(
|
|
908
|
+
msg_reason=_errors.MSG_REASON_DIRECT_CAUSE,
|
|
909
|
+
traceback_reason=_errors.TRACEBACK_REASON_EXCEPTION_DIRECT_WARNING,
|
|
910
|
+
event=event,
|
|
911
|
+
),
|
|
912
|
+
)
|
|
913
|
+
|
|
914
|
+
warning = _messages.WarningSummary(
|
|
915
|
+
event=event,
|
|
916
|
+
)
|
|
917
|
+
|
|
918
|
+
if warning_ctx := _DeferredWarningContext.current(optional=True):
|
|
919
|
+
warning_ctx.capture(warning)
|
|
920
|
+
return
|
|
921
|
+
|
|
922
|
+
self._warning(warning)
|
|
923
|
+
|
|
924
|
+
def error(self, msg: str | BaseException, wrap_text: bool = True, stderr: bool = True) -> None:
|
|
925
|
+
"""Display an error message."""
|
|
926
|
+
_skip_stackwalk = True
|
|
927
|
+
|
|
928
|
+
# deprecated: description='The wrap_text argument has no effect.' core_version='2.23'
|
|
929
|
+
# deprecated: description='The stderr argument has no effect.' core_version='2.23'
|
|
930
|
+
|
|
931
|
+
# This is the pre-proxy half of the `error` implementation.
|
|
932
|
+
# Any logic that must occur on workers needs to be implemented here.
|
|
933
|
+
|
|
934
|
+
if isinstance(msg, BaseException):
|
|
935
|
+
event = _error_factory.ControllerEventFactory.from_exception(msg, _traceback.is_traceback_enabled(_traceback.TracebackEvent.ERROR))
|
|
663
936
|
else:
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
937
|
+
event = _messages.Event(
|
|
938
|
+
msg=msg,
|
|
939
|
+
formatted_traceback=_traceback.maybe_capture_traceback(msg, _traceback.TracebackEvent.ERROR),
|
|
940
|
+
)
|
|
941
|
+
|
|
942
|
+
error = _messages.ErrorSummary(
|
|
943
|
+
event=event,
|
|
944
|
+
)
|
|
945
|
+
|
|
946
|
+
self._error(error, stderr=True)
|
|
947
|
+
|
|
948
|
+
@_proxy
|
|
949
|
+
def _error(self, error: _messages.ErrorSummary, stderr: bool) -> None:
|
|
950
|
+
"""Internal implementation detail, use `error` instead."""
|
|
951
|
+
|
|
952
|
+
# This is the post-proxy half of the `error` implementation.
|
|
953
|
+
# Any logic that must occur in the primary controller process needs to be implemented here.
|
|
954
|
+
|
|
955
|
+
msg = _format_message(error, _traceback.is_traceback_enabled(_traceback.TracebackEvent.ERROR))
|
|
956
|
+
msg = f'[ERROR]: {msg}'
|
|
957
|
+
|
|
958
|
+
if self._deduplicate(msg, self._errors):
|
|
959
|
+
return
|
|
960
|
+
|
|
961
|
+
self.display(msg, color=C.config.get_config_value('COLOR_ERROR'), stderr=stderr, caplevel=-1)
|
|
668
962
|
|
|
669
963
|
@staticmethod
|
|
670
964
|
def prompt(msg: str, private: bool = False) -> str:
|
|
@@ -722,8 +1016,10 @@ class Display(metaclass=Singleton):
|
|
|
722
1016
|
# handle utf-8 chars
|
|
723
1017
|
result = to_text(result, errors='surrogate_or_strict')
|
|
724
1018
|
|
|
725
|
-
if unsafe:
|
|
726
|
-
|
|
1019
|
+
if not unsafe:
|
|
1020
|
+
# to maintain backward compatibility, assume these values are safe to template
|
|
1021
|
+
result = TrustedAsTemplate().tag(result)
|
|
1022
|
+
|
|
727
1023
|
return result
|
|
728
1024
|
|
|
729
1025
|
def _set_column_width(self) -> None:
|
|
@@ -738,8 +1034,8 @@ class Display(metaclass=Singleton):
|
|
|
738
1034
|
msg: str,
|
|
739
1035
|
private: bool = False,
|
|
740
1036
|
seconds: int | None = None,
|
|
741
|
-
interrupt_input: c.
|
|
742
|
-
complete_input: c.
|
|
1037
|
+
interrupt_input: c.Iterable[bytes] | None = None,
|
|
1038
|
+
complete_input: c.Iterable[bytes] | None = None,
|
|
743
1039
|
) -> bytes:
|
|
744
1040
|
if self._final_q:
|
|
745
1041
|
from ansible.executor.process.worker import current_worker
|
|
@@ -794,8 +1090,8 @@ class Display(metaclass=Singleton):
|
|
|
794
1090
|
self,
|
|
795
1091
|
echo: bool = False,
|
|
796
1092
|
seconds: int | None = None,
|
|
797
|
-
interrupt_input: c.
|
|
798
|
-
complete_input: c.
|
|
1093
|
+
interrupt_input: c.Iterable[bytes] | None = None,
|
|
1094
|
+
complete_input: c.Iterable[bytes] | None = None,
|
|
799
1095
|
) -> bytes:
|
|
800
1096
|
if self._final_q:
|
|
801
1097
|
raise NotImplementedError
|
|
@@ -872,3 +1168,119 @@ class Display(metaclass=Singleton):
|
|
|
872
1168
|
return self._stdout.fileno()
|
|
873
1169
|
except (ValueError, AttributeError):
|
|
874
1170
|
return None
|
|
1171
|
+
|
|
1172
|
+
|
|
1173
|
+
_display = Display()
|
|
1174
|
+
|
|
1175
|
+
|
|
1176
|
+
class _DeferredWarningContext(_ambient_context.AmbientContextBase):
|
|
1177
|
+
"""
|
|
1178
|
+
Calls to `Display.warning()` and `Display.deprecated()` within this context will cause the resulting warnings to be captured and not displayed.
|
|
1179
|
+
The intended use is for task-initiated warnings to be recorded with the task result, which makes them visible to registered results, callbacks, etc.
|
|
1180
|
+
The active display callback is responsible for communicating any warnings to the user.
|
|
1181
|
+
"""
|
|
1182
|
+
|
|
1183
|
+
# DTFIX-FUTURE: once we start implementing nested scoped contexts for our own bookkeeping, this should be an interface facade that forwards to the nearest
|
|
1184
|
+
# context that actually implements the warnings collection capability
|
|
1185
|
+
|
|
1186
|
+
def __init__(self, *, variables: dict[str, object]) -> None:
|
|
1187
|
+
self._variables = variables # DTFIX-FUTURE: move this to an AmbientContext-derived TaskContext (once it exists)
|
|
1188
|
+
self._deprecation_warnings: list[_messages.DeprecationSummary] = []
|
|
1189
|
+
self._warnings: list[_messages.WarningSummary] = []
|
|
1190
|
+
self._seen: set[_messages.WarningSummary] = set()
|
|
1191
|
+
|
|
1192
|
+
@classmethod
|
|
1193
|
+
def deprecation_warnings_enabled(cls) -> bool:
|
|
1194
|
+
"""Return True if deprecation warnings are enabled for the current calling context, otherwise False."""
|
|
1195
|
+
# DTFIX-FUTURE: move this capability into config using an AmbientContext-derived TaskContext (once it exists)
|
|
1196
|
+
if warning_ctx := cls.current(optional=True):
|
|
1197
|
+
variables = warning_ctx._variables
|
|
1198
|
+
else:
|
|
1199
|
+
variables = None
|
|
1200
|
+
|
|
1201
|
+
return C.config.get_config_value('DEPRECATION_WARNINGS', variables=variables)
|
|
1202
|
+
|
|
1203
|
+
def capture(self, warning: _messages.WarningSummary) -> None:
|
|
1204
|
+
"""Add the warning/deprecation to the context if it has not already been seen by this context."""
|
|
1205
|
+
if warning in self._seen:
|
|
1206
|
+
return
|
|
1207
|
+
|
|
1208
|
+
self._seen.add(warning)
|
|
1209
|
+
|
|
1210
|
+
if isinstance(warning, _messages.DeprecationSummary):
|
|
1211
|
+
self._deprecation_warnings.append(warning)
|
|
1212
|
+
else:
|
|
1213
|
+
self._warnings.append(warning)
|
|
1214
|
+
|
|
1215
|
+
def get_warnings(self) -> list[_messages.WarningSummary]:
|
|
1216
|
+
"""Return a list of the captured non-deprecation warnings."""
|
|
1217
|
+
# DTFIX-FUTURE: return a read-only list proxy instead
|
|
1218
|
+
return self._warnings
|
|
1219
|
+
|
|
1220
|
+
def get_deprecation_warnings(self) -> list[_messages.DeprecationSummary]:
|
|
1221
|
+
"""Return a list of the captured deprecation warnings."""
|
|
1222
|
+
# DTFIX-FUTURE: return a read-only list proxy instead
|
|
1223
|
+
return self._deprecation_warnings
|
|
1224
|
+
|
|
1225
|
+
|
|
1226
|
+
def _join_sentences(first: str | None, second: str | None) -> str:
|
|
1227
|
+
"""Join two sentences together."""
|
|
1228
|
+
first = (first or '').strip()
|
|
1229
|
+
second = (second or '').strip()
|
|
1230
|
+
|
|
1231
|
+
if first and first[-1] not in ('!', '?', '.'):
|
|
1232
|
+
first += '.'
|
|
1233
|
+
|
|
1234
|
+
if second and second[-1] not in ('!', '?', '.'):
|
|
1235
|
+
second += '.'
|
|
1236
|
+
|
|
1237
|
+
if first and not second:
|
|
1238
|
+
return first
|
|
1239
|
+
|
|
1240
|
+
if not first and second:
|
|
1241
|
+
return second
|
|
1242
|
+
|
|
1243
|
+
return ' '.join((first, second))
|
|
1244
|
+
|
|
1245
|
+
|
|
1246
|
+
def _format_message(summary: _messages.SummaryBase, include_traceback: bool) -> str:
|
|
1247
|
+
if isinstance(summary, _messages.DeprecationSummary):
|
|
1248
|
+
deprecation_message = _display._get_deprecation_message_with_plugin_info(
|
|
1249
|
+
msg=summary.event.msg,
|
|
1250
|
+
version=summary.version,
|
|
1251
|
+
date=summary.date,
|
|
1252
|
+
deprecator=summary.deprecator,
|
|
1253
|
+
)
|
|
1254
|
+
|
|
1255
|
+
event = dataclasses.replace(summary.event, msg=deprecation_message)
|
|
1256
|
+
else:
|
|
1257
|
+
event = summary.event
|
|
1258
|
+
|
|
1259
|
+
return _event_formatting.format_event(event, include_traceback)
|
|
1260
|
+
|
|
1261
|
+
|
|
1262
|
+
def _report_config_warnings(deprecator: _messages.PluginInfo) -> None:
|
|
1263
|
+
"""Called by config to report warnings/deprecations collected during a config parse."""
|
|
1264
|
+
while config._errors:
|
|
1265
|
+
msg, exception = config._errors.pop()
|
|
1266
|
+
_display.error_as_warning(msg=msg, exception=exception)
|
|
1267
|
+
|
|
1268
|
+
while config.WARNINGS:
|
|
1269
|
+
warn = config.WARNINGS.pop()
|
|
1270
|
+
_display.warning(warn)
|
|
1271
|
+
|
|
1272
|
+
while config.DEPRECATED:
|
|
1273
|
+
# tuple with name and options
|
|
1274
|
+
dep = config.DEPRECATED.pop(0)
|
|
1275
|
+
msg = config.get_deprecated_msg_from_config(dep[1]).replace("\t", "")
|
|
1276
|
+
|
|
1277
|
+
_display.deprecated( # pylint: disable=ansible-deprecated-unnecessary-collection-name,ansible-invalid-deprecated-version
|
|
1278
|
+
msg=f"{dep[0]} option. {msg}",
|
|
1279
|
+
version=dep[1]['version'],
|
|
1280
|
+
deprecator=deprecator,
|
|
1281
|
+
)
|
|
1282
|
+
|
|
1283
|
+
|
|
1284
|
+
# emit any warnings or deprecations
|
|
1285
|
+
# in the event config fails before display is up, we'll lose warnings -- but that's OK, since everything is broken anyway
|
|
1286
|
+
_report_config_warnings(_deprecator.ANSIBLE_CORE_DEPRECATOR)
|