ansible-core 2.19.3rc1__py3-none-any.whl → 2.20.0b2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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/_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 +70 -68
- 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/collections/list.py +4 -2
- 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/task_executor.py +26 -18
- 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 +24 -118
- 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 +26 -23
- 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 +19 -6
- 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/known_hosts.py +7 -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 +1 -63
- ansible/playbook/collectionsearch.py +1 -2
- ansible/playbook/handler.py +1 -7
- ansible/playbook/helpers.py +15 -20
- ansible/playbook/included_file.py +1 -1
- ansible/playbook/play.py +105 -49
- 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 +3 -5
- 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/toml.py +3 -6
- ansible/plugins/inventory/yaml.py +1 -2
- ansible/plugins/loader.py +3 -4
- 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/falsy.yml +1 -1
- ansible/plugins/test/regex.yml +18 -6
- ansible/plugins/test/truthy.yml +1 -1
- 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 +7 -6
- 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 +28 -22
- ansible/vars/plugins.py +1 -31
- {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/METADATA +3 -3
- {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/RECORD +199 -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 +40 -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.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/WHEEL +0 -0
- {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/top_level.txt +0 -0
ansible/_internal/__init__.py
CHANGED
|
@@ -30,10 +30,7 @@ def import_controller_module(module_name: str, /) -> t.Any:
|
|
|
30
30
|
return importlib.import_module(module_name)
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def experimental(obj: _T) -> _T:
|
|
33
|
+
def experimental[T](obj: T) -> T:
|
|
37
34
|
"""
|
|
38
35
|
Decorator for experimental types and methods outside the `_internal` package which accept or expose internal types.
|
|
39
36
|
As with internal APIs, these are subject to change at any time without notice.
|
|
@@ -9,8 +9,6 @@ from ansible.module_utils._internal._ansiballz import _extensions
|
|
|
9
9
|
from ansible.module_utils._internal._ansiballz._extensions import _debugpy, _pydevd, _coverage
|
|
10
10
|
from ansible.constants import config
|
|
11
11
|
|
|
12
|
-
_T = t.TypeVar('_T')
|
|
13
|
-
|
|
14
12
|
|
|
15
13
|
class ExtensionManager:
|
|
16
14
|
"""AnsiballZ extension manager."""
|
|
@@ -101,7 +99,7 @@ class ExtensionManager:
|
|
|
101
99
|
)
|
|
102
100
|
|
|
103
101
|
@classmethod
|
|
104
|
-
def _get_options(cls, name: str, config_type: type[
|
|
102
|
+
def _get_options[T](cls, name: str, config_type: type[T], task_vars: dict[str, object]) -> T | None:
|
|
105
103
|
"""Parse configuration from the named environment variable as the specified type, or None if not configured."""
|
|
106
104
|
if (value := config.get_config_value(name, variables=task_vars)) is None:
|
|
107
105
|
return None
|
|
@@ -3,26 +3,24 @@ from __future__ import annotations as _annotations
|
|
|
3
3
|
import collections.abc as _c
|
|
4
4
|
import typing as _t
|
|
5
5
|
|
|
6
|
-
_T_co = _t.TypeVar('_T_co', covariant=True)
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
class SequenceProxy(_c.Sequence[_T_co]):
|
|
7
|
+
class SequenceProxy[T](_c.Sequence[T]):
|
|
10
8
|
"""A read-only sequence proxy."""
|
|
11
9
|
|
|
12
10
|
# DTFIX5: needs unit test coverage
|
|
13
11
|
|
|
14
12
|
__slots__ = ('__value',)
|
|
15
13
|
|
|
16
|
-
def __init__(self, value: _c.Sequence[
|
|
14
|
+
def __init__(self, value: _c.Sequence[T]) -> None:
|
|
17
15
|
self.__value = value
|
|
18
16
|
|
|
19
17
|
@_t.overload
|
|
20
|
-
def __getitem__(self, index: int) ->
|
|
18
|
+
def __getitem__(self, index: int) -> T: ...
|
|
21
19
|
|
|
22
20
|
@_t.overload
|
|
23
|
-
def __getitem__(self, index: slice) -> _c.Sequence[
|
|
21
|
+
def __getitem__(self, index: slice) -> _c.Sequence[T]: ...
|
|
24
22
|
|
|
25
|
-
def __getitem__(self, index: int | slice) ->
|
|
23
|
+
def __getitem__(self, index: int | slice) -> T | _c.Sequence[T]:
|
|
26
24
|
if isinstance(index, slice):
|
|
27
25
|
return self.__class__(self.__value[index])
|
|
28
26
|
|
|
@@ -34,10 +32,10 @@ class SequenceProxy(_c.Sequence[_T_co]):
|
|
|
34
32
|
def __contains__(self, item: object) -> bool:
|
|
35
33
|
return item in self.__value
|
|
36
34
|
|
|
37
|
-
def __iter__(self) -> _t.Iterator[
|
|
35
|
+
def __iter__(self) -> _t.Iterator[T]:
|
|
38
36
|
yield from self.__value
|
|
39
37
|
|
|
40
|
-
def __reversed__(self) -> _c.Iterator[
|
|
38
|
+
def __reversed__(self) -> _c.Iterator[T]:
|
|
41
39
|
return reversed(self.__value)
|
|
42
40
|
|
|
43
41
|
def index(self, *args) -> int:
|
|
@@ -24,7 +24,6 @@ from ansible._internal._templating import _transform
|
|
|
24
24
|
from ansible.module_utils import _internal
|
|
25
25
|
from ansible.module_utils._internal import _datatag
|
|
26
26
|
|
|
27
|
-
_T = t.TypeVar('_T')
|
|
28
27
|
_sentinel = object()
|
|
29
28
|
|
|
30
29
|
|
|
@@ -115,7 +114,7 @@ class AnsibleVariableVisitor:
|
|
|
115
114
|
if func := getattr(super(), '__exit__', None):
|
|
116
115
|
func(*args, **kwargs)
|
|
117
116
|
|
|
118
|
-
def visit(self, value:
|
|
117
|
+
def visit[T](self, value: T) -> T:
|
|
119
118
|
"""
|
|
120
119
|
Enforces Ansible's variable type system restrictions before a var is accepted in inventory. Also, conditionally implements template trust
|
|
121
120
|
compatibility, depending on the plugin's declared understanding (or lack thereof). This always recursively copies inputs to fully isolate
|
|
@@ -143,7 +142,7 @@ class AnsibleVariableVisitor:
|
|
|
143
142
|
|
|
144
143
|
return self._visit(None, key) # key=None prevents state tracking from seeing the key as value
|
|
145
144
|
|
|
146
|
-
def _visit(self, key: t.Any, value:
|
|
145
|
+
def _visit[T](self, key: t.Any, value: T) -> T:
|
|
147
146
|
"""Internal implementation to recursively visit a data structure's contents."""
|
|
148
147
|
self._current = key # supports StateTrackingMixIn
|
|
149
148
|
|
|
@@ -168,7 +167,7 @@ class AnsibleVariableVisitor:
|
|
|
168
167
|
value = value._native_copy()
|
|
169
168
|
value_type = type(value)
|
|
170
169
|
|
|
171
|
-
result:
|
|
170
|
+
result: T
|
|
172
171
|
|
|
173
172
|
# DTFIX-FUTURE: Visitor generally ignores dict/mapping keys by default except for debugging and schema-aware checking.
|
|
174
173
|
# It could be checking keys destined for variable storage to apply more strict rules about key shape and type.
|
|
@@ -193,7 +193,7 @@ class TemplateEngine:
|
|
|
193
193
|
return self._variables
|
|
194
194
|
|
|
195
195
|
@available_variables.setter
|
|
196
|
-
def available_variables(self, variables: dict[str, t.Any]) -> None:
|
|
196
|
+
def available_variables(self, variables: dict[str, t.Any] | ChainMap[str, t.Any]) -> None:
|
|
197
197
|
self._variables = variables
|
|
198
198
|
|
|
199
199
|
def resolve_variable_expression(
|
|
@@ -29,7 +29,6 @@ from ._utils import LazyOptions, TemplateContext
|
|
|
29
29
|
|
|
30
30
|
_display = Display()
|
|
31
31
|
|
|
32
|
-
_TCallable = t.TypeVar("_TCallable", bound=t.Callable)
|
|
33
32
|
_ITERATOR_TYPES: t.Final = (c.Iterator, c.ItemsView, c.KeysView, c.ValuesView, range)
|
|
34
33
|
|
|
35
34
|
|
|
@@ -174,7 +173,7 @@ class _DirectCall:
|
|
|
174
173
|
_marker_attr: t.Final[str] = "_directcall"
|
|
175
174
|
|
|
176
175
|
@classmethod
|
|
177
|
-
def mark(cls, src:
|
|
176
|
+
def mark[T: t.Callable](cls, src: T) -> T:
|
|
178
177
|
setattr(src, cls._marker_attr, True)
|
|
179
178
|
return src
|
|
180
179
|
|
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)
|