diff --git a/docs/changes.rst b/docs/changes.rst index 33be045..9567bda 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -36,6 +36,9 @@ Version 1.2.0 ObjectProxy was being used. The derived class __getattr__() could also get ignored. +* Using inspect.getargspec() now works correctly on bound methods when an + adapter function can be provided to @decorator. + Version 1.1.3 ------------- diff --git a/src/_wrappers.c b/src/_wrappers.c index 9b6a026..778b8ec 100644 --- a/src/_wrappers.c +++ b/src/_wrappers.c @@ -24,7 +24,6 @@ typedef struct { PyObject *instance; PyObject *wrapper; - PyObject *adapter; PyObject *enabled; PyObject *binding; PyObject *parent; @@ -57,10 +56,55 @@ static PyObject *WraptObjectProxy_new(PyTypeObject *type, static int WraptObjectProxy_raw_init(WraptObjectProxyObject *self, PyObject *wrapped) { + static PyObject *module_str = NULL; + static PyObject *doc_str = NULL; + + PyObject *object = NULL; + Py_INCREF(wrapped); Py_XDECREF(self->wrapped); self->wrapped = wrapped; + if (!module_str) { +#if PY_MAJOR_VERSION >= 3 + module_str = PyUnicode_InternFromString("__module__"); +#else + module_str = PyString_InternFromString("__module__"); +#endif + } + + if (!doc_str) { +#if PY_MAJOR_VERSION >= 3 + doc_str = PyUnicode_InternFromString("__doc__"); +#else + doc_str = PyString_InternFromString("__doc__"); +#endif + } + + object = PyObject_GetAttr(wrapped, module_str); + + if (object) { + if (PyDict_SetItem(self->dict, module_str, object) == -1) { + Py_DECREF(object); + return -1; + } + Py_DECREF(object); + } + else + PyErr_Clear(); + + object = PyObject_GetAttr(wrapped, doc_str); + + if (object) { + if (PyDict_SetItem(self->dict, doc_str, object) == -1) { + Py_DECREF(object); + return -1; + } + Py_DECREF(object); + } + else + PyErr_Clear(); + return 0; } @@ -116,7 +160,7 @@ static void WraptObjectProxy_dealloc(WraptObjectProxyObject *self) static PyObject *WraptObjectProxy_repr(WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -136,7 +180,7 @@ static PyObject *WraptObjectProxy_repr(WraptObjectProxyObject *self) static long WraptObjectProxy_hash(WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return -1; } @@ -149,7 +193,7 @@ static PyObject *WraptObjectProxy_call( WraptObjectProxyObject *self, PyObject *args, PyObject *kwds) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -161,7 +205,7 @@ static PyObject *WraptObjectProxy_call( static PyObject *WraptObjectProxy_str(WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -268,7 +312,7 @@ static PyObject *WraptObjectProxy_power(PyObject *o1, PyObject *o2, static PyObject *WraptObjectProxy_negative(WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -280,7 +324,7 @@ static PyObject *WraptObjectProxy_negative(WraptObjectProxyObject *self) static PyObject *WraptObjectProxy_positive(WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -292,7 +336,7 @@ static PyObject *WraptObjectProxy_positive(WraptObjectProxyObject *self) static PyObject *WraptObjectProxy_absolute(WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -304,7 +348,7 @@ static PyObject *WraptObjectProxy_absolute(WraptObjectProxyObject *self) static int WraptObjectProxy_bool(WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return -1; } @@ -316,7 +360,7 @@ static int WraptObjectProxy_bool(WraptObjectProxyObject *self) static PyObject *WraptObjectProxy_invert(WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -394,7 +438,7 @@ static PyObject *WraptObjectProxy_or(PyObject *o1, PyObject *o2) static PyObject *WraptObjectProxy_int(WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -407,7 +451,7 @@ static PyObject *WraptObjectProxy_int(WraptObjectProxyObject *self) static PyObject *WraptObjectProxy_long(WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -419,7 +463,7 @@ static PyObject *WraptObjectProxy_long(WraptObjectProxyObject *self) static PyObject *WraptObjectProxy_float(WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -434,7 +478,7 @@ static PyObject *WraptObjectProxy_oct(WraptObjectProxyObject *self) PyNumberMethods *nb; if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -457,7 +501,7 @@ static PyObject *WraptObjectProxy_hex(WraptObjectProxyObject *self) PyNumberMethods *nb; if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -480,7 +524,7 @@ static PyObject *WraptObjectProxy_inplace_add(WraptObjectProxyObject *self, PyObject *object = NULL; if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -507,7 +551,7 @@ static PyObject *WraptObjectProxy_inplace_subtract( PyObject *object = NULL; if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -534,7 +578,7 @@ static PyObject *WraptObjectProxy_inplace_multiply( PyObject *object = NULL; if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -562,7 +606,7 @@ static PyObject *WraptObjectProxy_inplace_divide( PyObject *object = NULL; if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -590,7 +634,7 @@ static PyObject *WraptObjectProxy_inplace_remainder( PyObject *object = NULL; if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -617,7 +661,7 @@ static PyObject *WraptObjectProxy_inplace_power(WraptObjectProxyObject *self, PyObject *object = NULL; if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -644,7 +688,7 @@ static PyObject *WraptObjectProxy_inplace_lshift(WraptObjectProxyObject *self, PyObject *object = NULL; if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -671,7 +715,7 @@ static PyObject *WraptObjectProxy_inplace_rshift(WraptObjectProxyObject *self, PyObject *object = NULL; if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -698,7 +742,7 @@ static PyObject *WraptObjectProxy_inplace_and(WraptObjectProxyObject *self, PyObject *object = NULL; if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -725,7 +769,7 @@ static PyObject *WraptObjectProxy_inplace_xor(WraptObjectProxyObject *self, PyObject *object = NULL; if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -752,7 +796,7 @@ static PyObject *WraptObjectProxy_inplace_or(WraptObjectProxyObject *self, PyObject *object = NULL; if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -802,7 +846,7 @@ static PyObject *WraptObjectProxy_inplace_floor_divide( PyObject *object = NULL; if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -829,7 +873,7 @@ static PyObject *WraptObjectProxy_inplace_true_divide( PyObject *object = NULL; if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -853,7 +897,7 @@ static PyObject *WraptObjectProxy_inplace_true_divide( static PyObject *WraptObjectProxy_index(WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -865,7 +909,7 @@ static PyObject *WraptObjectProxy_index(WraptObjectProxyObject *self) static Py_ssize_t WraptObjectProxy_length(WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return -1; } @@ -878,7 +922,7 @@ static int WraptObjectProxy_contains(WraptObjectProxyObject *self, PyObject *value) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return -1; } @@ -891,7 +935,7 @@ static PyObject *WraptObjectProxy_getitem(WraptObjectProxyObject *self, PyObject *key) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -904,7 +948,7 @@ static int WraptObjectProxy_setitem(WraptObjectProxyObject *self, PyObject *key, PyObject* value) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return -1; } @@ -920,7 +964,7 @@ static PyObject *WraptObjectProxy_dir( WraptObjectProxyObject *self, PyObject *args) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -936,7 +980,7 @@ static PyObject *WraptObjectProxy_enter( PyObject *result = NULL; if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -961,7 +1005,7 @@ static PyObject *WraptObjectProxy_exit( PyObject *result = NULL; if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -983,7 +1027,7 @@ static PyObject *WraptObjectProxy_get_name( WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -996,7 +1040,7 @@ static int WraptObjectProxy_set_name(WraptObjectProxyObject *self, PyObject *value) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return -1; } @@ -1009,7 +1053,7 @@ static PyObject *WraptObjectProxy_get_qualname( WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -1022,7 +1066,7 @@ static int WraptObjectProxy_set_qualname(WraptObjectProxyObject *self, PyObject *value) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return -1; } @@ -1035,7 +1079,7 @@ static PyObject *WraptObjectProxy_get_module( WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -1048,11 +1092,14 @@ static int WraptObjectProxy_set_module(WraptObjectProxyObject *self, PyObject *value) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return -1; } - return PyObject_SetAttrString(self->wrapped, "__module__", value); + if (PyObject_SetAttrString(self->wrapped, "__module__", value) == -1) + return -1; + + return PyDict_SetItemString(self->dict, "__module__", value); } /* ------------------------------------------------------------------------- */ @@ -1061,7 +1108,7 @@ static PyObject *WraptObjectProxy_get_doc( WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -1074,11 +1121,14 @@ static int WraptObjectProxy_set_doc(WraptObjectProxyObject *self, PyObject *value) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return -1; } - return PyObject_SetAttrString(self->wrapped, "__doc__", value); + if (PyObject_SetAttrString(self->wrapped, "__doc__", value) == -1) + return -1; + + return PyDict_SetItemString(self->dict, "__doc__", value); } /* ------------------------------------------------------------------------- */ @@ -1087,7 +1137,7 @@ static PyObject *WraptObjectProxy_get_class( WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -1100,7 +1150,7 @@ static PyObject *WraptObjectProxy_get_wrapped( WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -1114,7 +1164,7 @@ static int WraptObjectProxy_set_wrapped(WraptObjectProxyObject *self, PyObject *value) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return -1; } @@ -1137,7 +1187,7 @@ static PyObject *WraptObjectProxy_get_annotations( WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -1150,7 +1200,7 @@ static int WraptObjectProxy_set_annotations(WraptObjectProxyObject *self, PyObject *value) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return -1; } @@ -1210,7 +1260,7 @@ static PyObject *WraptObjectProxy_getattr( #endif if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -1273,7 +1323,7 @@ static int WraptObjectProxy_setattro( } if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return -1; } @@ -1286,7 +1336,7 @@ static PyObject *WraptObjectProxy_richcompare(WraptObjectProxyObject *self, PyObject *other, int opcode) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -1298,7 +1348,7 @@ static PyObject *WraptObjectProxy_richcompare(WraptObjectProxyObject *self, static PyObject *WraptObjectProxy_iter(WraptObjectProxyObject *self) { if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialized"); return NULL; } @@ -1473,7 +1523,6 @@ static PyObject *WraptFunctionWrapperBase_new(PyTypeObject *type, self->instance = NULL; self->wrapper = NULL; - self->adapter = NULL; self->enabled = NULL; self->binding = NULL; self->parent = NULL; @@ -1485,8 +1534,7 @@ static PyObject *WraptFunctionWrapperBase_new(PyTypeObject *type, static int WraptFunctionWrapperBase_raw_init(WraptFunctionWrapperObject *self, PyObject *wrapped, PyObject *instance, PyObject *wrapper, - PyObject *adapter, PyObject *enabled, PyObject *binding, - PyObject *parent) + PyObject *enabled, PyObject *binding, PyObject *parent) { int result = 0; @@ -1502,10 +1550,6 @@ static int WraptFunctionWrapperBase_raw_init(WraptFunctionWrapperObject *self, Py_XDECREF(self->wrapper); self->wrapper = wrapper; - Py_INCREF(adapter); - Py_XDECREF(self->adapter); - self->adapter = adapter; - Py_INCREF(enabled); Py_XDECREF(self->enabled); self->enabled = enabled; @@ -1530,22 +1574,21 @@ static int WraptFunctionWrapperBase_init(WraptFunctionWrapperObject *self, PyObject *wrapped = NULL; PyObject *instance = NULL; PyObject *wrapper = NULL; - PyObject *adapter = Py_None; PyObject *enabled = Py_None; PyObject *binding = Py_None; PyObject *parent = Py_None; static char *kwlist[] = { "wrapped", "instance", "wrapper", - "adapter", "enabled", "binding", "parent", NULL }; + "enabled", "binding", "parent", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwds, - "OOO|OOOO:FunctionWrapperBase", kwlist, &wrapped, &instance, - &wrapper, &adapter, &enabled, &binding, &parent)) { + "OOO|OOO:FunctionWrapperBase", kwlist, &wrapped, &instance, + &wrapper, &enabled, &binding, &parent)) { return -1; } return WraptFunctionWrapperBase_raw_init(self, wrapped, instance, wrapper, - adapter, enabled, binding, parent); + enabled, binding, parent); } /* ------------------------------------------------------------------------- */ @@ -1557,7 +1600,6 @@ static int WraptFunctionWrapperBase_traverse(WraptFunctionWrapperObject *self, Py_VISIT(self->instance); Py_VISIT(self->wrapper); - Py_VISIT(self->adapter); Py_VISIT(self->enabled); Py_VISIT(self->binding); Py_VISIT(self->parent); @@ -1573,7 +1615,6 @@ static int WraptFunctionWrapperBase_clear(WraptFunctionWrapperObject *self) Py_CLEAR(self->instance); Py_CLEAR(self->wrapper); - Py_CLEAR(self->adapter); Py_CLEAR(self->enabled); Py_CLEAR(self->binding); Py_CLEAR(self->parent); @@ -1708,7 +1749,7 @@ static PyObject *WraptFunctionWrapperBase_descr_get( if (descriptor) { result = PyObject_CallFunctionObjArgs(bound_type ? bound_type : (PyObject *)&WraptBoundFunctionWrapper_Type, descriptor, - obj, self->wrapper, self->adapter, Py_None, self->binding, + obj, self->wrapper, Py_None, self->binding, self, NULL); } @@ -1720,70 +1761,6 @@ static PyObject *WraptFunctionWrapperBase_descr_get( /* ------------------------------------------------------------------------- */ -static PyObject *WraptFunctionWrapperBase_get_code( - WraptFunctionWrapperObject *self) -{ - if (!self->object_proxy.wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); - return NULL; - } - - if (self->adapter != Py_None) - return PyObject_GetAttrString(self->adapter, "__code__"); - - return PyObject_GetAttrString(self->object_proxy.wrapped, "__code__"); -} - -/* ------------------------------------------------------------------------- */ - -static PyObject *WraptFunctionWrapperBase_get_defaults( - WraptFunctionWrapperObject *self) -{ - if (!self->object_proxy.wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); - return NULL; - } - - if (self->adapter != Py_None) - return PyObject_GetAttrString(self->adapter, "__defaults__"); - - return PyObject_GetAttrString(self->object_proxy.wrapped, "__defaults__"); -} - -/* ------------------------------------------------------------------------- */ - -static PyObject *WraptFunctionWrapperBase_get_kwdefaults( - WraptFunctionWrapperObject *self) -{ - if (!self->object_proxy.wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); - return NULL; - } - - if (self->adapter != Py_None) - return PyObject_GetAttrString(self->adapter, "__kwdefaults__"); - - return PyObject_GetAttrString(self->object_proxy.wrapped, "__kwdefaults__"); -} - -/* ------------------------------------------------------------------------- */ - -static PyObject *WraptFunctionWrapperBase_get_signature( - WraptFunctionWrapperObject *self) -{ - if (!self->object_proxy.wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); - return NULL; - } - - if (self->adapter != Py_None) - return PyObject_GetAttrString(self->adapter, "__signature__"); - - return PyObject_GetAttrString(self->object_proxy.wrapped, "__signature__"); -} - -/* ------------------------------------------------------------------------- */ - static PyObject *WraptFunctionWrapperBase_get_self_instance( WraptFunctionWrapperObject *self, void *closure) { @@ -1812,20 +1789,6 @@ static PyObject *WraptFunctionWrapperBase_get_self_wrapper( /* ------------------------------------------------------------------------- */ -static PyObject *WraptFunctionWrapperBase_get_self_adapter( - WraptFunctionWrapperObject *self, void *closure) -{ - if (!self->adapter) { - Py_INCREF(Py_None); - return Py_None; - } - - Py_INCREF(self->adapter); - return self->adapter; -} - -/* ------------------------------------------------------------------------- */ - static PyObject *WraptFunctionWrapperBase_get_self_enabled( WraptFunctionWrapperObject *self, void *closure) { @@ -1873,26 +1836,10 @@ static PyGetSetDef WraptFunctionWrapperBase_getset[] = { (setter)WraptObjectProxy_set_module, 0 }, { "__doc__", (getter)WraptObjectProxy_get_doc, (setter)WraptObjectProxy_set_doc, 0 }, - { "__code__", (getter)WraptFunctionWrapperBase_get_code, - NULL, 0 }, - { "__defaults__", (getter)WraptFunctionWrapperBase_get_defaults, - NULL, 0 }, - { "__kwdefaults__", (getter)WraptFunctionWrapperBase_get_kwdefaults, - NULL, 0 }, - { "__signature__", (getter)WraptFunctionWrapperBase_get_signature, - NULL, 0 }, -#if PY_MAJOR_VERSION < 3 - { "func_code", (getter)WraptFunctionWrapperBase_get_code, - NULL, 0 }, - { "func_defaults", (getter)WraptFunctionWrapperBase_get_defaults, - NULL, 0 }, -#endif { "_self_instance", (getter)WraptFunctionWrapperBase_get_self_instance, NULL, 0 }, { "_self_wrapper", (getter)WraptFunctionWrapperBase_get_self_wrapper, NULL, 0 }, - { "_self_adapter", (getter)WraptFunctionWrapperBase_get_self_adapter, - NULL, 0 }, { "_self_enabled", (getter)WraptFunctionWrapperBase_get_self_enabled, NULL, 0 }, { "_self_binding", (getter)WraptFunctionWrapperBase_get_self_binding, @@ -2157,7 +2104,6 @@ static int WraptFunctionWrapper_init(WraptFunctionWrapperObject *self, { PyObject *wrapped = NULL; PyObject *wrapper = NULL; - PyObject *adapter = Py_None; PyObject *enabled = Py_None; PyObject *binding = NULL; @@ -2167,10 +2113,10 @@ static int WraptFunctionWrapper_init(WraptFunctionWrapperObject *self, int result = 0; - static char *kwlist[] = { "wrapped", "wrapper", "adapter", "enabled", NULL }; + static char *kwlist[] = { "wrapped", "wrapper", "enabled", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO:FunctionWrapper", - kwlist, &wrapped, &wrapper, &adapter, &enabled)) { + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O:FunctionWrapper", + kwlist, &wrapped, &wrapper, &enabled)) { return -1; } @@ -2206,7 +2152,7 @@ static int WraptFunctionWrapper_init(WraptFunctionWrapperObject *self, binding = instancemethod_str; result = WraptFunctionWrapperBase_raw_init(self, wrapped, Py_None, - wrapper, adapter, enabled, binding, Py_None); + wrapper, enabled, binding, Py_None); return result; } diff --git a/src/decorators.py b/src/decorators.py index 7c4b3f6..fda3935 100644 --- a/src/decorators.py +++ b/src/decorators.py @@ -13,9 +13,9 @@ from threading import Lock, RLock if not six.PY2: from inspect import signature -from .wrappers import FunctionWrapper, ObjectProxy +from .wrappers import FunctionWrapper, BoundFunctionWrapper, ObjectProxy -# Object proxy for the wrapped function which will overlay certain +# Adapter wrapper for the wrapped function which will overlay certain # properties from the adapter function onto the wrapped function so that # functions such as inspect.getargspec(), inspect.getfullargspec(), # inspect.signature() and inspect.getsource() return the correct results @@ -47,10 +47,10 @@ class _AdapterFunctionCode(ObjectProxy): def co_varnames(self): return self._self_adapter_code.co_varnames -class _AdapterFunction(ObjectProxy): +class _AdapterFunctionSurrogate(ObjectProxy): def __init__(self, wrapped, adapter): - super(_AdapterFunction, self).__init__(wrapped) + super(_AdapterFunctionSurrogate, self).__init__(wrapped) self._self_adapter = adapter @property @@ -82,6 +82,47 @@ class _AdapterFunction(ObjectProxy): func_code = __code__ func_defaults = __defaults__ +class _BoundAdapterWrapper(BoundFunctionWrapper): + + @property + def __func__(self): + return _AdapterFunctionSurrogate(self.__wrapped__.__func__, + self._self_parent._self_adapter) + + if six.PY2: + im_func = __func__ + +class AdapterWrapper(FunctionWrapper): + + __bound_function_wrapper__ = _BoundAdapterWrapper + + def __init__(self, *args, **kwargs): + adapter = kwargs.pop('adapter') + super(AdapterWrapper, self).__init__(*args, **kwargs) + self._self_surrogate = _AdapterFunctionSurrogate( + self.__wrapped__, adapter) + self._self_adapter = adapter + + @property + def __code__(self): + return self._self_surrogate.__code__ + + @property + def __defaults__(self): + return self._self_surrogate.__defaults__ + + @property + def __kwdefaults__(self): + return self._self_surrogate.__kwdefaults__ + + if six.PY2: + func_code = __code__ + func_defaults = __defaults__ + + @property + def __signature__(self): + return self._self_surrogate.__signature__ + # Decorator for creating other decorators. This decorator and the # wrappers which they use are designed to properly preserve any name # attributes, function signatures etc, in addition to the wrappers @@ -122,9 +163,12 @@ def decorator(wrapper=None, adapter=None, enabled=None): return func _enabled = None - _adapter = adapter and _AdapterFunction(func, adapter) - result = FunctionWrapper(wrapped=func, wrapper=wrapper, - adapter=_adapter, enabled=_enabled) + if adapter: + result = AdapterWrapper(wrapped=func, wrapper=wrapper, + enabled=_enabled, adapter=adapter) + else: + result = FunctionWrapper(wrapped=func, wrapper=wrapper, + enabled=_enabled) return result diff --git a/src/wrappers.py b/src/wrappers.py index d2c0101..e54283c 100644 --- a/src/wrappers.py +++ b/src/wrappers.py @@ -380,17 +380,16 @@ class ObjectProxy(six.with_metaclass(_ObjectProxyMetaType)): class _FunctionWrapperBase(ObjectProxy): - __slots__ = ('_self_instance', '_self_wrapper', '_self_adapter', - '_self_enabled', '_self_binding', '_self_parent') + __slots__ = ('_self_instance', '_self_wrapper', '_self_enabled', + '_self_binding', '_self_parent') - def __init__(self, wrapped, instance, wrapper, adapter=None, - enabled=None, binding=None, parent=None): + def __init__(self, wrapped, instance, wrapper, enabled=None, + binding=None, parent=None): super(_FunctionWrapperBase, self).__init__(wrapped) object.__setattr__(self, '_self_instance', instance) object.__setattr__(self, '_self_wrapper', wrapper) - object.__setattr__(self, '_self_adapter', adapter) object.__setattr__(self, '_self_enabled', enabled) object.__setattr__(self, '_self_binding', binding) object.__setattr__(self, '_self_parent', parent) @@ -420,8 +419,7 @@ class _FunctionWrapperBase(ObjectProxy): return descriptor return self.__bound_function_wrapper__(descriptor, instance, - self._self_wrapper, self._self_adapter, None, - self._self_binding, self) + self._self_wrapper, None, self._self_binding, self) def __call__(self, *args, **kwargs): # If enabled has been specified, then evaluate it at this point @@ -446,43 +444,6 @@ class _FunctionWrapperBase(ObjectProxy): return self._self_wrapper(self.__wrapped__, self._self_instance, args, kwargs) - # If an adapter function was provided we want to return certain - # attributes of the function from the adapter rather than the - # wrapped function so things like inspect.getargspec() will reflect - # the prototype of the adapter and not the wrapped function. - - @property - def __code__(self): - if self._self_adapter: - return self._self_adapter.__code__ - return self.__wrapped__.__code__ - - @property - def __defaults__(self): - if self._self_adapter: - return self._self_adapter.__defaults__ - return self.__wrapped__.__defaults__ - - @property - def __kwdefaults__(self): - if self._self_adapter: - return self._self_adapter.__kwdefaults__ - return self.__wrapped__.__kwdefaults__ - - if six.PY2: - func_code = __code__ - func_defaults = __defaults__ - - # If an adapter function was provided, we also want to override the - # __signature__ attribute introduced in Python 3 so that we get the - # correct result when using inspect.signature(). - - @property - def __signature__(self): - if self._self_adapter: - return self._self_adapter.__signature__ - return self.__wrapped__.__signature__ - class BoundFunctionWrapper(_FunctionWrapperBase): def __call__(self, *args, **kwargs): @@ -529,7 +490,7 @@ class FunctionWrapper(_FunctionWrapperBase): __bound_function_wrapper__ = BoundFunctionWrapper - def __init__(self, wrapped, wrapper, adapter=None, enabled=None): + def __init__(self, wrapped, wrapper, enabled=None): # We need to do special fixups on the args in the case of an # instancemethod where called via the class and the instance is # passed explicitly as the first argument. So work out when we @@ -563,7 +524,7 @@ class FunctionWrapper(_FunctionWrapperBase): binding = 'instancemethod' super(FunctionWrapper, self).__init__(wrapped, None, wrapper, - adapter, enabled, binding) + enabled, binding) try: from ._wrappers import (ObjectProxy, FunctionWrapper, diff --git a/tests/test_adapter.py b/tests/test_adapter.py index fdca3d2..c44fc06 100644 --- a/tests/test_adapter.py +++ b/tests/test_adapter.py @@ -76,6 +76,13 @@ class TestArgumentSpecification(unittest.TestCase): function1d_argspec = inspect.getargspec(function1d) self.assertEqual(function1a_argspec, function1d_argspec) + # Now bind the function to an instance. The argspec should + # still match. + + bound_function1d = function1d.__get__(object(), object) + bound_function1d_argspec = inspect.getargspec(bound_function1d) + self.assertEqual(function1a_argspec, bound_function1d_argspec) + def test_signature(self): # Test preservation of function argument specification. It # actually needs to match that of the adapter function the