ansible-core 2.18.5rc1__py3-none-any.whl → 2.19.0b2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ansible/_internal/__init__.py +53 -0
- ansible/_internal/_ansiballz.py +265 -0
- ansible/_internal/_collection_proxy.py +47 -0
- ansible/_internal/_datatag/__init__.py +0 -0
- ansible/_internal/_datatag/_tags.py +130 -0
- ansible/_internal/_datatag/_utils.py +19 -0
- ansible/_internal/_datatag/_wrappers.py +33 -0
- ansible/_internal/_errors/__init__.py +0 -0
- ansible/_internal/_errors/_captured.py +128 -0
- ansible/_internal/_errors/_handler.py +91 -0
- ansible/_internal/_errors/_utils.py +310 -0
- ansible/_internal/_json/__init__.py +203 -0
- ansible/_internal/_json/_legacy_encoder.py +34 -0
- ansible/_internal/_json/_profiles/__init__.py +0 -0
- ansible/_internal/_json/_profiles/_cache_persistence.py +55 -0
- ansible/_internal/_json/_profiles/_inventory_legacy.py +40 -0
- ansible/_internal/_json/_profiles/_legacy.py +197 -0
- ansible/_internal/_locking.py +21 -0
- ansible/_internal/_plugins/__init__.py +0 -0
- ansible/_internal/_plugins/_cache.py +57 -0
- ansible/_internal/_task.py +78 -0
- ansible/_internal/_templating/__init__.py +10 -0
- ansible/_internal/_templating/_access.py +86 -0
- ansible/_internal/_templating/_chain_templar.py +63 -0
- ansible/_internal/_templating/_datatag.py +95 -0
- ansible/_internal/_templating/_engine.py +588 -0
- ansible/_internal/_templating/_errors.py +28 -0
- ansible/_internal/_templating/_jinja_bits.py +1066 -0
- ansible/_internal/_templating/_jinja_common.py +332 -0
- ansible/_internal/_templating/_jinja_patches.py +44 -0
- ansible/_internal/_templating/_jinja_plugins.py +345 -0
- ansible/_internal/_templating/_lazy_containers.py +633 -0
- ansible/_internal/_templating/_marker_behaviors.py +103 -0
- ansible/_internal/_templating/_transform.py +63 -0
- ansible/_internal/_templating/_utils.py +107 -0
- ansible/_internal/_wrapt.py +1052 -0
- ansible/_internal/_yaml/__init__.py +0 -0
- ansible/_internal/_yaml/_constructor.py +240 -0
- ansible/_internal/_yaml/_dumper.py +62 -0
- ansible/_internal/_yaml/_errors.py +166 -0
- ansible/_internal/_yaml/_loader.py +66 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/README.md +11 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/debug.py +36 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/apply_trust.py +19 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/dump_object.py +18 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/finalize.py +16 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/origin.py +18 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.py +24 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.yml +33 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/tag_names.py +16 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +17 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +49 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.py +21 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.yml +2 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.py +15 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.yml +19 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.py +18 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.yml +19 -0
- ansible/cli/__init__.py +159 -89
- ansible/cli/_ssh_askpass.py +47 -0
- ansible/cli/adhoc.py +14 -7
- ansible/cli/arguments/option_helpers.py +154 -7
- ansible/cli/config.py +43 -68
- ansible/cli/console.py +10 -8
- ansible/cli/doc.py +62 -53
- ansible/cli/galaxy.py +27 -20
- ansible/cli/inventory.py +28 -26
- ansible/cli/playbook.py +4 -12
- ansible/cli/pull.py +51 -11
- ansible/cli/scripts/ansible_connection_cli_stub.py +7 -7
- ansible/cli/vault.py +12 -11
- ansible/compat/__init__.py +2 -2
- ansible/config/base.yml +166 -112
- ansible/config/manager.py +52 -49
- ansible/constants.py +3 -4
- ansible/errors/__init__.py +277 -235
- ansible/executor/interpreter_discovery.py +28 -149
- ansible/executor/module_common.py +426 -493
- ansible/executor/play_iterator.py +22 -27
- ansible/executor/playbook_executor.py +11 -11
- ansible/executor/powershell/async_watchdog.ps1 +97 -102
- ansible/executor/powershell/async_wrapper.ps1 +202 -151
- ansible/executor/powershell/become_wrapper.ps1 +89 -144
- ansible/executor/powershell/bootstrap_wrapper.ps1 +24 -9
- ansible/executor/powershell/coverage_wrapper.ps1 +82 -135
- ansible/executor/powershell/exec_wrapper.ps1 +462 -196
- ansible/executor/powershell/module_manifest.py +417 -265
- ansible/executor/powershell/module_wrapper.ps1 +169 -186
- ansible/executor/powershell/psrp_fetch_file.ps1 +41 -0
- ansible/executor/powershell/psrp_put_file.ps1 +122 -0
- ansible/executor/powershell/winrm_fetch_file.ps1 +46 -0
- ansible/executor/powershell/winrm_put_file.ps1 +36 -0
- ansible/executor/process/worker.py +161 -96
- ansible/executor/stats.py +5 -5
- ansible/executor/task_executor.py +268 -258
- ansible/executor/task_queue_manager.py +124 -90
- ansible/executor/task_result.py +183 -78
- ansible/galaxy/__init__.py +2 -2
- ansible/galaxy/api.py +22 -18
- ansible/galaxy/collection/__init__.py +1 -1
- ansible/galaxy/collection/concrete_artifact_manager.py +8 -11
- ansible/galaxy/dependency_resolution/dataclasses.py +14 -4
- ansible/galaxy/dependency_resolution/providers.py +1 -1
- ansible/galaxy/dependency_resolution/reporters.py +81 -0
- ansible/galaxy/role.py +4 -8
- ansible/galaxy/token.py +28 -21
- ansible/inventory/data.py +47 -57
- ansible/inventory/group.py +44 -72
- ansible/inventory/helpers.py +9 -0
- ansible/inventory/host.py +32 -54
- ansible/inventory/manager.py +78 -34
- ansible/keyword_desc.yml +1 -1
- ansible/module_utils/_internal/__init__.py +55 -0
- ansible/module_utils/_internal/_ambient_context.py +58 -0
- ansible/module_utils/_internal/_ansiballz.py +133 -0
- ansible/module_utils/_internal/_concurrent/_daemon_threading.py +1 -0
- ansible/module_utils/_internal/_dataclass_annotation_patch.py +64 -0
- ansible/module_utils/_internal/_dataclass_validation.py +217 -0
- ansible/module_utils/_internal/_datatag/__init__.py +928 -0
- ansible/module_utils/_internal/_datatag/_tags.py +38 -0
- ansible/module_utils/_internal/_debugging.py +31 -0
- ansible/module_utils/_internal/_errors.py +30 -0
- ansible/module_utils/_internal/_json/__init__.py +63 -0
- ansible/module_utils/_internal/_json/_legacy_encoder.py +26 -0
- ansible/module_utils/_internal/_json/_profiles/__init__.py +410 -0
- ansible/module_utils/_internal/_json/_profiles/_fallback_to_str.py +73 -0
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +31 -0
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +35 -0
- ansible/module_utils/_internal/_json/_profiles/_module_modern_c2m.py +35 -0
- ansible/module_utils/_internal/_json/_profiles/_module_modern_m2c.py +33 -0
- ansible/module_utils/_internal/_json/_profiles/_tagless.py +50 -0
- ansible/module_utils/_internal/_patches/__init__.py +66 -0
- ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +55 -0
- ansible/module_utils/_internal/_patches/_socket_patch.py +34 -0
- ansible/module_utils/_internal/_patches/_sys_intern_patch.py +34 -0
- ansible/module_utils/_internal/_plugin_exec_context.py +49 -0
- ansible/module_utils/_internal/_testing.py +0 -0
- ansible/module_utils/_internal/_traceback.py +89 -0
- ansible/module_utils/ansible_release.py +2 -2
- ansible/module_utils/api.py +1 -2
- ansible/module_utils/basic.py +152 -120
- ansible/module_utils/common/_utils.py +24 -28
- ansible/module_utils/common/collections.py +1 -2
- ansible/module_utils/common/dict_transformations.py +2 -2
- ansible/module_utils/common/file.py +2 -2
- ansible/module_utils/common/json.py +90 -84
- ansible/module_utils/common/locale.py +2 -2
- ansible/module_utils/common/messages.py +108 -0
- ansible/module_utils/common/parameters.py +27 -24
- ansible/module_utils/common/process.py +2 -2
- ansible/module_utils/common/respawn.py +41 -19
- ansible/module_utils/common/sentinel.py +66 -0
- ansible/module_utils/common/sys_info.py +8 -8
- ansible/module_utils/common/text/converters.py +16 -37
- ansible/module_utils/common/validation.py +35 -24
- ansible/module_utils/common/warnings.py +86 -25
- ansible/module_utils/common/yaml.py +29 -3
- ansible/module_utils/compat/datetime.py +33 -21
- ansible/module_utils/compat/paramiko.py +21 -10
- ansible/module_utils/compat/typing.py +6 -5
- ansible/module_utils/connection.py +2 -2
- ansible/module_utils/csharp/Ansible.Basic.cs +14 -11
- ansible/module_utils/csharp/Ansible.Become.cs +1 -0
- ansible/module_utils/csharp/Ansible._Async.cs +517 -0
- ansible/module_utils/datatag.py +46 -0
- ansible/module_utils/distro/__init__.py +2 -2
- ansible/module_utils/facts/ansible_collector.py +4 -5
- ansible/module_utils/facts/collector.py +13 -14
- ansible/module_utils/facts/compat.py +4 -4
- ansible/module_utils/facts/default_collectors.py +1 -1
- ansible/module_utils/facts/hardware/aix.py +34 -0
- ansible/module_utils/facts/hardware/base.py +1 -1
- ansible/module_utils/facts/hardware/darwin.py +1 -3
- ansible/module_utils/facts/hardware/freebsd.py +2 -2
- ansible/module_utils/facts/hardware/linux.py +4 -4
- ansible/module_utils/facts/namespace.py +1 -1
- ansible/module_utils/facts/network/base.py +1 -1
- ansible/module_utils/facts/network/fc_wwn.py +1 -2
- ansible/module_utils/facts/network/iscsi.py +1 -2
- ansible/module_utils/facts/network/nvme.py +1 -2
- ansible/module_utils/facts/other/facter.py +1 -2
- ansible/module_utils/facts/other/ohai.py +2 -3
- ansible/module_utils/facts/system/apparmor.py +1 -2
- ansible/module_utils/facts/system/caps.py +1 -1
- ansible/module_utils/facts/system/chroot.py +1 -2
- ansible/module_utils/facts/system/cmdline.py +1 -2
- ansible/module_utils/facts/system/date_time.py +5 -3
- ansible/module_utils/facts/system/distribution.py +9 -8
- ansible/module_utils/facts/system/dns.py +1 -1
- ansible/module_utils/facts/system/env.py +1 -2
- ansible/module_utils/facts/system/fips.py +7 -20
- ansible/module_utils/facts/system/loadavg.py +1 -2
- ansible/module_utils/facts/system/local.py +1 -2
- ansible/module_utils/facts/system/lsb.py +1 -2
- ansible/module_utils/facts/system/pkg_mgr.py +1 -2
- ansible/module_utils/facts/system/platform.py +1 -2
- ansible/module_utils/facts/system/python.py +1 -2
- ansible/module_utils/facts/system/selinux.py +1 -1
- ansible/module_utils/facts/system/service_mgr.py +1 -2
- ansible/module_utils/facts/system/ssh_pub_keys.py +1 -1
- ansible/module_utils/facts/system/systemd.py +1 -1
- ansible/module_utils/facts/system/user.py +1 -2
- ansible/module_utils/facts/utils.py +3 -3
- ansible/module_utils/facts/virtual/base.py +1 -1
- ansible/module_utils/facts/virtual/sunos.py +3 -15
- ansible/module_utils/facts/virtual/sysctl.py +3 -16
- ansible/module_utils/json_utils.py +2 -2
- ansible/module_utils/parsing/convert_bool.py +1 -1
- ansible/module_utils/service.py +18 -21
- ansible/module_utils/splitter.py +7 -7
- ansible/module_utils/testing.py +31 -0
- ansible/module_utils/urls.py +60 -31
- ansible/modules/add_host.py +4 -4
- ansible/modules/apt.py +60 -46
- ansible/modules/apt_key.py +19 -12
- ansible/modules/apt_repository.py +19 -16
- ansible/modules/assemble.py +6 -6
- ansible/modules/assert.py +4 -4
- ansible/modules/async_status.py +10 -12
- ansible/modules/async_wrapper.py +8 -3
- ansible/modules/blockinfile.py +6 -7
- ansible/modules/command.py +10 -17
- ansible/modules/copy.py +57 -144
- ansible/modules/cron.py +20 -15
- ansible/modules/deb822_repository.py +8 -9
- ansible/modules/debconf.py +5 -5
- ansible/modules/debug.py +4 -4
- ansible/modules/dnf.py +8 -8
- ansible/modules/dnf5.py +39 -13
- ansible/modules/dpkg_selections.py +4 -4
- ansible/modules/expect.py +8 -10
- ansible/modules/fail.py +4 -4
- ansible/modules/fetch.py +4 -4
- ansible/modules/file.py +174 -133
- ansible/modules/find.py +19 -17
- ansible/modules/gather_facts.py +3 -3
- ansible/modules/get_url.py +59 -53
- ansible/modules/getent.py +7 -9
- ansible/modules/git.py +28 -25
- ansible/modules/group.py +6 -6
- ansible/modules/group_by.py +4 -4
- ansible/modules/hostname.py +13 -29
- ansible/modules/import_playbook.py +6 -6
- ansible/modules/import_role.py +6 -6
- ansible/modules/import_tasks.py +6 -6
- ansible/modules/include_role.py +6 -6
- ansible/modules/include_tasks.py +6 -6
- ansible/modules/include_vars.py +6 -6
- ansible/modules/iptables.py +86 -73
- ansible/modules/known_hosts.py +10 -10
- ansible/modules/lineinfile.py +5 -5
- ansible/modules/meta.py +4 -4
- ansible/modules/mount_facts.py +2 -2
- ansible/modules/package.py +4 -4
- ansible/modules/package_facts.py +22 -10
- ansible/modules/pause.py +6 -6
- ansible/modules/ping.py +6 -6
- ansible/modules/pip.py +10 -11
- ansible/modules/raw.py +4 -4
- ansible/modules/reboot.py +6 -6
- ansible/modules/replace.py +9 -13
- ansible/modules/rpm_key.py +7 -8
- ansible/modules/script.py +4 -4
- ansible/modules/service.py +7 -8
- ansible/modules/service_facts.py +87 -10
- ansible/modules/set_fact.py +5 -5
- ansible/modules/set_stats.py +4 -4
- ansible/modules/setup.py +2 -2
- ansible/modules/shell.py +6 -6
- ansible/modules/slurp.py +6 -6
- ansible/modules/stat.py +9 -23
- ansible/modules/subversion.py +15 -15
- ansible/modules/systemd.py +6 -6
- ansible/modules/systemd_service.py +6 -6
- ansible/modules/sysvinit.py +6 -6
- ansible/modules/tempfile.py +5 -6
- ansible/modules/template.py +6 -6
- ansible/modules/unarchive.py +32 -11
- ansible/modules/uri.py +33 -26
- ansible/modules/user.py +53 -34
- ansible/modules/validate_argument_spec.py +10 -7
- ansible/modules/wait_for.py +32 -27
- ansible/modules/wait_for_connection.py +6 -6
- ansible/modules/yum_repository.py +6 -6
- ansible/parsing/ajson.py +14 -32
- ansible/parsing/dataloader.py +99 -54
- ansible/parsing/mod_args.py +28 -44
- ansible/parsing/plugin_docs.py +21 -86
- ansible/parsing/quoting.py +1 -1
- ansible/parsing/splitter.py +27 -12
- ansible/parsing/utils/addresses.py +24 -24
- ansible/parsing/utils/jsonify.py +5 -1
- ansible/parsing/utils/yaml.py +32 -61
- ansible/parsing/vault/__init__.py +319 -87
- ansible/parsing/yaml/__init__.py +0 -18
- ansible/parsing/yaml/dumper.py +6 -120
- ansible/parsing/yaml/loader.py +6 -39
- ansible/parsing/yaml/objects.py +43 -335
- ansible/playbook/__init__.py +1 -1
- ansible/playbook/attribute.py +8 -3
- ansible/playbook/base.py +182 -132
- ansible/playbook/block.py +26 -24
- ansible/playbook/collectionsearch.py +1 -15
- ansible/playbook/conditional.py +3 -77
- ansible/playbook/handler.py +8 -2
- ansible/playbook/helpers.py +41 -53
- ansible/playbook/included_file.py +31 -27
- ansible/playbook/loop_control.py +2 -2
- ansible/playbook/play.py +85 -44
- ansible/playbook/play_context.py +12 -17
- ansible/playbook/playbook_include.py +14 -15
- ansible/playbook/role/__init__.py +24 -26
- ansible/playbook/role/definition.py +15 -17
- ansible/playbook/role/include.py +2 -4
- ansible/playbook/role/metadata.py +10 -11
- ansible/playbook/role_include.py +3 -3
- ansible/playbook/taggable.py +13 -8
- ansible/playbook/task.py +188 -118
- ansible/playbook/task_include.py +5 -5
- ansible/plugins/__init__.py +68 -21
- ansible/plugins/action/__init__.py +209 -176
- ansible/plugins/action/add_host.py +1 -1
- ansible/plugins/action/assemble.py +1 -1
- ansible/plugins/action/assert.py +54 -66
- ansible/plugins/action/copy.py +7 -11
- ansible/plugins/action/debug.py +37 -31
- ansible/plugins/action/dnf.py +3 -4
- ansible/plugins/action/fail.py +1 -1
- ansible/plugins/action/fetch.py +4 -5
- ansible/plugins/action/gather_facts.py +7 -6
- ansible/plugins/action/group_by.py +1 -1
- ansible/plugins/action/include_vars.py +10 -11
- ansible/plugins/action/package.py +3 -6
- ansible/plugins/action/pause.py +2 -2
- ansible/plugins/action/script.py +15 -8
- ansible/plugins/action/service.py +6 -11
- ansible/plugins/action/set_fact.py +3 -12
- ansible/plugins/action/set_stats.py +3 -8
- ansible/plugins/action/template.py +35 -59
- ansible/plugins/action/unarchive.py +1 -1
- ansible/plugins/action/validate_argument_spec.py +5 -5
- ansible/plugins/action/wait_for_connection.py +1 -1
- ansible/plugins/become/__init__.py +31 -8
- ansible/plugins/become/runas.py +71 -0
- ansible/plugins/become/su.py +13 -8
- ansible/plugins/become/sudo.py +19 -0
- ansible/plugins/cache/__init__.py +35 -44
- ansible/plugins/cache/base.py +8 -0
- ansible/plugins/cache/jsonfile.py +10 -16
- ansible/plugins/cache/memory.py +6 -12
- ansible/plugins/callback/__init__.py +284 -179
- ansible/plugins/callback/default.py +99 -92
- ansible/plugins/callback/junit.py +44 -39
- ansible/plugins/callback/minimal.py +28 -25
- ansible/plugins/callback/oneline.py +28 -21
- ansible/plugins/callback/tree.py +16 -11
- ansible/plugins/connection/__init__.py +47 -34
- ansible/plugins/connection/local.py +150 -54
- ansible/plugins/connection/paramiko_ssh.py +21 -18
- ansible/plugins/connection/psrp.py +76 -165
- ansible/plugins/connection/ssh.py +301 -78
- ansible/plugins/connection/winrm.py +58 -140
- ansible/plugins/doc_fragments/action_common_attributes.py +14 -14
- ansible/plugins/doc_fragments/action_core.py +6 -6
- ansible/plugins/doc_fragments/backup.py +2 -2
- ansible/plugins/doc_fragments/checksum_common.py +27 -0
- ansible/plugins/doc_fragments/constructed.py +6 -2
- ansible/plugins/doc_fragments/decrypt.py +2 -2
- ansible/plugins/doc_fragments/default_callback.py +2 -2
- ansible/plugins/doc_fragments/files.py +2 -2
- ansible/plugins/doc_fragments/inventory_cache.py +2 -2
- ansible/plugins/doc_fragments/result_format_callback.py +2 -2
- ansible/plugins/doc_fragments/return_common.py +2 -2
- ansible/plugins/doc_fragments/template_common.py +4 -4
- ansible/plugins/doc_fragments/url.py +17 -1
- ansible/plugins/doc_fragments/url_windows.py +2 -2
- ansible/plugins/doc_fragments/validate.py +2 -2
- ansible/plugins/doc_fragments/vars_plugin_staging.py +2 -2
- ansible/plugins/filter/__init__.py +6 -2
- ansible/plugins/filter/b64decode.yml +22 -0
- ansible/plugins/filter/b64encode.yml +22 -0
- ansible/plugins/filter/bool.yml +11 -4
- ansible/plugins/filter/core.py +225 -108
- ansible/plugins/filter/encryption.py +32 -32
- ansible/plugins/filter/flatten.yml +3 -2
- ansible/plugins/filter/human_to_bytes.yml +1 -1
- ansible/plugins/filter/mathstuff.py +30 -37
- ansible/plugins/filter/password_hash.yml +8 -0
- ansible/plugins/filter/regex_search.yml +1 -4
- ansible/plugins/filter/split.yml +1 -1
- ansible/plugins/filter/to_nice_yaml.yml +0 -4
- ansible/plugins/filter/to_yaml.yml +0 -4
- ansible/plugins/filter/unvault.yml +1 -1
- ansible/plugins/filter/urls.py +1 -1
- ansible/plugins/filter/urlsplit.py +8 -9
- ansible/plugins/filter/vault.yml +14 -9
- ansible/plugins/filter/win_basename.yml +6 -1
- ansible/plugins/filter/win_dirname.yml +5 -0
- ansible/plugins/inventory/__init__.py +97 -77
- ansible/plugins/inventory/advanced_host_list.py +7 -5
- ansible/plugins/inventory/auto.py +11 -4
- ansible/plugins/inventory/constructed.py +21 -24
- ansible/plugins/inventory/generator.py +16 -11
- ansible/plugins/inventory/host_list.py +7 -5
- ansible/plugins/inventory/ini.py +78 -44
- ansible/plugins/inventory/script.py +189 -119
- ansible/plugins/inventory/toml.py +16 -126
- ansible/plugins/inventory/yaml.py +10 -8
- ansible/plugins/list.py +3 -3
- ansible/plugins/loader.py +197 -82
- ansible/plugins/lookup/__init__.py +21 -4
- ansible/plugins/lookup/config.py +21 -35
- ansible/plugins/lookup/csvfile.py +3 -2
- ansible/plugins/lookup/dict.py +1 -6
- ansible/plugins/lookup/env.py +12 -9
- ansible/plugins/lookup/file.py +5 -8
- ansible/plugins/lookup/first_found.py +86 -55
- ansible/plugins/lookup/indexed_items.py +1 -10
- ansible/plugins/lookup/ini.py +14 -13
- ansible/plugins/lookup/items.py +1 -1
- ansible/plugins/lookup/lines.py +8 -1
- ansible/plugins/lookup/list.py +1 -1
- ansible/plugins/lookup/nested.py +2 -18
- ansible/plugins/lookup/password.py +5 -5
- ansible/plugins/lookup/pipe.py +5 -7
- ansible/plugins/lookup/sequence.py +18 -8
- ansible/plugins/lookup/subelements.py +1 -4
- ansible/plugins/lookup/template.py +42 -36
- ansible/plugins/lookup/together.py +0 -12
- ansible/plugins/lookup/unvault.py +1 -5
- ansible/plugins/lookup/url.py +2 -8
- ansible/plugins/lookup/vars.py +16 -24
- ansible/plugins/shell/__init__.py +2 -2
- ansible/plugins/shell/cmd.py +2 -2
- ansible/plugins/shell/powershell.py +39 -22
- ansible/plugins/shell/sh.py +3 -2
- ansible/plugins/strategy/__init__.py +159 -184
- ansible/plugins/strategy/debug.py +2 -2
- ansible/plugins/strategy/free.py +16 -31
- ansible/plugins/strategy/host_pinned.py +2 -2
- ansible/plugins/strategy/linear.py +41 -41
- ansible/plugins/terminal/__init__.py +4 -4
- ansible/plugins/test/__init__.py +7 -2
- ansible/plugins/test/core.py +55 -21
- ansible/plugins/test/files.py +1 -1
- ansible/plugins/test/mathstuff.py +3 -3
- ansible/plugins/test/uri.py +3 -3
- ansible/plugins/vars/host_group_vars.py +7 -14
- ansible/release.py +2 -2
- ansible/template/__init__.py +370 -944
- ansible/utils/__init__.py +0 -18
- ansible/utils/_ssh_agent.py +657 -0
- ansible/utils/collection_loader/__init__.py +52 -5
- ansible/utils/collection_loader/_collection_config.py +5 -6
- ansible/utils/collection_loader/_collection_finder.py +79 -93
- ansible/utils/collection_loader/_collection_meta.py +13 -8
- ansible/utils/display.py +433 -63
- ansible/utils/encrypt.py +27 -19
- ansible/utils/fqcn.py +2 -2
- ansible/utils/hashing.py +2 -2
- ansible/utils/helpers.py +2 -2
- ansible/utils/listify.py +8 -8
- ansible/utils/lock.py +2 -2
- ansible/utils/path.py +4 -4
- ansible/utils/plugin_docs.py +14 -13
- ansible/utils/sentinel.py +4 -62
- ansible/utils/singleton.py +2 -0
- ansible/utils/ssh_functions.py +1 -1
- ansible/utils/unsafe_proxy.py +23 -332
- ansible/utils/vars.py +51 -8
- ansible/utils/version.py +2 -2
- ansible/vars/clean.py +5 -5
- ansible/vars/hostvars.py +60 -90
- ansible/vars/manager.py +206 -282
- ansible/vars/reserved.py +8 -9
- ansible_core-2.19.0b2.dist-info/BSD-3-Clause.txt +28 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/METADATA +5 -4
- ansible_core-2.19.0b2.dist-info/RECORD +1072 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/WHEEL +1 -1
- ansible_test/_data/completion/docker.txt +7 -7
- ansible_test/_data/completion/remote.txt +6 -6
- ansible_test/_data/completion/windows.txt +1 -0
- ansible_test/_data/requirements/ansible.txt +2 -2
- ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
- ansible_test/_data/requirements/sanity.changelog.txt +1 -1
- ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
- ansible_test/_data/requirements/sanity.pylint.txt +4 -4
- ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
- ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
- ansible_test/_data/requirements/units.txt +1 -0
- ansible_test/_internal/__init__.py +1 -0
- ansible_test/_internal/ansible_util.py +2 -0
- ansible_test/_internal/become.py +1 -0
- ansible_test/_internal/bootstrap.py +1 -0
- ansible_test/_internal/cache.py +1 -0
- ansible_test/_internal/cgroup.py +1 -0
- ansible_test/_internal/ci/__init__.py +1 -0
- ansible_test/_internal/ci/azp.py +1 -0
- ansible_test/_internal/ci/local.py +1 -0
- ansible_test/_internal/classification/__init__.py +1 -0
- ansible_test/_internal/classification/common.py +1 -0
- ansible_test/_internal/classification/csharp.py +1 -0
- ansible_test/_internal/classification/powershell.py +1 -0
- ansible_test/_internal/classification/python.py +1 -0
- ansible_test/_internal/cli/__init__.py +1 -0
- ansible_test/_internal/cli/actions.py +1 -0
- ansible_test/_internal/cli/argparsing/__init__.py +1 -0
- ansible_test/_internal/cli/argparsing/actions.py +1 -0
- ansible_test/_internal/cli/argparsing/argcompletion.py +1 -0
- ansible_test/_internal/cli/argparsing/parsers.py +1 -0
- ansible_test/_internal/cli/commands/__init__.py +11 -0
- ansible_test/_internal/cli/commands/coverage/__init__.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/__init__.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/__init__.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/combine.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/expand.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/filter.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/generate.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/missing.py +1 -0
- ansible_test/_internal/cli/commands/coverage/combine.py +1 -0
- ansible_test/_internal/cli/commands/coverage/erase.py +1 -0
- ansible_test/_internal/cli/commands/coverage/html.py +1 -0
- ansible_test/_internal/cli/commands/coverage/report.py +1 -0
- ansible_test/_internal/cli/commands/coverage/xml.py +1 -0
- ansible_test/_internal/cli/commands/env.py +1 -0
- ansible_test/_internal/cli/commands/integration/__init__.py +1 -0
- ansible_test/_internal/cli/commands/integration/network.py +1 -0
- ansible_test/_internal/cli/commands/integration/posix.py +1 -0
- ansible_test/_internal/cli/commands/integration/windows.py +1 -0
- ansible_test/_internal/cli/commands/sanity.py +9 -0
- ansible_test/_internal/cli/commands/shell.py +1 -0
- ansible_test/_internal/cli/commands/units.py +1 -0
- ansible_test/_internal/cli/compat.py +1 -0
- ansible_test/_internal/cli/completers.py +1 -0
- ansible_test/_internal/cli/converters.py +1 -0
- ansible_test/_internal/cli/environments.py +1 -0
- ansible_test/_internal/cli/epilog.py +1 -0
- ansible_test/_internal/cli/parsers/__init__.py +1 -0
- ansible_test/_internal/cli/parsers/base_argument_parsers.py +1 -0
- ansible_test/_internal/cli/parsers/helpers.py +1 -0
- ansible_test/_internal/cli/parsers/host_config_parsers.py +1 -0
- ansible_test/_internal/cli/parsers/key_value_parsers.py +1 -0
- ansible_test/_internal/cli/parsers/value_parsers.py +1 -0
- ansible_test/_internal/commands/__init__.py +1 -0
- ansible_test/_internal/commands/coverage/__init__.py +2 -1
- ansible_test/_internal/commands/coverage/analyze/__init__.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/__init__.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/combine.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/expand.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/filter.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/generate.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/missing.py +1 -0
- ansible_test/_internal/commands/coverage/combine.py +2 -1
- ansible_test/_internal/commands/coverage/erase.py +1 -0
- ansible_test/_internal/commands/coverage/html.py +1 -0
- ansible_test/_internal/commands/coverage/report.py +1 -0
- ansible_test/_internal/commands/coverage/xml.py +1 -0
- ansible_test/_internal/commands/env/__init__.py +2 -0
- ansible_test/_internal/commands/integration/__init__.py +4 -0
- ansible_test/_internal/commands/integration/cloud/__init__.py +1 -0
- ansible_test/_internal/commands/integration/cloud/acme.py +2 -1
- ansible_test/_internal/commands/integration/cloud/aws.py +1 -0
- ansible_test/_internal/commands/integration/cloud/azure.py +1 -0
- ansible_test/_internal/commands/integration/cloud/cs.py +1 -0
- ansible_test/_internal/commands/integration/cloud/digitalocean.py +1 -0
- ansible_test/_internal/commands/integration/cloud/galaxy.py +3 -2
- ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -0
- ansible_test/_internal/commands/integration/cloud/httptester.py +2 -1
- ansible_test/_internal/commands/integration/cloud/nios.py +2 -1
- ansible_test/_internal/commands/integration/cloud/opennebula.py +1 -0
- ansible_test/_internal/commands/integration/cloud/openshift.py +1 -0
- ansible_test/_internal/commands/integration/cloud/scaleway.py +1 -0
- ansible_test/_internal/commands/integration/cloud/vcenter.py +1 -0
- ansible_test/_internal/commands/integration/cloud/vultr.py +1 -0
- ansible_test/_internal/commands/integration/coverage.py +1 -0
- ansible_test/_internal/commands/integration/filters.py +1 -0
- ansible_test/_internal/commands/integration/network.py +1 -0
- ansible_test/_internal/commands/integration/posix.py +1 -0
- ansible_test/_internal/commands/integration/windows.py +1 -0
- ansible_test/_internal/commands/sanity/__init__.py +16 -1
- ansible_test/_internal/commands/sanity/ansible_doc.py +1 -0
- ansible_test/_internal/commands/sanity/bin_symlinks.py +1 -0
- ansible_test/_internal/commands/sanity/compile.py +1 -0
- ansible_test/_internal/commands/sanity/ignores.py +1 -0
- ansible_test/_internal/commands/sanity/import.py +1 -0
- ansible_test/_internal/commands/sanity/integration_aliases.py +1 -0
- ansible_test/_internal/commands/sanity/pep8.py +1 -0
- ansible_test/_internal/commands/sanity/pslint.py +1 -0
- ansible_test/_internal/commands/sanity/pylint.py +24 -26
- ansible_test/_internal/commands/sanity/shellcheck.py +1 -0
- ansible_test/_internal/commands/sanity/validate_modules.py +1 -0
- ansible_test/_internal/commands/sanity/yamllint.py +1 -0
- ansible_test/_internal/commands/shell/__init__.py +1 -0
- ansible_test/_internal/commands/units/__init__.py +1 -0
- ansible_test/_internal/compat/__init__.py +1 -0
- ansible_test/_internal/compat/packaging.py +1 -0
- ansible_test/_internal/compat/yaml.py +1 -0
- ansible_test/_internal/completion.py +1 -0
- ansible_test/_internal/config.py +2 -0
- ansible_test/_internal/connections.py +1 -0
- ansible_test/_internal/constants.py +1 -0
- ansible_test/_internal/containers.py +1 -0
- ansible_test/_internal/content_config.py +1 -0
- ansible_test/_internal/core_ci.py +1 -0
- ansible_test/_internal/coverage_util.py +11 -10
- ansible_test/_internal/data.py +1 -0
- ansible_test/_internal/delegation.py +1 -0
- ansible_test/_internal/dev/__init__.py +1 -0
- ansible_test/_internal/dev/container_probe.py +1 -0
- ansible_test/_internal/diff.py +3 -2
- ansible_test/_internal/docker_util.py +2 -1
- ansible_test/_internal/encoding.py +1 -0
- ansible_test/_internal/executor.py +1 -0
- ansible_test/_internal/git.py +1 -0
- ansible_test/_internal/host_configs.py +1 -0
- ansible_test/_internal/host_profiles.py +1 -0
- ansible_test/_internal/http.py +1 -0
- ansible_test/_internal/init.py +1 -0
- ansible_test/_internal/inventory.py +35 -3
- ansible_test/_internal/io.py +1 -0
- ansible_test/_internal/metadata.py +1 -0
- ansible_test/_internal/payload.py +1 -0
- ansible_test/_internal/provider/__init__.py +1 -0
- ansible_test/_internal/provider/layout/__init__.py +1 -0
- ansible_test/_internal/provider/layout/ansible.py +1 -0
- ansible_test/_internal/provider/layout/collection.py +1 -0
- ansible_test/_internal/provider/layout/unsupported.py +1 -0
- ansible_test/_internal/provider/source/__init__.py +1 -0
- ansible_test/_internal/provider/source/git.py +1 -0
- ansible_test/_internal/provider/source/installed.py +1 -0
- ansible_test/_internal/provider/source/unsupported.py +1 -0
- ansible_test/_internal/provider/source/unversioned.py +1 -0
- ansible_test/_internal/provisioning.py +1 -0
- ansible_test/_internal/pypi_proxy.py +6 -5
- ansible_test/_internal/python_requirements.py +1 -0
- ansible_test/_internal/ssh.py +1 -0
- ansible_test/_internal/target.py +1 -0
- ansible_test/_internal/test.py +3 -2
- ansible_test/_internal/thread.py +1 -0
- ansible_test/_internal/timeout.py +1 -0
- ansible_test/_internal/util.py +1 -0
- ansible_test/_internal/util_common.py +5 -2
- ansible_test/_internal/venv.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/changelog/sphinx.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/changelog.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/empty-init.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/line-endings.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-assert.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-get-exception.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-illegal-filenames.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-smart-quotes.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/replace-urlopen.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +28 -1
- ansible_test/_util/controller/sanity/code-smell/shebang.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/symlinks.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/use-argspec-type-path.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/use-compat-six.py +1 -0
- ansible_test/_util/controller/sanity/integration-aliases/yaml_to_json.py +2 -1
- ansible_test/_util/controller/sanity/pep8/current-ignore.txt +4 -0
- ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +7 -5
- ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +7 -5
- ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +7 -5
- ansible_test/_util/controller/sanity/pylint/config/collection.cfg +3 -5
- ansible_test/_util/controller/sanity/pylint/config/default.cfg +7 -7
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -13
- ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +1 -0
- ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +1 -8
- ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +1 -8
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +55 -28
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +12 -5
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +13 -2
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -0
- ansible_test/_util/controller/sanity/yamllint/yamllinter.py +35 -17
- ansible_test/_util/controller/tools/collection_detail.py +1 -0
- ansible_test/_util/controller/tools/yaml_to_json.py +2 -1
- ansible_test/_util/target/pytest/plugins/ansible_forked.py +6 -1
- ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py +2 -1
- ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +1 -0
- ansible_test/_util/target/sanity/compile/compile.py +1 -0
- ansible_test/_util/target/sanity/import/importer.py +15 -16
- ansible_test/_util/target/setup/bootstrap.sh +9 -20
- ansible_test/_util/target/setup/probe_cgroups.py +1 -0
- ansible_test/_util/target/setup/quiet_pip.py +1 -0
- ansible_test/_util/target/setup/requirements.py +35 -27
- ansible_test/_util/target/tools/virtualenvcheck.py +2 -1
- ansible_test/_util/target/tools/yamlcheck.py +2 -1
- ansible/compat/selectors.py +0 -32
- ansible/errors/yaml_strings.py +0 -138
- ansible/executor/action_write_locks.py +0 -44
- ansible/executor/discovery/python_target.py +0 -47
- ansible/executor/powershell/module_powershell_wrapper.ps1 +0 -86
- ansible/executor/powershell/module_script_wrapper.ps1 +0 -22
- ansible/module_utils/compat/importlib.py +0 -26
- ansible/module_utils/compat/selectors.py +0 -32
- ansible/module_utils/pycompat24.py +0 -73
- ansible/parsing/yaml/constructor.py +0 -178
- ansible/template/native_helpers.py +0 -251
- ansible/template/template.py +0 -43
- ansible/template/vars.py +0 -77
- ansible/utils/native_jinja.py +0 -11
- ansible/vars/fact_cache.py +0 -71
- ansible_core-2.18.5rc1.dist-info/RECORD +0 -992
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/Apache-License.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/COPYING +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/MIT-license.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/PSF-license.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/simplified_bsd.txt +0 -0
- {ansible_core-2.18.5rc1.dist-info → ansible_core-2.19.0b2.dist-info}/top_level.txt +0 -0
ansible/utils/display.py
CHANGED
@@ -17,6 +17,9 @@
|
|
17
17
|
|
18
18
|
from __future__ import annotations
|
19
19
|
|
20
|
+
import dataclasses
|
21
|
+
import datetime
|
22
|
+
|
20
23
|
try:
|
21
24
|
import curses
|
22
25
|
except ImportError:
|
@@ -47,13 +50,17 @@ from functools import wraps
|
|
47
50
|
from struct import unpack, pack
|
48
51
|
|
49
52
|
from ansible import constants as C
|
50
|
-
from ansible.errors import
|
53
|
+
from ansible.errors import AnsibleAssertionError, AnsiblePromptInterrupt, AnsiblePromptNoninteractive, AnsibleError
|
54
|
+
from ansible._internal._errors import _utils
|
55
|
+
from ansible.module_utils._internal import _ambient_context, _plugin_exec_context
|
51
56
|
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
57
|
+
from ansible._internal._datatag._tags import TrustedAsTemplate
|
58
|
+
from ansible.module_utils.common.messages import ErrorSummary, WarningSummary, DeprecationSummary, Detail, SummaryBase, PluginInfo
|
52
59
|
from ansible.module_utils.six import text_type
|
60
|
+
from ansible.module_utils._internal import _traceback
|
53
61
|
from ansible.utils.color import stringc
|
54
62
|
from ansible.utils.multiprocessing import context as multiprocessing_context
|
55
63
|
from ansible.utils.singleton import Singleton
|
56
|
-
from ansible.utils.unsafe_proxy import wrap_var
|
57
64
|
|
58
65
|
if t.TYPE_CHECKING:
|
59
66
|
# avoid circular import at runtime
|
@@ -69,10 +76,28 @@ _LIBC.wcswidth.argtypes = (ctypes.c_wchar_p, ctypes.c_int)
|
|
69
76
|
# Max for c_int
|
70
77
|
_MAX_INT = 2 ** (ctypes.sizeof(ctypes.c_int) * 8 - 1) - 1
|
71
78
|
|
79
|
+
_UNSET = t.cast(t.Any, object())
|
80
|
+
|
72
81
|
MOVE_TO_BOL = b'\r'
|
73
82
|
CLEAR_TO_EOL = b'\x1b[K'
|
74
83
|
|
75
84
|
|
85
|
+
def _is_controller_traceback_enabled(event: _traceback.TracebackEvent) -> bool:
|
86
|
+
"""Controller utility function to determine if traceback collection is enabled for the specified event."""
|
87
|
+
flag_values: set[str] = set(value for value in C.config.get_config_value('DISPLAY_TRACEBACK'))
|
88
|
+
|
89
|
+
if 'always' in flag_values:
|
90
|
+
return True
|
91
|
+
|
92
|
+
if 'never' in flag_values:
|
93
|
+
return False
|
94
|
+
|
95
|
+
return event.name.lower() in flag_values
|
96
|
+
|
97
|
+
|
98
|
+
_traceback._is_traceback_enabled = _is_controller_traceback_enabled
|
99
|
+
|
100
|
+
|
76
101
|
def get_text_width(text: str) -> int:
|
77
102
|
"""Function that utilizes ``wcswidth`` or ``wcwidth`` to determine the
|
78
103
|
number of columns used to display a text string.
|
@@ -281,14 +306,15 @@ class Display(metaclass=Singleton):
|
|
281
306
|
self.log_verbosity = max(verbosity, C.LOG_VERBOSITY)
|
282
307
|
|
283
308
|
# list of all deprecation messages to prevent duplicate display
|
284
|
-
self._deprecations:
|
285
|
-
self._warns:
|
286
|
-
self._errors:
|
309
|
+
self._deprecations: set[str] = set()
|
310
|
+
self._warns: set[str] = set()
|
311
|
+
self._errors: set[str] = set()
|
287
312
|
|
288
313
|
self.b_cowsay: bytes | None = None
|
289
314
|
self.noncow = C.ANSIBLE_COW_SELECTION
|
290
315
|
|
291
316
|
self.set_cowsay_info()
|
317
|
+
self._wrap_stderr = C.WRAP_STDERR
|
292
318
|
|
293
319
|
if self.b_cowsay:
|
294
320
|
try:
|
@@ -322,12 +348,9 @@ class Display(metaclass=Singleton):
|
|
322
348
|
self.setup_curses = False
|
323
349
|
|
324
350
|
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
|
-
)
|
351
|
+
# This can't be removed as long as we have the possibility of encountering un-renderable strings
|
352
|
+
# created with `surrogateescape`; the alternative of having display methods hard fail is untenable.
|
353
|
+
self.warning('Non UTF-8 encoded data replaced with "?" while displaying text to stdout/stderr.')
|
331
354
|
return '?', exception.end
|
332
355
|
|
333
356
|
def set_queue(self, queue: FinalQueue) -> None:
|
@@ -532,29 +555,54 @@ class Display(metaclass=Singleton):
|
|
532
555
|
msg: str,
|
533
556
|
version: str | None = None,
|
534
557
|
removed: bool = False,
|
535
|
-
date: str | None = None,
|
558
|
+
date: str | datetime.date | None = None,
|
536
559
|
collection_name: str | None = None,
|
537
560
|
) -> str:
|
538
|
-
|
561
|
+
"""Return a deprecation message and help text for non-display purposes (e.g., exception messages)."""
|
562
|
+
self.deprecated(
|
563
|
+
msg="The `get_deprecation_message` method is deprecated.",
|
564
|
+
help_text="Use the `deprecated` method instead.",
|
565
|
+
version="2.23",
|
566
|
+
)
|
567
|
+
|
568
|
+
msg = self._get_deprecation_message_with_plugin_info(
|
569
|
+
msg=msg,
|
570
|
+
version=version,
|
571
|
+
removed=removed,
|
572
|
+
date=date,
|
573
|
+
plugin=_plugin_exec_context.PluginExecContext.get_current_plugin_info(),
|
574
|
+
)
|
575
|
+
|
576
|
+
if removed:
|
577
|
+
msg = f'[DEPRECATED]: {msg}'
|
578
|
+
else:
|
579
|
+
msg = f'[DEPRECATION WARNING]: {msg}'
|
580
|
+
|
581
|
+
return msg
|
582
|
+
|
583
|
+
def _get_deprecation_message_with_plugin_info(
|
584
|
+
self,
|
585
|
+
msg: str,
|
586
|
+
version: str | None = None,
|
587
|
+
removed: bool = False,
|
588
|
+
date: str | datetime.date | None = None,
|
589
|
+
plugin: PluginInfo | None = None,
|
590
|
+
) -> str:
|
591
|
+
"""Internal use only. Return a deprecation message and help text for display."""
|
539
592
|
msg = msg.strip()
|
593
|
+
|
540
594
|
if msg and msg[-1] not in ['!', '?', '.']:
|
541
595
|
msg += '.'
|
542
596
|
|
543
|
-
if collection_name == 'ansible.builtin':
|
544
|
-
collection_name = 'ansible-core'
|
545
|
-
|
546
597
|
if removed:
|
547
|
-
header = '[DEPRECATED]: {0}'.format(msg)
|
548
598
|
removal_fragment = 'This feature was removed'
|
549
599
|
help_text = 'Please update your playbooks.'
|
550
600
|
else:
|
551
|
-
header = '[DEPRECATION WARNING]: {0}'.format(msg)
|
552
601
|
removal_fragment = 'This feature will be removed'
|
553
|
-
|
554
|
-
help_text = 'Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.'
|
602
|
+
help_text = ''
|
555
603
|
|
556
|
-
if
|
557
|
-
from_fragment = 'from {
|
604
|
+
if plugin:
|
605
|
+
from_fragment = f'from the {self._describe_plugin_info(plugin)}'
|
558
606
|
else:
|
559
607
|
from_fragment = ''
|
560
608
|
|
@@ -565,47 +613,203 @@ class Display(metaclass=Singleton):
|
|
565
613
|
else:
|
566
614
|
when = 'in a future release.'
|
567
615
|
|
568
|
-
message_text = ' '.join(f for f in [
|
616
|
+
message_text = ' '.join(f for f in [msg, removal_fragment, from_fragment, when, help_text] if f)
|
569
617
|
|
570
618
|
return message_text
|
571
619
|
|
572
|
-
@
|
620
|
+
@staticmethod
|
621
|
+
def _describe_plugin_info(plugin_info: PluginInfo) -> str:
|
622
|
+
"""Return a brief description of the plugin info, including name(s) and type."""
|
623
|
+
name = repr(plugin_info.resolved_name)
|
624
|
+
clarification = f' (requested as {plugin_info.requested_name!r})' if plugin_info.requested_name != plugin_info.resolved_name else ''
|
625
|
+
|
626
|
+
if plugin_info.type in ("module", "modules"):
|
627
|
+
# DTFIX-RELEASE: pluginloader or AnsiblePlugin needs a "type desc" property that doesn't suffer from legacy "inconsistencies" like this
|
628
|
+
plugin_type = "module"
|
629
|
+
elif plugin_info.type == "collection":
|
630
|
+
# not a real plugin type, but used for tombstone errors generated by plugin loader
|
631
|
+
plugin_type = plugin_info.type
|
632
|
+
else:
|
633
|
+
plugin_type = f'{plugin_info.type} plugin'
|
634
|
+
|
635
|
+
return f'{name} {plugin_type}{clarification}'
|
636
|
+
|
637
|
+
def _wrap_message(self, msg: str, wrap_text: bool) -> str:
|
638
|
+
if wrap_text and self._wrap_stderr:
|
639
|
+
wrapped = textwrap.wrap(msg, self.columns, drop_whitespace=False)
|
640
|
+
msg = "\n".join(wrapped) + "\n"
|
641
|
+
|
642
|
+
return msg
|
643
|
+
|
644
|
+
@staticmethod
|
645
|
+
def _deduplicate(msg: str, messages: set[str]) -> bool:
|
646
|
+
"""
|
647
|
+
Return True if the given message was previously seen, otherwise record the message as seen and return False.
|
648
|
+
This is done very late (at display-time) to avoid loss of attribution of messages to individual tasks.
|
649
|
+
Duplicates included in task results will always be visible to registered variables and callbacks.
|
650
|
+
"""
|
651
|
+
|
652
|
+
if msg in messages:
|
653
|
+
return True
|
654
|
+
|
655
|
+
messages.add(msg)
|
656
|
+
|
657
|
+
return False
|
658
|
+
|
573
659
|
def deprecated(
|
574
660
|
self,
|
575
661
|
msg: str,
|
576
662
|
version: str | None = None,
|
577
663
|
removed: bool = False,
|
578
|
-
date: str | None = None,
|
579
|
-
collection_name: str | None =
|
664
|
+
date: str | datetime.date | None = None,
|
665
|
+
collection_name: str | None = _UNSET,
|
666
|
+
*,
|
667
|
+
help_text: str | None = None,
|
668
|
+
obj: t.Any = None,
|
580
669
|
) -> None:
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
670
|
+
"""Display a deprecation warning message, if enabled."""
|
671
|
+
# deprecated: description='enable the deprecation message for collection_name' core_version='2.23'
|
672
|
+
# if collection_name is not _UNSET:
|
673
|
+
# self.deprecated('The `collection_name` argument to `deprecated` is deprecated.', version='2.27')
|
674
|
+
|
675
|
+
# DTFIX-RELEASE: are there any deprecation calls where the feature is switching from enabled to disabled, rather than being removed entirely?
|
676
|
+
# DTFIX-RELEASE: are there deprecated features which should going through deferred deprecation instead?
|
677
|
+
|
678
|
+
self._deprecated_with_plugin_info(
|
679
|
+
msg=msg,
|
680
|
+
version=version,
|
681
|
+
removed=removed,
|
682
|
+
date=date,
|
683
|
+
help_text=help_text,
|
684
|
+
obj=obj,
|
685
|
+
plugin=_plugin_exec_context.PluginExecContext.get_current_plugin_info(),
|
686
|
+
)
|
585
687
|
|
688
|
+
def _deprecated_with_plugin_info(
|
689
|
+
self,
|
690
|
+
msg: str,
|
691
|
+
version: str | None = None,
|
692
|
+
removed: bool = False,
|
693
|
+
date: str | datetime.date | None = None,
|
694
|
+
*,
|
695
|
+
help_text: str | None = None,
|
696
|
+
obj: t.Any = None,
|
697
|
+
plugin: PluginInfo | None = None,
|
698
|
+
) -> None:
|
699
|
+
"""
|
700
|
+
This is the internal pre-proxy half of the `deprecated` implementation.
|
701
|
+
Any logic that must occur on workers needs to be implemented here.
|
702
|
+
"""
|
586
703
|
if removed:
|
587
|
-
raise AnsibleError(
|
704
|
+
raise AnsibleError(self._get_deprecation_message_with_plugin_info(
|
705
|
+
msg=msg,
|
706
|
+
version=version,
|
707
|
+
removed=removed,
|
708
|
+
date=date,
|
709
|
+
plugin=plugin,
|
710
|
+
))
|
711
|
+
|
712
|
+
if source_context := _utils.SourceContext.from_value(obj):
|
713
|
+
formatted_source_context = str(source_context)
|
714
|
+
else:
|
715
|
+
formatted_source_context = None
|
716
|
+
|
717
|
+
deprecation = DeprecationSummary(
|
718
|
+
details=(
|
719
|
+
Detail(
|
720
|
+
msg=msg,
|
721
|
+
formatted_source_context=formatted_source_context,
|
722
|
+
help_text=help_text,
|
723
|
+
),
|
724
|
+
),
|
725
|
+
version=version,
|
726
|
+
date=str(date) if isinstance(date, datetime.date) else date,
|
727
|
+
plugin=plugin,
|
728
|
+
formatted_traceback=_traceback.maybe_capture_traceback(_traceback.TracebackEvent.DEPRECATED),
|
729
|
+
)
|
588
730
|
|
589
|
-
|
590
|
-
|
731
|
+
if warning_ctx := _DeferredWarningContext.current(optional=True):
|
732
|
+
warning_ctx.capture(deprecation)
|
733
|
+
return
|
591
734
|
|
592
|
-
|
593
|
-
self.display(message_text.strip(), color=C.COLOR_DEPRECATE, stderr=True)
|
594
|
-
self._deprecations[message_text] = 1
|
735
|
+
self._deprecated(deprecation)
|
595
736
|
|
596
737
|
@_proxy
|
597
|
-
def
|
738
|
+
def _deprecated(self, warning: DeprecationSummary) -> None:
|
739
|
+
"""Internal implementation detail, use `deprecated` instead."""
|
740
|
+
|
741
|
+
# This is the post-proxy half of the `deprecated` implementation.
|
742
|
+
# Any logic that must occur in the primary controller process needs to be implemented here.
|
743
|
+
|
744
|
+
if not _DeferredWarningContext.deprecation_warnings_enabled():
|
745
|
+
return
|
746
|
+
|
747
|
+
self.warning('Deprecation warnings can be disabled by setting `deprecation_warnings=False` in ansible.cfg.')
|
748
|
+
|
749
|
+
msg = format_message(warning)
|
750
|
+
msg = f'[DEPRECATION WARNING]: {msg}'
|
751
|
+
|
752
|
+
# DTFIX-RELEASE: what should we do with wrap_message?
|
753
|
+
msg = self._wrap_message(msg=msg, wrap_text=True)
|
754
|
+
|
755
|
+
if self._deduplicate(msg, self._deprecations):
|
756
|
+
return
|
757
|
+
|
758
|
+
self.display(msg, color=C.config.get_config_value('COLOR_DEPRECATE'), stderr=True)
|
598
759
|
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
760
|
+
def warning(
|
761
|
+
self,
|
762
|
+
msg: str,
|
763
|
+
formatted: bool = False,
|
764
|
+
*,
|
765
|
+
help_text: str | None = None,
|
766
|
+
obj: t.Any = None
|
767
|
+
) -> None:
|
768
|
+
"""Display a warning message."""
|
769
|
+
|
770
|
+
# This is the pre-proxy half of the `warning` implementation.
|
771
|
+
# Any logic that must occur on workers needs to be implemented here.
|
772
|
+
|
773
|
+
if source_context := _utils.SourceContext.from_value(obj):
|
774
|
+
formatted_source_context = str(source_context)
|
603
775
|
else:
|
604
|
-
|
776
|
+
formatted_source_context = None
|
777
|
+
|
778
|
+
warning = WarningSummary(
|
779
|
+
details=(
|
780
|
+
Detail(
|
781
|
+
msg=msg,
|
782
|
+
help_text=help_text,
|
783
|
+
formatted_source_context=formatted_source_context,
|
784
|
+
),
|
785
|
+
),
|
786
|
+
formatted_traceback=_traceback.maybe_capture_traceback(_traceback.TracebackEvent.WARNING),
|
787
|
+
)
|
788
|
+
|
789
|
+
if warning_ctx := _DeferredWarningContext.current(optional=True):
|
790
|
+
warning_ctx.capture(warning)
|
791
|
+
# DTFIX-RELEASE: what to do about propagating wrap_text?
|
792
|
+
return
|
793
|
+
|
794
|
+
self._warning(warning, wrap_text=not formatted)
|
795
|
+
|
796
|
+
@_proxy
|
797
|
+
def _warning(self, warning: WarningSummary, wrap_text: bool) -> None:
|
798
|
+
"""Internal implementation detail, use `warning` instead."""
|
799
|
+
|
800
|
+
# This is the post-proxy half of the `warning` implementation.
|
801
|
+
# Any logic that must occur in the primary controller process needs to be implemented here.
|
802
|
+
|
803
|
+
msg = format_message(warning)
|
804
|
+
msg = f"[WARNING]: {msg}"
|
805
|
+
|
806
|
+
if self._deduplicate(msg, self._warns):
|
807
|
+
return
|
808
|
+
|
809
|
+
# DTFIX-RELEASE: what should we do with wrap_message?
|
810
|
+
msg = self._wrap_message(msg=msg, wrap_text=wrap_text)
|
605
811
|
|
606
|
-
|
607
|
-
self.display(new_msg, color=C.COLOR_WARN, stderr=True, caplevel=-2)
|
608
|
-
self._warns[new_msg] = 1
|
812
|
+
self.display(msg, color=C.config.get_config_value('COLOR_WARN'), stderr=True, caplevel=-2)
|
609
813
|
|
610
814
|
@_proxy
|
611
815
|
def system_warning(self, msg: str) -> None:
|
@@ -614,9 +818,9 @@ class Display(metaclass=Singleton):
|
|
614
818
|
|
615
819
|
@_proxy
|
616
820
|
def banner(self, msg: str, color: str | None = None, cows: bool = True) -> None:
|
617
|
-
|
821
|
+
"""
|
618
822
|
Prints a header-looking line with cowsay or stars with length depending on terminal width (3 minimum)
|
619
|
-
|
823
|
+
"""
|
620
824
|
msg = to_text(msg)
|
621
825
|
|
622
826
|
if self.b_cowsay and cows:
|
@@ -654,17 +858,56 @@ class Display(metaclass=Singleton):
|
|
654
858
|
(out, err) = cmd.communicate()
|
655
859
|
self.display(u"%s\n" % to_text(out), color=color)
|
656
860
|
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
861
|
+
def error_as_warning(self, msg: str | None, exception: BaseException) -> None:
|
862
|
+
"""Display an exception as a warning."""
|
863
|
+
|
864
|
+
error = _utils._create_error_summary(exception, _traceback.TracebackEvent.WARNING)
|
865
|
+
|
866
|
+
if msg:
|
867
|
+
error = dataclasses.replace(error, details=(Detail(msg=msg),) + error.details)
|
868
|
+
|
869
|
+
warning = WarningSummary(
|
870
|
+
details=error.details,
|
871
|
+
formatted_traceback=error.formatted_traceback,
|
872
|
+
)
|
873
|
+
|
874
|
+
if warning_ctx := _DeferredWarningContext.current(optional=True):
|
875
|
+
warning_ctx.capture(warning)
|
876
|
+
return
|
877
|
+
|
878
|
+
self._warning(warning, wrap_text=False)
|
879
|
+
|
880
|
+
def error(self, msg: str | BaseException, wrap_text: bool = True, stderr: bool = True) -> None:
|
881
|
+
"""Display an error message."""
|
882
|
+
|
883
|
+
# This is the pre-proxy half of the `error` implementation.
|
884
|
+
# Any logic that must occur on workers needs to be implemented here.
|
885
|
+
|
886
|
+
if isinstance(msg, BaseException):
|
887
|
+
error = _utils._create_error_summary(msg, _traceback.TracebackEvent.ERROR)
|
888
|
+
wrap_text = False
|
663
889
|
else:
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
890
|
+
error = ErrorSummary(details=(Detail(msg=msg),), formatted_traceback=_traceback.maybe_capture_traceback(_traceback.TracebackEvent.ERROR))
|
891
|
+
|
892
|
+
self._error(error, wrap_text=wrap_text, stderr=stderr)
|
893
|
+
|
894
|
+
@_proxy
|
895
|
+
def _error(self, error: ErrorSummary, wrap_text: bool, stderr: bool) -> None:
|
896
|
+
"""Internal implementation detail, use `error` instead."""
|
897
|
+
|
898
|
+
# This is the post-proxy half of the `error` implementation.
|
899
|
+
# Any logic that must occur in the primary controller process needs to be implemented here.
|
900
|
+
|
901
|
+
msg = format_message(error)
|
902
|
+
msg = f'[ERROR]: {msg}'
|
903
|
+
|
904
|
+
if self._deduplicate(msg, self._errors):
|
905
|
+
return
|
906
|
+
|
907
|
+
# DTFIX-RELEASE: what should we do with wrap_message?
|
908
|
+
msg = self._wrap_message(msg=msg, wrap_text=wrap_text)
|
909
|
+
|
910
|
+
self.display(msg, color=C.config.get_config_value('COLOR_ERROR'), stderr=stderr, caplevel=-1)
|
668
911
|
|
669
912
|
@staticmethod
|
670
913
|
def prompt(msg: str, private: bool = False) -> str:
|
@@ -722,8 +965,10 @@ class Display(metaclass=Singleton):
|
|
722
965
|
# handle utf-8 chars
|
723
966
|
result = to_text(result, errors='surrogate_or_strict')
|
724
967
|
|
725
|
-
if unsafe:
|
726
|
-
|
968
|
+
if not unsafe:
|
969
|
+
# to maintain backward compatibility, assume these values are safe to template
|
970
|
+
result = TrustedAsTemplate().tag(result)
|
971
|
+
|
727
972
|
return result
|
728
973
|
|
729
974
|
def _set_column_width(self) -> None:
|
@@ -738,8 +983,8 @@ class Display(metaclass=Singleton):
|
|
738
983
|
msg: str,
|
739
984
|
private: bool = False,
|
740
985
|
seconds: int | None = None,
|
741
|
-
interrupt_input: c.
|
742
|
-
complete_input: c.
|
986
|
+
interrupt_input: c.Iterable[bytes] | None = None,
|
987
|
+
complete_input: c.Iterable[bytes] | None = None,
|
743
988
|
) -> bytes:
|
744
989
|
if self._final_q:
|
745
990
|
from ansible.executor.process.worker import current_worker
|
@@ -794,8 +1039,8 @@ class Display(metaclass=Singleton):
|
|
794
1039
|
self,
|
795
1040
|
echo: bool = False,
|
796
1041
|
seconds: int | None = None,
|
797
|
-
interrupt_input: c.
|
798
|
-
complete_input: c.
|
1042
|
+
interrupt_input: c.Iterable[bytes] | None = None,
|
1043
|
+
complete_input: c.Iterable[bytes] | None = None,
|
799
1044
|
) -> bytes:
|
800
1045
|
if self._final_q:
|
801
1046
|
raise NotImplementedError
|
@@ -872,3 +1117,128 @@ class Display(metaclass=Singleton):
|
|
872
1117
|
return self._stdout.fileno()
|
873
1118
|
except (ValueError, AttributeError):
|
874
1119
|
return None
|
1120
|
+
|
1121
|
+
|
1122
|
+
_display = Display()
|
1123
|
+
|
1124
|
+
|
1125
|
+
class _DeferredWarningContext(_ambient_context.AmbientContextBase):
|
1126
|
+
"""
|
1127
|
+
Calls to `Display.warning()` and `Display.deprecated()` within this context will cause the resulting warnings to be captured and not displayed.
|
1128
|
+
The intended use is for task-initiated warnings to be recorded with the task result, which makes them visible to registered results, callbacks, etc.
|
1129
|
+
The active display callback is responsible for communicating any warnings to the user.
|
1130
|
+
"""
|
1131
|
+
|
1132
|
+
# DTFIX-FUTURE: once we start implementing nested scoped contexts for our own bookkeeping, this should be an interface facade that forwards to the nearest
|
1133
|
+
# context that actually implements the warnings collection capability
|
1134
|
+
|
1135
|
+
def __init__(self, *, variables: dict[str, object]) -> None:
|
1136
|
+
self._variables = variables # DTFIX-FUTURE: move this to an AmbientContext-derived TaskContext (once it exists)
|
1137
|
+
self._deprecation_warnings: list[DeprecationSummary] = []
|
1138
|
+
self._warnings: list[WarningSummary] = []
|
1139
|
+
self._seen: set[WarningSummary] = set()
|
1140
|
+
|
1141
|
+
@classmethod
|
1142
|
+
def deprecation_warnings_enabled(cls) -> bool:
|
1143
|
+
"""Return True if deprecation warnings are enabled for the current calling context, otherwise False."""
|
1144
|
+
# DTFIX-FUTURE: move this capability into config using an AmbientContext-derived TaskContext (once it exists)
|
1145
|
+
if warning_ctx := cls.current(optional=True):
|
1146
|
+
variables = warning_ctx._variables
|
1147
|
+
else:
|
1148
|
+
variables = None
|
1149
|
+
|
1150
|
+
return C.config.get_config_value('DEPRECATION_WARNINGS', variables=variables)
|
1151
|
+
|
1152
|
+
def capture(self, warning: WarningSummary) -> None:
|
1153
|
+
"""Add the warning/deprecation to the context if it has not already been seen by this context."""
|
1154
|
+
if warning in self._seen:
|
1155
|
+
return
|
1156
|
+
|
1157
|
+
self._seen.add(warning)
|
1158
|
+
|
1159
|
+
if isinstance(warning, DeprecationSummary):
|
1160
|
+
self._deprecation_warnings.append(warning)
|
1161
|
+
else:
|
1162
|
+
self._warnings.append(warning)
|
1163
|
+
|
1164
|
+
def get_warnings(self) -> list[WarningSummary]:
|
1165
|
+
"""Return a list of the captured non-deprecation warnings."""
|
1166
|
+
# DTFIX-FUTURE: return a read-only list proxy instead
|
1167
|
+
return self._warnings
|
1168
|
+
|
1169
|
+
def get_deprecation_warnings(self) -> list[DeprecationSummary]:
|
1170
|
+
"""Return a list of the captured deprecation warnings."""
|
1171
|
+
# DTFIX-FUTURE: return a read-only list proxy instead
|
1172
|
+
return self._deprecation_warnings
|
1173
|
+
|
1174
|
+
|
1175
|
+
def _format_error_details(details: t.Sequence[Detail], formatted_tb: str | None = None) -> str:
|
1176
|
+
details = _utils._collapse_error_details(details)
|
1177
|
+
|
1178
|
+
message_lines: list[str] = []
|
1179
|
+
|
1180
|
+
if len(details) > 1:
|
1181
|
+
message_lines.append(_utils._dedupe_and_concat_message_chain([md.msg for md in details]))
|
1182
|
+
message_lines.append('')
|
1183
|
+
|
1184
|
+
for idx, edc in enumerate(details):
|
1185
|
+
if idx:
|
1186
|
+
message_lines.extend((
|
1187
|
+
'',
|
1188
|
+
'<<< caused by >>>',
|
1189
|
+
'',
|
1190
|
+
))
|
1191
|
+
|
1192
|
+
message_lines.extend(_get_message_lines(edc.msg, edc.help_text, edc.formatted_source_context))
|
1193
|
+
|
1194
|
+
message_lines = [f'{line}\n' for line in message_lines]
|
1195
|
+
|
1196
|
+
if formatted_tb:
|
1197
|
+
message_lines.append('\n')
|
1198
|
+
message_lines.append(formatted_tb)
|
1199
|
+
|
1200
|
+
msg = "".join(message_lines).strip()
|
1201
|
+
|
1202
|
+
if '\n' in msg:
|
1203
|
+
msg += '\n\n'
|
1204
|
+
else:
|
1205
|
+
msg += '\n'
|
1206
|
+
|
1207
|
+
return msg
|
1208
|
+
|
1209
|
+
|
1210
|
+
def _get_message_lines(message: str, help_text: str | None, formatted_source_context: str | None) -> list[str]:
|
1211
|
+
"""Return a list of error/warning message lines constructed from the given message, help text and source context."""
|
1212
|
+
|
1213
|
+
if help_text and not formatted_source_context and '\n' not in message and '\n' not in help_text:
|
1214
|
+
return [f'{message} {help_text}'] # prefer a single-line message with help text when there is no source context
|
1215
|
+
|
1216
|
+
message_lines = [message]
|
1217
|
+
|
1218
|
+
if formatted_source_context:
|
1219
|
+
message_lines.append(formatted_source_context)
|
1220
|
+
|
1221
|
+
if help_text:
|
1222
|
+
message_lines.append('')
|
1223
|
+
message_lines.append(help_text)
|
1224
|
+
|
1225
|
+
return message_lines
|
1226
|
+
|
1227
|
+
|
1228
|
+
def format_message(summary: SummaryBase) -> str:
|
1229
|
+
details: t.Sequence[Detail]
|
1230
|
+
|
1231
|
+
if isinstance(summary, DeprecationSummary):
|
1232
|
+
details = [detail if idx else dataclasses.replace(
|
1233
|
+
detail,
|
1234
|
+
msg=_display._get_deprecation_message_with_plugin_info(
|
1235
|
+
msg=detail.msg,
|
1236
|
+
version=summary.version,
|
1237
|
+
date=summary.date,
|
1238
|
+
plugin=summary.plugin,
|
1239
|
+
),
|
1240
|
+
) for idx, detail in enumerate(summary.details)]
|
1241
|
+
else:
|
1242
|
+
details = summary.details
|
1243
|
+
|
1244
|
+
return _format_error_details(details, summary.formatted_traceback)
|