From 0cc771dc3ce425db15ccd394ae90be24fe99fc58 Mon Sep 17 00:00:00 2001 From: Martin Krizek Date: Tue, 12 Aug 2025 12:19:49 +0200 Subject: [PATCH] six cleanup (#85284) Co-authored-by: Matt Clay --- lib/ansible/cli/__init__.py | 7 +- lib/ansible/cli/config.py | 11 +- lib/ansible/cli/doc.py | 15 +- lib/ansible/cli/galaxy.py | 2 - lib/ansible/executor/task_executor.py | 3 +- lib/ansible/galaxy/api.py | 5 +- .../galaxy/dependency_resolution/providers.py | 3 +- lib/ansible/inventory/manager.py | 5 +- lib/ansible/module_utils/_internal/_no_six.py | 86 ++++++++++++ lib/ansible/module_utils/_text.py | 36 +++-- lib/ansible/module_utils/basic.py | 44 +++--- .../common/_collections_compat.py | 13 +- .../module_utils/common/collections.py | 11 +- .../common/dict_transformations.py | 3 +- lib/ansible/module_utils/common/network.py | 6 +- lib/ansible/module_utils/common/parameters.py | 73 +++++----- .../module_utils/common/text/converters.py | 27 ++-- .../module_utils/common/text/formatters.py | 8 +- lib/ansible/module_utils/common/validation.py | 20 +-- lib/ansible/module_utils/connection.py | 11 +- .../module_utils/facts/hardware/linux.py | 14 +- .../module_utils/facts/hardware/netbsd.py | 2 +- .../module_utils/facts/hardware/sunos.py | 3 +- lib/ansible/module_utils/facts/packages.py | 8 +- lib/ansible/module_utils/facts/system/env.py | 9 +- .../module_utils/facts/system/local.py | 4 +- .../module_utils/parsing/convert_bool.py | 8 +- lib/ansible/module_utils/service.py | 5 +- lib/ansible/modules/apt.py | 3 +- lib/ansible/modules/assemble.py | 14 +- lib/ansible/modules/blockinfile.py | 20 +-- lib/ansible/modules/cron.py | 16 +-- lib/ansible/modules/deb822_repository.py | 14 +- lib/ansible/modules/find.py | 3 +- lib/ansible/modules/get_url.py | 2 +- lib/ansible/modules/git.py | 9 +- lib/ansible/modules/service.py | 7 +- lib/ansible/modules/uri.py | 19 ++- lib/ansible/parsing/dataloader.py | 3 +- lib/ansible/parsing/vault/__init__.py | 3 +- lib/ansible/playbook/base.py | 11 +- lib/ansible/playbook/collectionsearch.py | 3 +- lib/ansible/playbook/handler.py | 3 +- lib/ansible/playbook/play.py | 9 +- lib/ansible/playbook/role/__init__.py | 3 +- lib/ansible/playbook/role/definition.py | 7 +- lib/ansible/playbook/role/include.py | 5 +- lib/ansible/playbook/role/metadata.py | 3 +- lib/ansible/playbook/role/requirement.py | 3 +- lib/ansible/playbook/role_include.py | 3 +- lib/ansible/playbook/task.py | 3 +- lib/ansible/plugins/action/__init__.py | 17 ++- lib/ansible/plugins/action/add_host.py | 3 +- lib/ansible/plugins/action/fetch.py | 5 +- lib/ansible/plugins/action/group_by.py | 3 +- lib/ansible/plugins/action/include_vars.py | 5 +- lib/ansible/plugins/action/template.py | 3 +- lib/ansible/plugins/connection/local.py | 5 +- lib/ansible/plugins/connection/ssh.py | 3 +- lib/ansible/plugins/filter/core.py | 9 +- lib/ansible/plugins/filter/mathstuff.py | 3 +- lib/ansible/plugins/inventory/__init__.py | 3 +- lib/ansible/plugins/inventory/toml.py | 3 +- lib/ansible/plugins/inventory/yaml.py | 3 +- lib/ansible/plugins/loader.py | 3 +- lib/ansible/plugins/lookup/password.py | 3 +- lib/ansible/plugins/lookup/subelements.py | 5 +- lib/ansible/plugins/lookup/varnames.py | 3 +- lib/ansible/plugins/shell/__init__.py | 5 +- lib/ansible/utils/context_objects.py | 11 +- lib/ansible/utils/display.py | 9 +- lib/ansible/utils/helpers.py | 8 +- lib/ansible/utils/jsonrpc.py | 10 +- lib/ansible/utils/plugin_docs.py | 8 +- lib/ansible/utils/unsafe_proxy.py | 10 +- lib/ansible/vars/clean.py | 5 +- lib/ansible/vars/manager.py | 3 +- .../builtin_vars_prompt/test-vars_prompt.py | 8 +- test/integration/targets/pause/test-pause.py | 36 ++--- .../subdir/inventory_plugins/notyaml.py | 3 +- .../sanity/code-smell/runtime-metadata.py | 33 ++--- .../validate_modules/module_args.py | 3 +- .../validate_modules/schema.py | 130 ++++++++---------- .../validate_modules/utils.py | 3 +- .../windows/plugins/plugin_utils/_quote.py | 14 +- .../module_common/test_recursive_finder.py | 3 +- 86 files changed, 530 insertions(+), 459 deletions(-) create mode 100644 lib/ansible/module_utils/_internal/_no_six.py diff --git a/lib/ansible/cli/__init__.py b/lib/ansible/cli/__init__.py index 2a4ca0f3a71..292639daa18 100644 --- a/lib/ansible/cli/__init__.py +++ b/lib/ansible/cli/__init__.py @@ -107,7 +107,6 @@ from ansible import context from ansible.utils import display as _display from ansible.cli.arguments import option_helpers as opt_help from ansible.inventory.manager import InventoryManager -from ansible.module_utils.six import string_types from ansible.module_utils.common.text.converters import to_bytes, to_text from ansible.module_utils.common.collections import is_sequence from ansible.module_utils.common.file import is_executable @@ -403,8 +402,8 @@ class CLI(ABC): options = super(MyCLI, self).post_process_args(options) if options.addition and options.subtraction: raise AnsibleOptionsError('Only one of --addition and --subtraction can be specified') - if isinstance(options.listofhosts, string_types): - options.listofhosts = string_types.split(',') + if isinstance(options.listofhosts, str): + options.listofhosts = options.listofhosts.split(',') return options """ @@ -440,7 +439,7 @@ class CLI(ABC): if options.inventory: # should always be list - if isinstance(options.inventory, string_types): + if isinstance(options.inventory, str): options.inventory = [options.inventory] # Ensure full paths when needed diff --git a/lib/ansible/cli/config.py b/lib/ansible/cli/config.py index ed42545df47..8d21e78a238 100755 --- a/lib/ansible/cli/config.py +++ b/lib/ansible/cli/config.py @@ -24,7 +24,6 @@ from ansible.config.manager import ConfigManager from ansible.errors import AnsibleError, AnsibleOptionsError, AnsibleRequiredOptionError from ansible.module_utils.common.text.converters import to_native, to_text, to_bytes from ansible._internal import _json -from ansible.module_utils.six import string_types from ansible.parsing.quoting import is_quoted from ansible.parsing.yaml.dumper import AnsibleDumper from ansible.utils.color import stringc @@ -288,21 +287,21 @@ class ConfigCLI(CLI): default = '0' elif default: if stype == 'list': - if not isinstance(default, string_types): + if not isinstance(default, str): # python lists are not valid env ones try: default = ', '.join(default) except Exception as e: # list of other stuff default = '%s' % to_native(default) - if isinstance(default, string_types) and not is_quoted(default): + if isinstance(default, str) and not is_quoted(default): default = shlex.quote(default) elif default is None: default = '' if subkey in settings[setting] and settings[setting][subkey]: entry = settings[setting][subkey][-1]['name'] - if isinstance(settings[setting]['description'], string_types): + if isinstance(settings[setting]['description'], str): desc = settings[setting]['description'] else: desc = '\n#'.join(settings[setting]['description']) @@ -343,7 +342,7 @@ class ConfigCLI(CLI): sections[s] = new_sections[s] continue - if isinstance(opt['description'], string_types): + if isinstance(opt['description'], str): desc = '# (%s) %s' % (opt.get('type', 'string'), opt['description']) else: desc = "# (%s) " % opt.get('type', 'string') @@ -361,7 +360,7 @@ class ConfigCLI(CLI): seen[entry['section']].append(entry['key']) default = self.config.template_default(opt.get('default', ''), get_constants()) - if opt.get('type', '') == 'list' and not isinstance(default, string_types): + if opt.get('type', '') == 'list' and not isinstance(default, str): # python lists are not valid ini ones default = ', '.join(default) elif default is None: diff --git a/lib/ansible/cli/doc.py b/lib/ansible/cli/doc.py index 436cbcf52a1..9f6def99462 100755 --- a/lib/ansible/cli/doc.py +++ b/lib/ansible/cli/doc.py @@ -32,7 +32,6 @@ from ansible.errors import AnsibleError, AnsibleOptionsError, AnsibleParserError from ansible.module_utils.common.text.converters import to_native, to_text from ansible.module_utils.common.collections import is_sequence from ansible.module_utils.common.yaml import yaml_dump -from ansible.module_utils.six import string_types from ansible.parsing.plugin_docs import read_docstub from ansible.parsing.yaml.dumper import AnsibleDumper from ansible.parsing.yaml.loader import AnsibleLoader @@ -1274,7 +1273,7 @@ class DocCLI(CLI, RoleMixin): sub_indent = inline_indent + extra_indent if is_sequence(opt['description']): for entry_idx, entry in enumerate(opt['description'], 1): - if not isinstance(entry, string_types): + if not isinstance(entry, str): raise AnsibleError("Expected string in description of %s at index %s, got %s" % (o, entry_idx, type(entry))) if entry_idx == 1: text.append(key + DocCLI.warp_fill(DocCLI.tty_ify(entry), limit, @@ -1282,7 +1281,7 @@ class DocCLI(CLI, RoleMixin): else: text.append(DocCLI.warp_fill(DocCLI.tty_ify(entry), limit, initial_indent=sub_indent, subsequent_indent=sub_indent)) else: - if not isinstance(opt['description'], string_types): + if not isinstance(opt['description'], str): raise AnsibleError("Expected string in description of %s, got %s" % (o, type(opt['description']))) text.append(key + DocCLI.warp_fill(DocCLI.tty_ify(opt['description']), limit, initial_indent=inline_indent, subsequent_indent=sub_indent, initial_extra=len(extra_indent))) @@ -1466,7 +1465,7 @@ class DocCLI(CLI, RoleMixin): if k not in doc: continue text.append('') - if isinstance(doc[k], string_types): + if isinstance(doc[k], str): text.append('%s: %s' % (k.upper(), DocCLI.warp_fill(DocCLI.tty_ify(doc[k]), limit - (len(k) + 2), subsequent_indent=opt_indent))) elif isinstance(doc[k], (list, tuple)): @@ -1478,7 +1477,7 @@ class DocCLI(CLI, RoleMixin): if doc.get('examples', False): text.append('') text.append(_format("EXAMPLES:", 'bold')) - if isinstance(doc['examples'], string_types): + if isinstance(doc['examples'], str): text.append(doc.pop('examples').strip()) else: try: @@ -1572,7 +1571,7 @@ class DocCLI(CLI, RoleMixin): continue text.append('') header = _format(k.upper(), 'bold') - if isinstance(doc[k], string_types): + if isinstance(doc[k], str): text.append('%s: %s' % (header, DocCLI.warp_fill(DocCLI.tty_ify(doc[k]), limit - (len(k) + 2), subsequent_indent=opt_indent))) elif isinstance(doc[k], (list, tuple)): text.append('%s: %s' % (header, ', '.join(doc[k]))) @@ -1584,7 +1583,7 @@ class DocCLI(CLI, RoleMixin): if doc.get('plainexamples', False): text.append('') text.append(_format("EXAMPLES:", 'bold')) - if isinstance(doc['plainexamples'], string_types): + if isinstance(doc['plainexamples'], str): text.append(doc.pop('plainexamples').strip()) else: try: @@ -1621,7 +1620,7 @@ def _do_yaml_snippet(doc): for o in sorted(doc['options'].keys()): opt = doc['options'][o] - if isinstance(opt['description'], string_types): + if isinstance(opt['description'], str): desc = DocCLI.tty_ify(opt['description']) else: desc = DocCLI.tty_ify(" ".join(opt['description'])) diff --git a/lib/ansible/cli/galaxy.py b/lib/ansible/cli/galaxy.py index 981b02c7128..6fc310ea6b1 100755 --- a/lib/ansible/cli/galaxy.py +++ b/lib/ansible/cli/galaxy.py @@ -54,7 +54,6 @@ from ansible.module_utils.common.collections import is_iterable from ansible.module_utils.common.yaml import yaml_dump, yaml_load from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text from ansible._internal._datatag._tags import TrustedAsTemplate -from ansible.module_utils import six from ansible.parsing.dataloader import DataLoader from ansible.playbook.role.requirement import RoleRequirement from ansible._internal._templating._engine import TemplateEngine @@ -65,7 +64,6 @@ from ansible.utils.plugin_docs import get_versioned_doclink from ansible.utils.vars import load_extra_vars display = Display() -urlparse = six.moves.urllib.parse.urlparse def with_collection_artifacts_manager(wrapped_method): diff --git a/lib/ansible/executor/task_executor.py b/lib/ansible/executor/task_executor.py index 223abfc3ac8..208951eb73f 100644 --- a/lib/ansible/executor/task_executor.py +++ b/lib/ansible/executor/task_executor.py @@ -27,7 +27,6 @@ from ansible._internal._datatag._tags import TrustedAsTemplate from ansible.module_utils.parsing.convert_bool import boolean from ansible.module_utils.common.text.converters import to_text, to_native from ansible.module_utils.connection import write_to_stream -from ansible.module_utils.six import string_types from ansible.playbook.task import Task from ansible.plugins import get_plugin_class from ansible.plugins.loader import become_loader, cliconf_loader, connection_loader, httpapi_loader, netconf_loader, terminal_loader @@ -340,7 +339,7 @@ class TaskExecutor: }) # if plugin is loaded, get resolved name, otherwise leave original task connection - if self._connection and not isinstance(self._connection, string_types): + if self._connection and not isinstance(self._connection, str): task_fields['connection'] = getattr(self._connection, 'ansible_name') tr = _RawTaskResult( diff --git a/lib/ansible/galaxy/api.py b/lib/ansible/galaxy/api.py index 60689f44670..b34be950f8c 100644 --- a/lib/ansible/galaxy/api.py +++ b/lib/ansible/galaxy/api.py @@ -25,7 +25,6 @@ from ansible.errors import AnsibleError from ansible.galaxy.user_agent import user_agent from ansible.module_utils.api import retry_with_delays_and_condition from ansible.module_utils.api import generate_jittered_backoff -from ansible.module_utils.six import string_types from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text from ansible.module_utils.urls import open_url, prepare_multipart from ansible.utils.display import Display @@ -595,11 +594,11 @@ class GalaxyAPI: page_size = kwargs.get('page_size', None) author = kwargs.get('author', None) - if tags and isinstance(tags, string_types): + if tags and isinstance(tags, str): tags = tags.split(',') search_url += '&tags_autocomplete=' + '+'.join(tags) - if platforms and isinstance(platforms, string_types): + if platforms and isinstance(platforms, str): platforms = platforms.split(',') search_url += '&platforms_autocomplete=' + '+'.join(platforms) diff --git a/lib/ansible/galaxy/dependency_resolution/providers.py b/lib/ansible/galaxy/dependency_resolution/providers.py index 5f602b8242c..8cfb14b0b15 100644 --- a/lib/ansible/galaxy/dependency_resolution/providers.py +++ b/lib/ansible/galaxy/dependency_resolution/providers.py @@ -24,7 +24,6 @@ from ansible.galaxy.dependency_resolution.versioning import ( is_pre_release, meets_requirements, ) -from ansible.module_utils.six import string_types from ansible.utils.version import SemanticVersion, LooseVersion try: @@ -278,7 +277,7 @@ class CollectionDependencyProviderBase(AbstractProvider): # NOTE: Another known mistake is setting a minor part of the SemVer notation # NOTE: skipping the "patch" bit like "1.0" which is assumed non-compliant even # NOTE: after the conversion to string. - if not isinstance(version, string_types): + if not isinstance(version, str): raise ValueError(version_err) elif version != '*': try: diff --git a/lib/ansible/inventory/manager.py b/lib/ansible/inventory/manager.py index e6183ccd095..615b5a6d2eb 100644 --- a/lib/ansible/inventory/manager.py +++ b/lib/ansible/inventory/manager.py @@ -33,7 +33,6 @@ from ansible._internal import _json, _wrapt from ansible._internal._json import EncryptedStringBehavior from ansible.errors import AnsibleError, AnsibleOptionsError from ansible.inventory.data import InventoryData -from ansible.module_utils.six import string_types from ansible.module_utils.common.text.converters import to_bytes, to_text from ansible.parsing.utils.addresses import parse_address from ansible.plugins.loader import inventory_loader @@ -112,7 +111,7 @@ def split_host_pattern(pattern): results = (split_host_pattern(p) for p in pattern) # flatten the results return list(itertools.chain.from_iterable(results)) - elif not isinstance(pattern, string_types): + elif not isinstance(pattern, str): pattern = to_text(pattern, errors='surrogate_or_strict') # If it's got commas in it, we'll treat it as a straightforward @@ -162,7 +161,7 @@ class InventoryManager(object): # the inventory dirs, files, script paths or lists of hosts if sources is None: self._sources = [] - elif isinstance(sources, string_types): + elif isinstance(sources, str): self._sources = [sources] else: self._sources = sources diff --git a/lib/ansible/module_utils/_internal/_no_six.py b/lib/ansible/module_utils/_internal/_no_six.py new file mode 100644 index 00000000000..93263f94a83 --- /dev/null +++ b/lib/ansible/module_utils/_internal/_no_six.py @@ -0,0 +1,86 @@ +from __future__ import annotations + +import sys +import types + +from ansible.module_utils.common import warnings + + +# INLINED FROM THE SIX LIBRARY, see lib/ansible/module_utils/six/__init__.py +# Copyright (c) 2010-2024 Benjamin Peterson +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(type): + + def __new__(cls, name, this_bases, d): + if sys.version_info[:2] >= (3, 7): + # This version introduced PEP 560 that requires a bit + # of extra care (we mimic what is done by __build_class__). + resolved_bases = types.resolve_bases(bases) + if resolved_bases is not bases: + d['__orig_bases__'] = bases + else: + resolved_bases = bases + return meta(name, resolved_bases, d) + + @classmethod + def __prepare__(cls, name, this_bases): + return meta.__prepare__(name, bases) + + return type.__new__(metaclass, 'temporary_class', (), {}) + + +def add_metaclass(metaclass): + """Class decorator for creating a class with a metaclass.""" + + def wrapper(cls): + orig_vars = cls.__dict__.copy() + slots = orig_vars.get('__slots__') + if slots is not None: + if isinstance(slots, str): + slots = [slots] + for slots_var in slots: + orig_vars.pop(slots_var) + orig_vars.pop('__dict__', None) + orig_vars.pop('__weakref__', None) + if hasattr(cls, '__qualname__'): + orig_vars['__qualname__'] = cls.__qualname__ + return metaclass(cls.__name__, cls.__bases__, orig_vars) + + return wrapper + + +def iteritems(d, **kw): + return iter(d.items(**kw)) + + +_mini_six = { + "PY2": False, + "PY3": True, + "text_type": str, + "binary_type": bytes, + "string_types": (str,), + "integer_types": (int,), + "iteritems": iteritems, + "add_metaclass": add_metaclass, + "with_metaclass": with_metaclass, +} +# INLINED SIX END + + +def deprecate(importable_name: str, module_name: str, *deprecated_args) -> object: + """Inject import-time deprecation warnings.""" + if not (importable_name in deprecated_args and (importable := _mini_six.get(importable_name, ...) is not ...)): + raise AttributeError(f"module {module_name!r} has no attribute {importable_name!r}") + + # TODO Inspect and remove all calls to this function in 2.24 + warnings.deprecate( + msg=f"Importing {importable_name!r} from {module_name!r} is deprecated.", + version="2.24", + ) + + return importable diff --git a/lib/ansible/module_utils/_text.py b/lib/ansible/module_utils/_text.py index b6dd62074f6..e73361b6cd1 100644 --- a/lib/ansible/module_utils/_text.py +++ b/lib/ansible/module_utils/_text.py @@ -1,15 +1,35 @@ # Copyright (c), Toshio Kuratomi 2016 # Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause) -""" -.. warn:: Use ansible.module_utils.common.text.converters instead. -""" from __future__ import annotations -# Backwards compat for people still calling it from this package -# pylint: disable=unused-import -import codecs +from ansible.module_utils.common import warnings as _warnings -from ansible.module_utils.six import PY3, text_type, binary_type -from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text +_mini_six = { + "binary_type": bytes, + "text_type": str, + "PY3": True, +} + + +def __getattr__(importable_name: str) -> object: + """Inject import-time deprecation warnings.""" + help_text: str | None = None + importable: object + if importable_name == "codecs": + import codecs + importable = codecs + elif importable_name in {"to_bytes", "to_native", "to_text"}: + from ansible.module_utils.common.text import converters + importable = getattr(converters, importable_name) + help_text = "Use ansible.module_utils.common.text.converters instead." + elif (importable := _mini_six.get(importable_name, ...)) is ...: + raise AttributeError(f"module {__name__!r} has no attribute {importable_name!r}") + + _warnings.deprecate( + msg=f"Importing {importable_name!r} from {__name__!r} is deprecated.", + version="2.24", + help_text=help_text, + ) + return importable diff --git a/lib/ansible/module_utils/basic.py b/lib/ansible/module_utils/basic.py index ba87c7b3850..7f9742d836d 100644 --- a/lib/ansible/module_utils/basic.py +++ b/lib/ansible/module_utils/basic.py @@ -46,6 +46,15 @@ import tempfile import time import traceback +from collections.abc import ( + KeysView, + Mapping, + MutableMapping, + Sequence, + MutableSequence, + Set, + MutableSet, +) from functools import reduce try: @@ -123,13 +132,6 @@ def _get_available_hash_algorithms(): AVAILABLE_HASH_ALGORITHMS = _get_available_hash_algorithms() from ansible.module_utils.common import json as _json - -from ansible.module_utils.six.moves.collections_abc import ( - KeysView, - Mapping, MutableMapping, - Sequence, MutableSequence, - Set, MutableSet, -) from ansible.module_utils.common.locale import get_best_parsable_locale from ansible.module_utils.common.process import get_bin_path from ansible.module_utils.common.file import ( @@ -2186,6 +2188,18 @@ def get_module_path(): return os.path.dirname(os.path.realpath(__file__)) +_mini_six = { + "b": lambda s: s.encode("latin-1"), + "PY2": False, + "PY3": True, + "text_type": str, + "binary_type": bytes, + "string_types": (str,), + "integer_types": (int,), + "iteritems": lambda d, **kw: iter(d.items(**kw)), +} + + def __getattr__(importable_name): """Inject import-time deprecation warnings.""" if importable_name == 'datetime': @@ -2203,24 +2217,12 @@ def __getattr__(importable_name): elif importable_name == 'repeat': from itertools import repeat importable = repeat - elif importable_name in { - 'PY2', 'PY3', 'b', 'binary_type', 'integer_types', - 'iteritems', 'string_types', 'text_type', - }: - import importlib - importable = getattr( - importlib.import_module('ansible.module_utils.six'), - importable_name - ) elif importable_name == 'map': importable = map elif importable_name == 'shlex_quote': importable = shlex.quote - else: - raise AttributeError( - f'cannot import name {importable_name !r} ' - f"from '{__name__}' ({__file__ !s})" - ) + elif (importable := _mini_six.get(importable_name, ...)) is ...: + raise AttributeError(f"module {__name__!r} has no attribute {importable_name!r}") deprecate( msg=f"Importing '{importable_name}' from '{__name__}' is deprecated.", diff --git a/lib/ansible/module_utils/common/_collections_compat.py b/lib/ansible/module_utils/common/_collections_compat.py index 25f7889d8ef..684c33753e6 100644 --- a/lib/ansible/module_utils/common/_collections_compat.py +++ b/lib/ansible/module_utils/common/_collections_compat.py @@ -2,7 +2,7 @@ # Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause) """Collections ABC import shim. -Use `ansible.module_utils.six.moves.collections_abc` instead, which has been available since ansible-core 2.11. +Use `collections.abc` instead. This module exists only for backwards compatibility. """ @@ -10,7 +10,7 @@ from __future__ import annotations # Although this was originally intended for internal use only, it has wide adoption in collections. # This is due in part to sanity tests previously recommending its use over `collections` imports. -from ansible.module_utils.six.moves.collections_abc import ( # pylint: disable=unused-import +from collections.abc import ( # pylint: disable=unused-import MappingView, ItemsView, KeysView, @@ -25,3 +25,12 @@ from ansible.module_utils.six.moves.collections_abc import ( # pylint: disable= Iterable, Iterator, ) + +from ansible.module_utils.common import warnings as _warnings + + +_warnings.deprecate( + msg="The `ansible.module_utils.common._collections_compat` module is deprecated.", + help_text="Use `collections.abc` from the Python standard library instead.", + version="2.24", +) diff --git a/lib/ansible/module_utils/common/collections.py b/lib/ansible/module_utils/common/collections.py index 9f4dfb9b4d0..4fdc874269b 100644 --- a/lib/ansible/module_utils/common/collections.py +++ b/lib/ansible/module_utils/common/collections.py @@ -6,9 +6,10 @@ from __future__ import annotations +from collections.abc import Hashable, Mapping, MutableMapping, Sequence # pylint: disable=unused-import + +from ansible.module_utils._internal import _no_six from ansible.module_utils.common import warnings as _warnings -from ansible.module_utils.six import binary_type, text_type -from ansible.module_utils.six.moves.collections_abc import Hashable, Mapping, MutableMapping, Sequence # pylint: disable=unused-import class ImmutableDict(Hashable, Mapping): @@ -67,7 +68,7 @@ class ImmutableDict(Hashable, Mapping): def is_string(seq): """Identify whether the input has a string-like type (including bytes).""" - return isinstance(seq, (text_type, binary_type)) + return isinstance(seq, (str, bytes)) def is_iterable(seq, include_strings=False): @@ -114,3 +115,7 @@ def count(seq): for elem in seq: counters[elem] = counters.get(elem, 0) + 1 return counters + + +def __getattr__(importable_name): + return _no_six.deprecate(importable_name, __name__, "binary_type", "text_type") diff --git a/lib/ansible/module_utils/common/dict_transformations.py b/lib/ansible/module_utils/common/dict_transformations.py index 8d318f5ef63..3e6510c4b78 100644 --- a/lib/ansible/module_utils/common/dict_transformations.py +++ b/lib/ansible/module_utils/common/dict_transformations.py @@ -7,10 +7,9 @@ from __future__ import annotations import re +from collections.abc import MutableMapping from copy import deepcopy -from ansible.module_utils.six.moves.collections_abc import MutableMapping - def camel_dict_to_snake_dict(camel_dict, reversible=False, ignore_list=()): """ diff --git a/lib/ansible/module_utils/common/network.py b/lib/ansible/module_utils/common/network.py index a85fc1ce4ab..a5c2148c06f 100644 --- a/lib/ansible/module_utils/common/network.py +++ b/lib/ansible/module_utils/common/network.py @@ -6,11 +6,13 @@ from __future__ import annotations import re + +# backward compat +from builtins import zip # pylint: disable=unused-import + from struct import pack from socket import inet_ntoa -from ansible.module_utils.six.moves import zip - VALID_MASKS = [2**8 - 2**i for i in range(0, 9)] diff --git a/lib/ansible/module_utils/common/parameters.py b/lib/ansible/module_utils/common/parameters.py index fc886463c94..129bb05178a 100644 --- a/lib/ansible/module_utils/common/parameters.py +++ b/lib/ansible/module_utils/common/parameters.py @@ -9,9 +9,19 @@ import os import typing as t from collections import deque -from itertools import chain +from collections.abc import ( + KeysView, + Set, + Sequence, + Mapping, + MutableMapping, + MutableSet, + MutableSequence, +) +from itertools import chain # pylint: disable=unused-import from ansible.module_utils.common.collections import is_iterable +from ansible.module_utils._internal import _no_six from ansible.module_utils._internal._datatag import AnsibleSerializable, AnsibleTagHelper from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text from ansible.module_utils.common.warnings import warn @@ -33,26 +43,6 @@ from ansible.module_utils.errors import ( SubParameterTypeError, ) from ansible.module_utils.parsing.convert_bool import BOOLEANS_FALSE, BOOLEANS_TRUE - -from ansible.module_utils.six.moves.collections_abc import ( - KeysView, - Set, - Sequence, - Mapping, - MutableMapping, - MutableSet, - MutableSequence, -) - -from ansible.module_utils.six import ( - binary_type, - integer_types, - string_types, - text_type, - PY2, - PY3, -) - from ansible.module_utils.common.validation import ( check_mutually_exclusive, check_required_arguments, @@ -243,7 +233,7 @@ def _handle_aliases(argument_spec, parameters, alias_warnings=None, alias_deprec if aliases is None: continue - if not is_iterable(aliases) or isinstance(aliases, (binary_type, text_type)): + if not is_iterable(aliases) or isinstance(aliases, (bytes, str)): raise TypeError('internal error: aliases must be a list or tuple') for alias in aliases: @@ -346,7 +336,7 @@ def _list_no_log_values(argument_spec, params): for sub_param in sub_parameters: # Validate dict fields in case they came in as strings - if isinstance(sub_param, string_types): + if isinstance(sub_param, str): sub_param = check_type_dict(sub_param) if not isinstance(sub_param, Mapping): @@ -362,7 +352,7 @@ def _return_datastructure_name(obj): """ Return native stringified values from datastructures. For use with removing sensitive values pre-jsonification.""" - if isinstance(obj, (text_type, binary_type)): + if isinstance(obj, (str, bytes)): if obj: yield to_native(obj, errors='surrogate_or_strict') return @@ -375,7 +365,7 @@ def _return_datastructure_name(obj): elif obj is None or isinstance(obj, bool): # This must come before int because bools are also ints return - elif isinstance(obj, tuple(list(integer_types) + [float])): + elif isinstance(obj, (int, float)): yield to_native(obj, nonstring='simplerepr') else: raise TypeError('Unknown parameter type: %s' % (type(obj))) @@ -413,26 +403,23 @@ def _remove_values_conditions(value, no_log_strings, deferred_removals): """ original_value = value - if isinstance(value, (text_type, binary_type)): + if isinstance(value, (str, bytes)): # Need native str type native_str_value = value - if isinstance(value, text_type): + if isinstance(value, str): value_is_text = True - if PY2: - native_str_value = to_bytes(value, errors='surrogate_or_strict') - elif isinstance(value, binary_type): + elif isinstance(value, bytes): value_is_text = False - if PY3: - native_str_value = to_text(value, errors='surrogate_or_strict') + native_str_value = to_text(value, errors='surrogate_or_strict') if native_str_value in no_log_strings: return 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER' for omit_me in no_log_strings: native_str_value = native_str_value.replace(omit_me, '*' * 8) - if value_is_text and isinstance(native_str_value, binary_type): + if value_is_text and isinstance(native_str_value, bytes): value = to_text(native_str_value, encoding='utf-8', errors='surrogate_then_replace') - elif not value_is_text and isinstance(native_str_value, text_type): + elif not value_is_text and isinstance(native_str_value, str): value = to_bytes(native_str_value, encoding='utf-8', errors='surrogate_then_replace') else: value = native_str_value @@ -514,7 +501,7 @@ def _set_defaults(argument_spec, parameters, set_default=True): def _sanitize_keys_conditions(value, no_log_strings, ignore_keys, deferred_removals): """ Helper method to :func:`sanitize_keys` to build ``deferred_removals`` and avoid deep recursion. """ - if isinstance(value, (text_type, binary_type)): + if isinstance(value, (str, bytes)): return value if isinstance(value, Sequence): @@ -541,7 +528,7 @@ def _sanitize_keys_conditions(value, no_log_strings, ignore_keys, deferred_remov deferred_removals.append((value, new_value)) return new_value - if isinstance(value, tuple(chain(integer_types, (float, bool, NoneType)))): + if isinstance(value, (int, float, bool, NoneType)): return value if isinstance(value, (datetime.datetime, datetime.date, datetime.time)): @@ -560,8 +547,8 @@ def _validate_elements(wanted_type, parameter, values, options_context=None, err # Get param name for strings so we can later display this value in a useful error message if needed # Only pass 'kwargs' to our checkers and ignore custom callable checkers kwargs = {} - if wanted_element_type == 'str' and isinstance(wanted_type, string_types): - if isinstance(parameter, string_types): + if wanted_element_type == 'str' and isinstance(wanted_type, str): + if isinstance(parameter, str): kwargs['param'] = parameter elif isinstance(parameter, dict): kwargs['param'] = list(parameter.keys())[0] @@ -620,7 +607,7 @@ def _validate_argument_types(argument_spec, parameters, prefix='', options_conte # Get param name for strings so we can later display this value in a useful error message if needed # Only pass 'kwargs' to our checkers and ignore custom callable checkers kwargs = {} - if wanted_name == 'str' and isinstance(wanted_type, string_types): + if wanted_name == 'str' and isinstance(wanted_type, str): kwargs['param'] = list(parameters.keys())[0] # Get the name of the parent key if this is a nested option @@ -659,7 +646,7 @@ def _validate_argument_values(argument_spec, parameters, options_context=None, e if choices is None: continue - if isinstance(choices, (frozenset, KeysView, Sequence)) and not isinstance(choices, (binary_type, text_type)): + if isinstance(choices, (frozenset, KeysView, Sequence)) and not isinstance(choices, (bytes, str)): if param in parameters: # Allow one or more when type='list' param with choices if isinstance(parameters[param], list): @@ -745,7 +732,7 @@ def _validate_sub_spec( options_context.append(param) # Make sure we can iterate over the elements - if not isinstance(parameters[param], Sequence) or isinstance(parameters[param], string_types): + if not isinstance(parameters[param], Sequence) or isinstance(parameters[param], str): elements = [parameters[param]] else: elements = parameters[param] @@ -940,3 +927,7 @@ def remove_values(value, no_log_strings): raise TypeError('Unknown container type encountered when removing private values from output') return new_value + + +def __getattr__(importable_name): + return _no_six.deprecate(importable_name, __name__, "binary_type", "text_type", "integer_types", "string_types", "PY2", "PY3") diff --git a/lib/ansible/module_utils/common/text/converters.py b/lib/ansible/module_utils/common/text/converters.py index 057d06bdbea..ac044511853 100644 --- a/lib/ansible/module_utils/common/text/converters.py +++ b/lib/ansible/module_utils/common/text/converters.py @@ -8,11 +8,8 @@ from __future__ import annotations import codecs import json -from ansible.module_utils.six import ( - binary_type, - iteritems, - text_type, -) +from ansible.module_utils._internal import _no_six + try: codecs.lookup_error('surrogateescape') @@ -90,7 +87,7 @@ def to_bytes(obj, encoding='utf-8', errors=None, nonstring='simplerepr'): Added the ``surrogate_then_replace`` error handler and made it the default error handler. """ - if isinstance(obj, binary_type): + if isinstance(obj, bytes): return obj # We're given a text string @@ -104,7 +101,7 @@ def to_bytes(obj, encoding='utf-8', errors=None, nonstring='simplerepr'): else: errors = 'replace' - if isinstance(obj, text_type): + if isinstance(obj, str): try: # Try this first as it's the fastest return obj.encode(encoding, errors) @@ -194,7 +191,7 @@ def to_text(obj, encoding='utf-8', errors=None, nonstring='simplerepr'): Added the surrogate_then_replace error handler and made it the default error handler. """ - if isinstance(obj, text_type): + if isinstance(obj, str): return obj if errors in _COMPOSED_ERROR_HANDLERS: @@ -205,7 +202,7 @@ def to_text(obj, encoding='utf-8', errors=None, nonstring='simplerepr'): else: errors = 'replace' - if isinstance(obj, binary_type): + if isinstance(obj, bytes): # Note: We don't need special handling for surrogate_then_replace # because all bytes will either be made into surrogates or are valid # to decode. @@ -259,10 +256,10 @@ def container_to_bytes(d, encoding='utf-8', errors='surrogate_or_strict'): """ # DTFIX-FUTURE: deprecate - if isinstance(d, text_type): + if isinstance(d, str): return to_bytes(d, encoding=encoding, errors=errors) elif isinstance(d, dict): - return dict(container_to_bytes(o, encoding, errors) for o in iteritems(d)) + return dict(container_to_bytes(o, encoding, errors) for o in d.items()) elif isinstance(d, list): return [container_to_bytes(o, encoding, errors) for o in d] elif isinstance(d, tuple): @@ -279,14 +276,18 @@ def container_to_text(d, encoding='utf-8', errors='surrogate_or_strict'): """ # DTFIX-FUTURE: deprecate - if isinstance(d, binary_type): + if isinstance(d, bytes): # Warning, can traceback return to_text(d, encoding=encoding, errors=errors) elif isinstance(d, dict): - return dict(container_to_text(o, encoding, errors) for o in iteritems(d)) + return dict(container_to_text(o, encoding, errors) for o in d.items()) elif isinstance(d, list): return [container_to_text(o, encoding, errors) for o in d] elif isinstance(d, tuple): return tuple(container_to_text(o, encoding, errors) for o in d) else: return d + + +def __getattr__(importable_name): + return _no_six.deprecate(importable_name, __name__, "binary_type", "text_type", "iteritems") diff --git a/lib/ansible/module_utils/common/text/formatters.py b/lib/ansible/module_utils/common/text/formatters.py index d548085c57f..1eeae7c10f4 100644 --- a/lib/ansible/module_utils/common/text/formatters.py +++ b/lib/ansible/module_utils/common/text/formatters.py @@ -6,7 +6,7 @@ from __future__ import annotations import re -from ansible.module_utils.six import iteritems +from ansible.module_utils._internal import _no_six SIZE_RANGES = { 'Y': 1 << 80, @@ -117,7 +117,7 @@ def bytes_to_human(size, isbits=False, unit=None): base = 'bits' suffix = '' - for suffix, limit in sorted(iteritems(SIZE_RANGES), key=lambda item: -item[1]): + for suffix, limit in sorted(SIZE_RANGES.items(), key=lambda item: -item[1]): if (unit is None and size >= limit) or unit is not None and unit.upper() == suffix[0]: break @@ -127,3 +127,7 @@ def bytes_to_human(size, isbits=False, unit=None): suffix = base return '%.2f %s' % (size / limit, suffix) + + +def __getattr__(importable_name): + return _no_six.deprecate(importable_name, __name__, "iteritems") diff --git a/lib/ansible/module_utils/common/validation.py b/lib/ansible/module_utils/common/validation.py index f5d5f5a061f..498248c0ff3 100644 --- a/lib/ansible/module_utils/common/validation.py +++ b/lib/ansible/module_utils/common/validation.py @@ -10,15 +10,13 @@ import os import re from ast import literal_eval +from ansible.module_utils._internal import _no_six from ansible.module_utils.common import json as _common_json from ansible.module_utils.common.text.converters import to_native from ansible.module_utils.common.collections import is_iterable from ansible.module_utils.common.text.formatters import human_to_bytes from ansible.module_utils.common.warnings import deprecate from ansible.module_utils.parsing.convert_bool import boolean -from ansible.module_utils.six import ( - string_types, -) def count_terms(terms, parameters): @@ -43,7 +41,7 @@ def safe_eval(value, locals=None, include_exceptions=False): version="2.21", ) # do not allow method calls to modules - if not isinstance(value, string_types): + if not isinstance(value, str): # already templated to a datavaluestructure, perhaps? if include_exceptions: return (value, None) @@ -194,7 +192,7 @@ def check_required_by(requirements, parameters, options_context=None): if key not in parameters or parameters[key] is None: continue # Support strings (single-item lists) - if isinstance(value, string_types): + if isinstance(value, str): value = [value] if missing := [required for required in value if required not in parameters or parameters[required] is None]: @@ -373,7 +371,7 @@ def check_type_str(value, allow_conversion=True, param=None, prefix=''): :returns: Original value if it is a string, the value converted to a string if allow_conversion=True, or raises a TypeError if allow_conversion=False. """ - if isinstance(value, string_types): + if isinstance(value, str): return value if allow_conversion and value is not None: @@ -403,7 +401,7 @@ def check_type_list(value): return value # DTFIX-FUTURE: deprecate legacy comma split functionality, eventually replace with `_check_type_list_strict` - if isinstance(value, string_types): + if isinstance(value, str): return value.split(",") elif isinstance(value, int) or isinstance(value, float): return [str(value)] @@ -431,7 +429,7 @@ def check_type_dict(value): if isinstance(value, dict): return value - if isinstance(value, string_types): + if isinstance(value, str): if value.startswith("{"): try: return json.loads(value) @@ -494,7 +492,7 @@ def check_type_bool(value): if isinstance(value, bool): return value - if isinstance(value, string_types) or isinstance(value, (int, float)): + if isinstance(value, str) or isinstance(value, (int, float)): return boolean(value) raise TypeError('%s cannot be converted to a bool' % type(value)) @@ -594,3 +592,7 @@ def check_type_jsonarg(value): return json.dumps(value, cls=_common_json._get_legacy_encoder(), _decode_bytes=True) raise TypeError('%s cannot be converted to a json string' % type(value)) + + +def __getattr__(importable_name): + return _no_six.deprecate(importable_name, __name__, "string_types") diff --git a/lib/ansible/module_utils/connection.py b/lib/ansible/module_utils/connection.py index aa81095d93d..f40aceffa5c 100644 --- a/lib/ansible/module_utils/connection.py +++ b/lib/ansible/module_utils/connection.py @@ -36,9 +36,10 @@ import struct import uuid from functools import partial + +from ansible.module_utils._internal import _no_six from ansible.module_utils.common.text.converters import to_bytes, to_text from ansible.module_utils.common.json import _get_legacy_encoder -from ansible.module_utils.six import iteritems def write_to_stream(stream, obj): @@ -95,7 +96,7 @@ class ConnectionError(Exception): def __init__(self, message, *args, **kwargs): super(ConnectionError, self).__init__(message) - for k, v in iteritems(kwargs): + for k, v in kwargs.items(): setattr(self, k, v) @@ -149,7 +150,7 @@ class Connection(object): raise ConnectionError( "Unable to decode JSON from response to {0}. Received '{1}'.".format(name, out) ) - params = [repr(arg) for arg in args] + ['{0}={1!r}'.format(k, v) for k, v in iteritems(kwargs)] + params = [repr(arg) for arg in args] + ['{0}={1!r}'.format(k, v) for k, v in kwargs.items()] params = ', '.join(params) raise ConnectionError( "Unable to decode JSON from response to {0}({1}). Received '{2}'.".format(name, params, out) @@ -200,3 +201,7 @@ class Connection(object): sf.close() return to_text(response, errors='surrogate_or_strict') + + +def __getattr__(importable_name): + return _no_six.deprecate(importable_name, __name__, "iteritems") diff --git a/lib/ansible/module_utils/facts/hardware/linux.py b/lib/ansible/module_utils/facts/hardware/linux.py index 62fdb896f0f..88f16945811 100644 --- a/lib/ansible/module_utils/facts/hardware/linux.py +++ b/lib/ansible/module_utils/facts/hardware/linux.py @@ -24,13 +24,13 @@ import re import sys import time +from ansible.module_utils._internal import _no_six from ansible.module_utils._internal._concurrent import _futures from ansible.module_utils.common.locale import get_best_parsable_locale from ansible.module_utils.common.text.converters import to_text from ansible.module_utils.common.text.formatters import bytes_to_human from ansible.module_utils.facts.hardware.base import Hardware, HardwareCollector from ansible.module_utils.facts.utils import get_file_content, get_file_lines, get_mount_size -from ansible.module_utils.six import iteritems # import this as a module to ensure we get the same module instance from ansible.module_utils.facts import timeout @@ -653,7 +653,7 @@ class LinuxHardware(Hardware): retval[target].add(entry) except OSError: continue - return dict((k, list(sorted(v))) for (k, v) in iteritems(retval)) + return dict((k, list(sorted(v))) for (k, v) in retval.items()) except OSError: return {} @@ -665,7 +665,7 @@ class LinuxHardware(Hardware): device = elements[3] target = elements[5] retval[target].add(device) - return dict((k, list(sorted(v))) for (k, v) in iteritems(retval)) + return dict((k, list(sorted(v))) for (k, v) in retval.items()) except OSError: return {} @@ -750,7 +750,7 @@ class LinuxHardware(Hardware): d = {} d['virtual'] = virtual d['links'] = {} - for (link_type, link_values) in iteritems(links): + for (link_type, link_values) in links.items(): d['links'][link_type] = link_values.get(block, []) diskname = os.path.basename(sysdir) for key in ['vendor', 'model', 'sas_address', 'sas_device_handle']: @@ -801,7 +801,7 @@ class LinuxHardware(Hardware): part_sysdir = sysdir + "/" + partname part['links'] = {} - for (link_type, link_values) in iteritems(links): + for (link_type, link_values) in links.items(): part['links'][link_type] = link_values.get(partname, []) part['start'] = get_file_content(part_sysdir + "/start", 0) @@ -925,3 +925,7 @@ class LinuxHardwareCollector(HardwareCollector): _fact_class = LinuxHardware required_facts = set(['platform']) + + +def __getattr__(importable_name): + return _no_six.deprecate(importable_name, __name__, "iteritems") diff --git a/lib/ansible/module_utils/facts/hardware/netbsd.py b/lib/ansible/module_utils/facts/hardware/netbsd.py index 69ac583df64..226da7ffd54 100644 --- a/lib/ansible/module_utils/facts/hardware/netbsd.py +++ b/lib/ansible/module_utils/facts/hardware/netbsd.py @@ -19,7 +19,7 @@ import os import re import time -from ansible.module_utils.six.moves import reduce +from functools import reduce from ansible.module_utils.facts.hardware.base import Hardware, HardwareCollector from ansible.module_utils.facts.timeout import TimeoutError, timeout diff --git a/lib/ansible/module_utils/facts/hardware/sunos.py b/lib/ansible/module_utils/facts/hardware/sunos.py index 134e59a8c2c..26a26865dd6 100644 --- a/lib/ansible/module_utils/facts/hardware/sunos.py +++ b/lib/ansible/module_utils/facts/hardware/sunos.py @@ -18,12 +18,13 @@ from __future__ import annotations import re import time +from functools import reduce + from ansible.module_utils.common.locale import get_best_parsable_locale from ansible.module_utils.common.text.formatters import bytes_to_human from ansible.module_utils.facts.utils import get_file_content, get_mount_size from ansible.module_utils.facts.hardware.base import Hardware, HardwareCollector from ansible.module_utils.facts import timeout -from ansible.module_utils.six.moves import reduce class SunOSHardware(Hardware): diff --git a/lib/ansible/module_utils/facts/packages.py b/lib/ansible/module_utils/facts/packages.py index b5b9bcb35ef..fafdf5a67ec 100644 --- a/lib/ansible/module_utils/facts/packages.py +++ b/lib/ansible/module_utils/facts/packages.py @@ -7,7 +7,7 @@ import ansible.module_utils.compat.typing as t from abc import ABCMeta, abstractmethod -from ansible.module_utils.six import with_metaclass +from ansible.module_utils._internal import _no_six from ansible.module_utils.basic import missing_required_lib from ansible.module_utils.common.process import get_bin_path from ansible.module_utils.common.respawn import has_respawned, probe_interpreters_for_module, respawn_module @@ -19,7 +19,7 @@ def get_all_pkg_managers(): return {obj.__name__.lower(): obj for obj in get_all_subclasses(PkgMgr) if obj not in (CLIMgr, LibMgr, RespawningLibMgr)} -class PkgMgr(with_metaclass(ABCMeta, object)): # type: ignore[misc] +class PkgMgr(metaclass=ABCMeta): @abstractmethod def is_available(self, handle_exceptions): @@ -125,3 +125,7 @@ class CLIMgr(PkgMgr): if not handle_exceptions: raise return found + + +def __getattr__(importable_name): + return _no_six.deprecate(importable_name, __name__, "with_metaclass") diff --git a/lib/ansible/module_utils/facts/system/env.py b/lib/ansible/module_utils/facts/system/env.py index cf6a22457a9..1327ffd9d37 100644 --- a/lib/ansible/module_utils/facts/system/env.py +++ b/lib/ansible/module_utils/facts/system/env.py @@ -18,8 +18,7 @@ from __future__ import annotations import os import typing as t -from ansible.module_utils.six import iteritems - +from ansible.module_utils._internal import _no_six from ansible.module_utils.facts.collector import BaseFactCollector @@ -31,7 +30,11 @@ class EnvFactCollector(BaseFactCollector): env_facts = {} env_facts['env'] = {} - for k, v in iteritems(os.environ): + for k, v in os.environ.items(): env_facts['env'][k] = v return env_facts + + +def __getattr__(importable_name): + return _no_six.deprecate(importable_name, __name__, "iteritems") diff --git a/lib/ansible/module_utils/facts/system/local.py b/lib/ansible/module_utils/facts/system/local.py index 7cf0f144d26..50abe123126 100644 --- a/lib/ansible/module_utils/facts/system/local.py +++ b/lib/ansible/module_utils/facts/system/local.py @@ -3,16 +3,18 @@ from __future__ import annotations +import configparser import glob import json import os import stat import typing as t +from io import StringIO + from ansible.module_utils.common.text.converters import to_text from ansible.module_utils.facts.utils import get_file_content from ansible.module_utils.facts.collector import BaseFactCollector -from ansible.module_utils.six.moves import configparser, StringIO class LocalFactCollector(BaseFactCollector): diff --git a/lib/ansible/module_utils/parsing/convert_bool.py b/lib/ansible/module_utils/parsing/convert_bool.py index b97a6d05780..e6f1405af97 100644 --- a/lib/ansible/module_utils/parsing/convert_bool.py +++ b/lib/ansible/module_utils/parsing/convert_bool.py @@ -5,7 +5,7 @@ from __future__ import annotations import collections.abc as c -from ansible.module_utils.six import binary_type, text_type +from ansible.module_utils._internal import _no_six from ansible.module_utils.common.text.converters import to_text @@ -20,7 +20,7 @@ def boolean(value, strict=True): normalized_value = value - if isinstance(value, (text_type, binary_type)): + if isinstance(value, (str, bytes)): normalized_value = to_text(value, errors='surrogate_or_strict').lower().strip() if not isinstance(value, c.Hashable): @@ -32,3 +32,7 @@ def boolean(value, strict=True): return False raise TypeError("The value '%s' is not a valid boolean. Valid booleans include: %s" % (to_text(value), ', '.join(repr(i) for i in BOOLEANS))) + + +def __getattr__(importable_name): + return _no_six.deprecate(importable_name, __name__, "binary_type", "text_type") diff --git a/lib/ansible/module_utils/service.py b/lib/ansible/module_utils/service.py index 013ec0435f6..a75668e3f24 100644 --- a/lib/ansible/module_utils/service.py +++ b/lib/ansible/module_utils/service.py @@ -36,7 +36,6 @@ import select import shlex import subprocess -from ansible.module_utils.six import b from ansible.module_utils.common.text.converters import to_bytes, to_text @@ -200,7 +199,7 @@ def daemonize(module, cmd): fds = [p.stdout, p.stderr] # loop reading output till it is done - output = {p.stdout: b(""), p.stderr: b("")} + output = {p.stdout: b"", p.stderr: b""} while fds: rfd, wfd, efd = select.select(fds, [], fds, 1) if (rfd + wfd + efd) or p.poll() is None: @@ -234,7 +233,7 @@ def daemonize(module, cmd): os.waitpid(pid, 0) # Grab response data after child finishes - return_data = b("") + return_data = b"" while True: rfd, wfd, efd = select.select([pipe[0]], [], [pipe[0]]) if pipe[0] in rfd: diff --git a/lib/ansible/modules/apt.py b/lib/ansible/modules/apt.py index 53c403133a2..97452f03106 100644 --- a/lib/ansible/modules/apt.py +++ b/lib/ansible/modules/apt.py @@ -383,7 +383,6 @@ from ansible.module_utils.common.file import S_IRWXU_RXG_RXO from ansible.module_utils.common.locale import get_best_parsable_locale from ansible.module_utils.common.respawn import has_respawned, probe_interpreters_for_module, respawn_module from ansible.module_utils.common.text.converters import to_native, to_text -from ansible.module_utils.six import string_types from ansible.module_utils.urls import fetch_file DPKG_OPTIONS = 'force-confdef,force-confold' @@ -633,7 +632,7 @@ def expand_pkgspec_from_fnmatches(m, pkgspec, cache): if pkgspec: for pkgspec_pattern in pkgspec: - if not isinstance(pkgspec_pattern, string_types): + if not isinstance(pkgspec_pattern, str): m.fail_json(msg="Invalid type for package name, expected string but got %s" % type(pkgspec_pattern)) pkgname_pattern, version_cmp, version = package_split(pkgspec_pattern) diff --git a/lib/ansible/modules/assemble.py b/lib/ansible/modules/assemble.py index b1329496d96..b28b696ea85 100644 --- a/lib/ansible/modules/assemble.py +++ b/lib/ansible/modules/assemble.py @@ -131,7 +131,6 @@ import re import tempfile from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.six import b, indexbytes from ansible.module_utils.common.text.converters import to_native @@ -141,6 +140,7 @@ def assemble_from_fragments(src_path, delimiter=None, compiled_regexp=None, igno tmp = os.fdopen(tmpfd, 'wb') delimit_me = False add_newline = False + b_linesep = os.linesep.encode() for f in sorted(os.listdir(src_path)): if compiled_regexp and not compiled_regexp.search(f): @@ -153,7 +153,7 @@ def assemble_from_fragments(src_path, delimiter=None, compiled_regexp=None, igno # always put a newline between fragments if the previous fragment didn't end with a newline. if add_newline: - tmp.write(b('\n')) + tmp.write(b_linesep) # delimiters should only appear between fragments if delimit_me: @@ -163,16 +163,12 @@ def assemble_from_fragments(src_path, delimiter=None, compiled_regexp=None, igno tmp.write(delimiter) # always make sure there's a newline after the # delimiter, so lines don't run together - - # byte indexing differs on Python 2 and 3, - # use indexbytes for compat - # chr(10) == '\n' - if indexbytes(delimiter, -1) != 10: - tmp.write(b('\n')) + if not delimiter.endswith(b_linesep): + tmp.write(b_linesep) tmp.write(fragment_content) delimit_me = True - if fragment_content.endswith(b('\n')): + if fragment_content.endswith(b_linesep): add_newline = False else: add_newline = True diff --git a/lib/ansible/modules/blockinfile.py b/lib/ansible/modules/blockinfile.py index e5240a0cc4f..f6531f798b5 100644 --- a/lib/ansible/modules/blockinfile.py +++ b/lib/ansible/modules/blockinfile.py @@ -192,7 +192,6 @@ EXAMPLES = r""" import re import os import tempfile -from ansible.module_utils.six import b from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.common.text.converters import to_bytes, to_native @@ -291,7 +290,8 @@ def main(): block = to_bytes(params['block']) marker = to_bytes(params['marker']) present = params['state'] == 'present' - blank_line = [b(os.linesep)] + b_linesep = os.linesep.encode() + blank_line = [b_linesep] if not present and not path_exists: module.exit_json(changed=False, msg="File %s not present" % path) @@ -306,11 +306,11 @@ def main(): else: insertre = None - marker0 = re.sub(b(r'{mark}'), b(params['marker_begin']), marker) + b(os.linesep) - marker1 = re.sub(b(r'{mark}'), b(params['marker_end']), marker) + b(os.linesep) + marker0 = re.sub(r'{mark}'.encode(), to_bytes(params['marker_begin']), marker) + b_linesep + marker1 = re.sub(r'{mark}'.encode(), to_bytes(params['marker_end']), marker) + b_linesep if present and block: - if not block.endswith(b(os.linesep)): - block += b(os.linesep) + if not block.endswith(b_linesep): + block += b_linesep blocklines = [marker0] + block.splitlines(True) + [marker1] else: blocklines = [] @@ -352,15 +352,15 @@ def main(): # Ensure there is a line separator before the block of lines to be inserted if n0 > 0: - if not lines[n0 - 1].endswith(b(os.linesep)): - lines[n0 - 1] += b(os.linesep) + if not lines[n0 - 1].endswith(b_linesep): + lines[n0 - 1] += b_linesep # Before the block: check if we need to prepend a blank line # If yes, we need to add the blank line if we are not at the beginning of the file # and the previous line is not a blank line # In both cases, we need to shift by one on the right the inserting position of the block if params['prepend_newline'] and present: - if n0 != 0 and lines[n0 - 1] != b(os.linesep): + if n0 != 0 and lines[n0 - 1] != b_linesep: lines[n0:n0] = blank_line n0 += 1 @@ -372,7 +372,7 @@ def main(): # and the line right after is not a blank line if params['append_newline'] and present: line_after_block = n0 + len(blocklines) - if line_after_block < len(lines) and lines[line_after_block] != b(os.linesep): + if line_after_block < len(lines) and lines[line_after_block] != b_linesep: lines[line_after_block:line_after_block] = blank_line if lines: diff --git a/lib/ansible/modules/cron.py b/lib/ansible/modules/cron.py index e64be5d7b9f..1cf7f61f8cb 100644 --- a/lib/ansible/modules/cron.py +++ b/lib/ansible/modules/cron.py @@ -219,13 +219,13 @@ import os import platform import pwd import re +import shlex import sys import tempfile from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.common.file import S_IRWU_RWG_RWO from ansible.module_utils.common.text.converters import to_bytes, to_native -from ansible.module_utils.six.moves import shlex_quote class CronTabError(Exception): @@ -529,13 +529,13 @@ class CronTab(object): user = '' if self.user: if platform.system() == 'SunOS': - return "su %s -c '%s -l'" % (shlex_quote(self.user), shlex_quote(self.cron_cmd)) + return "su %s -c '%s -l'" % (shlex.quote(self.user), shlex.quote(self.cron_cmd)) elif platform.system() == 'AIX': - return "%s -l %s" % (shlex_quote(self.cron_cmd), shlex_quote(self.user)) + return "%s -l %s" % (shlex.quote(self.cron_cmd), shlex.quote(self.user)) elif platform.system() == 'HP-UX': - return "%s %s %s" % (self.cron_cmd, '-l', shlex_quote(self.user)) + return "%s %s %s" % (self.cron_cmd, '-l', shlex.quote(self.user)) elif pwd.getpwuid(os.getuid())[0] != self.user: - user = '-u %s' % shlex_quote(self.user) + user = '-u %s' % shlex.quote(self.user) return "%s %s %s" % (self.cron_cmd, user, '-l') def _write_execute(self, path): @@ -546,10 +546,10 @@ class CronTab(object): if self.user: if platform.system() in ['SunOS', 'HP-UX', 'AIX']: return "chown %s %s ; su '%s' -c '%s %s'" % ( - shlex_quote(self.user), shlex_quote(path), shlex_quote(self.user), self.cron_cmd, shlex_quote(path)) + shlex.quote(self.user), shlex.quote(path), shlex.quote(self.user), self.cron_cmd, shlex.quote(path)) elif pwd.getpwuid(os.getuid())[0] != self.user: - user = '-u %s' % shlex_quote(self.user) - return "%s %s %s" % (self.cron_cmd, user, shlex_quote(path)) + user = '-u %s' % shlex.quote(self.user) + return "%s %s %s" % (self.cron_cmd, user, shlex.quote(path)) def main(): diff --git a/lib/ansible/modules/deb822_repository.py b/lib/ansible/modules/deb822_repository.py index 00278fb0342..68b08d41a4e 100644 --- a/lib/ansible/modules/deb822_repository.py +++ b/lib/ansible/modules/deb822_repository.py @@ -250,7 +250,6 @@ from ansible.module_utils.common.file import S_IRWXU_RXG_RXO, S_IRWU_RG_RO from ansible.module_utils.common.respawn import has_respawned, probe_interpreters_for_module, respawn_module from ansible.module_utils.common.text.converters import to_bytes from ansible.module_utils.common.text.converters import to_native -from ansible.module_utils.six import raise_from # type: ignore[attr-defined] from ansible.module_utils.urls import generic_urlparse from ansible.module_utils.urls import open_url from ansible.module_utils.urls import get_user_agent @@ -339,7 +338,7 @@ def write_signed_by_key(module, v, slug): try: r = open_url(v, http_agent=get_user_agent()) except Exception as exc: - raise_from(RuntimeError(to_native(exc)), exc) + raise RuntimeError('Could not fetch signed_by key.') from exc else: b_data = r.read() else: @@ -587,14 +586,9 @@ def main(): elif is_sequence(value): value = format_list(value) elif key == 'signed_by': - try: - key_changed, signed_by_filename, signed_by_data = write_signed_by_key(module, value, slug) - value = signed_by_filename or signed_by_data - changed |= key_changed - except RuntimeError as exc: - module.fail_json( - msg='Could not fetch signed_by key: %s' % to_native(exc) - ) + key_changed, signed_by_filename, signed_by_data = write_signed_by_key(module, value, slug) + value = signed_by_filename or signed_by_data + changed |= key_changed if value.count('\n') > 0: value = format_multiline(value) diff --git a/lib/ansible/modules/find.py b/lib/ansible/modules/find.py index b30f6c71697..970eb0cf929 100644 --- a/lib/ansible/modules/find.py +++ b/lib/ansible/modules/find.py @@ -291,7 +291,6 @@ import time from ansible.module_utils.common.text.converters import to_text, to_native from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.six import string_types class _Object: @@ -496,7 +495,7 @@ def main(): params = module.params - if params['mode'] and not isinstance(params['mode'], string_types): + if params['mode'] and not isinstance(params['mode'], str): module.fail_json( msg="argument 'mode' is not a string and conversion is not allowed, value is of type %s" % params['mode'].__class__.__name__ ) diff --git a/lib/ansible/modules/get_url.py b/lib/ansible/modules/get_url.py index f25743b9a41..b679d08d9c4 100644 --- a/lib/ansible/modules/get_url.py +++ b/lib/ansible/modules/get_url.py @@ -374,9 +374,9 @@ import shutil import tempfile from datetime import datetime, timezone +from urllib.parse import urlsplit from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.six.moves.urllib.parse import urlsplit from ansible.module_utils.common.text.converters import to_native from ansible.module_utils.urls import fetch_url, url_argument_spec diff --git a/lib/ansible/modules/git.py b/lib/ansible/modules/git.py index f4c1100fda1..4564277cec5 100644 --- a/lib/ansible/modules/git.py +++ b/lib/ansible/modules/git.py @@ -343,7 +343,6 @@ from ansible.module_utils.common.text.converters import to_native, to_text from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.common.locale import get_best_parsable_locale from ansible.module_utils.common.process import get_bin_path -from ansible.module_utils.six import b, string_types def relocate_repo(module, result, repo_dir, old_repo_dir, worktree_dir): @@ -443,12 +442,12 @@ def write_ssh_wrapper(module): fd, wrapper_path = tempfile.mkstemp() # use existing git_ssh/ssh_command, fallback to 'ssh' - template = b("""#!/bin/sh + template = """#!/bin/sh %s $GIT_SSH_OPTS "$@" -""" % os.environ.get('GIT_SSH', os.environ.get('GIT_SSH_COMMAND', 'ssh'))) +""" % os.environ.get('GIT_SSH', os.environ.get('GIT_SSH_COMMAND', 'ssh')) # write it - with os.fdopen(fd, 'w+b') as fh: + with os.fdopen(fd, 'w') as fh: fh.write(template) # set execute @@ -1257,7 +1256,7 @@ def main(): # evaluate and set the umask before doing anything else if umask is not None: - if not isinstance(umask, string_types): + if not isinstance(umask, str): module.fail_json(msg="umask must be defined as a quoted octal integer") try: umask = int(umask, 8) diff --git a/lib/ansible/modules/service.py b/lib/ansible/modules/service.py index 438aeb0e1a4..f430903dffe 100644 --- a/lib/ansible/modules/service.py +++ b/lib/ansible/modules/service.py @@ -180,7 +180,6 @@ from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.common.locale import get_best_parsable_locale from ansible.module_utils.common.sys_info import get_platform_subclass from ansible.module_utils.service import fail_if_missing, is_systemd_managed -from ansible.module_utils.six import b class Service(object): @@ -292,8 +291,8 @@ class Service(object): # chkconfig localizes messages and we're screen scraping so make # sure we use the C locale p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=lang_env, preexec_fn=lambda: os.close(pipe[1])) - stdout = b("") - stderr = b("") + stdout = b"" + stderr = b"" fds = [p.stdout, p.stderr] # Wait for all output, or until the main process is dead and its output is done. while fds: @@ -322,7 +321,7 @@ class Service(object): os.close(pipe[1]) os.waitpid(pid, 0) # Wait for data from daemon process and process it. - data = b("") + data = b"" while True: rfd, wfd, efd = select.select([pipe[0]], [], [pipe[0]]) if pipe[0] in rfd: diff --git a/lib/ansible/modules/uri.py b/lib/ansible/modules/uri.py index e19450b358d..ceb6bcae764 100644 --- a/lib/ansible/modules/uri.py +++ b/lib/ansible/modules/uri.py @@ -438,13 +438,12 @@ import os import re import shutil import tempfile +from collections.abc import Mapping, Sequence from datetime import datetime, timezone +from urllib.parse import urlencode, urljoin from ansible.module_utils.basic import AnsibleModule, sanitize_keys -from ansible.module_utils.six import binary_type, iteritems, string_types -from ansible.module_utils.six.moves.urllib.parse import urlencode, urljoin from ansible.module_utils.common.text.converters import to_native, to_text -from ansible.module_utils.six.moves.collections_abc import Mapping, Sequence from ansible.module_utils.urls import ( fetch_url, get_response_filename, @@ -479,7 +478,7 @@ def write_file(module, dest, content, resp): try: fd, tmpsrc = tempfile.mkstemp(dir=module.tmpdir) with os.fdopen(fd, 'wb') as f: - if isinstance(content, binary_type): + if isinstance(content, bytes): f.write(content) else: shutil.copyfileobj(content, f) @@ -521,14 +520,14 @@ def kv_list(data): def form_urlencoded(body): """ Convert data into a form-urlencoded string """ - if isinstance(body, string_types): + if isinstance(body, str): return body if isinstance(body, (Mapping, Sequence)): result = [] # Turn a list of lists into a list of tuples that urlencode accepts for key, values in kv_list(body): - if isinstance(values, string_types) or not isinstance(values, (Mapping, Sequence)): + if isinstance(values, str) or not isinstance(values, (Mapping, Sequence)): values = [values] for value in values: if value is not None: @@ -641,12 +640,12 @@ def main(): if body_format == 'json': # Encode the body unless its a string, then assume it is pre-formatted JSON - if not isinstance(body, string_types): + if not isinstance(body, str): body = json.dumps(body) if 'content-type' not in [header.lower() for header in dict_headers]: dict_headers['Content-Type'] = 'application/json' elif body_format == 'form-urlencoded': - if not isinstance(body, string_types): + if not isinstance(body, str): try: body = form_urlencoded(body) except ValueError as e: @@ -747,7 +746,7 @@ def main(): # In python3, the headers are title cased. Lowercase them to be # compatible with the python2 behaviour. uresp = {} - for key, value in iteritems(resp): + for key, value in resp.items(): ukey = key.replace("-", "_").lower() uresp[ukey] = value @@ -755,7 +754,7 @@ def main(): uresp['location'] = urljoin(url, uresp['location']) # Default content_encoding to try - if isinstance(content, binary_type): + if isinstance(content, bytes): u_content = to_text(content, encoding=content_encoding) if maybe_json: try: diff --git a/lib/ansible/parsing/dataloader.py b/lib/ansible/parsing/dataloader.py index d8ce2a95ef9..af470340832 100644 --- a/lib/ansible/parsing/dataloader.py +++ b/lib/ansible/parsing/dataloader.py @@ -19,7 +19,6 @@ from ansible._internal._errors import _error_utils from ansible.module_utils.basic import is_executable from ansible._internal._datatag._tags import Origin, TrustedAsTemplate, SourceWasEncrypted from ansible.module_utils._internal._datatag import AnsibleTagHelper -from ansible.module_utils.six import binary_type, text_type from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text from ansible.parsing.quoting import unquote from ansible.parsing.utils.yaml import from_yaml @@ -418,7 +417,7 @@ class DataLoader: Temporary files are cleanup in the destructor """ - if not file_path or not isinstance(file_path, (binary_type, text_type)): + if not file_path or not isinstance(file_path, (bytes, str)): raise AnsibleParserError("Invalid filename: '%s'" % to_native(file_path)) b_file_path = to_bytes(file_path, errors='surrogate_or_strict') diff --git a/lib/ansible/parsing/vault/__init__.py b/lib/ansible/parsing/vault/__init__.py index 0322dd7b2e0..3128be8b060 100644 --- a/lib/ansible/parsing/vault/__init__.py +++ b/lib/ansible/parsing/vault/__init__.py @@ -59,7 +59,6 @@ except ImportError: from ansible.errors import AnsibleError, AnsibleAssertionError from ansible import constants as C -from ansible.module_utils.six import binary_type from ansible.module_utils.common.text.converters import to_bytes, to_text, to_native from ansible.utils.display import Display from ansible.utils.path import makedirs_safe, unfrackpath @@ -1237,7 +1236,7 @@ class VaultAES256: It would be nice if there were a library for this but hey. """ - if not (isinstance(b_a, binary_type) and isinstance(b_b, binary_type)): + if not (isinstance(b_a, bytes) and isinstance(b_b, bytes)): raise TypeError('_is_equal can only be used to compare two byte strings') # http://codahale.com/a-lesson-in-timing-attacks/ diff --git a/lib/ansible/playbook/base.py b/lib/ansible/playbook/base.py index 955962ea324..5a166929540 100644 --- a/lib/ansible/playbook/base.py +++ b/lib/ansible/playbook/base.py @@ -19,7 +19,6 @@ from ansible import context from ansible.errors import AnsibleError, AnsibleParserError, AnsibleAssertionError, AnsibleValueOmittedError, AnsibleFieldAttributeError from ansible.module_utils.datatag import native_type_name from ansible._internal._datatag._tags import Origin -from ansible.module_utils.six import string_types from ansible.module_utils.parsing.convert_bool import boolean from ansible.module_utils.common.sentinel import Sentinel from ansible.module_utils.common.text.converters import to_text @@ -37,7 +36,7 @@ display = Display() def _validate_action_group_metadata(action, found_group_metadata, fq_group_name): valid_metadata = { 'extend_group': { - 'types': (list, string_types,), + 'types': (list, str,), 'errortype': 'list', }, } @@ -204,7 +203,7 @@ class FieldAttributeBase: value = self.set_to_context(attr.name) valid_values = frozenset(('always', 'on_failed', 'on_unreachable', 'on_skipped', 'never')) - if value and isinstance(value, string_types) and value not in valid_values: + if value and isinstance(value, str) and value not in valid_values: raise AnsibleParserError("'%s' is not a valid value for debugger. Must be one of %s" % (value, ', '.join(valid_values)), obj=self.get_ds()) return value @@ -350,14 +349,14 @@ class FieldAttributeBase: found_group_metadata = False for action in action_group: # Everything should be a string except the metadata entry - if not isinstance(action, string_types): + if not isinstance(action, str): _validate_action_group_metadata(action, found_group_metadata, fq_group_name) if isinstance(action['metadata'], dict): found_group_metadata = True include_groups = action['metadata'].get('extend_group', []) - if isinstance(include_groups, string_types): + if isinstance(include_groups, str): include_groups = [include_groups] if not isinstance(include_groups, list): # Bad entries may be a warning above, but prevent tracebacks by setting it back to the acceptable type. @@ -472,7 +471,7 @@ class FieldAttributeBase: elif attribute.isa == 'percent': # special value, which may be an integer or float # with an optional '%' at the end - if isinstance(value, string_types) and '%' in value: + if isinstance(value, str) and '%' in value: value = value.replace('%', '') value = float(value) elif attribute.isa == 'list': diff --git a/lib/ansible/playbook/collectionsearch.py b/lib/ansible/playbook/collectionsearch.py index d5bc9450ef2..b0036a5b9e6 100644 --- a/lib/ansible/playbook/collectionsearch.py +++ b/lib/ansible/playbook/collectionsearch.py @@ -3,7 +3,6 @@ from __future__ import annotations -from ansible.module_utils.six import string_types from ansible.playbook.attribute import FieldAttribute from ansible.utils.collection_loader import AnsibleCollectionConfig from ansible.utils.display import Display @@ -32,7 +31,7 @@ def _ensure_default_collection(collection_list=None): class CollectionSearch: # this needs to be populated before we can resolve tasks/roles/etc - collections = FieldAttribute(isa='list', listof=string_types, priority=100, default=_ensure_default_collection, always_post_validate=True, static=True) + collections = FieldAttribute(isa='list', listof=(str,), priority=100, default=_ensure_default_collection, always_post_validate=True, static=True) def _load_collections(self, attr, ds): # We are always a mixin with Base, so we can validate this untemplated diff --git a/lib/ansible/playbook/handler.py b/lib/ansible/playbook/handler.py index 125a9cddc75..5a212c3f1d4 100644 --- a/lib/ansible/playbook/handler.py +++ b/lib/ansible/playbook/handler.py @@ -20,12 +20,11 @@ from __future__ import annotations from ansible.errors import AnsibleAssertionError from ansible.playbook.attribute import NonInheritableFieldAttribute from ansible.playbook.task import Task -from ansible.module_utils.six import string_types class Handler(Task): - listen = NonInheritableFieldAttribute(isa='list', default=list, listof=string_types, static=True) + listen = NonInheritableFieldAttribute(isa='list', default=list, listof=(str,), static=True) def __init__(self, block=None, role=None, task_include=None): self.notified_hosts = [] diff --git a/lib/ansible/playbook/play.py b/lib/ansible/playbook/play.py index 3a14405f35d..032716e90b4 100644 --- a/lib/ansible/playbook/play.py +++ b/lib/ansible/playbook/play.py @@ -22,7 +22,6 @@ from ansible import context from ansible.errors import AnsibleError from ansible.errors import AnsibleParserError, AnsibleAssertionError from ansible.module_utils.common.collections import is_sequence -from ansible.module_utils.six import binary_type, string_types, text_type from ansible.playbook.attribute import NonInheritableFieldAttribute from ansible.playbook.base import Base from ansible.playbook.block import Block @@ -53,11 +52,11 @@ class Play(Base, Taggable, CollectionSearch): """ # ================================================================================= - hosts = NonInheritableFieldAttribute(isa='list', required=True, listof=string_types, always_post_validate=True, priority=-2) + hosts = NonInheritableFieldAttribute(isa='list', required=True, listof=(str,), always_post_validate=True, priority=-2) # Facts gather_facts = NonInheritableFieldAttribute(isa='bool', default=None, always_post_validate=True) - gather_subset = NonInheritableFieldAttribute(isa='list', default=None, listof=string_types, always_post_validate=True) + gather_subset = NonInheritableFieldAttribute(isa='list', default=None, listof=(str,), always_post_validate=True) gather_timeout = NonInheritableFieldAttribute(isa='int', default=None, always_post_validate=True) fact_path = NonInheritableFieldAttribute(isa='string', default=None) @@ -120,10 +119,10 @@ class Play(Base, Taggable, CollectionSearch): for entry in value: if entry is None: raise AnsibleParserError("Hosts list cannot contain values of 'None'. Please check your playbook") - elif not isinstance(entry, (binary_type, text_type)): + elif not isinstance(entry, (bytes, str)): raise AnsibleParserError("Hosts list contains an invalid host value: '{host!s}'".format(host=entry)) - elif not isinstance(value, (binary_type, text_type, EncryptedString)): + elif not isinstance(value, (bytes, str, EncryptedString)): raise AnsibleParserError("Hosts list must be a sequence or string. Please check your playbook.") def get_name(self): diff --git a/lib/ansible/playbook/role/__init__.py b/lib/ansible/playbook/role/__init__.py index a86bcd9234a..c52102128dc 100644 --- a/lib/ansible/playbook/role/__init__.py +++ b/lib/ansible/playbook/role/__init__.py @@ -27,7 +27,6 @@ from ansible import constants as C from ansible.errors import AnsibleError, AnsibleParserError, AnsibleAssertionError from ansible.module_utils.common.sentinel import Sentinel from ansible.module_utils.common.text.converters import to_text -from ansible.module_utils.six import binary_type, text_type from ansible.playbook.base import Base from ansible.playbook.collectionsearch import CollectionSearch from ansible.playbook.conditional import Conditional @@ -74,7 +73,7 @@ def hash_params(params): # Any container is unhashable if it contains unhashable items (for # instance, tuple() is a Hashable subclass but if it contains a dict, it # cannot be hashed) - if isinstance(params, Container) and not isinstance(params, (text_type, binary_type)): + if isinstance(params, Container) and not isinstance(params, (str, bytes)): if isinstance(params, Mapping): try: # Optimistically hope the contents are all hashable diff --git a/lib/ansible/playbook/role/definition.py b/lib/ansible/playbook/role/definition.py index 670a4e101ca..017344062eb 100644 --- a/lib/ansible/playbook/role/definition.py +++ b/lib/ansible/playbook/role/definition.py @@ -22,7 +22,6 @@ import os from ansible import constants as C from ansible.errors import AnsibleError, AnsibleAssertionError from ansible.module_utils._internal._datatag import AnsibleTagHelper -from ansible.module_utils.six import string_types from ansible.playbook.attribute import NonInheritableFieldAttribute from ansible.playbook.base import Base from ansible.playbook.collectionsearch import CollectionSearch @@ -70,7 +69,7 @@ class RoleDefinition(Base, Conditional, Taggable, CollectionSearch): if isinstance(ds, int): ds = "%s" % ds - if not isinstance(ds, dict) and not isinstance(ds, string_types): + if not isinstance(ds, dict) and not isinstance(ds, str): raise AnsibleAssertionError() if isinstance(ds, dict): @@ -113,11 +112,11 @@ class RoleDefinition(Base, Conditional, Taggable, CollectionSearch): string), just that string """ - if isinstance(ds, string_types): + if isinstance(ds, str): return ds role_name = ds.get('role', ds.get('name')) - if not role_name or not isinstance(role_name, string_types): + if not role_name or not isinstance(role_name, str): raise AnsibleError('role definitions must contain a role name', obj=ds) # if we have the required datastructures, and if the role_name diff --git a/lib/ansible/playbook/role/include.py b/lib/ansible/playbook/role/include.py index 3ab3d153a39..a9eaeb9f12f 100644 --- a/lib/ansible/playbook/role/include.py +++ b/lib/ansible/playbook/role/include.py @@ -18,7 +18,6 @@ from __future__ import annotations from ansible.errors import AnsibleError, AnsibleParserError -from ansible.module_utils.six import string_types from ansible.playbook.delegatable import Delegatable from ansible.playbook.role.definition import RoleDefinition @@ -40,10 +39,10 @@ class RoleInclude(RoleDefinition, Delegatable): @staticmethod def load(data, play, current_role_path=None, parent_role=None, variable_manager=None, loader=None, collection_list=None): - if not (isinstance(data, string_types) or isinstance(data, dict)): + if not (isinstance(data, str) or isinstance(data, dict)): raise AnsibleParserError("Invalid role definition.", obj=data) - if isinstance(data, string_types) and ',' in data: + if isinstance(data, str) and ',' in data: raise AnsibleError("Invalid old style role requirement: %s" % data) ri = RoleInclude(play=play, role_basedir=current_role_path, variable_manager=variable_manager, loader=loader, collection_list=collection_list) diff --git a/lib/ansible/playbook/role/metadata.py b/lib/ansible/playbook/role/metadata.py index 0125ae2e084..5b07d35ec27 100644 --- a/lib/ansible/playbook/role/metadata.py +++ b/lib/ansible/playbook/role/metadata.py @@ -20,7 +20,6 @@ from __future__ import annotations import os from ansible.errors import AnsibleParserError, AnsibleError -from ansible.module_utils.six import string_types from ansible.playbook.attribute import NonInheritableFieldAttribute from ansible.playbook.base import Base from ansible.playbook.collectionsearch import CollectionSearch @@ -70,7 +69,7 @@ class RoleMetadata(Base, CollectionSearch): for role_def in ds: # FIXME: consolidate with ansible-galaxy to keep this in sync - if isinstance(role_def, string_types) or 'role' in role_def or 'name' in role_def: + if isinstance(role_def, str) or 'role' in role_def or 'name' in role_def: roles.append(role_def) continue try: diff --git a/lib/ansible/playbook/role/requirement.py b/lib/ansible/playbook/role/requirement.py index d68f686e013..716ad51b233 100644 --- a/lib/ansible/playbook/role/requirement.py +++ b/lib/ansible/playbook/role/requirement.py @@ -18,7 +18,6 @@ from __future__ import annotations from ansible.errors import AnsibleError -from ansible.module_utils.six import string_types from ansible.playbook.role.definition import RoleDefinition from ansible.utils.display import Display from ansible.utils.galaxy import scm_archive_resource @@ -65,7 +64,7 @@ class RoleRequirement(RoleDefinition): @staticmethod def role_yaml_parse(role): - if isinstance(role, string_types): + if isinstance(role, str): name = None scm = None src = None diff --git a/lib/ansible/playbook/role_include.py b/lib/ansible/playbook/role_include.py index 48003db7dff..e9a6d7072b2 100644 --- a/lib/ansible/playbook/role_include.py +++ b/lib/ansible/playbook/role_include.py @@ -23,7 +23,6 @@ from ansible.playbook.task_include import TaskInclude from ansible.playbook.role import Role from ansible.playbook.role.include import RoleInclude from ansible.utils.display import Display -from ansible.module_utils.six import string_types from ansible._internal._templating._engine import TemplateEngine __all__ = ['IncludeRole'] @@ -137,7 +136,7 @@ class IncludeRole(TaskInclude): for key in my_arg_names.intersection(IncludeRole.FROM_ARGS): from_key = key.removesuffix('_from') args_value = ir.args.get(key) - if not isinstance(args_value, string_types): + if not isinstance(args_value, str): raise AnsibleParserError('Expected a string for %s but got %s instead' % (key, type(args_value))) ir._from_files[from_key] = args_value diff --git a/lib/ansible/playbook/task.py b/lib/ansible/playbook/task.py index 09bd9c63696..91e410ebc86 100644 --- a/lib/ansible/playbook/task.py +++ b/lib/ansible/playbook/task.py @@ -25,7 +25,6 @@ from ansible.errors import AnsibleError, AnsibleParserError, AnsibleUndefinedVar from ansible.executor.module_common import _get_action_arg_defaults from ansible.module_utils.common.text.converters import to_native from ansible.module_utils._internal._datatag import AnsibleTagHelper -from ansible.module_utils.six import string_types from ansible.parsing.mod_args import ModuleArgsParser, RAW_PARAM_MODULES from ansible.plugins.action import ActionBase from ansible.plugins.loader import action_loader, module_loader, lookup_loader @@ -161,7 +160,7 @@ class Task(Base, Conditional, Taggable, CollectionSearch, Notifiable, Delegatabl def _merge_kv(self, ds): if ds is None: return "" - elif isinstance(ds, string_types): + elif isinstance(ds, str): return ds elif isinstance(ds, dict): buf = "" diff --git a/lib/ansible/plugins/action/__init__.py b/lib/ansible/plugins/action/__init__.py index b719000f66a..0383b8c1dfb 100644 --- a/lib/ansible/plugins/action/__init__.py +++ b/lib/ansible/plugins/action/__init__.py @@ -29,7 +29,6 @@ from ansible.module_utils.common.arg_spec import ArgumentSpecValidator from ansible.module_utils.errors import UnsupportedError from ansible.module_utils.json_utils import _filter_non_json_lines from ansible.module_utils.common.json import Direction, get_module_encoder, get_module_decoder -from ansible.module_utils.six import binary_type, string_types, text_type from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text from ansible.release import __version__ from ansible.utils.collection_loader import resource_from_fqcr @@ -52,7 +51,7 @@ if t.TYPE_CHECKING: def _validate_utf8_json(d): - if isinstance(d, text_type): + if isinstance(d, str): # Purposefully not using to_bytes here for performance reasons d.encode(encoding='utf-8', errors='strict') elif isinstance(d, dict): @@ -874,7 +873,7 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin): # happens sometimes when it is a dir and not on bsd if 'checksum' not in mystat['stat']: mystat['stat']['checksum'] = '' - elif not isinstance(mystat['stat']['checksum'], string_types): + elif not isinstance(mystat['stat']['checksum'], str): raise AnsibleError("Invalid checksum returned by stat: expected a string type but got %s" % type(mystat['stat']['checksum'])) return mystat['stat'] @@ -1084,7 +1083,7 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin): # the remote system, which can be read and parsed by the module args_data = "" for k, v in module_args.items(): - args_data += '%s=%s ' % (k, shlex.quote(text_type(v))) + args_data += '%s=%s ' % (k, shlex.quote(str(v))) self._transfer_data(args_file_path, args_data) elif module_style in ('non_native_want_json', 'binary'): profile_encoder = get_module_encoder(module_bits.serialization_profile, Direction.CONTROLLER_TO_MODULE) @@ -1169,7 +1168,7 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin): self._cleanup_remote_tmp = False # NOTE: dnf returns results .. but that made it 'compatible' with squashing, so we allow mappings, for now - if 'results' in data and (not isinstance(data['results'], Sequence) or isinstance(data['results'], string_types)): + if 'results' in data and (not isinstance(data['results'], Sequence) or isinstance(data['results'], str)): data['ansible_module_results'] = data['results'] del data['results'] display.warning("Found internal 'results' key in module return, renamed to 'ansible_module_results'.") @@ -1322,16 +1321,16 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin): # stdout and stderr may be either a file-like or a bytes object. # Convert either one to a text type - if isinstance(stdout, binary_type): + if isinstance(stdout, bytes): out = to_text(stdout, errors=encoding_errors) - elif not isinstance(stdout, text_type): + elif not isinstance(stdout, str): out = to_text(b''.join(stdout.readlines()), errors=encoding_errors) else: out = stdout - if isinstance(stderr, binary_type): + if isinstance(stderr, bytes): err = to_text(stderr, errors=encoding_errors) - elif not isinstance(stderr, text_type): + elif not isinstance(stderr, str): err = to_text(b''.join(stderr.readlines()), errors=encoding_errors) else: err = stderr diff --git a/lib/ansible/plugins/action/add_host.py b/lib/ansible/plugins/action/add_host.py index 1e80fa68e24..827d7b71012 100644 --- a/lib/ansible/plugins/action/add_host.py +++ b/lib/ansible/plugins/action/add_host.py @@ -21,7 +21,6 @@ from __future__ import annotations from collections.abc import Mapping from ansible.errors import AnsibleActionFail -from ansible.module_utils.six import string_types from ansible.plugins.action import ActionBase from ansible.parsing.utils.addresses import parse_address from ansible.utils.display import Display @@ -74,7 +73,7 @@ class ActionModule(ActionBase): if groups: if isinstance(groups, list): group_list = groups - elif isinstance(groups, string_types): + elif isinstance(groups, str): group_list = groups.split(",") else: raise AnsibleActionFail("Groups must be specified as a list.", obj=groups) diff --git a/lib/ansible/plugins/action/fetch.py b/lib/ansible/plugins/action/fetch.py index 3fb21fbe3c5..b9f3bb8661c 100644 --- a/lib/ansible/plugins/action/fetch.py +++ b/lib/ansible/plugins/action/fetch.py @@ -20,7 +20,6 @@ import os import base64 from ansible.errors import AnsibleConnectionFailure, AnsibleError, AnsibleActionFail, AnsibleActionSkip from ansible.module_utils.common.text.converters import to_bytes, to_text -from ansible.module_utils.six import string_types from ansible.module_utils.parsing.convert_bool import boolean from ansible.plugins.action import ActionBase from ansible.utils.display import Display @@ -52,10 +51,10 @@ class ActionModule(ActionBase): msg = '' # FIXME: validate source and dest are strings; use basic.py and module specs - if not isinstance(source, string_types): + if not isinstance(source, str): msg = "Invalid type supplied for source option, it must be a string" - if not isinstance(dest, string_types): + if not isinstance(dest, str): msg = "Invalid type supplied for dest option, it must be a string" if source is None or dest is None: diff --git a/lib/ansible/plugins/action/group_by.py b/lib/ansible/plugins/action/group_by.py index 27c433ac69c..1b9997c0b79 100644 --- a/lib/ansible/plugins/action/group_by.py +++ b/lib/ansible/plugins/action/group_by.py @@ -17,7 +17,6 @@ from __future__ import annotations from ansible.plugins.action import ActionBase -from ansible.module_utils.six import string_types class ActionModule(ActionBase): @@ -42,7 +41,7 @@ class ActionModule(ActionBase): group_name = self._task.args.get('key') parent_groups = self._task.args.get('parents', ['all']) - if isinstance(parent_groups, string_types): + if isinstance(parent_groups, str): parent_groups = [parent_groups] result['changed'] = False diff --git a/lib/ansible/plugins/action/include_vars.py b/lib/ansible/plugins/action/include_vars.py index 3eeef2d9c8d..3874441059f 100644 --- a/lib/ansible/plugins/action/include_vars.py +++ b/lib/ansible/plugins/action/include_vars.py @@ -10,7 +10,6 @@ import pathlib import ansible.constants as C from ansible.errors import AnsibleError from ansible._internal._datatag._tags import SourceWasEncrypted -from ansible.module_utils.six import string_types from ansible.module_utils.common.text.converters import to_native from ansible.plugins.action import ActionBase from ansible.utils.vars import combine_vars @@ -38,7 +37,7 @@ class ActionModule(ActionBase): if not self.ignore_files: self.ignore_files = list() - if isinstance(self.ignore_files, string_types): + if isinstance(self.ignore_files, str): self.ignore_files = self.ignore_files.split() elif isinstance(self.ignore_files, dict): @@ -66,7 +65,7 @@ class ActionModule(ActionBase): self.valid_extensions = self._task.args.get('extensions', self.VALID_FILE_EXTENSIONS) # convert/validate extensions list - if isinstance(self.valid_extensions, string_types): + if isinstance(self.valid_extensions, str): self.valid_extensions = list(self.valid_extensions) if not isinstance(self.valid_extensions, list): raise AnsibleError('Invalid type for "extensions" option, it must be a list') diff --git a/lib/ansible/plugins/action/template.py b/lib/ansible/plugins/action/template.py index 19844827341..e8cc2bbbf8b 100644 --- a/lib/ansible/plugins/action/template.py +++ b/lib/ansible/plugins/action/template.py @@ -23,7 +23,6 @@ from ansible.config.manager import ensure_type from ansible.errors import AnsibleError, AnsibleActionFail from ansible.module_utils.common.text.converters import to_bytes, to_text, to_native from ansible.module_utils.parsing.convert_bool import boolean -from ansible.module_utils.six import string_types from ansible.plugins.action import ActionBase from ansible.template import trust_as_template from ansible._internal._templating import _template_vars @@ -49,7 +48,7 @@ class ActionModule(ActionBase): 'block_end_string', 'comment_start_string', 'comment_end_string'): if s_type in self._task.args: value = ensure_type(self._task.args[s_type], 'string') - if value is not None and not isinstance(value, string_types): + if value is not None and not isinstance(value, str): raise AnsibleActionFail("%s is expected to be a string, but got %s instead" % (s_type, type(value))) self._task.args[s_type] = value diff --git a/lib/ansible/plugins/connection/local.py b/lib/ansible/plugins/connection/local.py index 0e650fd14f0..6b7581a2f45 100644 --- a/lib/ansible/plugins/connection/local.py +++ b/lib/ansible/plugins/connection/local.py @@ -47,7 +47,6 @@ import typing as t import ansible.constants as C from ansible.errors import AnsibleError, AnsibleFileNotFound, AnsibleConnectionFailure -from ansible.module_utils.six import text_type, binary_type from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text from ansible.plugins.connection import ConnectionBase from ansible.utils.display import Display @@ -100,7 +99,7 @@ class Connection(ConnectionBase): display.vvv(u"EXEC {0}".format(to_text(cmd)), host=self._play_context.remote_addr) display.debug("opening command with Popen()") - if isinstance(cmd, (text_type, binary_type)): + if isinstance(cmd, (str, bytes)): cmd = to_text(cmd) else: cmd = map(to_text, cmd) @@ -119,7 +118,7 @@ class Connection(ConnectionBase): p = subprocess.Popen( cmd, - shell=isinstance(cmd, (text_type, binary_type)), + shell=isinstance(cmd, (str, bytes)), executable=executable, cwd=self.cwd, stdin=stdin, diff --git a/lib/ansible/plugins/connection/ssh.py b/lib/ansible/plugins/connection/ssh.py index b9b6c1356a1..36b4fdcc377 100644 --- a/lib/ansible/plugins/connection/ssh.py +++ b/lib/ansible/plugins/connection/ssh.py @@ -441,7 +441,6 @@ from ansible.errors import ( AnsibleError, AnsibleFileNotFound, ) -from ansible.module_utils.six import text_type, binary_type from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text from ansible.plugins.connection import ConnectionBase, BUFSIZE from ansible.plugins.shell.powershell import _replace_stderr_clixml @@ -1122,7 +1121,7 @@ class Connection(ConnectionBase): p = None - if isinstance(cmd, (text_type, binary_type)): + if isinstance(cmd, (str, bytes)): cmd = to_bytes(cmd) else: cmd = list(map(to_bytes, cmd)) diff --git a/lib/ansible/plugins/filter/core.py b/lib/ansible/plugins/filter/core.py index f9f9da73a00..eed6511bce2 100644 --- a/lib/ansible/plugins/filter/core.py +++ b/lib/ansible/plugins/filter/core.py @@ -29,7 +29,6 @@ from ansible._internal._templating import _lazy_containers from ansible.errors import AnsibleFilterError, AnsibleTypeError, AnsibleTemplatePluginError from ansible.module_utils.datatag import native_type_name from ansible.module_utils.common.json import get_encoder, get_decoder -from ansible.module_utils.six import string_types, integer_types, text_type from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text from ansible.module_utils.common.collections import is_sequence from ansible.parsing.yaml.dumper import AnsibleDumper @@ -278,7 +277,7 @@ def rand(environment, end, start=None, step=None, seed=None): r = SystemRandom() else: r = Random(seed) - if isinstance(end, integer_types): + if isinstance(end, int): if not start: start = 0 if not step: @@ -555,7 +554,7 @@ def subelements(obj, subelements, skip_missing=False): if isinstance(subelements, list): subelement_list = subelements[:] - elif isinstance(subelements, string_types): + elif isinstance(subelements, str): subelement_list = subelements.split('.') else: raise AnsibleTypeError('subelements must be a list or a string') @@ -617,7 +616,7 @@ def list_of_dict_key_value_elements_to_dict(mylist, key_name='key', value_name=' def path_join(paths): """ takes a sequence or a string, and return a concatenation of the different members """ - if isinstance(paths, string_types): + if isinstance(paths, str): return os.path.join(paths) if is_sequence(paths): return os.path.join(*paths) @@ -809,7 +808,7 @@ class FilterModule(object): 'dict2items': dict_to_list_of_dict_key_value_elements, 'items2dict': list_of_dict_key_value_elements_to_dict, 'subelements': subelements, - 'split': partial(unicode_wrap, text_type.split), + 'split': partial(unicode_wrap, str.split), # FDI038 - replace this with a standard type compat shim 'groupby': _cleansed_groupby, diff --git a/lib/ansible/plugins/filter/mathstuff.py b/lib/ansible/plugins/filter/mathstuff.py index a9247a2c984..c2fe8e8b3e3 100644 --- a/lib/ansible/plugins/filter/mathstuff.py +++ b/lib/ansible/plugins/filter/mathstuff.py @@ -29,7 +29,6 @@ from jinja2.filters import pass_environment from ansible.errors import AnsibleError from ansible.module_utils.common.text import formatters -from ansible.module_utils.six import binary_type, text_type from ansible.utils.display import Display try: @@ -180,7 +179,7 @@ def rekey_on_member(data, key, duplicates='error'): if isinstance(data, Mapping): iterate_over = data.values() - elif isinstance(data, Iterable) and not isinstance(data, (text_type, binary_type)): + elif isinstance(data, Iterable) and not isinstance(data, (str, bytes)): iterate_over = data else: raise AnsibleError("Type is not a valid list, set, or dict") diff --git a/lib/ansible/plugins/inventory/__init__.py b/lib/ansible/plugins/inventory/__init__.py index 348e8dc8834..b6f70b3c44f 100644 --- a/lib/ansible/plugins/inventory/__init__.py +++ b/lib/ansible/plugins/inventory/__init__.py @@ -34,7 +34,6 @@ from ansible.parsing.dataloader import DataLoader from ansible.plugins import AnsiblePlugin, _ConfigurablePlugin from ansible.plugins.cache import CachePluginAdjudicator from ansible.module_utils.common.text.converters import to_bytes, to_native -from ansible.module_utils.six import string_types from ansible.utils.display import Display from ansible.utils.vars import combine_vars, load_extra_vars @@ -439,7 +438,7 @@ class Constructable(_BaseInventoryPlugin): new_raw_group_names = [] if use_default: new_raw_group_names.append(default_value_name) - elif isinstance(key, string_types): + elif isinstance(key, str): new_raw_group_names.append(key) elif isinstance(key, list): for name in key: diff --git a/lib/ansible/plugins/inventory/toml.py b/lib/ansible/plugins/inventory/toml.py index f0b62a85a2a..c7a434659f1 100644 --- a/lib/ansible/plugins/inventory/toml.py +++ b/lib/ansible/plugins/inventory/toml.py @@ -90,7 +90,6 @@ from collections.abc import MutableMapping, MutableSequence from ansible.errors import AnsibleFileNotFound, AnsibleParserError from ansible.module_utils.common.text.converters import to_bytes, to_native -from ansible.module_utils.six import string_types from ansible.plugins.inventory import BaseFileInventoryPlugin from ansible.utils.display import Display @@ -147,7 +146,7 @@ class InventoryModule(BaseFileInventoryPlugin): ) def _load_file(self, file_name): - if not file_name or not isinstance(file_name, string_types): + if not file_name or not isinstance(file_name, str): raise AnsibleParserError("Invalid filename: '%s'" % to_native(file_name)) b_file_name = to_bytes(self.loader.path_dwim(file_name)) diff --git a/lib/ansible/plugins/inventory/yaml.py b/lib/ansible/plugins/inventory/yaml.py index c822c6ad5a9..3b7ac16911a 100644 --- a/lib/ansible/plugins/inventory/yaml.py +++ b/lib/ansible/plugins/inventory/yaml.py @@ -70,7 +70,6 @@ import os from collections.abc import MutableMapping from ansible.errors import AnsibleError, AnsibleParserError -from ansible.module_utils.six import string_types from ansible.module_utils.common.text.converters import to_native, to_text from ansible.plugins.inventory import BaseFileInventoryPlugin @@ -136,7 +135,7 @@ class InventoryModule(BaseFileInventoryPlugin): for section in ['vars', 'children', 'hosts']: if section in group_data: # convert strings to dicts as these are allowed - if isinstance(group_data[section], string_types): + if isinstance(group_data[section], str): group_data[section] = {group_data[section]: None} if not isinstance(group_data[section], (MutableMapping, NoneType)): # type: ignore[misc] diff --git a/lib/ansible/plugins/loader.py b/lib/ansible/plugins/loader.py index bad7f88991b..e8a39a095fa 100644 --- a/lib/ansible/plugins/loader.py +++ b/lib/ansible/plugins/loader.py @@ -27,7 +27,6 @@ from ansible import _internal, constants as C from ansible.errors import AnsibleError, AnsiblePluginCircularRedirect, AnsiblePluginRemovedError, AnsibleCollectionUnsupportedVersionError from ansible.module_utils.common.text.converters import to_bytes, to_text, to_native from ansible.module_utils.datatag import deprecator_from_collection_name -from ansible.module_utils.six import string_types from ansible.parsing.yaml.loader import AnsibleLoader from ansible._internal._yaml._loader import AnsibleInstrumentedLoader from ansible.plugins import get_plugin_class, MODULE_CACHE, PATH_CACHE, PLUGIN_PATH_CACHE, AnsibleJinja2Plugin @@ -96,7 +95,7 @@ def get_shell_plugin(shell_type=None, executable=None): # mostly for backwards compat if executable: - if isinstance(executable, string_types): + if isinstance(executable, str): shell_filename = os.path.basename(executable) try: shell = shell_loader.get(shell_filename) diff --git a/lib/ansible/plugins/lookup/password.py b/lib/ansible/plugins/lookup/password.py index 86afb2ae8f6..a0718fbf18f 100644 --- a/lib/ansible/plugins/lookup/password.py +++ b/lib/ansible/plugins/lookup/password.py @@ -134,7 +134,6 @@ import hashlib from ansible.errors import AnsibleError, AnsibleAssertionError from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text -from ansible.module_utils.six import string_types from ansible.parsing.splitter import parse_kv from ansible.plugins.lookup import LookupBase from ansible.utils.encrypt import BaseHash, do_encrypt, random_password, random_salt @@ -335,7 +334,7 @@ class LookupModule(LookupBase): # chars still might need more chars = params.get('chars', self.get_option('chars')) - if chars and isinstance(chars, string_types): + if chars and isinstance(chars, str): tmp_chars = [] if u',,' in chars: tmp_chars.append(u',') diff --git a/lib/ansible/plugins/lookup/subelements.py b/lib/ansible/plugins/lookup/subelements.py index a08d14ec912..7b1a475c2ae 100644 --- a/lib/ansible/plugins/lookup/subelements.py +++ b/lib/ansible/plugins/lookup/subelements.py @@ -83,7 +83,6 @@ _list: """ from ansible.errors import AnsibleError -from ansible.module_utils.six import string_types from ansible.module_utils.parsing.convert_bool import boolean from ansible.plugins.lookup import LookupBase @@ -104,7 +103,7 @@ class LookupModule(LookupBase): _raise_terms_error() # first term should be a list (or dict), second a string holding the subkey - if not isinstance(terms[0], (list, dict)) or not isinstance(terms[1], string_types): + if not isinstance(terms[0], (list, dict)) or not isinstance(terms[1], str): _raise_terms_error("first a dict or a list, second a string pointing to the subkey") subelements = terms[1].split(".") @@ -122,7 +121,7 @@ class LookupModule(LookupBase): flags = {} if len(terms) == 3: flags = terms[2] - if not isinstance(flags, dict) and not all(isinstance(key, string_types) and key in FLAGS for key in flags): + if not isinstance(flags, dict) and not all(isinstance(key, str) and key in FLAGS for key in flags): _raise_terms_error("the optional third item must be a dict with flags %s" % FLAGS) # build_items diff --git a/lib/ansible/plugins/lookup/varnames.py b/lib/ansible/plugins/lookup/varnames.py index ef6159f3902..6eeef66f62f 100644 --- a/lib/ansible/plugins/lookup/varnames.py +++ b/lib/ansible/plugins/lookup/varnames.py @@ -52,7 +52,6 @@ import re from ansible.errors import AnsibleError from ansible.module_utils.common.text.converters import to_native -from ansible.module_utils.six import string_types from ansible.plugins.lookup import LookupBase @@ -69,7 +68,7 @@ class LookupModule(LookupBase): variable_names = list(variables.keys()) for term in terms: - if not isinstance(term, string_types): + if not isinstance(term, str): raise AnsibleError('Invalid setting identifier, "%s" is not a string, it is a %s' % (term, type(term))) try: diff --git a/lib/ansible/plugins/shell/__init__.py b/lib/ansible/plugins/shell/__init__.py index 57e0e930b71..225ec1f3b06 100644 --- a/lib/ansible/plugins/shell/__init__.py +++ b/lib/ansible/plugins/shell/__init__.py @@ -24,11 +24,8 @@ import secrets import shlex import time -from collections.abc import Mapping, Sequence - from ansible.errors import AnsibleError from ansible.module_utils.common.text.converters import to_native -from ansible.module_utils.six import text_type, string_types from ansible.plugins import AnsiblePlugin _USER_HOME_PATH_RE = re.compile(r'^~[_.A-Za-z0-9][-_.A-Za-z0-9]*$') @@ -84,7 +81,7 @@ class ShellBase(AnsiblePlugin): return 'ansible-tmp-%s-%s-%s' % (time.time(), os.getpid(), secrets.randbelow(2**48)) def env_prefix(self, **kwargs): - return ' '.join(['%s=%s' % (k, self.quote(text_type(v))) for k, v in kwargs.items()]) + return ' '.join(['%s=%s' % (k, self.quote(str(v))) for k, v in kwargs.items()]) def join_path(self, *args): return os.path.join(*args) diff --git a/lib/ansible/utils/context_objects.py b/lib/ansible/utils/context_objects.py index 02db666b0a4..9f67827b7ea 100644 --- a/lib/ansible/utils/context_objects.py +++ b/lib/ansible/utils/context_objects.py @@ -9,14 +9,14 @@ from __future__ import annotations from abc import ABCMeta from collections.abc import Container, Mapping, Sequence, Set +from ansible.module_utils._internal import _no_six from ansible.module_utils.common.collections import ImmutableDict -from ansible.module_utils.six import add_metaclass, binary_type, text_type from ansible.utils.singleton import Singleton def _make_immutable(obj): """Recursively convert a container and objects inside of it into immutable data types""" - if isinstance(obj, (text_type, binary_type)): + if isinstance(obj, (str, bytes)): # Strings first because they are also sequences return obj elif isinstance(obj, Mapping): @@ -79,11 +79,14 @@ class CLIArgs(ImmutableDict): return cls(vars(options)) -@add_metaclass(_ABCSingleton) -class GlobalCLIArgs(CLIArgs): +class GlobalCLIArgs(CLIArgs, metaclass=_ABCSingleton): """ Globally hold a parsed copy of cli arguments. Only one of these exist per program as it is for global context """ pass + + +def __getattr__(importable_name): + return _no_six.deprecate(importable_name, __name__, "binary_type", "text_type", "add_metaclass") diff --git a/lib/ansible/utils/display.py b/lib/ansible/utils/display.py index a0abd5dccd5..b5e2ff134a8 100644 --- a/lib/ansible/utils/display.py +++ b/lib/ansible/utils/display.py @@ -53,11 +53,10 @@ from ansible.constants import config from ansible.errors import AnsibleAssertionError, AnsiblePromptInterrupt, AnsiblePromptNoninteractive, AnsibleError from ansible._internal._errors import _error_utils, _error_factory from ansible._internal import _event_formatting -from ansible.module_utils._internal import _ambient_context, _deprecator, _messages +from ansible.module_utils._internal import _ambient_context, _deprecator, _messages, _no_six from ansible.module_utils.common.text.converters import to_bytes, to_text from ansible.module_utils.datatag import deprecator_from_collection_name from ansible._internal._datatag._tags import TrustedAsTemplate -from ansible.module_utils.six import text_type from ansible.module_utils._internal import _traceback, _errors from ansible.utils.color import stringc from ansible.utils.multiprocessing import context as multiprocessing_context @@ -106,7 +105,7 @@ def get_text_width(text: str) -> int: character and using wcwidth individually, falling back to a value of 0 for non-printable wide characters. """ - if not isinstance(text, text_type): + if not isinstance(text, str): raise TypeError('get_text_width requires text, not %s' % type(text)) try: @@ -1282,3 +1281,7 @@ def _report_config_warnings(deprecator: _messages.PluginInfo) -> None: # emit any warnings or deprecations # in the event config fails before display is up, we'll lose warnings -- but that's OK, since everything is broken anyway _report_config_warnings(_deprecator.ANSIBLE_CORE_DEPRECATOR) + + +def __getattr__(importable_name): + return _no_six.deprecate(importable_name, __name__, "text_type") diff --git a/lib/ansible/utils/helpers.py b/lib/ansible/utils/helpers.py index 97f34acd0e8..5714c885f74 100644 --- a/lib/ansible/utils/helpers.py +++ b/lib/ansible/utils/helpers.py @@ -17,7 +17,7 @@ from __future__ import annotations -from ansible.module_utils.six import string_types +from ansible.module_utils._internal import _no_six def pct_to_int(value, num_items, min_value=1): @@ -25,7 +25,7 @@ def pct_to_int(value, num_items, min_value=1): Converts a given value to a percentage if specified as "x%", otherwise converts the given value to an integer. """ - if isinstance(value, string_types) and value.endswith('%'): + if isinstance(value, str) and value.endswith('%'): value_pct = int(value.replace("%", "")) return int((value_pct / 100.0) * num_items) or min_value else: @@ -47,3 +47,7 @@ def deduplicate_list(original_list): """ seen = set() return [x for x in original_list if x not in seen and not seen.add(x)] + + +def __getattr__(importable_name): + return _no_six.deprecate(importable_name, __name__, "string_types") diff --git a/lib/ansible/utils/jsonrpc.py b/lib/ansible/utils/jsonrpc.py index 82d1c02ea12..e6e5e950824 100644 --- a/lib/ansible/utils/jsonrpc.py +++ b/lib/ansible/utils/jsonrpc.py @@ -7,9 +7,9 @@ import json import pickle import traceback +from ansible.module_utils._internal import _no_six from ansible.module_utils.common.text.converters import to_text from ansible.module_utils.connection import ConnectionError -from ansible.module_utils.six import binary_type, text_type from ansible.utils.display import Display display = Display() @@ -79,9 +79,9 @@ class JsonRpcServer(object): def response(self, result=None): response = self.header() - if isinstance(result, binary_type): + if isinstance(result, bytes): result = to_text(result) - if not isinstance(result, text_type): + if not isinstance(result, str): response["result_type"] = "pickle" result = to_text(pickle.dumps(result), errors='surrogateescape') response['result'] = result @@ -110,3 +110,7 @@ class JsonRpcServer(object): def internal_error(self, data=None): return self.error(-32603, 'Internal error', data) + + +def __getattr__(importable_name): + return _no_six.deprecate(importable_name, __name__, "binary_type", "text_type") diff --git a/lib/ansible/utils/plugin_docs.py b/lib/ansible/utils/plugin_docs.py index 8c1d9b46658..a0960b960f7 100644 --- a/lib/ansible/utils/plugin_docs.py +++ b/lib/ansible/utils/plugin_docs.py @@ -11,7 +11,7 @@ import yaml from ansible import constants as C from ansible.release import __version__ as ansible_version from ansible.errors import AnsibleError, AnsibleParserError, AnsiblePluginNotFound -from ansible.module_utils.six import string_types +from ansible.module_utils._internal import _no_six from ansible.module_utils.common.text.converters import to_native from ansible.parsing.plugin_docs import read_docstring from ansible.parsing.yaml.loader import AnsibleLoader @@ -133,7 +133,7 @@ def add_fragments(doc, filename, fragment_loader, is_module=False, section='DOCU fragments = doc.pop('extends_documentation_fragment', []) - if isinstance(fragments, string_types): + if isinstance(fragments, str): fragments = fragments.split(',') unknown_fragments = [] @@ -355,3 +355,7 @@ def get_plugin_docs(plugin, plugin_type, loader, fragment_loader, verbose): docs[0]['plugin_name'] = context.resolved_fqcn return docs + + +def __getattr__(importable_name): + return _no_six.deprecate(importable_name, __name__, "string_types") diff --git a/lib/ansible/utils/unsafe_proxy.py b/lib/ansible/utils/unsafe_proxy.py index 1a2c6d04b24..07695a6cc9b 100644 --- a/lib/ansible/utils/unsafe_proxy.py +++ b/lib/ansible/utils/unsafe_proxy.py @@ -7,10 +7,10 @@ from __future__ import annotations from collections.abc import Mapping, Set +from ansible.module_utils._internal import _no_six from ansible.module_utils.common.text.converters import to_bytes, to_text from ansible.module_utils.common.collections import is_sequence from ansible._internal._datatag._tags import TrustedAsTemplate -from ansible.module_utils.six import binary_type, text_type __all__ = ['AnsibleUnsafe', 'wrap_var'] @@ -62,9 +62,9 @@ def wrap_var(v): v = _wrap_set(v) elif is_sequence(v): v = _wrap_sequence(v) - elif isinstance(v, binary_type): + elif isinstance(v, bytes): v = AnsibleUnsafeBytes(v) - elif isinstance(v, text_type): + elif isinstance(v, str): v = AnsibleUnsafeText(v) return v @@ -76,3 +76,7 @@ def to_unsafe_bytes(*args, **kwargs): def to_unsafe_text(*args, **kwargs): return wrap_var(to_text(*args, **kwargs)) + + +def __getattr__(importable_name): + return _no_six.deprecate(importable_name, __name__, "binary_type", "text_type") diff --git a/lib/ansible/vars/clean.py b/lib/ansible/vars/clean.py index 8be64b2679a..f9a0722ec59 100644 --- a/lib/ansible/vars/clean.py +++ b/lib/ansible/vars/clean.py @@ -10,7 +10,6 @@ from collections.abc import MutableMapping, MutableSequence from ansible import constants as C from ansible.errors import AnsibleError -from ansible.module_utils import six from ansible.plugins.loader import connection_loader from ansible.utils.display import Display @@ -48,7 +47,7 @@ def module_response_deepcopy(v): """ if isinstance(v, dict): ret = v.copy() - items = six.iteritems(ret) + items = ret.items() elif isinstance(v, list): ret = v[:] items = enumerate(ret) @@ -80,7 +79,7 @@ def strip_internal_keys(dirty, exceptions=None): # listify to avoid updating dict while iterating over it for k in list(dirty.keys()): - if isinstance(k, six.string_types): + if isinstance(k, str): if k.startswith('_ansible_') and k not in exceptions: del dirty[k] continue diff --git a/lib/ansible/vars/manager.py b/lib/ansible/vars/manager.py index 7af718e558b..ede96f47455 100644 --- a/lib/ansible/vars/manager.py +++ b/lib/ansible/vars/manager.py @@ -33,7 +33,6 @@ from ansible.inventory.host import Host from ansible.inventory.helpers import sort_groups, get_group_vars from ansible.inventory.manager import InventoryManager from ansible.module_utils.datatag import native_type_name -from ansible.module_utils.six import text_type from ansible.parsing.dataloader import DataLoader from ansible._internal._templating._engine import TemplateEngine from ansible.plugins.loader import cache_loader @@ -467,7 +466,7 @@ class VariableManager: if task._role: variables['role_name'] = task._role.get_name(include_role_fqcn=False) variables['role_path'] = task._role._role_path - variables['role_uuid'] = text_type(task._role._uuid) + variables['role_uuid'] = str(task._role._uuid) variables['ansible_collection_name'] = task._role._role_collection variables['ansible_role_name'] = task._role.get_name() diff --git a/test/integration/targets/builtin_vars_prompt/test-vars_prompt.py b/test/integration/targets/builtin_vars_prompt/test-vars_prompt.py index 435a7eb979a..e85c39e987b 100644 --- a/test/integration/targets/builtin_vars_prompt/test-vars_prompt.py +++ b/test/integration/targets/builtin_vars_prompt/test-vars_prompt.py @@ -6,12 +6,6 @@ import os import pexpect import sys -from ansible.module_utils.six import PY2 - -if PY2: - log_buffer = sys.stdout -else: - log_buffer = sys.stdout.buffer env_vars = { 'ANSIBLE_ROLES_PATH': './roles', @@ -36,7 +30,7 @@ def run_test(playbook, test_spec, args=None, timeout=10, env=None): env=env, ) - vars_prompt_test.logfile = log_buffer + vars_prompt_test.logfile = sys.stdout.buffer for item in test_spec[0]: vars_prompt_test.expect(item[0]) if item[1]: diff --git a/test/integration/targets/pause/test-pause.py b/test/integration/targets/pause/test-pause.py index 6fcb5bf10a2..bdde0a47380 100755 --- a/test/integration/targets/pause/test-pause.py +++ b/test/integration/targets/pause/test-pause.py @@ -7,7 +7,6 @@ import pexpect import sys import termios -from ansible.module_utils.six import PY2 args = sys.argv[1:] @@ -22,11 +21,6 @@ try: except Exception: backspace = b'\x7f' -if PY2: - log_buffer = sys.stdout -else: - log_buffer = sys.stdout.buffer - os.environ.update(env_vars) # -- Plain pause -- # @@ -40,7 +34,7 @@ pause_test = pexpect.spawn( env=os.environ ) -pause_test.logfile = log_buffer +pause_test.logfile = sys.stdout.buffer pause_test.expect(r'Press enter to continue, Ctrl\+C to interrupt:') pause_test.send('\r') pause_test.expect('Task after pause') @@ -56,7 +50,7 @@ pause_test = pexpect.spawn( env=os.environ ) -pause_test.logfile = log_buffer +pause_test.logfile = sys.stdout.buffer pause_test.expect(r'Press enter to continue, Ctrl\+C to interrupt:') pause_test.send('\x03') pause_test.expect("Press 'C' to continue the play or 'A' to abort") @@ -74,7 +68,7 @@ pause_test = pexpect.spawn( env=os.environ ) -pause_test.logfile = log_buffer +pause_test.logfile = sys.stdout.buffer pause_test.expect(r'Press enter to continue, Ctrl\+C to interrupt:') pause_test.send('\x03') pause_test.expect("Press 'C' to continue the play or 'A' to abort") @@ -94,7 +88,7 @@ pause_test = pexpect.spawn( env=os.environ ) -pause_test.logfile = log_buffer +pause_test.logfile = sys.stdout.buffer pause_test.expect(r'Custom prompt:') pause_test.send('\r') pause_test.expect('Task after pause') @@ -110,7 +104,7 @@ pause_test = pexpect.spawn( env=os.environ ) -pause_test.logfile = log_buffer +pause_test.logfile = sys.stdout.buffer pause_test.expect(r'Custom prompt:') pause_test.send('\x03') pause_test.expect("Press 'C' to continue the play or 'A' to abort") @@ -128,7 +122,7 @@ pause_test = pexpect.spawn( env=os.environ ) -pause_test.logfile = log_buffer +pause_test.logfile = sys.stdout.buffer pause_test.expect(r'Custom prompt:') pause_test.send('\x03') pause_test.expect("Press 'C' to continue the play or 'A' to abort") @@ -149,7 +143,7 @@ pause_test = pexpect.spawn( env=os.environ ) -pause_test.logfile = log_buffer +pause_test.logfile = sys.stdout.buffer pause_test.expect(r'Pausing for \d+ seconds') pause_test.expect(r"\(ctrl\+C then 'C' = continue early, ctrl\+C then 'A' = abort\)") pause_test.expect('Task after pause') @@ -164,7 +158,7 @@ pause_test = pexpect.spawn( env=os.environ ) -pause_test.logfile = log_buffer +pause_test.logfile = sys.stdout.buffer pause_test.expect(r'Pausing for \d+ seconds') pause_test.expect(r"\(ctrl\+C then 'C' = continue early, ctrl\+C then 'A' = abort\)") pause_test.send('\n') # test newline does not stop the prompt - waiting for a timeout or ctrl+C @@ -184,7 +178,7 @@ pause_test = pexpect.spawn( env=os.environ ) -pause_test.logfile = log_buffer +pause_test.logfile = sys.stdout.buffer pause_test.expect(r'Pausing for \d+ seconds') pause_test.expect(r"\(ctrl\+C then 'C' = continue early, ctrl\+C then 'A' = abort\)") pause_test.send('\x03') @@ -206,7 +200,7 @@ pause_test = pexpect.spawn( env=os.environ ) -pause_test.logfile = log_buffer +pause_test.logfile = sys.stdout.buffer pause_test.expect(r'Pausing for \d+ seconds') pause_test.expect(r"\(ctrl\+C then 'C' = continue early, ctrl\+C then 'A' = abort\)") pause_test.expect(r"Waiting for two seconds:") @@ -222,7 +216,7 @@ pause_test = pexpect.spawn( env=os.environ ) -pause_test.logfile = log_buffer +pause_test.logfile = sys.stdout.buffer pause_test.expect(r'Pausing for \d+ seconds') pause_test.expect(r"\(ctrl\+C then 'C' = continue early, ctrl\+C then 'A' = abort\)") pause_test.expect(r"Waiting for two seconds:") @@ -242,7 +236,7 @@ pause_test = pexpect.spawn( env=os.environ ) -pause_test.logfile = log_buffer +pause_test.logfile = sys.stdout.buffer pause_test.expect(r'Pausing for \d+ seconds') pause_test.expect(r"\(ctrl\+C then 'C' = continue early, ctrl\+C then 'A' = abort\)") pause_test.expect(r"Waiting for two seconds:") @@ -264,7 +258,7 @@ pause_test = pexpect.spawn( env=os.environ ) -pause_test.logfile = log_buffer +pause_test.logfile = sys.stdout.buffer pause_test.expect(r'Enter some text:') pause_test.send('hello there') pause_test.send('\r') @@ -290,7 +284,7 @@ pause_test = pexpect.spawn( env=os.environ ) -pause_test.logfile = log_buffer +pause_test.logfile = sys.stdout.buffer pause_test.expect(r'Wait for three seconds:') pause_test.send('ignored user input') pause_test.expect('Task after pause') @@ -307,7 +301,7 @@ pause_test = pexpect.spawn( env=os.environ ) -pause_test.logfile = log_buffer +pause_test.logfile = sys.stdout.buffer pause_test.expect(r"\(ctrl\+C then 'C' = continue early, ctrl\+C then 'A' = abort\)") pause_test.send('\r') pause_test.expect(pexpect.EOF) diff --git a/test/integration/targets/rel_plugin_loading/subdir/inventory_plugins/notyaml.py b/test/integration/targets/rel_plugin_loading/subdir/inventory_plugins/notyaml.py index c068681292d..f5c0abbfe0c 100644 --- a/test/integration/targets/rel_plugin_loading/subdir/inventory_plugins/notyaml.py +++ b/test/integration/targets/rel_plugin_loading/subdir/inventory_plugins/notyaml.py @@ -62,7 +62,6 @@ import os from collections.abc import MutableMapping from ansible.errors import AnsibleError, AnsibleParserError -from ansible.module_utils.six import string_types from ansible.module_utils.common.text.converters import to_native, to_text from ansible.plugins.inventory import BaseFileInventoryPlugin @@ -126,7 +125,7 @@ class InventoryModule(BaseFileInventoryPlugin): for section in ['vars', 'children', 'hosts']: if section in group_data: # convert strings to dicts as these are allowed - if isinstance(group_data[section], string_types): + if isinstance(group_data[section], str): group_data[section] = {group_data[section]: None} if not isinstance(group_data[section], (MutableMapping, NoneType)): diff --git a/test/lib/ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py b/test/lib/ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py index 99c809918c3..90d99c06093 100644 --- a/test/lib/ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +++ b/test/lib/ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py @@ -17,14 +17,13 @@ from voluptuous import Required, Schema, Invalid from voluptuous.humanize import humanize_error from ansible.module_utils.compat.version import StrictVersion, LooseVersion -from ansible.module_utils.six import string_types from ansible.utils.collection_loader import AnsibleCollectionRef from ansible.utils.version import SemanticVersion def fqcr(value): """Validate a FQCR.""" - if not isinstance(value, string_types): + if not isinstance(value, str): raise Invalid('Must be a string that is a FQCR') if not AnsibleCollectionRef.is_valid_fqcr(value): raise Invalid('Must be a FQCR') @@ -33,7 +32,7 @@ def fqcr(value): def fqcr_or_shortname(value): """Validate a FQCR or a shortname.""" - if not isinstance(value, string_types): + if not isinstance(value, str): raise Invalid('Must be a string that is a FQCR or a short name') if '.' in value and not AnsibleCollectionRef.is_valid_fqcr(value): raise Invalid('Must be a FQCR or a short name') @@ -48,7 +47,7 @@ def isodate(value, check_deprecation_date=False, is_tombstone=False): else: # make sure we have a string msg = 'Expected ISO 8601 date string (YYYY-MM-DD), or YAML date' - if not isinstance(value, string_types): + if not isinstance(value, str): raise Invalid(msg) # From Python 3.7 in, there is datetime.date.fromisoformat(). For older versions, # we have to do things manually. @@ -80,7 +79,7 @@ def removal_version(value, is_ansible, current_version=None, is_tombstone=False) 'Removal version must be a string' if is_ansible else 'Removal version must be a semantic version (https://semver.org/)' ) - if not isinstance(value, string_types): + if not isinstance(value, str): raise Invalid(msg) try: if is_ansible: @@ -191,7 +190,7 @@ def validate_metadata_file(path, is_ansible, check_deprecation_dates=False): 'removal_version': partial(removal_version, is_ansible=is_ansible, current_version=current_version), 'removal_date': partial(isodate, check_deprecation_date=check_deprecation_dates), - 'warning_text': Any(*string_types), + 'warning_text': str, } ), avoid_additional_data @@ -204,7 +203,7 @@ def validate_metadata_file(path, is_ansible, check_deprecation_dates=False): 'removal_version': partial(removal_version, is_ansible=is_ansible, current_version=current_version, is_tombstone=True), 'removal_date': partial(isodate, is_tombstone=True), - 'warning_text': Any(*string_types), + 'warning_text': str, } ), avoid_additional_data @@ -228,18 +227,15 @@ def validate_metadata_file(path, is_ansible, check_deprecation_dates=False): # Adjusted schema for module_utils plugin_routing_schema_mu = Any( plugins_routing_common_schema.extend({ - ('redirect'): Any(*string_types)} + ('redirect'): str} ), ) - list_dict_plugin_routing_schema = [{str_type: plugin_routing_schema} - for str_type in string_types] + list_dict_plugin_routing_schema = [{str: plugin_routing_schema}] - list_dict_plugin_routing_schema_mu = [{str_type: plugin_routing_schema_mu} - for str_type in string_types] + list_dict_plugin_routing_schema_mu = [{str: plugin_routing_schema_mu}] - list_dict_plugin_routing_schema_modules = [{str_type: plugin_routing_schema_modules} - for str_type in string_types] + list_dict_plugin_routing_schema_modules = [{str: plugin_routing_schema_modules}] plugin_schema = Schema({ ('action'): Any(None, *list_dict_plugin_routing_schema), @@ -267,13 +263,12 @@ def validate_metadata_file(path, is_ansible, check_deprecation_dates=False): import_redirection_schema = Any( Schema({ - ('redirect'): Any(*string_types), + ('redirect'): str, # import_redirect doesn't currently support deprecation }, extra=PREVENT_EXTRA) ) - list_dict_import_redirection_schema = [{str_type: import_redirection_schema} - for str_type in string_types] + list_dict_import_redirection_schema = [{str: import_redirection_schema}] # action_groups schema @@ -289,7 +284,7 @@ def validate_metadata_file(path, is_ansible, check_deprecation_dates=False): }, extra=PREVENT_EXTRA) }, extra=PREVENT_EXTRA) action_group_schema = All([metadata_dict, fqcr_or_shortname], at_most_one_dict) - list_dict_action_groups_schema = [{str_type: action_group_schema} for str_type in string_types] + list_dict_action_groups_schema = [{str: action_group_schema}] # top level schema @@ -298,7 +293,7 @@ def validate_metadata_file(path, is_ansible, check_deprecation_dates=False): ('plugin_routing'): Any(plugin_schema), ('import_redirection'): Any(None, *list_dict_import_redirection_schema), # requires_ansible: In the future we should validate this with SpecifierSet - ('requires_ansible'): Any(*string_types), + ('requires_ansible'): str, ('action_groups'): Any(*list_dict_action_groups_schema), }, extra=PREVENT_EXTRA) diff --git a/test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py b/test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py index daeb57ac1f6..9c6b44f1d98 100644 --- a/test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +++ b/test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py @@ -28,7 +28,6 @@ from contextlib import contextmanager from ansible.executor.powershell.module_manifest import PSModuleDepFinder from ansible.module_utils.basic import FILE_COMMON_ARGUMENTS, AnsibleModule -from ansible.module_utils.six import reraise from ansible.module_utils.common.text.converters import to_bytes, to_text from .utils import CaptureStd, find_executable, get_module_name_from_filename @@ -153,7 +152,7 @@ def get_py_argument_spec(filename, collection): pass except BaseException as e: # we want to catch all exceptions here, including sys.exit - reraise(AnsibleModuleImportError, AnsibleModuleImportError('%s' % e), sys.exc_info()[2]) + raise AnsibleModuleImportError from e if not fake.called: raise AnsibleModuleNotInitialized() diff --git a/test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py b/test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py index abbbd66c25c..6c2b3415430 100644 --- a/test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +++ b/test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py @@ -13,7 +13,6 @@ from urllib.parse import urlparse from voluptuous import ALLOW_EXTRA, PREVENT_EXTRA, All, Any, Invalid, Length, MultipleInvalid, Required, Schema, Self, ValueInvalid, Exclusive from ansible.constants import DOCUMENTABLE_PLUGINS -from ansible.module_utils.six import string_types from ansible.module_utils.common.collections import is_iterable from ansible.module_utils.parsing.convert_bool import boolean from ansible.parsing.quoting import unquote @@ -25,9 +24,8 @@ from antsibull_docs_parser.parser import parse, Context from .utils import parse_isodate -list_string_types = list(string_types) -tuple_string_types = tuple(string_types) -any_string_types = Any(*string_types) +list_string_types = [str] +tuple_string_types = (str,) # Valid DOCUMENTATION.author lines # Based on Ansibulbot's extract_github_id() @@ -57,7 +55,7 @@ FULLY_QUALIFIED_COLLECTION_RESOURCE_RE = re.compile(r'^\w+(?:\.\w+){2,}$') def collection_name(v, error_code=None): - if not isinstance(v, string_types): + if not isinstance(v, str): raise _add_ansible_error_code( Invalid('Collection name must be a string'), error_code or 'collection-invalid-name') m = COLLECTION_NAME_RE.match(v) @@ -68,7 +66,7 @@ def collection_name(v, error_code=None): def fqcn(v, error_code=None): - if not isinstance(v, string_types): + if not isinstance(v, str): raise _add_ansible_error_code( Invalid('Module/plugin name must be a string'), error_code or 'invalid-documentation') m = FULLY_QUALIFIED_COLLECTION_RESOURCE_RE.match(v) @@ -87,8 +85,8 @@ def deprecation_versions(): def version(for_collection=False): if for_collection: # We do not accept floats for versions in collections - return Any(*string_types) - return Any(float, *string_types) + return str + return Any(float, str) def date(error_code=None): @@ -128,7 +126,7 @@ def _check_url(directive, content): def doc_string(v): """Match a documentation string.""" - if not isinstance(v, string_types): + if not isinstance(v, str): raise _add_ansible_error_code( Invalid('Must be a string'), 'invalid-documentation') errors = [] @@ -216,12 +214,12 @@ seealso_schema = Schema( 'description': doc_string, }, { - Required('ref'): Any(*string_types), + Required('ref'): str, Required('description'): doc_string, }, { - Required('name'): Any(*string_types), - Required('link'): Any(*string_types), + Required('name'): str, + Required('link'): str, Required('description'): doc_string, }, ), @@ -238,7 +236,7 @@ argument_spec_modifiers = { 'required_together': sequence_of_sequences(min=2), 'required_one_of': sequence_of_sequences(min=2), 'required_if': sequence_of_sequences(min=3, max=4), - 'required_by': Schema({str: Any(list_string_types, tuple_string_types, *string_types)}), + 'required_by': Schema({str: Any(list_string_types, tuple_string_types, str)}), } @@ -263,7 +261,7 @@ def options_with_apply_defaults(v): def check_removal_version(v, version_field, collection_name_field, error_code='invalid-removal-version'): version = v.get(version_field) collection_name = v.get(collection_name_field) - if not isinstance(version, string_types) or not isinstance(collection_name, string_types): + if not isinstance(version, str) or not isinstance(collection_name, str): # If they are not strings, schema validation will have already complained. return v if collection_name == 'ansible.builtin': @@ -313,9 +311,8 @@ def option_deprecation(v): def argument_spec_schema(for_collection): - any_string_types = Any(*string_types) schema = { - any_string_types: { + str: { 'type': Any(is_callable, *argument_spec_types), 'elements': Any(*argument_spec_types), 'default': object, @@ -336,12 +333,12 @@ def argument_spec_schema(for_collection): 'deprecated_aliases': Any([All( Any( { - Required('name'): Any(*string_types), + Required('name'): str, Required('date'): date(), Required('collection_name'): collection_name, }, { - Required('name'): Any(*string_types), + Required('name'): str, Required('version'): version(for_collection), Required('collection_name'): collection_name, }, @@ -353,13 +350,13 @@ def argument_spec_schema(for_collection): )]), } } - schema[any_string_types].update(argument_spec_modifiers) + schema[str].update(argument_spec_modifiers) schemas = All( schema, - Schema({any_string_types: no_required_with_default}), - Schema({any_string_types: elements_with_list}), - Schema({any_string_types: options_with_apply_defaults}), - Schema({any_string_types: option_deprecation}), + Schema({str: no_required_with_default}), + Schema({str: elements_with_list}), + Schema({str: options_with_apply_defaults}), + Schema({str: option_deprecation}), ) return Schema(schemas) @@ -385,14 +382,15 @@ json_value = Schema(Any( int, float, [Self], - *(list({str_type: Self} for str_type in string_types) + list(string_types)) + {str: Self}, + str, )) def version_added(v, error_code='version-added-invalid', accept_historical=False): if 'version_added' in v: version_added = v.get('version_added') - if isinstance(version_added, string_types): + if isinstance(version_added, str): # If it is not a string, schema validation will have already complained # - or we have a float and we are in ansible/ansible, in which case we're # also happy. @@ -451,7 +449,7 @@ def get_type_checker(v): elt_checker, elt_name = get_type_checker({'type': v.get('elements')}) def list_checker(value): - if isinstance(value, string_types): + if isinstance(value, str): value = [unquote(x.strip()) for x in value.split(',')] if not isinstance(value, list): raise ValueError('Value must be a list') @@ -482,14 +480,14 @@ def get_type_checker(v): if v_type in ('str', 'string', 'path', 'tmp', 'temppath', 'tmppath'): def str_checker(value): - if not isinstance(value, string_types): + if not isinstance(value, str): raise ValueError('Value must be string') return str_checker, v_type if v_type in ('pathspec', 'pathlist'): def path_list_checker(value): - if not isinstance(value, string_types) and not is_iterable(value): + if not isinstance(value, str) and not is_iterable(value): raise ValueError('Value must be string or list of strings') return path_list_checker, v_type @@ -588,7 +586,7 @@ def list_dict_option_schema(for_collection, plugin_type): 'elements': element_types, } if plugin_type != 'module': - basic_option_schema['name'] = Any(*string_types) + basic_option_schema['name'] = str deprecated_schema = All( Schema( All( @@ -605,10 +603,10 @@ def list_dict_option_schema(for_collection, plugin_type): }, { # This definition makes sure that everything we require is there - Required('why'): Any(*string_types), - Required(Any('alternatives', 'alternative')): Any(*string_types), - Required(Any('removed_at_date', 'version')): Any(*string_types), - Required('collection_name'): Any(*string_types), + Required('why'): str, + Required(Any('alternatives', 'alternative')): str, + Required(Any('removed_at_date', 'version')): str, + Required('collection_name'): str, }, ), extra=PREVENT_EXTRA @@ -620,7 +618,7 @@ def list_dict_option_schema(for_collection, plugin_type): ) env_schema = All( Schema({ - Required('name'): Any(*string_types), + Required('name'): str, 'deprecated': deprecated_schema, 'version_added': version(for_collection), 'version_added_collection': collection_name, @@ -629,8 +627,8 @@ def list_dict_option_schema(for_collection, plugin_type): ) ini_schema = All( Schema({ - Required('key'): Any(*string_types), - Required('section'): Any(*string_types), + Required('key'): str, + Required('section'): str, 'deprecated': deprecated_schema, 'version_added': version(for_collection), 'version_added_collection': collection_name, @@ -639,7 +637,7 @@ def list_dict_option_schema(for_collection, plugin_type): ) vars_schema = All( Schema({ - Required('name'): Any(*string_types), + Required('name'): str, 'deprecated': deprecated_schema, 'version_added': version(for_collection), 'version_added_collection': collection_name, @@ -648,8 +646,8 @@ def list_dict_option_schema(for_collection, plugin_type): ) cli_schema = All( Schema({ - Required('name'): Any(*string_types), - 'option': Any(*string_types), + Required('name'): str, + 'option': str, 'deprecated': deprecated_schema, 'version_added': version(for_collection), 'version_added_collection': collection_name, @@ -658,7 +656,7 @@ def list_dict_option_schema(for_collection, plugin_type): ) keyword_schema = All( Schema({ - Required('name'): Any(*string_types), + Required('name'): str, 'deprecated': deprecated_schema, 'version_added': version(for_collection), 'version_added_collection': collection_name, @@ -677,7 +675,7 @@ def list_dict_option_schema(for_collection, plugin_type): suboption_schema = dict(basic_option_schema) suboption_schema.update({ # Recursive suboptions - 'suboptions': Any(None, *list({str_type: Self} for str_type in string_types)), + 'suboptions': Any(None, {str: Self}), }) suboption_schema = Schema(All( suboption_schema, @@ -686,13 +684,9 @@ def list_dict_option_schema(for_collection, plugin_type): check_option_default, ), extra=PREVENT_EXTRA) - # This generates list of dicts with keys from string_types and suboption_schema value - # for example in Python 3: {str: suboption_schema} - list_dict_suboption_schema = [{str_type: suboption_schema} for str_type in string_types] - option_schema = dict(basic_option_schema) option_schema.update({ - 'suboptions': Any(None, *list_dict_suboption_schema), + 'suboptions': Any(None, {str: suboption_schema}), }) option_schema = Schema(All( option_schema, @@ -703,20 +697,18 @@ def list_dict_option_schema(for_collection, plugin_type): option_version_added = Schema( All({ - 'suboptions': Any(None, *[{str_type: Self} for str_type in string_types]), + 'suboptions': Any(None, {str: Self}), }, partial(version_added, error_code='option-invalid-version-added')), extra=ALLOW_EXTRA ) - # This generates list of dicts with keys from string_types and option_schema value - # for example in Python 3: {str: option_schema} - return [{str_type: All(option_schema, option_version_added)} for str_type in string_types] + return [{str: All(option_schema, option_version_added)}] def return_contains(v): schema = Schema( { - Required('contains'): Any(dict, list, *string_types) + Required('contains'): Any(dict, list, str) }, extra=ALLOW_EXTRA ) @@ -752,7 +744,7 @@ def return_schema(for_collection, plugin_type='module'): inner_return_option_schema = dict(basic_return_option_schema) inner_return_option_schema.update({ - 'contains': Any(None, *list({str_type: Self} for str_type in string_types)), + 'contains': Any(None, {str: Self}), }) return_contains_schema = Any( All( @@ -763,27 +755,23 @@ def return_schema(for_collection, plugin_type='module'): Schema(type(None)), ) - # This generates list of dicts with keys from string_types and return_contains_schema value - # for example in Python 3: {str: return_contains_schema} - list_dict_return_contains_schema = [{str_type: return_contains_schema} for str_type in string_types] - return_option_schema = dict(basic_return_option_schema) return_option_schema.update({ - 'contains': Any(None, *list_dict_return_contains_schema), + 'contains': Any(None, {str: return_contains_schema}), }) if plugin_type == 'module': # 'returned' is required on top-level del return_option_schema['returned'] - return_option_schema[Required('returned')] = Any(*string_types) + return_option_schema[Required('returned')] = str return Any( All( Schema( { - any_string_types: return_option_schema + str: return_option_schema } ), - Schema({any_string_types: return_contains}), - Schema({any_string_types: partial(version_added, error_code='option-invalid-version-added')}), + Schema({str: return_contains}), + Schema({str: partial(version_added, error_code='option-invalid-version-added')}), ), Schema(type(None)), ) @@ -840,7 +828,7 @@ def author(value): value = [value] for line in value: - if not isinstance(line, string_types): + if not isinstance(line, str): continue # let schema checks handle m = author_line.search(line) if not m: @@ -868,14 +856,14 @@ def doc_schema(module_name, for_collection=False, deprecated_module=False, plugi 'requirements': [doc_string], 'todo': Any(None, doc_string_or_strings), 'options': Any(None, *list_dict_option_schema(for_collection, plugin_type)), - 'extends_documentation_fragment': Any(list_string_types, *string_types), + 'extends_documentation_fragment': Any(list_string_types, str), 'version_added_collection': collection_name, } if plugin_type == 'module': - doc_schema_dict[Required('author')] = All(Any(None, list_string_types, *string_types), author) + doc_schema_dict[Required('author')] = All(Any(None, list_string_types, str), author) else: # author is optional for plugins (for now) - doc_schema_dict['author'] = All(Any(None, list_string_types, *string_types), author) + doc_schema_dict['author'] = All(Any(None, list_string_types, str), author) if plugin_type == 'callback': doc_schema_dict[Required('type')] = Any('aggregate', 'notification', 'stdout') @@ -896,9 +884,9 @@ def doc_schema(module_name, for_collection=False, deprecated_module=False, plugi schema = { 'description': doc_string_or_strings, 'details': doc_string_or_strings, - 'support': any_string_types, - 'version_added_collection': any_string_types, - 'version_added': any_string_types, + 'support': str, + 'version_added_collection': str, + 'version_added': str, } if more: schema.update(more) @@ -907,7 +895,7 @@ def doc_schema(module_name, for_collection=False, deprecated_module=False, plugi doc_schema_dict['attributes'] = Schema( All( Schema({ - any_string_types: { + str: { Required('description'): doc_string_or_strings, Required('support'): Any('full', 'partial', 'none', 'N/A'), 'details': doc_string_or_strings, @@ -917,12 +905,12 @@ def doc_schema(module_name, for_collection=False, deprecated_module=False, plugi }, extra=ALLOW_EXTRA), partial(version_added, error_code='attribute-invalid-version-added', accept_historical=False), Schema({ - any_string_types: add_default_attributes(), + str: add_default_attributes(), 'action_group': add_default_attributes({ Required('membership'): list_string_types, }), 'platform': add_default_attributes({ - Required('platforms'): Any(list_string_types, *string_types) + Required('platforms'): Any(list_string_types, str) }), }, extra=PREVENT_EXTRA), ) diff --git a/test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py b/test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py index 065c39cbc94..4481fa4285e 100644 --- a/test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +++ b/test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py @@ -31,7 +31,6 @@ import yaml.reader from ansible.module_utils.common.text.converters import to_text from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.common.yaml import SafeLoader -from ansible.module_utils.six import string_types from ansible.parsing.yaml.loader import AnsibleLoader @@ -211,7 +210,7 @@ def parse_isodate(v, allow_date): msg = 'Expected ISO 8601 date string (YYYY-MM-DD) or YAML date' else: msg = 'Expected ISO 8601 date string (YYYY-MM-DD)' - if not isinstance(v, string_types): + if not isinstance(v, str): raise ValueError(msg) # From Python 3.7 in, there is datetime.date.fromisoformat(). For older versions, # we have to do things manually. diff --git a/test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/plugin_utils/_quote.py b/test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/plugin_utils/_quote.py index d01386efc75..aa895f932b4 100644 --- a/test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/plugin_utils/_quote.py +++ b/test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/plugin_utils/_quote.py @@ -18,8 +18,6 @@ from __future__ import annotations import re -from ansible.module_utils.six import text_type - _UNSAFE_C = re.compile(u'[\\s\t"]') _UNSAFE_CMD = re.compile(u'[\\s\\(\\)\\^\\|%!"<>&]') @@ -30,7 +28,7 @@ _UNSAFE_CMD = re.compile(u'[\\s\\(\\)\\^\\|%!"<>&]') _UNSAFE_PWSH = re.compile(u"(['\u2018\u2019\u201a\u201b])") -def quote_c(s): # type: (text_type) -> text_type +def quote_c(s): # type: (str) -> str """Quotes a value for the raw Win32 process command line. Quotes a value to be safely used by anything that calls the Win32 @@ -40,7 +38,7 @@ def quote_c(s): # type: (text_type) -> text_type s: The string to quote. Returns: - (text_type): The quoted string value. + (str): The quoted string value. """ # https://docs.microsoft.com/en-us/archive/blogs/twistylittlepassagesallalike/everyone-quotes-command-line-arguments-the-wrong-way if not s: @@ -62,7 +60,7 @@ def quote_c(s): # type: (text_type) -> text_type return u'"{0}"'.format(s) -def quote_cmd(s): # type: (text_type) -> text_type +def quote_cmd(s): # type: (str) -> str """Quotes a value for cmd. Quotes a value to be safely used by a command prompt call. @@ -71,7 +69,7 @@ def quote_cmd(s): # type: (text_type) -> text_type s: The string to quote. Returns: - (text_type): The quoted string value. + (str): The quoted string value. """ # https://docs.microsoft.com/en-us/archive/blogs/twistylittlepassagesallalike/everyone-quotes-command-line-arguments-the-wrong-way#a-better-method-of-quoting if not s: @@ -92,7 +90,7 @@ def quote_cmd(s): # type: (text_type) -> text_type return u'^"{0}^"'.format(s) -def quote_pwsh(s): # type: (text_type) -> text_type +def quote_pwsh(s): # type: (str) -> str """Quotes a value for PowerShell. Quotes a value to be safely used by a PowerShell expression. The input @@ -102,7 +100,7 @@ def quote_pwsh(s): # type: (text_type) -> text_type s: The string to quote. Returns: - (text_type): The quoted string value. + (str): The quoted string value. """ # https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules?view=powershell-5.1 if not s: diff --git a/test/units/executor/module_common/test_recursive_finder.py b/test/units/executor/module_common/test_recursive_finder.py index 948e499bd82..799f5207b6c 100644 --- a/test/units/executor/module_common/test_recursive_finder.py +++ b/test/units/executor/module_common/test_recursive_finder.py @@ -26,7 +26,6 @@ from ansible.plugins.loader import init_plugin_loader MODULE_UTILS_BASIC_FILES = frozenset(('ansible/__init__.py', 'ansible/module_utils/__init__.py', 'ansible/module_utils/basic.py', - 'ansible/module_utils/six/__init__.py', 'ansible/module_utils/_internal/__init__.py', 'ansible/module_utils/_internal/_ansiballz/__init__.py', 'ansible/module_utils/_internal/_ansiballz/_loader.py', @@ -46,6 +45,7 @@ MODULE_UTILS_BASIC_FILES = frozenset(('ansible/__init__.py', 'ansible/module_utils/_internal/_traceback.py', 'ansible/module_utils/_internal/_validation.py', 'ansible/module_utils/_internal/_messages.py', + 'ansible/module_utils/_internal/_no_six.py', 'ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py', 'ansible/module_utils/_internal/_patches/_socket_patch.py', 'ansible/module_utils/_internal/_patches/_sys_intern_patch.py', @@ -78,7 +78,6 @@ MODULE_UTILS_BASIC_FILES = frozenset(('ansible/__init__.py', 'ansible/module_utils/errors.py', 'ansible/module_utils/parsing/__init__.py', 'ansible/module_utils/parsing/convert_bool.py', - 'ansible/module_utils/six/__init__.py', )) ONLY_BASIC_FILE = frozenset(('ansible/module_utils/basic.py',))