ansible-core 2.19.2__py3-none-any.whl → 2.20.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ansible-core might be problematic. Click here for more details.
- ansible/_internal/__init__.py +1 -4
- ansible/_internal/_ansiballz/_builder.py +1 -3
- ansible/_internal/_collection_proxy.py +7 -9
- ansible/_internal/_display_utils.py +145 -0
- ansible/_internal/_json/__init__.py +3 -4
- ansible/_internal/_templating/_engine.py +1 -1
- ansible/_internal/_templating/_jinja_plugins.py +1 -2
- ansible/_internal/_wrapt.py +105 -301
- ansible/cli/__init__.py +11 -10
- ansible/cli/adhoc.py +1 -2
- ansible/cli/arguments/option_helpers.py +1 -1
- ansible/cli/config.py +5 -6
- ansible/cli/doc.py +67 -67
- ansible/cli/galaxy.py +15 -24
- ansible/cli/inventory.py +0 -1
- ansible/cli/playbook.py +0 -1
- ansible/cli/pull.py +0 -1
- ansible/cli/scripts/ansible_connection_cli_stub.py +1 -1
- ansible/config/base.yml +1 -25
- ansible/config/manager.py +0 -2
- ansible/executor/play_iterator.py +42 -20
- ansible/executor/playbook_executor.py +0 -9
- ansible/executor/powershell/async_watchdog.ps1 +24 -4
- ansible/executor/task_executor.py +32 -22
- ansible/executor/task_queue_manager.py +1 -3
- ansible/galaxy/api.py +33 -80
- ansible/galaxy/collection/__init__.py +4 -17
- ansible/galaxy/dependency_resolution/dataclasses.py +0 -10
- ansible/galaxy/dependency_resolution/providers.py +1 -2
- ansible/galaxy/role.py +1 -33
- ansible/inventory/manager.py +2 -3
- ansible/keyword_desc.yml +0 -3
- ansible/module_utils/_internal/_datatag/__init__.py +2 -10
- ansible/module_utils/_internal/_no_six.py +86 -0
- ansible/module_utils/_text.py +28 -8
- ansible/module_utils/ansible_release.py +2 -2
- ansible/module_utils/basic.py +27 -24
- ansible/module_utils/common/_collections_compat.py +11 -2
- ansible/module_utils/common/collections.py +8 -3
- ansible/module_utils/common/dict_transformations.py +1 -2
- ansible/module_utils/common/network.py +4 -2
- ansible/module_utils/common/parameters.py +32 -41
- ansible/module_utils/common/text/converters.py +109 -23
- ansible/module_utils/common/text/formatters.py +6 -2
- ansible/module_utils/common/validation.py +11 -9
- ansible/module_utils/connection.py +8 -3
- ansible/module_utils/facts/hardware/linux.py +23 -7
- ansible/module_utils/facts/hardware/netbsd.py +1 -1
- ansible/module_utils/facts/hardware/sunos.py +2 -1
- ansible/module_utils/facts/packages.py +6 -2
- ansible/module_utils/facts/system/distribution.py +2 -1
- ansible/module_utils/facts/system/env.py +6 -3
- ansible/module_utils/facts/system/local.py +3 -1
- ansible/module_utils/parsing/convert_bool.py +6 -2
- ansible/module_utils/service.py +2 -3
- ansible/module_utils/six/__init__.py +11 -6
- ansible/module_utils/urls.py +6 -2
- ansible/module_utils/yumdnf.py +0 -5
- ansible/modules/apt.py +18 -13
- ansible/modules/apt_repository.py +1 -1
- ansible/modules/assemble.py +5 -9
- ansible/modules/blockinfile.py +39 -23
- ansible/modules/cron.py +26 -35
- ansible/modules/deb822_repository.py +83 -12
- ansible/modules/dnf.py +3 -7
- ansible/modules/dnf5.py +4 -6
- ansible/modules/expect.py +0 -3
- ansible/modules/find.py +1 -2
- ansible/modules/get_url.py +1 -1
- ansible/modules/git.py +4 -5
- ansible/modules/include_vars.py +1 -1
- ansible/modules/lineinfile.py +71 -63
- ansible/modules/package_facts.py +1 -1
- ansible/modules/pip.py +8 -2
- ansible/modules/replace.py +6 -6
- ansible/modules/service.py +3 -4
- ansible/modules/stat.py +20 -0
- ansible/modules/uri.py +9 -10
- ansible/modules/user.py +1 -2
- ansible/modules/wait_for.py +2 -2
- ansible/modules/wait_for_connection.py +2 -1
- ansible/modules/yum_repository.py +1 -16
- ansible/parsing/dataloader.py +24 -31
- ansible/parsing/mod_args.py +3 -0
- ansible/parsing/vault/__init__.py +1 -2
- ansible/playbook/base.py +8 -56
- ansible/playbook/block.py +0 -60
- ansible/playbook/collectionsearch.py +1 -2
- ansible/playbook/handler.py +1 -7
- ansible/playbook/helpers.py +0 -7
- ansible/playbook/included_file.py +1 -1
- ansible/playbook/play.py +103 -37
- ansible/playbook/play_context.py +4 -0
- ansible/playbook/role/__init__.py +10 -65
- ansible/playbook/role/definition.py +3 -4
- ansible/playbook/role/include.py +2 -3
- ansible/playbook/role/metadata.py +1 -12
- ansible/playbook/role/requirement.py +1 -2
- ansible/playbook/role_include.py +1 -2
- ansible/playbook/taggable.py +16 -5
- ansible/playbook/task.py +51 -55
- ansible/plugins/action/__init__.py +20 -19
- ansible/plugins/action/add_host.py +1 -2
- ansible/plugins/action/fetch.py +2 -4
- ansible/plugins/action/group_by.py +1 -2
- ansible/plugins/action/include_vars.py +20 -22
- ansible/plugins/action/script.py +1 -3
- ansible/plugins/action/template.py +1 -2
- ansible/plugins/action/uri.py +4 -2
- ansible/plugins/cache/__init__.py +1 -0
- ansible/plugins/callback/__init__.py +13 -6
- ansible/plugins/connection/__init__.py +3 -7
- ansible/plugins/connection/local.py +2 -3
- ansible/plugins/connection/psrp.py +0 -2
- ansible/plugins/connection/ssh.py +2 -7
- ansible/plugins/connection/winrm.py +0 -2
- ansible/plugins/doc_fragments/result_format_callback.py +15 -0
- ansible/plugins/filter/core.py +4 -5
- ansible/plugins/filter/encryption.py +3 -27
- ansible/plugins/filter/mathstuff.py +1 -2
- ansible/plugins/filter/to_nice_yaml.yml +31 -3
- ansible/plugins/filter/to_yaml.yml +29 -12
- ansible/plugins/inventory/__init__.py +1 -2
- ansible/plugins/inventory/script.py +2 -1
- ansible/plugins/inventory/toml.py +3 -6
- ansible/plugins/inventory/yaml.py +1 -2
- ansible/plugins/list.py +10 -3
- ansible/plugins/loader.py +6 -6
- ansible/plugins/lookup/password.py +1 -2
- ansible/plugins/lookup/subelements.py +2 -3
- ansible/plugins/lookup/url.py +1 -1
- ansible/plugins/lookup/varnames.py +1 -2
- ansible/plugins/shell/__init__.py +9 -4
- ansible/plugins/shell/powershell.py +8 -24
- ansible/plugins/strategy/__init__.py +6 -3
- ansible/plugins/test/core.py +4 -1
- ansible/plugins/test/regex.yml +18 -6
- ansible/release.py +2 -2
- ansible/template/__init__.py +3 -7
- ansible/utils/collection_loader/_collection_config.py +5 -0
- ansible/utils/collection_loader/_collection_finder.py +11 -14
- ansible/utils/context_objects.py +7 -4
- ansible/utils/display.py +28 -167
- ansible/utils/encrypt.py +0 -5
- ansible/utils/helpers.py +6 -2
- ansible/utils/jsonrpc.py +7 -3
- ansible/utils/plugin_docs.py +49 -38
- ansible/utils/ssh_functions.py +0 -19
- ansible/utils/unsafe_proxy.py +7 -7
- ansible/vars/clean.py +2 -3
- ansible/vars/manager.py +27 -20
- ansible/vars/plugins.py +1 -31
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/METADATA +3 -3
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/RECORD +200 -200
- ansible_test/_data/completion/docker.txt +7 -7
- ansible_test/_data/completion/network.txt +0 -1
- ansible_test/_data/completion/remote.txt +4 -4
- ansible_test/_data/requirements/ansible-test.txt +1 -1
- ansible_test/_data/requirements/sanity.changelog.txt +1 -1
- ansible_test/_data/requirements/sanity.pep8.txt +1 -1
- ansible_test/_data/requirements/sanity.pylint.txt +4 -4
- ansible_test/_internal/cache.py +2 -5
- ansible_test/_internal/cli/compat.py +1 -1
- ansible_test/_internal/commands/coverage/combine.py +1 -3
- ansible_test/_internal/commands/integration/__init__.py +3 -7
- ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
- ansible_test/_internal/commands/integration/coverage.py +1 -3
- ansible_test/_internal/commands/integration/filters.py +5 -10
- ansible_test/_internal/commands/sanity/validate_modules.py +1 -5
- ansible_test/_internal/commands/units/__init__.py +1 -13
- ansible_test/_internal/completion.py +2 -5
- ansible_test/_internal/config.py +2 -7
- ansible_test/_internal/coverage_util.py +1 -1
- ansible_test/_internal/delegation.py +2 -0
- ansible_test/_internal/docker_util.py +1 -1
- ansible_test/_internal/host_profiles.py +6 -11
- ansible_test/_internal/provider/__init__.py +2 -5
- ansible_test/_internal/provisioning.py +2 -5
- ansible_test/_internal/pypi_proxy.py +1 -1
- ansible_test/_internal/target.py +2 -6
- ansible_test/_internal/thread.py +1 -4
- ansible_test/_internal/util.py +9 -14
- ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +14 -19
- ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +30 -27
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +31 -18
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +1 -2
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +59 -71
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -2
- ansible_test/_util/target/cli/ansible_test_cli_stub.py +4 -2
- ansible_test/_util/target/common/constants.py +2 -2
- ansible_test/_util/target/setup/bootstrap.sh +0 -6
- ansible/utils/py3compat.py +0 -27
- ansible_test/_data/pytest/config/legacy.ini +0 -4
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/WHEEL +0 -0
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/top_level.txt +0 -0
ansible/_internal/_wrapt.py
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
24
24
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
25
25
|
|
|
26
|
-
# copied from https://github.com/GrahamDumpleton/wrapt/blob/1.
|
|
26
|
+
# copied from https://github.com/GrahamDumpleton/wrapt/blob/1.17.2/src/wrapt/wrappers.py
|
|
27
27
|
|
|
28
28
|
# LOCAL PATCHES:
|
|
29
29
|
# - disabled optional relative import of the _wrappers C extension; we shouldn't need it
|
|
@@ -31,13 +31,10 @@
|
|
|
31
31
|
from __future__ import annotations
|
|
32
32
|
|
|
33
33
|
# The following makes it easier for us to script updates of the bundled code
|
|
34
|
-
_BUNDLED_METADATA = {"pypi_name": "wrapt", "version": "1.
|
|
34
|
+
_BUNDLED_METADATA = {"pypi_name": "wrapt", "version": "1.17.2"}
|
|
35
35
|
|
|
36
|
-
import os
|
|
37
36
|
import sys
|
|
38
|
-
import functools
|
|
39
37
|
import operator
|
|
40
|
-
import weakref
|
|
41
38
|
import inspect
|
|
42
39
|
|
|
43
40
|
PY2 = sys.version_info[0] == 2
|
|
@@ -129,6 +126,9 @@ class ObjectProxy(with_metaclass(_ObjectProxyMetaType)):
|
|
|
129
126
|
except AttributeError:
|
|
130
127
|
pass
|
|
131
128
|
|
|
129
|
+
def __self_setattr__(self, name, value):
|
|
130
|
+
object.__setattr__(self, name, value)
|
|
131
|
+
|
|
132
132
|
@property
|
|
133
133
|
def __name__(self):
|
|
134
134
|
return self.__wrapped__.__name__
|
|
@@ -161,12 +161,15 @@ class ObjectProxy(with_metaclass(_ObjectProxyMetaType)):
|
|
|
161
161
|
type(self.__wrapped__).__name__,
|
|
162
162
|
id(self.__wrapped__))
|
|
163
163
|
|
|
164
|
+
def __format__(self, format_spec):
|
|
165
|
+
return format(self.__wrapped__, format_spec)
|
|
166
|
+
|
|
164
167
|
def __reversed__(self):
|
|
165
168
|
return reversed(self.__wrapped__)
|
|
166
169
|
|
|
167
170
|
if not PY2:
|
|
168
|
-
def __round__(self):
|
|
169
|
-
return round(self.__wrapped__)
|
|
171
|
+
def __round__(self, ndigits=None):
|
|
172
|
+
return round(self.__wrapped__, ndigits)
|
|
170
173
|
|
|
171
174
|
if sys.hexversion >= 0x03070000:
|
|
172
175
|
def __mro_entries__(self, bases):
|
|
@@ -472,7 +475,7 @@ class ObjectProxy(with_metaclass(_ObjectProxyMetaType)):
|
|
|
472
475
|
|
|
473
476
|
def __reduce__(self):
|
|
474
477
|
raise NotImplementedError(
|
|
475
|
-
'object proxy must define
|
|
478
|
+
'object proxy must define __reduce__()')
|
|
476
479
|
|
|
477
480
|
def __reduce_ex__(self, protocol):
|
|
478
481
|
raise NotImplementedError(
|
|
@@ -525,10 +528,10 @@ class PartialCallableObjectProxy(ObjectProxy):
|
|
|
525
528
|
class _FunctionWrapperBase(ObjectProxy):
|
|
526
529
|
|
|
527
530
|
__slots__ = ('_self_instance', '_self_wrapper', '_self_enabled',
|
|
528
|
-
'_self_binding', '_self_parent')
|
|
531
|
+
'_self_binding', '_self_parent', '_self_owner')
|
|
529
532
|
|
|
530
533
|
def __init__(self, wrapped, instance, wrapper, enabled=None,
|
|
531
|
-
binding='
|
|
534
|
+
binding='callable', parent=None, owner=None):
|
|
532
535
|
|
|
533
536
|
super(_FunctionWrapperBase, self).__init__(wrapped)
|
|
534
537
|
|
|
@@ -537,60 +540,68 @@ class _FunctionWrapperBase(ObjectProxy):
|
|
|
537
540
|
object.__setattr__(self, '_self_enabled', enabled)
|
|
538
541
|
object.__setattr__(self, '_self_binding', binding)
|
|
539
542
|
object.__setattr__(self, '_self_parent', parent)
|
|
543
|
+
object.__setattr__(self, '_self_owner', owner)
|
|
540
544
|
|
|
541
545
|
def __get__(self, instance, owner):
|
|
542
|
-
# This method is actually doing double duty for both unbound and
|
|
543
|
-
#
|
|
544
|
-
#
|
|
545
|
-
#
|
|
546
|
-
#
|
|
546
|
+
# This method is actually doing double duty for both unbound and bound
|
|
547
|
+
# derived wrapper classes. It should possibly be broken up and the
|
|
548
|
+
# distinct functionality moved into the derived classes. Can't do that
|
|
549
|
+
# straight away due to some legacy code which is relying on it being
|
|
550
|
+
# here in this base class.
|
|
547
551
|
#
|
|
548
|
-
# The distinguishing attribute which determines whether we are
|
|
549
|
-
#
|
|
550
|
-
#
|
|
551
|
-
# be None.
|
|
552
|
+
# The distinguishing attribute which determines whether we are being
|
|
553
|
+
# called in an unbound or bound wrapper is the parent attribute. If
|
|
554
|
+
# binding has never occurred, then the parent will be None.
|
|
552
555
|
#
|
|
553
|
-
# First therefore, is if we are called in an unbound wrapper. In
|
|
554
|
-
#
|
|
556
|
+
# First therefore, is if we are called in an unbound wrapper. In this
|
|
557
|
+
# case we perform the binding.
|
|
555
558
|
#
|
|
556
|
-
# We have
|
|
557
|
-
#
|
|
558
|
-
#
|
|
559
|
-
# simply return self.
|
|
559
|
+
# We have two special cases to worry about here. These are where we are
|
|
560
|
+
# decorating a class or builtin function as neither provide a __get__()
|
|
561
|
+
# method to call. In this case we simply return self.
|
|
560
562
|
#
|
|
561
|
-
# Note that we otherwise still do binding even if instance is
|
|
562
|
-
#
|
|
563
|
-
#
|
|
564
|
-
#
|
|
565
|
-
# first argument of those passed in.
|
|
563
|
+
# Note that we otherwise still do binding even if instance is None and
|
|
564
|
+
# accessing an unbound instance method from a class. This is because we
|
|
565
|
+
# need to be able to later detect that specific case as we will need to
|
|
566
|
+
# extract the instance from the first argument of those passed in.
|
|
566
567
|
|
|
567
568
|
if self._self_parent is None:
|
|
568
|
-
|
|
569
|
-
|
|
569
|
+
# Technically can probably just check for existence of __get__ on
|
|
570
|
+
# the wrapped object, but this is more explicit.
|
|
571
|
+
|
|
572
|
+
if self._self_binding == 'builtin':
|
|
573
|
+
return self
|
|
570
574
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
self._self_binding, self)
|
|
575
|
+
if self._self_binding == "class":
|
|
576
|
+
return self
|
|
574
577
|
|
|
575
|
-
|
|
578
|
+
binder = getattr(self.__wrapped__, '__get__', None)
|
|
576
579
|
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
+
if binder is None:
|
|
581
|
+
return self
|
|
582
|
+
|
|
583
|
+
descriptor = binder(instance, owner)
|
|
584
|
+
|
|
585
|
+
return self.__bound_function_wrapper__(descriptor, instance,
|
|
586
|
+
self._self_wrapper, self._self_enabled,
|
|
587
|
+
self._self_binding, self, owner)
|
|
588
|
+
|
|
589
|
+
# Now we have the case of binding occurring a second time on what was
|
|
590
|
+
# already a bound function. In this case we would usually return
|
|
591
|
+
# ourselves again. This mirrors what Python does.
|
|
580
592
|
#
|
|
581
|
-
# The special case this time is where we were originally bound
|
|
582
|
-
#
|
|
583
|
-
#
|
|
584
|
-
# function from the parent again.
|
|
593
|
+
# The special case this time is where we were originally bound with an
|
|
594
|
+
# instance of None and we were likely an instance method. In that case
|
|
595
|
+
# we rebind against the original wrapped function from the parent again.
|
|
585
596
|
|
|
586
|
-
if self._self_instance is None and self._self_binding
|
|
597
|
+
if self._self_instance is None and self._self_binding in ('function', 'instancemethod', 'callable'):
|
|
587
598
|
descriptor = self._self_parent.__wrapped__.__get__(
|
|
588
599
|
instance, owner)
|
|
589
600
|
|
|
590
601
|
return self._self_parent.__bound_function_wrapper__(
|
|
591
602
|
descriptor, instance, self._self_wrapper,
|
|
592
603
|
self._self_enabled, self._self_binding,
|
|
593
|
-
self._self_parent)
|
|
604
|
+
self._self_parent, owner)
|
|
594
605
|
|
|
595
606
|
return self
|
|
596
607
|
|
|
@@ -617,7 +628,7 @@ class _FunctionWrapperBase(ObjectProxy):
|
|
|
617
628
|
# a function that was already bound to an instance. In that case
|
|
618
629
|
# we want to extract the instance from the function and use it.
|
|
619
630
|
|
|
620
|
-
if self._self_binding in ('function', 'classmethod'):
|
|
631
|
+
if self._self_binding in ('function', 'instancemethod', 'classmethod', 'callable'):
|
|
621
632
|
if self._self_instance is None:
|
|
622
633
|
instance = getattr(self.__wrapped__, '__self__', None)
|
|
623
634
|
if instance is not None:
|
|
@@ -668,11 +679,11 @@ class BoundFunctionWrapper(_FunctionWrapperBase):
|
|
|
668
679
|
|
|
669
680
|
self, args = _unpack_self(*args)
|
|
670
681
|
|
|
671
|
-
# If enabled has been specified, then evaluate it at this point
|
|
672
|
-
#
|
|
673
|
-
#
|
|
674
|
-
#
|
|
675
|
-
#
|
|
682
|
+
# If enabled has been specified, then evaluate it at this point and if
|
|
683
|
+
# the wrapper is not to be executed, then simply return the bound
|
|
684
|
+
# function rather than a bound wrapper for the bound function. When
|
|
685
|
+
# evaluating enabled, if it is callable we call it, otherwise we
|
|
686
|
+
# evaluate it as a boolean.
|
|
676
687
|
|
|
677
688
|
if self._self_enabled is not None:
|
|
678
689
|
if callable(self._self_enabled):
|
|
@@ -681,18 +692,27 @@ class BoundFunctionWrapper(_FunctionWrapperBase):
|
|
|
681
692
|
elif not self._self_enabled:
|
|
682
693
|
return self.__wrapped__(*args, **kwargs)
|
|
683
694
|
|
|
684
|
-
# We need to do things different depending on whether we are
|
|
685
|
-
#
|
|
686
|
-
# method.
|
|
695
|
+
# We need to do things different depending on whether we are likely
|
|
696
|
+
# wrapping an instance method vs a static method or class method.
|
|
687
697
|
|
|
688
698
|
if self._self_binding == 'function':
|
|
699
|
+
if self._self_instance is None and args:
|
|
700
|
+
instance, newargs = args[0], args[1:]
|
|
701
|
+
if isinstance(instance, self._self_owner):
|
|
702
|
+
wrapped = PartialCallableObjectProxy(self.__wrapped__, instance)
|
|
703
|
+
return self._self_wrapper(wrapped, instance, newargs, kwargs)
|
|
704
|
+
|
|
705
|
+
return self._self_wrapper(self.__wrapped__, self._self_instance,
|
|
706
|
+
args, kwargs)
|
|
707
|
+
|
|
708
|
+
elif self._self_binding == 'callable':
|
|
689
709
|
if self._self_instance is None:
|
|
690
710
|
# This situation can occur where someone is calling the
|
|
691
|
-
# instancemethod via the class type and passing the instance
|
|
692
|
-
#
|
|
693
|
-
#
|
|
694
|
-
#
|
|
695
|
-
#
|
|
711
|
+
# instancemethod via the class type and passing the instance as
|
|
712
|
+
# the first argument. We need to shift the args before making
|
|
713
|
+
# the call to the wrapper and effectively bind the instance to
|
|
714
|
+
# the wrapped function using a partial so the wrapper doesn't
|
|
715
|
+
# see anything as being different.
|
|
696
716
|
|
|
697
717
|
if not args:
|
|
698
718
|
raise TypeError('missing 1 required positional argument')
|
|
@@ -794,259 +814,43 @@ class FunctionWrapper(_FunctionWrapperBase):
|
|
|
794
814
|
# or patch it in the __dict__ of the class type.
|
|
795
815
|
#
|
|
796
816
|
# So to get the best outcome we can, whenever we aren't sure what
|
|
797
|
-
# it is, we label it as a '
|
|
817
|
+
# it is, we label it as a 'callable'. If it was already bound and
|
|
798
818
|
# that is rebound later, we assume that it will be an instance
|
|
799
|
-
# method and try
|
|
819
|
+
# method and try and cope with the possibility that the 'self'
|
|
800
820
|
# argument it being passed as an explicit argument and shuffle
|
|
801
821
|
# the arguments around to extract 'self' for use as the instance.
|
|
802
822
|
|
|
803
|
-
|
|
804
|
-
binding = 'classmethod'
|
|
805
|
-
|
|
806
|
-
elif isinstance(wrapped, staticmethod):
|
|
807
|
-
binding = 'staticmethod'
|
|
808
|
-
|
|
809
|
-
elif hasattr(wrapped, '__self__'):
|
|
810
|
-
if inspect.isclass(wrapped.__self__):
|
|
811
|
-
binding = 'classmethod'
|
|
812
|
-
else:
|
|
813
|
-
binding = 'function'
|
|
814
|
-
|
|
815
|
-
else:
|
|
816
|
-
binding = 'function'
|
|
817
|
-
|
|
818
|
-
super(FunctionWrapper, self).__init__(wrapped, None, wrapper,
|
|
819
|
-
enabled, binding)
|
|
820
|
-
|
|
821
|
-
# disabled support for native extension; we likely don't need it
|
|
822
|
-
# try:
|
|
823
|
-
# if not os.environ.get('WRAPT_DISABLE_EXTENSIONS'):
|
|
824
|
-
# from ._wrappers import (ObjectProxy, CallableObjectProxy,
|
|
825
|
-
# PartialCallableObjectProxy, FunctionWrapper,
|
|
826
|
-
# BoundFunctionWrapper, _FunctionWrapperBase)
|
|
827
|
-
# except ImportError:
|
|
828
|
-
# pass
|
|
829
|
-
|
|
830
|
-
# Helper functions for applying wrappers to existing functions.
|
|
831
|
-
|
|
832
|
-
def resolve_path(module, name):
|
|
833
|
-
if isinstance(module, string_types):
|
|
834
|
-
__import__(module)
|
|
835
|
-
module = sys.modules[module]
|
|
836
|
-
|
|
837
|
-
parent = module
|
|
838
|
-
|
|
839
|
-
path = name.split('.')
|
|
840
|
-
attribute = path[0]
|
|
841
|
-
|
|
842
|
-
# We can't just always use getattr() because in doing
|
|
843
|
-
# that on a class it will cause binding to occur which
|
|
844
|
-
# will complicate things later and cause some things not
|
|
845
|
-
# to work. For the case of a class we therefore access
|
|
846
|
-
# the __dict__ directly. To cope though with the wrong
|
|
847
|
-
# class being given to us, or a method being moved into
|
|
848
|
-
# a base class, we need to walk the class hierarchy to
|
|
849
|
-
# work out exactly which __dict__ the method was defined
|
|
850
|
-
# in, as accessing it from __dict__ will fail if it was
|
|
851
|
-
# not actually on the class given. Fallback to using
|
|
852
|
-
# getattr() if we can't find it. If it truly doesn't
|
|
853
|
-
# exist, then that will fail.
|
|
854
|
-
|
|
855
|
-
def lookup_attribute(parent, attribute):
|
|
856
|
-
if inspect.isclass(parent):
|
|
857
|
-
for cls in inspect.getmro(parent):
|
|
858
|
-
if attribute in vars(cls):
|
|
859
|
-
return vars(cls)[attribute]
|
|
860
|
-
else:
|
|
861
|
-
return getattr(parent, attribute)
|
|
862
|
-
else:
|
|
863
|
-
return getattr(parent, attribute)
|
|
864
|
-
|
|
865
|
-
original = lookup_attribute(parent, attribute)
|
|
866
|
-
|
|
867
|
-
for attribute in path[1:]:
|
|
868
|
-
parent = original
|
|
869
|
-
original = lookup_attribute(parent, attribute)
|
|
870
|
-
|
|
871
|
-
return (parent, attribute, original)
|
|
872
|
-
|
|
873
|
-
def apply_patch(parent, attribute, replacement):
|
|
874
|
-
setattr(parent, attribute, replacement)
|
|
875
|
-
|
|
876
|
-
def wrap_object(module, name, factory, args=(), kwargs={}):
|
|
877
|
-
(parent, attribute, original) = resolve_path(module, name)
|
|
878
|
-
wrapper = factory(original, *args, **kwargs)
|
|
879
|
-
apply_patch(parent, attribute, wrapper)
|
|
880
|
-
return wrapper
|
|
881
|
-
|
|
882
|
-
# Function for applying a proxy object to an attribute of a class
|
|
883
|
-
# instance. The wrapper works by defining an attribute of the same name
|
|
884
|
-
# on the class which is a descriptor and which intercepts access to the
|
|
885
|
-
# instance attribute. Note that this cannot be used on attributes which
|
|
886
|
-
# are themselves defined by a property object.
|
|
887
|
-
|
|
888
|
-
class AttributeWrapper(object):
|
|
889
|
-
|
|
890
|
-
def __init__(self, attribute, factory, args, kwargs):
|
|
891
|
-
self.attribute = attribute
|
|
892
|
-
self.factory = factory
|
|
893
|
-
self.args = args
|
|
894
|
-
self.kwargs = kwargs
|
|
895
|
-
|
|
896
|
-
def __get__(self, instance, owner):
|
|
897
|
-
value = instance.__dict__[self.attribute]
|
|
898
|
-
return self.factory(value, *self.args, **self.kwargs)
|
|
899
|
-
|
|
900
|
-
def __set__(self, instance, value):
|
|
901
|
-
instance.__dict__[self.attribute] = value
|
|
902
|
-
|
|
903
|
-
def __delete__(self, instance):
|
|
904
|
-
del instance.__dict__[self.attribute]
|
|
905
|
-
|
|
906
|
-
def wrap_object_attribute(module, name, factory, args=(), kwargs={}):
|
|
907
|
-
path, attribute = name.rsplit('.', 1)
|
|
908
|
-
parent = resolve_path(module, path)[2]
|
|
909
|
-
wrapper = AttributeWrapper(attribute, factory, args, kwargs)
|
|
910
|
-
apply_patch(parent, attribute, wrapper)
|
|
911
|
-
return wrapper
|
|
912
|
-
|
|
913
|
-
# Functions for creating a simple decorator using a FunctionWrapper,
|
|
914
|
-
# plus short cut functions for applying wrappers to functions. These are
|
|
915
|
-
# for use when doing monkey patching. For a more featured way of
|
|
916
|
-
# creating decorators see the decorator decorator instead.
|
|
917
|
-
|
|
918
|
-
def function_wrapper(wrapper):
|
|
919
|
-
def _wrapper(wrapped, instance, args, kwargs):
|
|
920
|
-
target_wrapped = args[0]
|
|
921
|
-
if instance is None:
|
|
922
|
-
target_wrapper = wrapper
|
|
923
|
-
elif inspect.isclass(instance):
|
|
924
|
-
target_wrapper = wrapper.__get__(None, instance)
|
|
925
|
-
else:
|
|
926
|
-
target_wrapper = wrapper.__get__(instance, type(instance))
|
|
927
|
-
return FunctionWrapper(target_wrapped, target_wrapper)
|
|
928
|
-
return FunctionWrapper(wrapper, _wrapper)
|
|
929
|
-
|
|
930
|
-
def wrap_function_wrapper(module, name, wrapper):
|
|
931
|
-
return wrap_object(module, name, FunctionWrapper, (wrapper,))
|
|
932
|
-
|
|
933
|
-
def patch_function_wrapper(module, name):
|
|
934
|
-
def _wrapper(wrapper):
|
|
935
|
-
return wrap_object(module, name, FunctionWrapper, (wrapper,))
|
|
936
|
-
return _wrapper
|
|
937
|
-
|
|
938
|
-
def transient_function_wrapper(module, name):
|
|
939
|
-
def _decorator(wrapper):
|
|
940
|
-
def _wrapper(wrapped, instance, args, kwargs):
|
|
941
|
-
target_wrapped = args[0]
|
|
942
|
-
if instance is None:
|
|
943
|
-
target_wrapper = wrapper
|
|
944
|
-
elif inspect.isclass(instance):
|
|
945
|
-
target_wrapper = wrapper.__get__(None, instance)
|
|
946
|
-
else:
|
|
947
|
-
target_wrapper = wrapper.__get__(instance, type(instance))
|
|
948
|
-
def _execute(wrapped, instance, args, kwargs):
|
|
949
|
-
(parent, attribute, original) = resolve_path(module, name)
|
|
950
|
-
replacement = FunctionWrapper(original, target_wrapper)
|
|
951
|
-
setattr(parent, attribute, replacement)
|
|
952
|
-
try:
|
|
953
|
-
return wrapped(*args, **kwargs)
|
|
954
|
-
finally:
|
|
955
|
-
setattr(parent, attribute, original)
|
|
956
|
-
return FunctionWrapper(target_wrapped, _execute)
|
|
957
|
-
return FunctionWrapper(wrapper, _wrapper)
|
|
958
|
-
return _decorator
|
|
959
|
-
|
|
960
|
-
# A weak function proxy. This will work on instance methods, class
|
|
961
|
-
# methods, static methods and regular functions. Special treatment is
|
|
962
|
-
# needed for the method types because the bound method is effectively a
|
|
963
|
-
# transient object and applying a weak reference to one will immediately
|
|
964
|
-
# result in it being destroyed and the weakref callback called. The weak
|
|
965
|
-
# reference is therefore applied to the instance the method is bound to
|
|
966
|
-
# and the original function. The function is then rebound at the point
|
|
967
|
-
# of a call via the weak function proxy.
|
|
968
|
-
|
|
969
|
-
def _weak_function_proxy_callback(ref, proxy, callback):
|
|
970
|
-
if proxy._self_expired:
|
|
971
|
-
return
|
|
972
|
-
|
|
973
|
-
proxy._self_expired = True
|
|
974
|
-
|
|
975
|
-
# This could raise an exception. We let it propagate back and let
|
|
976
|
-
# the weakref.proxy() deal with it, at which point it generally
|
|
977
|
-
# prints out a short error message direct to stderr and keeps going.
|
|
978
|
-
|
|
979
|
-
if callback is not None:
|
|
980
|
-
callback(proxy)
|
|
981
|
-
|
|
982
|
-
class WeakFunctionProxy(ObjectProxy):
|
|
983
|
-
|
|
984
|
-
__slots__ = ('_self_expired', '_self_instance')
|
|
985
|
-
|
|
986
|
-
def __init__(self, wrapped, callback=None):
|
|
987
|
-
# We need to determine if the wrapped function is actually a
|
|
988
|
-
# bound method. In the case of a bound method, we need to keep a
|
|
989
|
-
# reference to the original unbound function and the instance.
|
|
990
|
-
# This is necessary because if we hold a reference to the bound
|
|
991
|
-
# function, it will be the only reference and given it is a
|
|
992
|
-
# temporary object, it will almost immediately expire and
|
|
993
|
-
# the weakref callback triggered. So what is done is that we
|
|
994
|
-
# hold a reference to the instance and unbound function and
|
|
995
|
-
# when called bind the function to the instance once again and
|
|
996
|
-
# then call it. Note that we avoid using a nested function for
|
|
997
|
-
# the callback here so as not to cause any odd reference cycles.
|
|
998
|
-
|
|
999
|
-
_callback = callback and functools.partial(
|
|
1000
|
-
_weak_function_proxy_callback, proxy=self,
|
|
1001
|
-
callback=callback)
|
|
1002
|
-
|
|
1003
|
-
self._self_expired = False
|
|
823
|
+
binding = None
|
|
1004
824
|
|
|
1005
825
|
if isinstance(wrapped, _FunctionWrapperBase):
|
|
1006
|
-
|
|
1007
|
-
_callback)
|
|
826
|
+
binding = wrapped._self_binding
|
|
1008
827
|
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
828
|
+
if not binding:
|
|
829
|
+
if inspect.isbuiltin(wrapped):
|
|
830
|
+
binding = 'builtin'
|
|
1012
831
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
weakref.proxy(wrapped, _callback))
|
|
1016
|
-
|
|
1017
|
-
return
|
|
1018
|
-
|
|
1019
|
-
try:
|
|
1020
|
-
self._self_instance = weakref.ref(wrapped.__self__, _callback)
|
|
1021
|
-
|
|
1022
|
-
super(WeakFunctionProxy, self).__init__(
|
|
1023
|
-
weakref.proxy(wrapped.__func__, _callback))
|
|
1024
|
-
|
|
1025
|
-
except AttributeError:
|
|
1026
|
-
self._self_instance = None
|
|
1027
|
-
|
|
1028
|
-
super(WeakFunctionProxy, self).__init__(
|
|
1029
|
-
weakref.proxy(wrapped, _callback))
|
|
1030
|
-
|
|
1031
|
-
def __call__(*args, **kwargs):
|
|
1032
|
-
def _unpack_self(self, *args):
|
|
1033
|
-
return self, args
|
|
832
|
+
elif inspect.isfunction(wrapped):
|
|
833
|
+
binding = 'function'
|
|
1034
834
|
|
|
1035
|
-
|
|
835
|
+
elif inspect.isclass(wrapped):
|
|
836
|
+
binding = 'class'
|
|
1036
837
|
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
# calling if the reference had expired.
|
|
838
|
+
elif isinstance(wrapped, classmethod):
|
|
839
|
+
binding = 'classmethod'
|
|
1040
840
|
|
|
1041
|
-
|
|
1042
|
-
|
|
841
|
+
elif isinstance(wrapped, staticmethod):
|
|
842
|
+
binding = 'staticmethod'
|
|
1043
843
|
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
844
|
+
elif hasattr(wrapped, '__self__'):
|
|
845
|
+
if inspect.isclass(wrapped.__self__):
|
|
846
|
+
binding = 'classmethod'
|
|
847
|
+
elif inspect.ismethod(wrapped):
|
|
848
|
+
binding = 'instancemethod'
|
|
849
|
+
else:
|
|
850
|
+
binding = 'callable'
|
|
1048
851
|
|
|
1049
|
-
|
|
1050
|
-
|
|
852
|
+
else:
|
|
853
|
+
binding = 'callable'
|
|
1051
854
|
|
|
1052
|
-
|
|
855
|
+
super(FunctionWrapper, self).__init__(wrapped, None, wrapper,
|
|
856
|
+
enabled, binding)
|
ansible/cli/__init__.py
CHANGED
|
@@ -23,10 +23,12 @@ if 1 <= len(sys.argv) <= 2 and os.path.basename(sys.argv[0]) == "ansible" and os
|
|
|
23
23
|
|
|
24
24
|
# Used for determining if the system is running a new enough python version
|
|
25
25
|
# and should only restrict on our documented minimum versions
|
|
26
|
-
|
|
26
|
+
_PY_MIN = (3, 12)
|
|
27
|
+
|
|
28
|
+
if sys.version_info < _PY_MIN:
|
|
27
29
|
raise SystemExit(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
f"ERROR: Ansible requires Python {'.'.join(map(str, _PY_MIN))} or newer on the controller. "
|
|
31
|
+
f"Current version: {''.join(sys.version.splitlines())}"
|
|
30
32
|
)
|
|
31
33
|
|
|
32
34
|
|
|
@@ -105,7 +107,6 @@ from ansible import context
|
|
|
105
107
|
from ansible.utils import display as _display
|
|
106
108
|
from ansible.cli.arguments import option_helpers as opt_help
|
|
107
109
|
from ansible.inventory.manager import InventoryManager
|
|
108
|
-
from ansible.module_utils.six import string_types
|
|
109
110
|
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
|
110
111
|
from ansible.module_utils.common.collections import is_sequence
|
|
111
112
|
from ansible.module_utils.common.file import is_executable
|
|
@@ -371,7 +372,7 @@ class CLI(ABC):
|
|
|
371
372
|
return op
|
|
372
373
|
|
|
373
374
|
@abstractmethod
|
|
374
|
-
def init_parser(self,
|
|
375
|
+
def init_parser(self, desc=None, epilog=None):
|
|
375
376
|
"""
|
|
376
377
|
Create an options parser for most ansible scripts
|
|
377
378
|
|
|
@@ -381,11 +382,11 @@ class CLI(ABC):
|
|
|
381
382
|
An implementation will look something like this::
|
|
382
383
|
|
|
383
384
|
def init_parser(self):
|
|
384
|
-
super(MyCLI, self).init_parser(
|
|
385
|
+
super(MyCLI, self).init_parser(desc='The purpose of the program is...')
|
|
385
386
|
ansible.arguments.option_helpers.add_runas_options(self.parser)
|
|
386
387
|
self.parser.add_option('--my-option', dest='my_option', action='store')
|
|
387
388
|
"""
|
|
388
|
-
self.parser = opt_help.create_base_parser(self.name,
|
|
389
|
+
self.parser = opt_help.create_base_parser(self.name, desc=desc, epilog=epilog)
|
|
389
390
|
|
|
390
391
|
@abstractmethod
|
|
391
392
|
def post_process_args(self, options):
|
|
@@ -401,8 +402,8 @@ class CLI(ABC):
|
|
|
401
402
|
options = super(MyCLI, self).post_process_args(options)
|
|
402
403
|
if options.addition and options.subtraction:
|
|
403
404
|
raise AnsibleOptionsError('Only one of --addition and --subtraction can be specified')
|
|
404
|
-
if isinstance(options.listofhosts,
|
|
405
|
-
options.listofhosts =
|
|
405
|
+
if isinstance(options.listofhosts, str):
|
|
406
|
+
options.listofhosts = options.listofhosts.split(',')
|
|
406
407
|
return options
|
|
407
408
|
"""
|
|
408
409
|
|
|
@@ -438,7 +439,7 @@ class CLI(ABC):
|
|
|
438
439
|
if options.inventory:
|
|
439
440
|
|
|
440
441
|
# should always be list
|
|
441
|
-
if isinstance(options.inventory,
|
|
442
|
+
if isinstance(options.inventory, str):
|
|
442
443
|
options.inventory = [options.inventory]
|
|
443
444
|
|
|
444
445
|
# Ensure full paths when needed
|
ansible/cli/adhoc.py
CHANGED
|
@@ -37,8 +37,7 @@ class AdHocCLI(CLI):
|
|
|
37
37
|
|
|
38
38
|
def init_parser(self):
|
|
39
39
|
""" create an options parser for bin/ansible """
|
|
40
|
-
super(AdHocCLI, self).init_parser(
|
|
41
|
-
desc="Define and run a single task 'playbook' against a set of hosts",
|
|
40
|
+
super(AdHocCLI, self).init_parser(desc="Define and run a single task 'playbook' against a set of hosts",
|
|
42
41
|
epilog="Some actions do not make sense in Ad-Hoc (include, meta, etc)")
|
|
43
42
|
|
|
44
43
|
opt_help.add_runas_options(self.parser)
|
|
@@ -322,7 +322,7 @@ def version(prog=None):
|
|
|
322
322
|
# Functions to add pre-canned options to an OptionParser
|
|
323
323
|
#
|
|
324
324
|
|
|
325
|
-
def create_base_parser(prog,
|
|
325
|
+
def create_base_parser(prog, desc=None, epilog=None):
|
|
326
326
|
"""
|
|
327
327
|
Create an options parser for all ansible scripts
|
|
328
328
|
"""
|
ansible/cli/config.py
CHANGED
|
@@ -24,7 +24,6 @@ from ansible.config.manager import ConfigManager
|
|
|
24
24
|
from ansible.errors import AnsibleError, AnsibleOptionsError, AnsibleRequiredOptionError
|
|
25
25
|
from ansible.module_utils.common.text.converters import to_native, to_text, to_bytes
|
|
26
26
|
from ansible._internal import _json
|
|
27
|
-
from ansible.module_utils.six import string_types
|
|
28
27
|
from ansible.parsing.quoting import is_quoted
|
|
29
28
|
from ansible.parsing.yaml.dumper import AnsibleDumper
|
|
30
29
|
from ansible.utils.color import stringc
|
|
@@ -288,21 +287,21 @@ class ConfigCLI(CLI):
|
|
|
288
287
|
default = '0'
|
|
289
288
|
elif default:
|
|
290
289
|
if stype == 'list':
|
|
291
|
-
if not isinstance(default,
|
|
290
|
+
if not isinstance(default, str):
|
|
292
291
|
# python lists are not valid env ones
|
|
293
292
|
try:
|
|
294
293
|
default = ', '.join(default)
|
|
295
294
|
except Exception as e:
|
|
296
295
|
# list of other stuff
|
|
297
296
|
default = '%s' % to_native(default)
|
|
298
|
-
if isinstance(default,
|
|
297
|
+
if isinstance(default, str) and not is_quoted(default):
|
|
299
298
|
default = shlex.quote(default)
|
|
300
299
|
elif default is None:
|
|
301
300
|
default = ''
|
|
302
301
|
|
|
303
302
|
if subkey in settings[setting] and settings[setting][subkey]:
|
|
304
303
|
entry = settings[setting][subkey][-1]['name']
|
|
305
|
-
if isinstance(settings[setting]['description'],
|
|
304
|
+
if isinstance(settings[setting]['description'], str):
|
|
306
305
|
desc = settings[setting]['description']
|
|
307
306
|
else:
|
|
308
307
|
desc = '\n#'.join(settings[setting]['description'])
|
|
@@ -343,7 +342,7 @@ class ConfigCLI(CLI):
|
|
|
343
342
|
sections[s] = new_sections[s]
|
|
344
343
|
continue
|
|
345
344
|
|
|
346
|
-
if isinstance(opt['description'],
|
|
345
|
+
if isinstance(opt['description'], str):
|
|
347
346
|
desc = '# (%s) %s' % (opt.get('type', 'string'), opt['description'])
|
|
348
347
|
else:
|
|
349
348
|
desc = "# (%s) " % opt.get('type', 'string')
|
|
@@ -361,7 +360,7 @@ class ConfigCLI(CLI):
|
|
|
361
360
|
seen[entry['section']].append(entry['key'])
|
|
362
361
|
|
|
363
362
|
default = self.config.template_default(opt.get('default', ''), get_constants())
|
|
364
|
-
if opt.get('type', '') == 'list' and not isinstance(default,
|
|
363
|
+
if opt.get('type', '') == 'list' and not isinstance(default, str):
|
|
365
364
|
# python lists are not valid ini ones
|
|
366
365
|
default = ', '.join(default)
|
|
367
366
|
elif default is None:
|