wrapt 2.0.1rc1__cp38-cp38-macosx_10_9_universal2.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 wrapt might be problematic. Click here for more details.
- wrapt/__init__.py +64 -0
- wrapt/__init__.pyi +319 -0
- wrapt/__wrapt__.py +44 -0
- wrapt/_wrappers.c +4097 -0
- wrapt/_wrappers.cpython-38-darwin.so +0 -0
- wrapt/arguments.py +59 -0
- wrapt/decorators.py +522 -0
- wrapt/importer.py +332 -0
- wrapt/patches.py +239 -0
- wrapt/proxies.py +351 -0
- wrapt/py.typed +1 -0
- wrapt/weakrefs.py +114 -0
- wrapt/wrappers.py +980 -0
- wrapt-2.0.1rc1.dist-info/LICENSE +24 -0
- wrapt-2.0.1rc1.dist-info/METADATA +215 -0
- wrapt-2.0.1rc1.dist-info/RECORD +18 -0
- wrapt-2.0.1rc1.dist-info/WHEEL +5 -0
- wrapt-2.0.1rc1.dist-info/top_level.txt +1 -0
wrapt/proxies.py
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
"""Variants of ObjectProxy for different use cases."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
from types import ModuleType
|
|
5
|
+
|
|
6
|
+
from .__wrapt__ import BaseObjectProxy
|
|
7
|
+
from .decorators import synchronized
|
|
8
|
+
|
|
9
|
+
# Define ObjectProxy which for compatibility adds `__iter__()` support which
|
|
10
|
+
# has been removed from `BaseObjectProxy`.
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ObjectProxy(BaseObjectProxy):
|
|
14
|
+
"""A generic object proxy which forwards special methods as needed.
|
|
15
|
+
For backwards compatibility this class adds support for `__iter__()`. If
|
|
16
|
+
you don't need backward compatibility for `__iter__()` support then it is
|
|
17
|
+
preferable to use `BaseObjectProxy` directly. If you want automatic
|
|
18
|
+
support for special dunder methods for callables, iterators, and async,
|
|
19
|
+
then use `AutoObjectProxy`."""
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def __object_proxy__(self):
|
|
23
|
+
return ObjectProxy
|
|
24
|
+
|
|
25
|
+
def __new__(cls, *args, **kwargs):
|
|
26
|
+
return super().__new__(cls)
|
|
27
|
+
|
|
28
|
+
def __iter__(self):
|
|
29
|
+
return iter(self.__wrapped__)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# Define variant of ObjectProxy which can automatically adjust to the wrapped
|
|
33
|
+
# object and add special dunder methods.
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def __wrapper_call__(*args, **kwargs):
|
|
37
|
+
def _unpack_self(self, *args):
|
|
38
|
+
return self, args
|
|
39
|
+
|
|
40
|
+
self, args = _unpack_self(*args)
|
|
41
|
+
|
|
42
|
+
return self.__wrapped__(*args, **kwargs)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def __wrapper_iter__(self):
|
|
46
|
+
return iter(self.__wrapped__)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def __wrapper_next__(self):
|
|
50
|
+
return self.__wrapped__.__next__()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def __wrapper_aiter__(self):
|
|
54
|
+
return self.__wrapped__.__aiter__()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
async def __wrapper_anext__(self):
|
|
58
|
+
return await self.__wrapped__.__anext__()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def __wrapper_length_hint__(self):
|
|
62
|
+
return self.__wrapped__.__length_hint__()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def __wrapper_await__(self):
|
|
66
|
+
return (yield from self.__wrapped__.__await__())
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def __wrapper_get__(self, instance, owner):
|
|
70
|
+
return self.__wrapped__.__get__(instance, owner)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def __wrapper_set__(self, instance, value):
|
|
74
|
+
return self.__wrapped__.__set__(instance, value)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def __wrapper_delete__(self, instance):
|
|
78
|
+
return self.__wrapped__.__delete__(instance)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def __wrapper_set_name__(self, owner, name):
|
|
82
|
+
return self.__wrapped__.__set_name__(owner, name)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class AutoObjectProxy(BaseObjectProxy):
|
|
86
|
+
"""An object proxy which can automatically adjust to the wrapped object
|
|
87
|
+
and add special dunder methods as needed. Note that this creates a new
|
|
88
|
+
class for each instance, so it has much higher memory overhead than using
|
|
89
|
+
`BaseObjectProxy` directly. If you know what special dunder methods you need
|
|
90
|
+
then it is preferable to use `BaseObjectProxy` directly and add them to a
|
|
91
|
+
subclass as needed. If you only need `__iter__()` support for backwards
|
|
92
|
+
compatibility then use `ObjectProxy` instead.
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
def __new__(cls, wrapped):
|
|
96
|
+
"""Injects special dunder methods into a dynamically created subclass
|
|
97
|
+
as needed based on the wrapped object.
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
namespace = {}
|
|
101
|
+
|
|
102
|
+
wrapped_attrs = dir(wrapped)
|
|
103
|
+
class_attrs = set(dir(cls))
|
|
104
|
+
|
|
105
|
+
if callable(wrapped) and "__call__" not in class_attrs:
|
|
106
|
+
namespace["__call__"] = __wrapper_call__
|
|
107
|
+
|
|
108
|
+
if "__iter__" in wrapped_attrs and "__iter__" not in class_attrs:
|
|
109
|
+
namespace["__iter__"] = __wrapper_iter__
|
|
110
|
+
|
|
111
|
+
if "__next__" in wrapped_attrs and "__next__" not in class_attrs:
|
|
112
|
+
namespace["__next__"] = __wrapper_next__
|
|
113
|
+
|
|
114
|
+
if "__aiter__" in wrapped_attrs and "__aiter__" not in class_attrs:
|
|
115
|
+
namespace["__aiter__"] = __wrapper_aiter__
|
|
116
|
+
|
|
117
|
+
if "__anext__" in wrapped_attrs and "__anext__" not in class_attrs:
|
|
118
|
+
namespace["__anext__"] = __wrapper_anext__
|
|
119
|
+
|
|
120
|
+
if "__length_hint__" in wrapped_attrs and "__length_hint__" not in class_attrs:
|
|
121
|
+
namespace["__length_hint__"] = __wrapper_length_hint__
|
|
122
|
+
|
|
123
|
+
# Note that not providing compatibility with generator-based coroutines
|
|
124
|
+
# (PEP 342) here as they are removed in Python 3.11+ and were deprecated
|
|
125
|
+
# in 3.8.
|
|
126
|
+
|
|
127
|
+
if "__await__" in wrapped_attrs and "__await__" not in class_attrs:
|
|
128
|
+
namespace["__await__"] = __wrapper_await__
|
|
129
|
+
|
|
130
|
+
if "__get__" in wrapped_attrs and "__get__" not in class_attrs:
|
|
131
|
+
namespace["__get__"] = __wrapper_get__
|
|
132
|
+
|
|
133
|
+
if "__set__" in wrapped_attrs and "__set__" not in class_attrs:
|
|
134
|
+
namespace["__set__"] = __wrapper_set__
|
|
135
|
+
|
|
136
|
+
if "__delete__" in wrapped_attrs and "__delete__" not in class_attrs:
|
|
137
|
+
namespace["__delete__"] = __wrapper_delete__
|
|
138
|
+
|
|
139
|
+
if "__set_name__" in wrapped_attrs and "__set_name__" not in class_attrs:
|
|
140
|
+
namespace["__set_name__"] = __wrapper_set_name__
|
|
141
|
+
|
|
142
|
+
name = cls.__name__
|
|
143
|
+
|
|
144
|
+
if cls is AutoObjectProxy:
|
|
145
|
+
name = BaseObjectProxy.__name__
|
|
146
|
+
|
|
147
|
+
return super(AutoObjectProxy, cls).__new__(type(name, (cls,), namespace))
|
|
148
|
+
|
|
149
|
+
def __wrapped_setattr_fixups__(self):
|
|
150
|
+
"""Adjusts special dunder methods on the class as needed based on the
|
|
151
|
+
wrapped object, when `__wrapped__` is changed.
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
cls = type(self)
|
|
155
|
+
class_attrs = set(dir(cls))
|
|
156
|
+
|
|
157
|
+
if callable(self.__wrapped__):
|
|
158
|
+
if "__call__" not in class_attrs:
|
|
159
|
+
cls.__call__ = __wrapper_call__
|
|
160
|
+
elif getattr(cls, "__call__", None) is __wrapper_call__:
|
|
161
|
+
delattr(cls, "__call__")
|
|
162
|
+
|
|
163
|
+
if hasattr(self.__wrapped__, "__iter__"):
|
|
164
|
+
if "__iter__" not in class_attrs:
|
|
165
|
+
cls.__iter__ = __wrapper_iter__
|
|
166
|
+
elif getattr(cls, "__iter__", None) is __wrapper_iter__:
|
|
167
|
+
delattr(cls, "__iter__")
|
|
168
|
+
|
|
169
|
+
if hasattr(self.__wrapped__, "__next__"):
|
|
170
|
+
if "__next__" not in class_attrs:
|
|
171
|
+
cls.__next__ = __wrapper_next__
|
|
172
|
+
elif getattr(cls, "__next__", None) is __wrapper_next__:
|
|
173
|
+
delattr(cls, "__next__")
|
|
174
|
+
|
|
175
|
+
if hasattr(self.__wrapped__, "__aiter__"):
|
|
176
|
+
if "__aiter__" not in class_attrs:
|
|
177
|
+
cls.__aiter__ = __wrapper_aiter__
|
|
178
|
+
elif getattr(cls, "__aiter__", None) is __wrapper_aiter__:
|
|
179
|
+
delattr(cls, "__aiter__")
|
|
180
|
+
|
|
181
|
+
if hasattr(self.__wrapped__, "__anext__"):
|
|
182
|
+
if "__anext__" not in class_attrs:
|
|
183
|
+
cls.__anext__ = __wrapper_anext__
|
|
184
|
+
elif getattr(cls, "__anext__", None) is __wrapper_anext__:
|
|
185
|
+
delattr(cls, "__anext__")
|
|
186
|
+
|
|
187
|
+
if hasattr(self.__wrapped__, "__length_hint__"):
|
|
188
|
+
if "__length_hint__" not in class_attrs:
|
|
189
|
+
cls.__length_hint__ = __wrapper_length_hint__
|
|
190
|
+
elif getattr(cls, "__length_hint__", None) is __wrapper_length_hint__:
|
|
191
|
+
delattr(cls, "__length_hint__")
|
|
192
|
+
|
|
193
|
+
if hasattr(self.__wrapped__, "__await__"):
|
|
194
|
+
if "__await__" not in class_attrs:
|
|
195
|
+
cls.__await__ = __wrapper_await__
|
|
196
|
+
elif getattr(cls, "__await__", None) is __wrapper_await__:
|
|
197
|
+
delattr(cls, "__await__")
|
|
198
|
+
|
|
199
|
+
if hasattr(self.__wrapped__, "__get__"):
|
|
200
|
+
if "__get__" not in class_attrs:
|
|
201
|
+
cls.__get__ = __wrapper_get__
|
|
202
|
+
elif getattr(cls, "__get__", None) is __wrapper_get__:
|
|
203
|
+
delattr(cls, "__get__")
|
|
204
|
+
|
|
205
|
+
if hasattr(self.__wrapped__, "__set__"):
|
|
206
|
+
if "__set__" not in class_attrs:
|
|
207
|
+
cls.__set__ = __wrapper_set__
|
|
208
|
+
elif getattr(cls, "__set__", None) is __wrapper_set__:
|
|
209
|
+
delattr(cls, "__set__")
|
|
210
|
+
|
|
211
|
+
if hasattr(self.__wrapped__, "__delete__"):
|
|
212
|
+
if "__delete__" not in class_attrs:
|
|
213
|
+
cls.__delete__ = __wrapper_delete__
|
|
214
|
+
elif getattr(cls, "__delete__", None) is __wrapper_delete__:
|
|
215
|
+
delattr(cls, "__delete__")
|
|
216
|
+
|
|
217
|
+
if hasattr(self.__wrapped__, "__set_name__"):
|
|
218
|
+
if "__set_name__" not in class_attrs:
|
|
219
|
+
cls.__set_name__ = __wrapper_set_name__
|
|
220
|
+
elif getattr(cls, "__set_name__", None) is __wrapper_set_name__:
|
|
221
|
+
delattr(cls, "__set_name__")
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
class LazyObjectProxy(AutoObjectProxy):
|
|
225
|
+
"""An object proxy which can generate/create the wrapped object on demand
|
|
226
|
+
when it is first needed.
|
|
227
|
+
"""
|
|
228
|
+
|
|
229
|
+
def __new__(cls, callback=None, *, interface=...):
|
|
230
|
+
"""Injects special dunder methods into a dynamically created subclass
|
|
231
|
+
as needed based on the wrapped object.
|
|
232
|
+
"""
|
|
233
|
+
|
|
234
|
+
if interface is ...:
|
|
235
|
+
interface = type(None)
|
|
236
|
+
|
|
237
|
+
namespace = {}
|
|
238
|
+
|
|
239
|
+
interface_attrs = dir(interface)
|
|
240
|
+
class_attrs = set(dir(cls))
|
|
241
|
+
|
|
242
|
+
if "__call__" in interface_attrs and "__call__" not in class_attrs:
|
|
243
|
+
namespace["__call__"] = __wrapper_call__
|
|
244
|
+
|
|
245
|
+
if "__iter__" in interface_attrs and "__iter__" not in class_attrs:
|
|
246
|
+
namespace["__iter__"] = __wrapper_iter__
|
|
247
|
+
|
|
248
|
+
if "__next__" in interface_attrs and "__next__" not in class_attrs:
|
|
249
|
+
namespace["__next__"] = __wrapper_next__
|
|
250
|
+
|
|
251
|
+
if "__aiter__" in interface_attrs and "__aiter__" not in class_attrs:
|
|
252
|
+
namespace["__aiter__"] = __wrapper_aiter__
|
|
253
|
+
|
|
254
|
+
if "__anext__" in interface_attrs and "__anext__" not in class_attrs:
|
|
255
|
+
namespace["__anext__"] = __wrapper_anext__
|
|
256
|
+
|
|
257
|
+
if (
|
|
258
|
+
"__length_hint__" in interface_attrs
|
|
259
|
+
and "__length_hint__" not in class_attrs
|
|
260
|
+
):
|
|
261
|
+
namespace["__length_hint__"] = __wrapper_length_hint__
|
|
262
|
+
|
|
263
|
+
# Note that not providing compatibility with generator-based coroutines
|
|
264
|
+
# (PEP 342) here as they are removed in Python 3.11+ and were deprecated
|
|
265
|
+
# in 3.8.
|
|
266
|
+
|
|
267
|
+
if "__await__" in interface_attrs and "__await__" not in class_attrs:
|
|
268
|
+
namespace["__await__"] = __wrapper_await__
|
|
269
|
+
|
|
270
|
+
if "__get__" in interface_attrs and "__get__" not in class_attrs:
|
|
271
|
+
namespace["__get__"] = __wrapper_get__
|
|
272
|
+
|
|
273
|
+
if "__set__" in interface_attrs and "__set__" not in class_attrs:
|
|
274
|
+
namespace["__set__"] = __wrapper_set__
|
|
275
|
+
|
|
276
|
+
if "__delete__" in interface_attrs and "__delete__" not in class_attrs:
|
|
277
|
+
namespace["__delete__"] = __wrapper_delete__
|
|
278
|
+
|
|
279
|
+
if "__set_name__" in interface_attrs and "__set_name__" not in class_attrs:
|
|
280
|
+
namespace["__set_name__"] = __wrapper_set_name__
|
|
281
|
+
|
|
282
|
+
name = cls.__name__
|
|
283
|
+
|
|
284
|
+
return super(AutoObjectProxy, cls).__new__(type(name, (cls,), namespace))
|
|
285
|
+
|
|
286
|
+
def __init__(self, callback=None, *, interface=...):
|
|
287
|
+
"""Initialize the object proxy with wrapped object as `None` but due
|
|
288
|
+
to presence of special `__wrapped_factory__` attribute addded first,
|
|
289
|
+
this will actually trigger the deferred creation of the wrapped object
|
|
290
|
+
when first needed.
|
|
291
|
+
"""
|
|
292
|
+
|
|
293
|
+
if callback is not None:
|
|
294
|
+
self.__wrapped_factory__ = callback
|
|
295
|
+
|
|
296
|
+
super().__init__(None)
|
|
297
|
+
|
|
298
|
+
__wrapped_initialized__ = False
|
|
299
|
+
|
|
300
|
+
def __wrapped_factory__(self):
|
|
301
|
+
return None
|
|
302
|
+
|
|
303
|
+
def __wrapped_get__(self):
|
|
304
|
+
"""Gets the wrapped object, creating it if necessary."""
|
|
305
|
+
|
|
306
|
+
# We synchronize on the class type, which will be unique to this instance
|
|
307
|
+
# since we inherit from `AutoObjectProxy` which creates a new class
|
|
308
|
+
# for each instance. If we synchronize on `self` or the method then
|
|
309
|
+
# we can end up in infinite recursion via `__getattr__()`.
|
|
310
|
+
|
|
311
|
+
with synchronized(type(self)):
|
|
312
|
+
# We were called because `__wrapped__` was not set, but because of
|
|
313
|
+
# multiple threads we may find that it has been set by the time
|
|
314
|
+
# we get the lock. So check again now whether `__wrapped__` is set.
|
|
315
|
+
# If it is then just return it, otherwise call the factory to
|
|
316
|
+
# create it.
|
|
317
|
+
|
|
318
|
+
if self.__wrapped_initialized__:
|
|
319
|
+
return self.__wrapped__
|
|
320
|
+
|
|
321
|
+
self.__wrapped__ = self.__wrapped_factory__()
|
|
322
|
+
|
|
323
|
+
self.__wrapped_initialized__ = True
|
|
324
|
+
|
|
325
|
+
return self.__wrapped__
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def lazy_import(name, attribute=None, *, interface=...):
|
|
329
|
+
"""Lazily imports the module `name`, returning a `LazyObjectProxy` which
|
|
330
|
+
will import the module when it is first needed. When `name is a dotted name,
|
|
331
|
+
then the full dotted name is imported and the last module is taken as the
|
|
332
|
+
target. If `attribute` is provided then it is used to retrieve an attribute
|
|
333
|
+
from the module.
|
|
334
|
+
"""
|
|
335
|
+
|
|
336
|
+
if attribute is not None:
|
|
337
|
+
if interface is ...:
|
|
338
|
+
interface = Callable
|
|
339
|
+
else:
|
|
340
|
+
if interface is ...:
|
|
341
|
+
interface = ModuleType
|
|
342
|
+
|
|
343
|
+
def _import():
|
|
344
|
+
module = __import__(name, fromlist=[""])
|
|
345
|
+
|
|
346
|
+
if attribute is not None:
|
|
347
|
+
return getattr(module, attribute)
|
|
348
|
+
|
|
349
|
+
return module
|
|
350
|
+
|
|
351
|
+
return LazyObjectProxy(_import, interface=interface)
|
wrapt/py.typed
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
partial
|
wrapt/weakrefs.py
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import weakref
|
|
3
|
+
|
|
4
|
+
from .__wrapt__ import BaseObjectProxy, _FunctionWrapperBase
|
|
5
|
+
|
|
6
|
+
# A weak function proxy. This will work on instance methods, class
|
|
7
|
+
# methods, static methods and regular functions. Special treatment is
|
|
8
|
+
# needed for the method types because the bound method is effectively a
|
|
9
|
+
# transient object and applying a weak reference to one will immediately
|
|
10
|
+
# result in it being destroyed and the weakref callback called. The weak
|
|
11
|
+
# reference is therefore applied to the instance the method is bound to
|
|
12
|
+
# and the original function. The function is then rebound at the point
|
|
13
|
+
# of a call via the weak function proxy.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _weak_function_proxy_callback(ref, proxy, callback):
|
|
17
|
+
if proxy._self_expired:
|
|
18
|
+
return
|
|
19
|
+
|
|
20
|
+
proxy._self_expired = True
|
|
21
|
+
|
|
22
|
+
# This could raise an exception. We let it propagate back and let
|
|
23
|
+
# the weakref.proxy() deal with it, at which point it generally
|
|
24
|
+
# prints out a short error message direct to stderr and keeps going.
|
|
25
|
+
|
|
26
|
+
if callback is not None:
|
|
27
|
+
callback(proxy)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class WeakFunctionProxy(BaseObjectProxy):
|
|
31
|
+
"""A weak function proxy."""
|
|
32
|
+
|
|
33
|
+
__slots__ = ("_self_expired", "_self_instance")
|
|
34
|
+
|
|
35
|
+
def __init__(self, wrapped, callback=None):
|
|
36
|
+
"""Create a proxy to object which uses a weak reference. This is
|
|
37
|
+
similar to the `weakref.proxy` but is designed to work with functions
|
|
38
|
+
and methods. It will automatically rebind the function to the instance
|
|
39
|
+
when called if the function was originally a bound method. This is
|
|
40
|
+
necessary because bound methods are transient objects and applying a
|
|
41
|
+
weak reference to one will immediately result in it being destroyed
|
|
42
|
+
and the weakref callback called. The weak reference is therefore
|
|
43
|
+
applied to the instance the method is bound to and the original
|
|
44
|
+
function. The function is then rebound at the point of a call via the
|
|
45
|
+
weak function proxy.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
# We need to determine if the wrapped function is actually a
|
|
49
|
+
# bound method. In the case of a bound method, we need to keep a
|
|
50
|
+
# reference to the original unbound function and the instance.
|
|
51
|
+
# This is necessary because if we hold a reference to the bound
|
|
52
|
+
# function, it will be the only reference and given it is a
|
|
53
|
+
# temporary object, it will almost immediately expire and
|
|
54
|
+
# the weakref callback triggered. So what is done is that we
|
|
55
|
+
# hold a reference to the instance and unbound function and
|
|
56
|
+
# when called bind the function to the instance once again and
|
|
57
|
+
# then call it. Note that we avoid using a nested function for
|
|
58
|
+
# the callback here so as not to cause any odd reference cycles.
|
|
59
|
+
|
|
60
|
+
_callback = callback and functools.partial(
|
|
61
|
+
_weak_function_proxy_callback, proxy=self, callback=callback
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
self._self_expired = False
|
|
65
|
+
|
|
66
|
+
if isinstance(wrapped, _FunctionWrapperBase):
|
|
67
|
+
self._self_instance = weakref.ref(wrapped._self_instance, _callback)
|
|
68
|
+
|
|
69
|
+
if wrapped._self_parent is not None:
|
|
70
|
+
super(WeakFunctionProxy, self).__init__(
|
|
71
|
+
weakref.proxy(wrapped._self_parent, _callback)
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
else:
|
|
75
|
+
super(WeakFunctionProxy, self).__init__(
|
|
76
|
+
weakref.proxy(wrapped, _callback)
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
return
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
self._self_instance = weakref.ref(wrapped.__self__, _callback)
|
|
83
|
+
|
|
84
|
+
super(WeakFunctionProxy, self).__init__(
|
|
85
|
+
weakref.proxy(wrapped.__func__, _callback)
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
except AttributeError:
|
|
89
|
+
self._self_instance = None
|
|
90
|
+
|
|
91
|
+
super(WeakFunctionProxy, self).__init__(weakref.proxy(wrapped, _callback))
|
|
92
|
+
|
|
93
|
+
def __call__(*args, **kwargs):
|
|
94
|
+
def _unpack_self(self, *args):
|
|
95
|
+
return self, args
|
|
96
|
+
|
|
97
|
+
self, args = _unpack_self(*args)
|
|
98
|
+
|
|
99
|
+
# We perform a boolean check here on the instance and wrapped
|
|
100
|
+
# function as that will trigger the reference error prior to
|
|
101
|
+
# calling if the reference had expired.
|
|
102
|
+
|
|
103
|
+
instance = self._self_instance and self._self_instance()
|
|
104
|
+
function = self.__wrapped__ and self.__wrapped__
|
|
105
|
+
|
|
106
|
+
# If the wrapped function was originally a bound function, for
|
|
107
|
+
# which we retained a reference to the instance and the unbound
|
|
108
|
+
# function we need to rebind the function and then call it. If
|
|
109
|
+
# not just called the wrapped function.
|
|
110
|
+
|
|
111
|
+
if instance is None:
|
|
112
|
+
return self.__wrapped__(*args, **kwargs)
|
|
113
|
+
|
|
114
|
+
return function.__get__(instance, type(instance))(*args, **kwargs)
|