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 target modules were registered in the same entry point list. Only the
callback for the last would be called regardless of the target module. 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** **Features Changed**
* The ``register_post_import_hook()`` function, modelled after the * The ``register_post_import_hook()`` function, modelled after the

View File

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

View File

@@ -855,6 +855,20 @@ class WeakFunctionProxy(ObjectProxy):
self._self_expired = False 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: try:
self._self_instance = weakref.ref(wrapped.__self__, _callback) 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(len(result), 1)
self.assertEqual(id(proxy), result[0]) 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__': if __name__ == '__main__':
unittest.main() unittest.main()