diff options
Diffstat (limited to 'lib/ansible/utils')
30 files changed, 148 insertions, 270 deletions
diff --git a/lib/ansible/utils/__init__.py b/lib/ansible/utils/__init__.py index ae8ccff..64fee52 100644 --- a/lib/ansible/utils/__init__.py +++ b/lib/ansible/utils/__init__.py @@ -15,6 +15,4 @@ # You should have received a copy of the GNU General Public License # along with Ansible. If not, see <http://www.gnu.org/licenses/>. -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations diff --git a/lib/ansible/utils/cmd_functions.py b/lib/ansible/utils/cmd_functions.py index 436d955..99de684 100644 --- a/lib/ansible/utils/cmd_functions.py +++ b/lib/ansible/utils/cmd_functions.py @@ -15,8 +15,7 @@ # You should have received a copy of the GNU General Public License # along with Ansible. If not, see <http://www.gnu.org/licenses/>. -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import os import select diff --git a/lib/ansible/utils/collection_loader/__init__.py b/lib/ansible/utils/collection_loader/__init__.py index 83cc246..2ae2fe5 100644 --- a/lib/ansible/utils/collection_loader/__init__.py +++ b/lib/ansible/utils/collection_loader/__init__.py @@ -4,8 +4,7 @@ # CAUTION: This implementation of the collection loader is used by ansible-test. # Because of this, it must be compatible with all Python versions supported on the controller or remote. -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations # FIXME: decide what of this we want to actually be public/toplevel, put other stuff on a utility class? from ._collection_config import AnsibleCollectionConfig diff --git a/lib/ansible/utils/collection_loader/_collection_config.py b/lib/ansible/utils/collection_loader/_collection_config.py index 4f73a1a..add20c6 100644 --- a/lib/ansible/utils/collection_loader/_collection_config.py +++ b/lib/ansible/utils/collection_loader/_collection_config.py @@ -4,8 +4,7 @@ # CAUTION: This implementation of the collection loader is used by ansible-test. # Because of this, it must be compatible with all Python versions supported on the controller or remote. -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations from ansible.module_utils.common.text.converters import to_text from ansible.module_utils.six import add_metaclass diff --git a/lib/ansible/utils/collection_loader/_collection_finder.py b/lib/ansible/utils/collection_loader/_collection_finder.py index 16d0bcc..85660b4 100644 --- a/lib/ansible/utils/collection_loader/_collection_finder.py +++ b/lib/ansible/utils/collection_loader/_collection_finder.py @@ -4,8 +4,7 @@ # CAUTION: This implementation of the collection loader is used by ansible-test. # Because of this, it must be compatible with all Python versions supported on the controller or remote. -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import itertools import os diff --git a/lib/ansible/utils/collection_loader/_collection_meta.py b/lib/ansible/utils/collection_loader/_collection_meta.py index deaac8e..3b0333f 100644 --- a/lib/ansible/utils/collection_loader/_collection_meta.py +++ b/lib/ansible/utils/collection_loader/_collection_meta.py @@ -4,8 +4,7 @@ # CAUTION: This implementation of the collection loader is used by ansible-test. # Because of this, it must be compatible with all Python versions supported on the controller or remote. -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations try: from collections.abc import Mapping diff --git a/lib/ansible/utils/color.py b/lib/ansible/utils/color.py index be8fb00..0e00635 100644 --- a/lib/ansible/utils/color.py +++ b/lib/ansible/utils/color.py @@ -14,8 +14,7 @@ # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see <http://www.gnu.org/licenses/>. -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import re import sys diff --git a/lib/ansible/utils/context_objects.py b/lib/ansible/utils/context_objects.py index efe15fe..02db666 100644 --- a/lib/ansible/utils/context_objects.py +++ b/lib/ansible/utils/context_objects.py @@ -1,13 +1,10 @@ # Copyright: (c) 2018, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - """ Hold command line arguments for use in other modules """ +from __future__ import annotations from abc import ABCMeta from collections.abc import Container, Mapping, Sequence, Set diff --git a/lib/ansible/utils/display.py b/lib/ansible/utils/display.py index 3f331ad..9616f18 100644 --- a/lib/ansible/utils/display.py +++ b/lib/ansible/utils/display.py @@ -59,6 +59,8 @@ if t.TYPE_CHECKING: # avoid circular import at runtime from ansible.executor.task_queue_manager import FinalQueue +P = t.ParamSpec('P') + _LIBC = ctypes.cdll.LoadLibrary(ctypes.util.find_library('c')) # Set argtypes, to avoid segfault if the wrong type is provided, # restype is assumed to be c_int @@ -122,20 +124,6 @@ def get_text_width(text: str) -> int: return width if width >= 0 else 0 -def proxy_display(method): - - def proxyit(self, *args, **kwargs): - if self._final_q: - # If _final_q is set, that means we are in a WorkerProcess - # and instead of displaying messages directly from the fork - # we will proxy them through the queue - return self._final_q.send_display(method.__name__, *args, **kwargs) - else: - return method(self, *args, **kwargs) - - return proxyit - - class FilterBlackList(logging.Filter): def __init__(self, blacklist): self.blacklist = [logging.Filter(name) for name in blacklist] @@ -283,6 +271,11 @@ class Display(metaclass=Singleton): self.columns = None self.verbosity = verbosity + if C.LOG_VERBOSITY is None: + self.log_verbosity = verbosity + else: + self.log_verbosity = max(verbosity, C.LOG_VERBOSITY) + # list of all deprecation messages to prevent duplicate display self._deprecations: dict[str, int] = {} self._warns: dict[str, int] = {} @@ -354,7 +347,49 @@ class Display(metaclass=Singleton): if os.path.exists(b_cow_path): self.b_cowsay = b_cow_path - @proxy_display + @staticmethod + def _proxy( + func: c.Callable[t.Concatenate[Display, P], None] + ) -> c.Callable[..., None]: + @wraps(func) + def wrapper(self, *args: P.args, **kwargs: P.kwargs) -> None: + if self._final_q: + # If _final_q is set, that means we are in a WorkerProcess + # and instead of displaying messages directly from the fork + # we will proxy them through the queue + return self._final_q.send_display(func.__name__, *args, **kwargs) + return func(self, *args, **kwargs) + return wrapper + + @staticmethod + def _meets_debug( + func: c.Callable[..., None] + ) -> c.Callable[..., None]: + """This method ensures that debug is enabled before delegating to the proxy + """ + @wraps(func) + def wrapper(self, msg: str, host: str | None = None) -> None: + if not C.DEFAULT_DEBUG: + return + return func(self, msg, host=host) + return wrapper + + @staticmethod + def _meets_verbosity( + func: c.Callable[..., None] + ) -> c.Callable[..., None]: + """This method ensures the verbosity has been met before delegating to the proxy + + Currently this method is unused, and the logic is handled directly in ``verbose`` + """ + @wraps(func) + def wrapper(self, msg: str, host: str | None = None, caplevel: int = None) -> None: + if self.verbosity > caplevel: + return func(self, msg, host=host, caplevel=caplevel) + return + return wrapper + + @_proxy def display( self, msg: str, @@ -412,7 +447,12 @@ class Display(metaclass=Singleton): # raise if logger and not screen_only: - msg2 = nocolor.lstrip('\n') + self._log(nocolor, color) + + def _log(self, msg: str, color: str | None = None, caplevel: int | None = None): + + if logger and (caplevel is None or self.log_verbosity > caplevel): + msg2 = msg.lstrip('\n') lvl = logging.INFO if color: @@ -422,6 +462,7 @@ class Display(metaclass=Singleton): except KeyError: # this should not happen, but JIC raise AnsibleAssertionError('Invalid color supplied to display: %s' % color) + # actually log logger.log(lvl, msg2) @@ -443,21 +484,35 @@ class Display(metaclass=Singleton): def vvvvvv(self, msg: str, host: str | None = None) -> None: return self.verbose(msg, host=host, caplevel=5) - def debug(self, msg: str, host: str | None = None) -> None: - if C.DEFAULT_DEBUG: - if host is None: - self.display("%6d %0.5f: %s" % (os.getpid(), time.time(), msg), color=C.COLOR_DEBUG) - else: - self.display("%6d %0.5f [%s]: %s" % (os.getpid(), time.time(), host, msg), color=C.COLOR_DEBUG) - def verbose(self, msg: str, host: str | None = None, caplevel: int = 2) -> None: + if self.verbosity > caplevel: + self._verbose_display(msg, host=host, caplevel=caplevel) + if self.log_verbosity > self.verbosity and self.log_verbosity > caplevel: + self._verbose_log(msg, host=host, caplevel=caplevel) + + @_proxy + def _verbose_display(self, msg: str, host: str | None = None, caplevel: int = 2) -> None: to_stderr = C.VERBOSE_TO_STDERR - if self.verbosity > caplevel: - if host is None: - self.display(msg, color=C.COLOR_VERBOSE, stderr=to_stderr) - else: - self.display("<%s> %s" % (host, msg), color=C.COLOR_VERBOSE, stderr=to_stderr) + if host is None: + self.display(msg, color=C.COLOR_VERBOSE, stderr=to_stderr) + else: + self.display("<%s> %s" % (host, msg), color=C.COLOR_VERBOSE, stderr=to_stderr) + + @_proxy + def _verbose_log(self, msg: str, host: str | None = None, caplevel: int = 2) -> None: + # we send to log if log was configured with higher verbosity + if host is not None: + msg = "<%s> %s" % (host, msg) + self._log(msg, C.COLOR_VERBOSE, caplevel) + + @_meets_debug + @_proxy + def debug(self, msg: str, host: str | None = None) -> None: + if host is None: + self.display("%6d %0.5f: %s" % (os.getpid(), time.time(), msg), color=C.COLOR_DEBUG) + else: + self.display("%6d %0.5f [%s]: %s" % (os.getpid(), time.time(), host, msg), color=C.COLOR_DEBUG) def get_deprecation_message( self, @@ -501,7 +556,7 @@ class Display(metaclass=Singleton): return message_text - @proxy_display + @_proxy def deprecated( self, msg: str, @@ -525,7 +580,7 @@ class Display(metaclass=Singleton): self.display(message_text.strip(), color=C.COLOR_DEPRECATE, stderr=True) self._deprecations[message_text] = 1 - @proxy_display + @_proxy def warning(self, msg: str, formatted: bool = False) -> None: if not formatted: @@ -539,10 +594,12 @@ class Display(metaclass=Singleton): self.display(new_msg, color=C.COLOR_WARN, stderr=True) self._warns[new_msg] = 1 + @_proxy def system_warning(self, msg: str) -> None: if C.SYSTEM_WARNINGS: self.warning(msg) + @_proxy def banner(self, msg: str, color: str | None = None, cows: bool = True) -> None: ''' Prints a header-looking line with cowsay or stars with length depending on terminal width (3 minimum) @@ -566,6 +623,7 @@ class Display(metaclass=Singleton): stars = u"*" * star_len self.display(u"\n%s %s" % (msg, stars), color=color) + @_proxy def banner_cowsay(self, msg: str, color: str | None = None) -> None: if u": [" in msg: msg = msg.replace(u"[", u"") @@ -583,6 +641,7 @@ class Display(metaclass=Singleton): (out, err) = cmd.communicate() self.display(u"%s\n" % to_text(out), color=color) + @_proxy def error(self, msg: str, wrap_text: bool = True) -> None: if wrap_text: new_msg = u"\n[ERROR]: %s" % msg diff --git a/lib/ansible/utils/encrypt.py b/lib/ansible/utils/encrypt.py index 541c5c8..3a279b7 100644 --- a/lib/ansible/utils/encrypt.py +++ b/lib/ansible/utils/encrypt.py @@ -1,13 +1,10 @@ # (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com> # (c) 2017 Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import random -import re import string -import sys from collections import namedtuple @@ -17,8 +14,8 @@ from ansible.module_utils.six import text_type from ansible.module_utils.common.text.converters import to_text, to_bytes from ansible.utils.display import Display -PASSLIB_E = CRYPT_E = None -HAS_CRYPT = PASSLIB_AVAILABLE = False +PASSLIB_E = None +PASSLIB_AVAILABLE = False try: import passlib import passlib.hash @@ -31,12 +28,6 @@ try: except Exception as e: PASSLIB_E = e -try: - import crypt - HAS_CRYPT = True -except Exception as e: - CRYPT_E = e - display = Display() @@ -84,96 +75,6 @@ class BaseHash(object): self.algorithm = algorithm -class CryptHash(BaseHash): - def __init__(self, algorithm): - super(CryptHash, self).__init__(algorithm) - - if not HAS_CRYPT: - raise AnsibleError("crypt.crypt cannot be used as the 'crypt' python library is not installed or is unusable.", orig_exc=CRYPT_E) - - if sys.platform.startswith('darwin'): - raise AnsibleError("crypt.crypt not supported on Mac OS X/Darwin, install passlib python module") - - if algorithm not in self.algorithms: - raise AnsibleError("crypt.crypt does not support '%s' algorithm" % self.algorithm) - - display.deprecated( - "Encryption using the Python crypt module is deprecated. The " - "Python crypt module is deprecated and will be removed from " - "Python 3.13. Install the passlib library for continued " - "encryption functionality.", - version="2.17", - ) - - self.algo_data = self.algorithms[algorithm] - - def hash(self, secret, salt=None, salt_size=None, rounds=None, ident=None): - salt = self._salt(salt, salt_size) - rounds = self._rounds(rounds) - ident = self._ident(ident) - return self._hash(secret, salt, rounds, ident) - - def _salt(self, salt, salt_size): - salt_size = salt_size or self.algo_data.salt_size - ret = salt or random_salt(salt_size) - if re.search(r'[^./0-9A-Za-z]', ret): - raise AnsibleError("invalid characters in salt") - if self.algo_data.salt_exact and len(ret) != self.algo_data.salt_size: - raise AnsibleError("invalid salt size") - elif not self.algo_data.salt_exact and len(ret) > self.algo_data.salt_size: - raise AnsibleError("invalid salt size") - return ret - - def _rounds(self, rounds): - if self.algorithm == 'bcrypt': - # crypt requires 2 digits for rounds - return rounds or self.algo_data.implicit_rounds - elif rounds == self.algo_data.implicit_rounds: - # Passlib does not include the rounds if it is the same as implicit_rounds. - # Make crypt lib behave the same, by not explicitly specifying the rounds in that case. - return None - else: - return rounds - - def _ident(self, ident): - if not ident: - return self.algo_data.crypt_id - if self.algorithm == 'bcrypt': - return ident - return None - - def _hash(self, secret, salt, rounds, ident): - saltstring = "" - if ident: - saltstring = "$%s" % ident - - if rounds: - if self.algorithm == 'bcrypt': - saltstring += "$%d" % rounds - else: - saltstring += "$rounds=%d" % rounds - - saltstring += "$%s" % salt - - # crypt.crypt throws OSError on Python >= 3.9 if it cannot parse saltstring. - try: - result = crypt.crypt(secret, saltstring) - orig_exc = None - except OSError as e: - result = None - orig_exc = e - - # None as result would be interpreted by some modules (user module) - # as no password at all. - if not result: - raise AnsibleError( - "crypt.crypt does not support '%s' algorithm" % self.algorithm, - orig_exc=orig_exc, - ) - - return result - - class PasslibHash(BaseHash): def __init__(self, algorithm): super(PasslibHash, self).__init__(algorithm) @@ -274,6 +175,4 @@ def passlib_or_crypt(secret, algorithm, salt=None, salt_size=None, rounds=None, def do_encrypt(result, encrypt, salt_size=None, salt=None, ident=None, rounds=None): if PASSLIB_AVAILABLE: return PasslibHash(encrypt).hash(result, salt=salt, salt_size=salt_size, rounds=rounds, ident=ident) - if HAS_CRYPT: - return CryptHash(encrypt).hash(result, salt=salt, salt_size=salt_size, rounds=rounds, ident=ident) - raise AnsibleError("Unable to encrypt nor hash, either crypt or passlib must be installed.", orig_exc=CRYPT_E) + raise AnsibleError("Unable to encrypt nor hash, passlib must be installed", orig_exc=PASSLIB_E) diff --git a/lib/ansible/utils/fqcn.py b/lib/ansible/utils/fqcn.py index a492be1..043d8a0 100644 --- a/lib/ansible/utils/fqcn.py +++ b/lib/ansible/utils/fqcn.py @@ -14,8 +14,7 @@ # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see <http://www.gnu.org/licenses/>. -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations def add_internal_fqcns(names): diff --git a/lib/ansible/utils/galaxy.py b/lib/ansible/utils/galaxy.py index bbb26fb..977ae2c 100644 --- a/lib/ansible/utils/galaxy.py +++ b/lib/ansible/utils/galaxy.py @@ -15,9 +15,7 @@ # You should have received a copy of the GNU General Public License # along with Ansible. If not, see <http://www.gnu.org/licenses/>. -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import os import tempfile diff --git a/lib/ansible/utils/hashing.py b/lib/ansible/utils/hashing.py index 97ea1dc..e8faf25 100644 --- a/lib/ansible/utils/hashing.py +++ b/lib/ansible/utils/hashing.py @@ -15,9 +15,7 @@ # You should have received a copy of the GNU General Public License # along with Ansible. If not, see <http://www.gnu.org/licenses/>. -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import os diff --git a/lib/ansible/utils/helpers.py b/lib/ansible/utils/helpers.py index 658ad99..c9b5f16 100644 --- a/lib/ansible/utils/helpers.py +++ b/lib/ansible/utils/helpers.py @@ -15,9 +15,7 @@ # You should have received a copy of the GNU General Public License # along with Ansible. If not, see <http://www.gnu.org/licenses/>. -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations from ansible.module_utils.six import string_types diff --git a/lib/ansible/utils/jsonrpc.py b/lib/ansible/utils/jsonrpc.py index 2af8bd3..37b286a 100644 --- a/lib/ansible/utils/jsonrpc.py +++ b/lib/ansible/utils/jsonrpc.py @@ -1,8 +1,7 @@ # (c) 2017, Peter Sprygada <psprygad@redhat.com> # (c) 2017 Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import json import pickle diff --git a/lib/ansible/utils/listify.py b/lib/ansible/utils/listify.py index 0e6a872..362a50b 100644 --- a/lib/ansible/utils/listify.py +++ b/lib/ansible/utils/listify.py @@ -15,9 +15,7 @@ # You should have received a copy of the GNU General Public License # along with Ansible. If not, see <http://www.gnu.org/licenses/>. -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations from collections.abc import Iterable diff --git a/lib/ansible/utils/lock.py b/lib/ansible/utils/lock.py index 34387dc..9f834da 100644 --- a/lib/ansible/utils/lock.py +++ b/lib/ansible/utils/lock.py @@ -1,9 +1,7 @@ # Copyright (c) 2020 Matt Martz <matt@sivel.net> # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations from functools import wraps diff --git a/lib/ansible/utils/multiprocessing.py b/lib/ansible/utils/multiprocessing.py index 2912f71..c573c72 100644 --- a/lib/ansible/utils/multiprocessing.py +++ b/lib/ansible/utils/multiprocessing.py @@ -1,9 +1,7 @@ # Copyright (c) 2019 Matt Martz <matt@sivel.net> # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import multiprocessing diff --git a/lib/ansible/utils/native_jinja.py b/lib/ansible/utils/native_jinja.py index 53ef140..15d1624 100644 --- a/lib/ansible/utils/native_jinja.py +++ b/lib/ansible/utils/native_jinja.py @@ -1,9 +1,7 @@ # Copyright: (c) 2020, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations from ansible.module_utils.six import text_type diff --git a/lib/ansible/utils/path.py b/lib/ansible/utils/path.py index e4e00ce..ac0b450 100644 --- a/lib/ansible/utils/path.py +++ b/lib/ansible/utils/path.py @@ -14,8 +14,7 @@ # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see <http://www.gnu.org/licenses/>. -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import os import shutil diff --git a/lib/ansible/utils/plugin_docs.py b/lib/ansible/utils/plugin_docs.py index 91b3722..c5089aa 100644 --- a/lib/ansible/utils/plugin_docs.py +++ b/lib/ansible/utils/plugin_docs.py @@ -1,8 +1,7 @@ # Copyright: (c) 2012, Jan-Piet Mens <jpmens () gmail.com> # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations from collections.abc import MutableMapping, MutableSet, MutableSequence from pathlib import Path @@ -128,7 +127,7 @@ def add_fragments(doc, filename, fragment_loader, is_module=False): fragments = doc.pop('extends_documentation_fragment', []) if isinstance(fragments, string_types): - fragments = [fragments] + fragments = fragments.split(',') unknown_fragments = [] @@ -138,7 +137,7 @@ def add_fragments(doc, filename, fragment_loader, is_module=False): # as-specified. If failure, assume the right-most component is a var, split it off, # and retry the load. for fragment_slug in fragments: - fragment_name = fragment_slug + fragment_name = fragment_slug.strip() fragment_var = 'DOCUMENTATION' fragment_class = fragment_loader.get(fragment_name) @@ -314,7 +313,7 @@ def find_plugin_docfile(plugin, plugin_type, loader): if filename is None: raise AnsibleError('%s cannot contain DOCUMENTATION nor does it have a companion documentation file' % (plugin)) - return filename, context.plugin_resolved_collection + return filename, context def get_plugin_docs(plugin, plugin_type, loader, fragment_loader, verbose): @@ -323,7 +322,8 @@ def get_plugin_docs(plugin, plugin_type, loader, fragment_loader, verbose): # find plugin doc file, if it doesn't exist this will throw error, we let it through # can raise exception and short circuit when 'not found' - filename, collection_name = find_plugin_docfile(plugin, plugin_type, loader) + filename, context = find_plugin_docfile(plugin, plugin_type, loader) + collection_name = context.plugin_resolved_collection try: docs = get_docstring(filename, fragment_loader, verbose=verbose, collection_name=collection_name, plugin_type=plugin_type) @@ -347,5 +347,6 @@ def get_plugin_docs(plugin, plugin_type, loader, fragment_loader, verbose): else: docs[0]['filename'] = filename docs[0]['collection'] = collection_name + docs[0]['plugin_name'] = context.resolved_fqcn return docs diff --git a/lib/ansible/utils/py3compat.py b/lib/ansible/utils/py3compat.py index 5201132..53f06ff 100644 --- a/lib/ansible/utils/py3compat.py +++ b/lib/ansible/utils/py3compat.py @@ -1,70 +1,32 @@ # -*- coding: utf-8 -*- # # (c) 2018, Toshio Kuratomi <a.badger@gmail.com> +# Copyright: Contributors to the Ansible project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -# -# Note that the original author of this, Toshio Kuratomi, is trying to submit this to six. If -# successful, the code in six will be available under six's more liberal license: -# https://mail.python.org/pipermail/python-porting/2018-July/000539.html -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations +import inspect import os -import sys - -from collections.abc import MutableMapping - -from ansible.module_utils.six import PY3 -from ansible.module_utils.common.text.converters import to_bytes, to_text - -__all__ = ('environ',) - - -class _TextEnviron(MutableMapping): - """ - Utility class to return text strings from the environment instead of byte strings - Mimics the behaviour of os.environ on Python3 - """ - def __init__(self, env=None, encoding=None): - if env is None: - env = os.environ - self._raw_environ = env - self._value_cache = {} - # Since we're trying to mimic Python3's os.environ, use sys.getfilesystemencoding() - # instead of utf-8 - if encoding is None: - # Since we're trying to mimic Python3's os.environ, use sys.getfilesystemencoding() - # instead of utf-8 - self.encoding = sys.getfilesystemencoding() - else: - self.encoding = encoding +from ansible.utils.display import Display - def __delitem__(self, key): - del self._raw_environ[key] - def __getitem__(self, key): - value = self._raw_environ[key] - if PY3: - return value - # Cache keys off of the undecoded values to handle any environment variables which change - # during a run - if value not in self._value_cache: - self._value_cache[value] = to_text(value, encoding=self.encoding, - nonstring='passthru', errors='surrogate_or_strict') - return self._value_cache[value] +display = Display() - def __setitem__(self, key, value): - self._raw_environ[key] = to_bytes(value, encoding=self.encoding, nonstring='strict', - errors='surrogate_or_strict') - def __iter__(self): - return self._raw_environ.__iter__() +def __getattr__(name): + if name != 'environ': + raise AttributeError(name) - def __len__(self): - return len(self._raw_environ) + caller = inspect.stack()[1] + display.deprecated( + ( + 'ansible.utils.py3compat.environ is deprecated in favor of os.environ. ' + f'Accessed by {caller.filename} line number {caller.lineno}' + ), + version='2.20', + ) -environ = _TextEnviron(encoding='utf-8') + return os.environ diff --git a/lib/ansible/utils/sentinel.py b/lib/ansible/utils/sentinel.py index ca4f827..0fdbf4c 100644 --- a/lib/ansible/utils/sentinel.py +++ b/lib/ansible/utils/sentinel.py @@ -1,9 +1,7 @@ # Copyright (c) 2019 Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations class Sentinel: diff --git a/lib/ansible/utils/shlex.py b/lib/ansible/utils/shlex.py index 8f50ffd..470270d 100644 --- a/lib/ansible/utils/shlex.py +++ b/lib/ansible/utils/shlex.py @@ -15,9 +15,7 @@ # You should have received a copy of the GNU General Public License # alongwith Ansible. If not, see <http://www.gnu.org/licenses/>. -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import shlex diff --git a/lib/ansible/utils/singleton.py b/lib/ansible/utils/singleton.py index 4299403..0b68423 100644 --- a/lib/ansible/utils/singleton.py +++ b/lib/ansible/utils/singleton.py @@ -1,9 +1,7 @@ # Copyright (c) 2017 Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations from threading import RLock diff --git a/lib/ansible/utils/ssh_functions.py b/lib/ansible/utils/ssh_functions.py index 594dbc0..a96249e 100644 --- a/lib/ansible/utils/ssh_functions.py +++ b/lib/ansible/utils/ssh_functions.py @@ -16,9 +16,7 @@ # You should have received a copy of the GNU General Public License # along with Ansible. If not, see <http://www.gnu.org/licenses/>. -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import subprocess diff --git a/lib/ansible/utils/unicode.py b/lib/ansible/utils/unicode.py index b5304ba..2ea456c 100644 --- a/lib/ansible/utils/unicode.py +++ b/lib/ansible/utils/unicode.py @@ -15,9 +15,7 @@ # You should have received a copy of the GNU General Public License # along with Ansible. If not, see <http://www.gnu.org/licenses/>. -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations from ansible.module_utils.common.text.converters import to_text diff --git a/lib/ansible/utils/unsafe_proxy.py b/lib/ansible/utils/unsafe_proxy.py index b3e7383..378725c 100644 --- a/lib/ansible/utils/unsafe_proxy.py +++ b/lib/ansible/utils/unsafe_proxy.py @@ -50,8 +50,7 @@ # http://code.activestate.com/recipes/496741-object-proxying/ # Author: Tomer Filiba -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import sys import types diff --git a/lib/ansible/utils/vars.py b/lib/ansible/utils/vars.py index 5e21cb3..373fc70 100644 --- a/lib/ansible/utils/vars.py +++ b/lib/ansible/utils/vars.py @@ -15,9 +15,7 @@ # You should have received a copy of the GNU General Public License # along with Ansible. If not, see <http://www.gnu.org/licenses/>. -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import keyword import random @@ -85,11 +83,11 @@ def combine_vars(a, b, merge=None): if merge or merge is None and C.DEFAULT_HASH_BEHAVIOUR == "merge": return merge_hash(a, b) - else: - # HASH_BEHAVIOUR == 'replace' - _validate_mutable_mappings(a, b) - result = a | b - return result + + # HASH_BEHAVIOUR == 'replace' + _validate_mutable_mappings(a, b) + result = a | b + return result def merge_hash(x, y, recursive=True, list_merge='replace'): diff --git a/lib/ansible/utils/version.py b/lib/ansible/utils/version.py index e7da9fd..77c8228 100644 --- a/lib/ansible/utils/version.py +++ b/lib/ansible/utils/version.py @@ -1,9 +1,7 @@ # Copyright (c) 2020 Matt Martz <matt@sivel.net> # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type +from __future__ import annotations import re |