Add weakref support for C implementation of function wrapper.

This commit is contained in:
Graham Dumpleton
2015-06-21 22:21:03 +10:00
parent 5461cd070d
commit b9feaf5e43
4 changed files with 46 additions and 5 deletions

View File

@@ -10,6 +10,10 @@ Version 1.10.5
target modules were registered in the same entry point list. Only the
callback for the last would be called regardless of the target module.
* If a ``WeakFunctionProxy`` wrapper was used around a method of a class
which was decorated using a wrapt decorator, the decorator wasn't being
invoked when the method was called via the weakref proxy.
**Features Changed**
* The ``register_post_import_hook()`` function, modelled after the

View File

@@ -15,6 +15,7 @@ typedef struct {
PyObject *dict;
PyObject *wrapped;
PyObject *weakreflist;
} WraptObjectProxyObject;
PyTypeObject WraptObjectProxy_Type;
@@ -48,6 +49,7 @@ static PyObject *WraptObjectProxy_new(PyTypeObject *type,
self->dict = PyDict_New();
self->wrapped = NULL;
self->weakreflist = NULL;
return (PyObject *)self;
}
@@ -153,6 +155,9 @@ static void WraptObjectProxy_dealloc(WraptObjectProxyObject *self)
{
PyObject_GC_UnTrack(self);
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *)self);
WraptObjectProxy_clear(self);
Py_TYPE(self)->tp_free(self);
@@ -1683,7 +1688,7 @@ PyTypeObject WraptObjectProxy_Type = {
(traverseproc)WraptObjectProxy_traverse, /*tp_traverse*/
(inquiry)WraptObjectProxy_clear, /*tp_clear*/
(richcmpfunc)WraptObjectProxy_richcompare, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
offsetof(WraptObjectProxyObject, weakreflist), /*tp_weaklistoffset*/
(getiterfunc)WraptObjectProxy_iter, /*tp_iter*/
0, /*tp_iternext*/
WraptObjectProxy_methods, /*tp_methods*/
@@ -1754,7 +1759,7 @@ PyTypeObject WraptCallableObjectProxy_Type = {
0, /*tp_traverse*/
0, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
offsetof(WraptObjectProxyObject, weakreflist), /*tp_weaklistoffset*/
0, /*tp_iter*/
0, /*tp_iternext*/
0, /*tp_methods*/
@@ -2249,7 +2254,7 @@ PyTypeObject WraptFunctionWrapperBase_Type = {
(traverseproc)WraptFunctionWrapperBase_traverse, /*tp_traverse*/
(inquiry)WraptFunctionWrapperBase_clear, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
offsetof(WraptObjectProxyObject, weakreflist), /*tp_weaklistoffset*/
0, /*tp_iter*/
0, /*tp_iternext*/
0, /*tp_methods*/
@@ -2482,7 +2487,7 @@ PyTypeObject WraptBoundFunctionWrapper_Type = {
0, /*tp_traverse*/
0, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
offsetof(WraptObjectProxyObject, weakreflist), /*tp_weaklistoffset*/
0, /*tp_iter*/
0, /*tp_iternext*/
0, /*tp_methods*/
@@ -2622,7 +2627,7 @@ PyTypeObject WraptFunctionWrapper_Type = {
0, /*tp_traverse*/
0, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
offsetof(WraptObjectProxyObject, weakreflist), /*tp_weaklistoffset*/
0, /*tp_iter*/
0, /*tp_iternext*/
0, /*tp_methods*/

View File

@@ -855,6 +855,20 @@ class WeakFunctionProxy(ObjectProxy):
self._self_expired = False
if isinstance(wrapped, _FunctionWrapperBase):
self._self_instance = weakref.ref(wrapped._self_instance,
_callback)
if wrapped._self_parent is not None:
super(WeakFunctionProxy, self).__init__(
weakref.proxy(wrapped._self_parent, _callback))
else:
super(WeakFunctionProxy, self).__init__(
weakref.proxy(wrapped, _callback))
return
try:
self._self_instance = weakref.ref(wrapped.__self__, _callback)

View File

@@ -172,5 +172,23 @@ class TestWeakFunctionProxy(unittest.TestCase):
self.assertEqual(len(result), 1)
self.assertEqual(id(proxy), result[0])
def test_decorator_method(self):
@wrapt.decorator
def bark(wrapped, instance, args, kwargs):
return 'bark'
class Animal(object):
@bark
def squeal(self):
return 'squeal'
animal = Animal()
self.assertEqual(animal.squeal(), 'bark')
method = wrapt.WeakFunctionProxy(animal.squeal)
self.assertEqual(method(), 'bark')
if __name__ == '__main__':
unittest.main()