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.

Files changed (201) hide show
  1. ansible/_internal/__init__.py +1 -4
  2. ansible/_internal/_ansiballz/_builder.py +1 -3
  3. ansible/_internal/_collection_proxy.py +7 -9
  4. ansible/_internal/_json/__init__.py +3 -4
  5. ansible/_internal/_templating/_engine.py +1 -1
  6. ansible/_internal/_templating/_jinja_plugins.py +1 -2
  7. ansible/_internal/_wrapt.py +105 -301
  8. ansible/cli/__init__.py +11 -10
  9. ansible/cli/adhoc.py +1 -2
  10. ansible/cli/arguments/option_helpers.py +1 -1
  11. ansible/cli/config.py +5 -6
  12. ansible/cli/doc.py +70 -68
  13. ansible/cli/galaxy.py +15 -24
  14. ansible/cli/inventory.py +0 -1
  15. ansible/cli/playbook.py +0 -1
  16. ansible/cli/pull.py +0 -1
  17. ansible/cli/scripts/ansible_connection_cli_stub.py +1 -1
  18. ansible/collections/list.py +4 -2
  19. ansible/config/base.yml +1 -25
  20. ansible/config/manager.py +0 -2
  21. ansible/executor/play_iterator.py +42 -20
  22. ansible/executor/playbook_executor.py +0 -9
  23. ansible/executor/task_executor.py +26 -18
  24. ansible/executor/task_queue_manager.py +1 -3
  25. ansible/galaxy/api.py +33 -80
  26. ansible/galaxy/collection/__init__.py +4 -17
  27. ansible/galaxy/dependency_resolution/dataclasses.py +0 -10
  28. ansible/galaxy/dependency_resolution/providers.py +24 -118
  29. ansible/galaxy/role.py +1 -33
  30. ansible/inventory/manager.py +2 -3
  31. ansible/keyword_desc.yml +0 -3
  32. ansible/module_utils/_internal/_datatag/__init__.py +2 -10
  33. ansible/module_utils/_internal/_no_six.py +86 -0
  34. ansible/module_utils/_text.py +28 -8
  35. ansible/module_utils/ansible_release.py +2 -2
  36. ansible/module_utils/basic.py +26 -23
  37. ansible/module_utils/common/_collections_compat.py +11 -2
  38. ansible/module_utils/common/collections.py +8 -3
  39. ansible/module_utils/common/dict_transformations.py +1 -2
  40. ansible/module_utils/common/network.py +4 -2
  41. ansible/module_utils/common/parameters.py +32 -41
  42. ansible/module_utils/common/text/converters.py +109 -23
  43. ansible/module_utils/common/text/formatters.py +6 -2
  44. ansible/module_utils/common/validation.py +11 -9
  45. ansible/module_utils/connection.py +8 -3
  46. ansible/module_utils/facts/hardware/linux.py +23 -7
  47. ansible/module_utils/facts/hardware/netbsd.py +1 -1
  48. ansible/module_utils/facts/hardware/sunos.py +2 -1
  49. ansible/module_utils/facts/packages.py +6 -2
  50. ansible/module_utils/facts/system/distribution.py +2 -1
  51. ansible/module_utils/facts/system/env.py +6 -3
  52. ansible/module_utils/facts/system/local.py +3 -1
  53. ansible/module_utils/parsing/convert_bool.py +6 -2
  54. ansible/module_utils/service.py +2 -3
  55. ansible/module_utils/six/__init__.py +19 -6
  56. ansible/module_utils/yumdnf.py +0 -5
  57. ansible/modules/apt.py +18 -13
  58. ansible/modules/apt_repository.py +1 -1
  59. ansible/modules/assemble.py +5 -9
  60. ansible/modules/blockinfile.py +39 -23
  61. ansible/modules/cron.py +26 -35
  62. ansible/modules/deb822_repository.py +83 -12
  63. ansible/modules/dnf.py +3 -7
  64. ansible/modules/dnf5.py +4 -6
  65. ansible/modules/expect.py +0 -3
  66. ansible/modules/find.py +1 -2
  67. ansible/modules/get_url.py +1 -1
  68. ansible/modules/git.py +4 -5
  69. ansible/modules/include_vars.py +1 -1
  70. ansible/modules/known_hosts.py +7 -1
  71. ansible/modules/lineinfile.py +71 -63
  72. ansible/modules/package_facts.py +1 -1
  73. ansible/modules/pip.py +8 -2
  74. ansible/modules/replace.py +6 -6
  75. ansible/modules/service.py +3 -4
  76. ansible/modules/stat.py +20 -0
  77. ansible/modules/uri.py +9 -10
  78. ansible/modules/user.py +1 -2
  79. ansible/modules/wait_for.py +2 -2
  80. ansible/modules/wait_for_connection.py +2 -1
  81. ansible/modules/yum_repository.py +1 -16
  82. ansible/parsing/dataloader.py +24 -31
  83. ansible/parsing/mod_args.py +3 -0
  84. ansible/parsing/vault/__init__.py +1 -2
  85. ansible/playbook/base.py +8 -56
  86. ansible/playbook/block.py +1 -63
  87. ansible/playbook/collectionsearch.py +1 -2
  88. ansible/playbook/handler.py +1 -7
  89. ansible/playbook/helpers.py +15 -20
  90. ansible/playbook/included_file.py +1 -1
  91. ansible/playbook/play.py +105 -49
  92. ansible/playbook/play_context.py +4 -0
  93. ansible/playbook/role/__init__.py +10 -65
  94. ansible/playbook/role/definition.py +3 -4
  95. ansible/playbook/role/include.py +2 -3
  96. ansible/playbook/role/metadata.py +1 -12
  97. ansible/playbook/role/requirement.py +1 -2
  98. ansible/playbook/role_include.py +1 -2
  99. ansible/playbook/taggable.py +16 -5
  100. ansible/playbook/task.py +51 -55
  101. ansible/plugins/action/__init__.py +20 -19
  102. ansible/plugins/action/add_host.py +1 -2
  103. ansible/plugins/action/fetch.py +3 -5
  104. ansible/plugins/action/group_by.py +1 -2
  105. ansible/plugins/action/include_vars.py +20 -22
  106. ansible/plugins/action/script.py +1 -3
  107. ansible/plugins/action/template.py +1 -2
  108. ansible/plugins/action/uri.py +4 -2
  109. ansible/plugins/cache/__init__.py +1 -0
  110. ansible/plugins/callback/__init__.py +13 -6
  111. ansible/plugins/connection/__init__.py +3 -7
  112. ansible/plugins/connection/local.py +2 -3
  113. ansible/plugins/connection/psrp.py +0 -2
  114. ansible/plugins/connection/ssh.py +2 -7
  115. ansible/plugins/connection/winrm.py +0 -2
  116. ansible/plugins/doc_fragments/result_format_callback.py +15 -0
  117. ansible/plugins/filter/core.py +4 -5
  118. ansible/plugins/filter/encryption.py +3 -27
  119. ansible/plugins/filter/mathstuff.py +1 -2
  120. ansible/plugins/filter/to_nice_yaml.yml +31 -3
  121. ansible/plugins/filter/to_yaml.yml +29 -12
  122. ansible/plugins/inventory/__init__.py +1 -2
  123. ansible/plugins/inventory/toml.py +3 -6
  124. ansible/plugins/inventory/yaml.py +1 -2
  125. ansible/plugins/loader.py +3 -4
  126. ansible/plugins/lookup/password.py +1 -2
  127. ansible/plugins/lookup/subelements.py +2 -3
  128. ansible/plugins/lookup/url.py +1 -1
  129. ansible/plugins/lookup/varnames.py +1 -2
  130. ansible/plugins/shell/__init__.py +9 -4
  131. ansible/plugins/shell/powershell.py +8 -24
  132. ansible/plugins/strategy/__init__.py +6 -3
  133. ansible/plugins/test/core.py +4 -1
  134. ansible/plugins/test/falsy.yml +1 -1
  135. ansible/plugins/test/regex.yml +18 -6
  136. ansible/plugins/test/truthy.yml +1 -1
  137. ansible/release.py +2 -2
  138. ansible/template/__init__.py +3 -7
  139. ansible/utils/collection_loader/_collection_config.py +5 -0
  140. ansible/utils/collection_loader/_collection_finder.py +11 -14
  141. ansible/utils/context_objects.py +7 -4
  142. ansible/utils/display.py +7 -6
  143. ansible/utils/encrypt.py +0 -5
  144. ansible/utils/helpers.py +6 -2
  145. ansible/utils/jsonrpc.py +7 -3
  146. ansible/utils/plugin_docs.py +49 -38
  147. ansible/utils/ssh_functions.py +0 -19
  148. ansible/utils/unsafe_proxy.py +7 -7
  149. ansible/vars/clean.py +2 -3
  150. ansible/vars/manager.py +28 -22
  151. ansible/vars/plugins.py +1 -31
  152. {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/METADATA +3 -3
  153. {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/RECORD +199 -200
  154. ansible_test/_data/completion/docker.txt +7 -7
  155. ansible_test/_data/completion/network.txt +0 -1
  156. ansible_test/_data/completion/remote.txt +4 -4
  157. ansible_test/_data/requirements/ansible-test.txt +1 -1
  158. ansible_test/_data/requirements/sanity.changelog.txt +1 -1
  159. ansible_test/_data/requirements/sanity.pep8.txt +1 -1
  160. ansible_test/_data/requirements/sanity.pylint.txt +4 -4
  161. ansible_test/_internal/cache.py +2 -5
  162. ansible_test/_internal/cli/compat.py +1 -1
  163. ansible_test/_internal/commands/coverage/combine.py +1 -3
  164. ansible_test/_internal/commands/integration/__init__.py +3 -7
  165. ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
  166. ansible_test/_internal/commands/integration/coverage.py +1 -3
  167. ansible_test/_internal/commands/integration/filters.py +5 -10
  168. ansible_test/_internal/commands/sanity/validate_modules.py +1 -5
  169. ansible_test/_internal/commands/units/__init__.py +1 -13
  170. ansible_test/_internal/completion.py +2 -5
  171. ansible_test/_internal/config.py +2 -7
  172. ansible_test/_internal/coverage_util.py +1 -1
  173. ansible_test/_internal/delegation.py +2 -0
  174. ansible_test/_internal/docker_util.py +1 -1
  175. ansible_test/_internal/host_profiles.py +6 -11
  176. ansible_test/_internal/provider/__init__.py +2 -5
  177. ansible_test/_internal/provisioning.py +2 -5
  178. ansible_test/_internal/pypi_proxy.py +1 -1
  179. ansible_test/_internal/target.py +2 -6
  180. ansible_test/_internal/thread.py +1 -4
  181. ansible_test/_internal/util.py +9 -14
  182. ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +14 -19
  183. ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +40 -27
  184. ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +31 -18
  185. ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +1 -2
  186. ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +59 -71
  187. ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -2
  188. ansible_test/_util/target/cli/ansible_test_cli_stub.py +4 -2
  189. ansible_test/_util/target/common/constants.py +2 -2
  190. ansible_test/_util/target/setup/bootstrap.sh +0 -6
  191. ansible/utils/py3compat.py +0 -27
  192. ansible_test/_data/pytest/config/legacy.ini +0 -4
  193. {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/WHEEL +0 -0
  194. {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/entry_points.txt +0 -0
  195. {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/licenses/COPYING +0 -0
  196. {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/licenses/licenses/Apache-License.txt +0 -0
  197. {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
  198. {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/licenses/licenses/MIT-license.txt +0 -0
  199. {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/licenses/licenses/PSF-license.txt +0 -0
  200. {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
  201. {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/top_level.txt +0 -0
@@ -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
- _T = t.TypeVar('_T')
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[_T], task_vars: dict[str, object]) -> _T | None:
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[_T_co]) -> None:
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) -> _T_co: ...
18
+ def __getitem__(self, index: int) -> T: ...
21
19
 
22
20
  @_t.overload
23
- def __getitem__(self, index: slice) -> _c.Sequence[_T_co]: ...
21
+ def __getitem__(self, index: slice) -> _c.Sequence[T]: ...
24
22
 
25
- def __getitem__(self, index: int | slice) -> _T_co | _c.Sequence[_T_co]:
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[_T_co]:
35
+ def __iter__(self) -> _t.Iterator[T]:
38
36
  yield from self.__value
39
37
 
40
- def __reversed__(self) -> _c.Iterator[_T_co]:
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: _T) -> _T:
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: _T) -> _T:
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: _T
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: _TCallable) -> _TCallable:
176
+ def mark[T: t.Callable](cls, src: T) -> T:
178
177
  setattr(src, cls._marker_attr, True)
179
178
  return src
180
179
 
@@ -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.15.0/src/wrapt/wrappers.py
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.15.0"}
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 __reduce_ex__()')
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='function', parent=None):
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
- # bound derived wrapper classes. It should possibly be broken up
544
- # and the distinct functionality moved into the derived classes.
545
- # Can't do that straight away due to some legacy code which is
546
- # relying on it being here in this base class.
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
- # being called in an unbound or bound wrapper is the parent
550
- # attribute. If binding has never occurred, then the parent will
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
- # this case we perform the binding.
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 one special case to worry about here. This is where we
557
- # are decorating a nested class. In this case the wrapped class
558
- # would not have a __get__() method to call. In that case we
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
- # None and accessing an unbound instance method from a class.
563
- # This is because we need to be able to later detect that
564
- # specific case as we will need to extract the instance from the
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
- if not inspect.isclass(self.__wrapped__):
569
- descriptor = self.__wrapped__.__get__(instance, owner)
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
- return self.__bound_function_wrapper__(descriptor, instance,
572
- self._self_wrapper, self._self_enabled,
573
- self._self_binding, self)
575
+ if self._self_binding == "class":
576
+ return self
574
577
 
575
- return self
578
+ binder = getattr(self.__wrapped__, '__get__', None)
576
579
 
577
- # Now we have the case of binding occurring a second time on what
578
- # was already a bound function. In this case we would usually
579
- # return ourselves again. This mirrors what Python does.
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
- # with an instance of None and we were likely an instance
583
- # method. In that case we rebind against the original wrapped
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 == 'function':
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
- # and if the wrapper is not to be executed, then simply return
673
- # the bound function rather than a bound wrapper for the bound
674
- # function. When evaluating enabled, if it is callable we call
675
- # it, otherwise we evaluate it as a boolean.
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
- # likely wrapping an instance method vs a static method or class
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
- # as the first argument. We need to shift the args before
693
- # making the call to the wrapper and effectively bind the
694
- # instance to the wrapped function using a partial so the
695
- # wrapper doesn't see anything as being different.
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 'function'. If it was already bound and
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 an cope with the possibility that the 'self'
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
- if isinstance(wrapped, classmethod):
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
- self._self_instance = weakref.ref(wrapped._self_instance,
1007
- _callback)
826
+ binding = wrapped._self_binding
1008
827
 
1009
- if wrapped._self_parent is not None:
1010
- super(WeakFunctionProxy, self).__init__(
1011
- weakref.proxy(wrapped._self_parent, _callback))
828
+ if not binding:
829
+ if inspect.isbuiltin(wrapped):
830
+ binding = 'builtin'
1012
831
 
1013
- else:
1014
- super(WeakFunctionProxy, self).__init__(
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
- self, args = _unpack_self(*args)
835
+ elif inspect.isclass(wrapped):
836
+ binding = 'class'
1036
837
 
1037
- # We perform a boolean check here on the instance and wrapped
1038
- # function as that will trigger the reference error prior to
1039
- # calling if the reference had expired.
838
+ elif isinstance(wrapped, classmethod):
839
+ binding = 'classmethod'
1040
840
 
1041
- instance = self._self_instance and self._self_instance()
1042
- function = self.__wrapped__ and self.__wrapped__
841
+ elif isinstance(wrapped, staticmethod):
842
+ binding = 'staticmethod'
1043
843
 
1044
- # If the wrapped function was originally a bound function, for
1045
- # which we retained a reference to the instance and the unbound
1046
- # function we need to rebind the function and then call it. If
1047
- # not just called the wrapped function.
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
- if instance is None:
1050
- return self.__wrapped__(*args, **kwargs)
852
+ else:
853
+ binding = 'callable'
1051
854
 
1052
- return function.__get__(instance, type(instance))(*args, **kwargs)
855
+ super(FunctionWrapper, self).__init__(wrapped, None, wrapper,
856
+ enabled, binding)