diff --git a/src/__init__.py b/src/__init__.py index ca76169..3eabb02 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -2,4 +2,4 @@ __version_info__ = ('0', '9', '0') __version__ = '.'.join(__version_info__) from .wrappers import ObjectProxy, FunctionWrapper -from .decorators import decorator, adapter +from .decorators import decorator diff --git a/src/_wrappers.c b/src/_wrappers.c index 2143c84..022f1bd 100644 --- a/src/_wrappers.c +++ b/src/_wrappers.c @@ -12,6 +12,7 @@ typedef struct { PyObject_HEAD + PyObject *dict; PyObject *wrapped; } WraptObjectProxyObject; @@ -20,33 +21,19 @@ PyTypeObject WraptObjectProxy_Type; typedef struct { WraptObjectProxyObject object_proxy; + + PyObject *instance; PyObject *wrapper; PyObject *wrapper_args; PyObject *wrapper_kwargs; + PyObject *adapter; PyObject *bound_type; } WraptFunctionWrapperObject; -PyTypeObject WraptFunctionWrapper_Type; - -typedef struct { - WraptObjectProxyObject object_proxy; - PyObject *instance; - PyObject *wrapper; - PyObject *wrapper_args; - PyObject *wrapper_kwargs; -} WraptBoundFunctionWrapperObject; - +PyTypeObject WraptFunctionWrapperBase_Type; PyTypeObject WraptBoundFunctionWrapper_Type; - -typedef struct { - WraptObjectProxyObject object_proxy; - PyObject *instance; - PyObject *wrapper; - PyObject *wrapper_args; - PyObject *wrapper_kwargs; -} WraptBoundMethodWrapperObject; - PyTypeObject WraptBoundMethodWrapper_Type; +PyTypeObject WraptFunctionWrapper_Type; /* ------------------------------------------------------------------------- */ @@ -68,21 +55,12 @@ static PyObject *WraptObjectProxy_new(PyTypeObject *type, /* ------------------------------------------------------------------------- */ -static int WraptObjectProxy_init(WraptObjectProxyObject *self, - PyObject *args, PyObject *kwds) +static int WraptObjectProxy_raw_init(WraptObjectProxyObject *self, + PyObject *wrapped) { - PyObject *wrapped = NULL; - PyObject *name = NULL; PyObject *object = NULL; - static char *kwlist[] = { "wrapped", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:ObjectProxy", - kwlist, &wrapped)) { - return -1; - } - Py_XDECREF(self->dict); Py_XDECREF(self->wrapped); @@ -127,6 +105,23 @@ static int WraptObjectProxy_init(WraptObjectProxyObject *self, /* ------------------------------------------------------------------------- */ +static int WraptObjectProxy_init(WraptObjectProxyObject *self, + PyObject *args, PyObject *kwds) +{ + PyObject *wrapped = NULL; + + static char *kwlist[] = { "wrapped", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:ObjectProxy", + kwlist, &wrapped)) { + return -1; + } + + return WraptObjectProxy_raw_init(self, wrapped); +} + +/* ------------------------------------------------------------------------- */ + static void WraptObjectProxy_dealloc(WraptObjectProxyObject *self) { Py_XDECREF(self->dict); @@ -414,53 +409,6 @@ static PyObject *WraptObjectProxy_or(PyObject *o1, PyObject *o2) /* ------------------------------------------------------------------------- */ -#if 0 -#if PY_MAJOR_VERSION < 3 -static int WraptObjectProxy_coerce(PyObject **p1, PyObject **p2) -{ - PyObject *w1 = NULL; - PyObject *w2 = NULL; - - PyObject *o1 = NULL; - PyObject *o2 = NULL; - - int result = 0; - - /* - * If we get here, then one or the other of the arguments, but - * not both, is going to be an instance of our wrapper. We have - * to unwrap which ever it is and then try the coercion again. - */ - - if (PyObject_IsInstance(*p1, (PyObject *)&WraptObjectProxy_Type)) - w1 = ((WraptObjectProxyObject *)*p1)->wrapped; - - if (PyObject_IsInstance(*p2, (PyObject *)&WraptObjectProxy_Type)) - w2 = ((WraptObjectProxyObject *)*p2)->wrapped; - - Py_XINCREF(w1); - Py_XINCREF(w2); - - o1 = w1 ? w1 : *p1; - o2 = w2 ? w2 : *p2; - - result = PyNumber_CoerceEx(&o1, &o2); - - if (result == 0) { - Py_XDECREF(w1); - Py_XDECREF(w2); - - *p1 = o1; - *p2 = o2; - } - - return result; -} -#endif -#endif - -/* ------------------------------------------------------------------------- */ - #if PY_MAJOR_VERSION < 3 static PyObject *WraptObjectProxy_int(WraptObjectProxyObject *self) { @@ -1273,7 +1221,7 @@ static PyGetSetDef WraptObjectProxy_getset[] = { PyTypeObject WraptObjectProxy_Type = { PyVarObject_HEAD_INIT(NULL, 0) - "_wrappers.ObjectProxy", /*tp_name*/ + "ObjectProxy", /*tp_name*/ sizeof(WraptObjectProxyObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ @@ -1321,7 +1269,7 @@ PyTypeObject WraptObjectProxy_Type = { /* ------------------------------------------------------------------------- */ -static PyObject *WraptFunctionWrapper_new(PyTypeObject *type, +static PyObject *WraptFunctionWrapperBase_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { WraptFunctionWrapperObject *self; @@ -1332,9 +1280,11 @@ static PyObject *WraptFunctionWrapper_new(PyTypeObject *type, if (!self) return NULL; + self->instance = NULL; self->wrapper = NULL; self->wrapper_args = NULL; self->wrapper_kwargs = NULL; + self->adapter = NULL; self->bound_type = NULL; return (PyObject *)self; @@ -1342,43 +1292,34 @@ static PyObject *WraptFunctionWrapper_new(PyTypeObject *type, /* ------------------------------------------------------------------------- */ -static int WraptFunctionWrapper_init(WraptFunctionWrapperObject *self, - PyObject *args, PyObject *kwds) +static int WraptFunctionWrapperBase_raw_init(WraptFunctionWrapperObject *self, + PyObject *wrapped, PyObject *instance, PyObject *wrapper, + PyObject *wrapper_args, PyObject *wrapper_kwargs, PyObject *adapter, + PyObject *bound_type) { - PyObject *wrapped = NULL; - PyObject *wrapper = NULL; - PyObject *wrapper_args = NULL; - PyObject *wrapper_kwargs = NULL; - - PyObject *base_args = NULL; - PyObject *base_kwds = NULL; - int result = 0; - static char *kwlist[] = { "wrapped", "wrapper", "args", "kwargs", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO:FunctionWrapper", - kwlist, &wrapped, &wrapper, &wrapper_args, &wrapper_kwargs)) { - return -1; - } - + Py_XDECREF(self->instance); Py_XDECREF(self->wrapper); Py_XDECREF(self->wrapper_args); Py_XDECREF(self->wrapper_kwargs); + Py_XDECREF(self->adapter); Py_XDECREF(self->bound_type); + self->instance = NULL; self->wrapper = NULL; self->wrapper_args = NULL; self->wrapper_kwargs = NULL; + self->adapter = NULL; self->bound_type = NULL; - base_args = PyTuple_Pack(1, wrapped); - base_kwds = PyDict_New(); - - result = WraptObjectProxy_init((WraptObjectProxyObject *)self, - base_args, base_kwds); + result = WraptObjectProxy_raw_init((WraptObjectProxyObject *)self, + wrapped); if (result == 0) { + Py_INCREF(instance); + self->instance = instance; + Py_INCREF(wrapper); self->wrapper = wrapper; @@ -1396,31 +1337,51 @@ static int WraptFunctionWrapper_init(WraptFunctionWrapperObject *self, else self->wrapper_kwargs = PyDict_New(); - if (PyObject_IsInstance(wrapped, - (PyObject *)&PyClassMethod_Type) || PyObject_IsInstance( - wrapped, (PyObject *)&PyStaticMethod_Type)) { - Py_INCREF((PyObject *)&WraptBoundFunctionWrapper_Type); - self->bound_type = (PyObject *)&WraptBoundFunctionWrapper_Type; - } - else { - Py_INCREF((PyObject *)&WraptBoundMethodWrapper_Type); - self->bound_type = (PyObject *)&WraptBoundMethodWrapper_Type; - } - } + Py_INCREF(adapter); + self->adapter = adapter; - Py_DECREF(base_args); - Py_DECREF(base_kwds); + Py_INCREF(bound_type); + self->bound_type = bound_type; + } return result; } /* ------------------------------------------------------------------------- */ -static void WraptFunctionWrapper_dealloc(WraptFunctionWrapperObject *self) +static int WraptFunctionWrapperBase_init(WraptFunctionWrapperObject *self, + PyObject *args, PyObject *kwds) { + PyObject *wrapped = NULL; + PyObject *instance = NULL; + PyObject *wrapper = NULL; + PyObject *wrapper_args = NULL; + PyObject *wrapper_kwargs = NULL; + PyObject *adapter = Py_None; + PyObject *bound_type = Py_None; + + static char *kwlist[] = { "wrapped", "instance", "wrapper", + "wrapper_args", "wrapper_kwargs", "adapter", "bound_type", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO|OOOO:FunctionWrapperBase", + kwlist, &wrapped, &instance, &wrapper, &wrapper_args, + &wrapper_kwargs, &adapter, &bound_type)) { + return -1; + } + + return WraptFunctionWrapperBase_raw_init(self, wrapped, instance, wrapper, + wrapper_args, wrapper_kwargs, adapter, bound_type); +} + +/* ------------------------------------------------------------------------- */ + +static void WraptFunctionWrapperBase_dealloc(WraptFunctionWrapperObject *self) +{ + Py_XDECREF(self->instance); Py_XDECREF(self->wrapper); Py_XDECREF(self->wrapper_args); Py_XDECREF(self->wrapper_kwargs); + Py_XDECREF(self->adapter); Py_XDECREF(self->bound_type); WraptObjectProxy_dealloc((WraptObjectProxyObject *)self); @@ -1428,7 +1389,7 @@ static void WraptFunctionWrapper_dealloc(WraptFunctionWrapperObject *self) /* ------------------------------------------------------------------------- */ -static PyObject *WraptFunctionWrapper_call( +static PyObject *WraptFunctionWrapperBase_call( WraptFunctionWrapperObject *self, PyObject *args, PyObject *kwds) { PyObject *call_args = NULL; @@ -1474,12 +1435,17 @@ static PyObject *WraptFunctionWrapper_call( /* ------------------------------------------------------------------------- */ -static PyObject *WraptFunctionWrapper_descr_get( +static PyObject *WraptFunctionWrapperBase_descr_get( WraptFunctionWrapperObject *self, PyObject *obj, PyObject *type) { PyObject *descriptor = NULL; PyObject *result = NULL; + if (self->bound_type == Py_None) { + Py_INCREF(self); + return (PyObject *)self; + } + descriptor = (Py_TYPE(self->object_proxy.wrapped)->tp_descr_get)( self->object_proxy.wrapped, obj, type); @@ -1501,7 +1467,53 @@ static PyObject *WraptFunctionWrapper_descr_get( /* ------------------------------------------------------------------------- */ -static PyObject *WraptFunctionWrapper_get_self_wrapper( +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_self_instance( + WraptFunctionWrapperObject *self, void *closure) +{ + if (!self->instance) { + Py_INCREF(Py_None); + return Py_None; + } + + Py_INCREF(self->instance); + return self->instance; +} + +/* ------------------------------------------------------------------------- */ + +static PyObject *WraptFunctionWrapperBase_get_self_wrapper( WraptFunctionWrapperObject *self, void *closure) { if (!self->wrapper) { @@ -1515,7 +1527,7 @@ static PyObject *WraptFunctionWrapper_get_self_wrapper( /* ------------------------------------------------------------------------- */ -static PyObject *WraptFunctionWrapper_get_self_wrapper_args( +static PyObject *WraptFunctionWrapperBase_get_self_wrapper_args( WraptFunctionWrapperObject *self, void *closure) { if (!self->wrapper_args) { @@ -1529,7 +1541,7 @@ static PyObject *WraptFunctionWrapper_get_self_wrapper_args( /* ------------------------------------------------------------------------- */ -static PyObject *WraptFunctionWrapper_get_self_wrapper_kwargs( +static PyObject *WraptFunctionWrapperBase_get_self_wrapper_kwargs( WraptFunctionWrapperObject *self, void *closure) { if (!self->wrapper_kwargs) { @@ -1543,7 +1555,21 @@ static PyObject *WraptFunctionWrapper_get_self_wrapper_kwargs( /* ------------------------------------------------------------------------- */ -static PyObject *WraptFunctionWrapper_get_self_bound_type( +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_bound_type( WraptFunctionWrapperObject *self, void *closure) { if (!self->bound_type) { @@ -1557,29 +1583,43 @@ static PyObject *WraptFunctionWrapper_get_self_bound_type( /* ------------------------------------------------------------------------- */; -static PyGetSetDef WraptFunctionWrapper_getset[] = { +static PyGetSetDef WraptFunctionWrapperBase_getset[] = { { "__module__", (getter)WraptObjectProxy_get_module, (setter)WraptObjectProxy_set_module, 0 }, { "__doc__", (getter)WraptObjectProxy_get_doc, (setter)WraptObjectProxy_set_doc, 0 }, - { "_self_wrapper", (getter)WraptFunctionWrapper_get_self_wrapper, + { "__code__", (getter)WraptFunctionWrapperBase_get_code, NULL, 0 }, - { "_self_wrapper_args", (getter)WraptFunctionWrapper_get_self_wrapper_args, + { "__defaults__", (getter)WraptFunctionWrapperBase_get_defaults, NULL, 0 }, - { "_self_wrapper_kwargs", (getter)WraptFunctionWrapper_get_self_wrapper_kwargs, +#if PY_MAJOR_VERSION < 3 + { "func_code", (getter)WraptFunctionWrapperBase_get_code, NULL, 0 }, - { "_self_bound_type", (getter)WraptFunctionWrapper_get_self_bound_type, + { "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_wrapper_args", (getter)WraptFunctionWrapperBase_get_self_wrapper_args, + NULL, 0 }, + { "_self_wrapper_kwargs", (getter)WraptFunctionWrapperBase_get_self_wrapper_kwargs, + NULL, 0 }, + { "_self_adapter", (getter)WraptFunctionWrapperBase_get_self_adapter, + NULL, 0 }, + { "_self_bound_type", (getter)WraptFunctionWrapperBase_get_self_bound_type, NULL, 0 }, { NULL }, }; -PyTypeObject WraptFunctionWrapper_Type = { +PyTypeObject WraptFunctionWrapperBase_Type = { PyVarObject_HEAD_INIT(NULL, 0) - "_wrappers.FunctionWrapper", /*tp_name*/ + "_FunctionWrapperBase", /*tp_name*/ sizeof(WraptFunctionWrapperObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ - (destructor)WraptFunctionWrapper_dealloc, /*tp_dealloc*/ + (destructor)WraptFunctionWrapperBase_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ @@ -1589,7 +1629,7 @@ PyTypeObject WraptFunctionWrapper_Type = { 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ - (ternaryfunc)WraptFunctionWrapper_call, /*tp_call*/ + (ternaryfunc)WraptFunctionWrapperBase_call, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ @@ -1608,126 +1648,23 @@ PyTypeObject WraptFunctionWrapper_Type = { 0, /*tp_iternext*/ 0, /*tp_methods*/ 0, /*tp_members*/ - WraptFunctionWrapper_getset, /*tp_getset*/ + WraptFunctionWrapperBase_getset, /*tp_getset*/ 0, /*tp_base*/ 0, /*tp_dict*/ - (descrgetfunc)WraptFunctionWrapper_descr_get, /*tp_descr_get*/ + (descrgetfunc)WraptFunctionWrapperBase_descr_get, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ - (initproc)WraptFunctionWrapper_init, /*tp_init*/ + (initproc)WraptFunctionWrapperBase_init, /*tp_init*/ 0, /*tp_alloc*/ - WraptFunctionWrapper_new, /*tp_new*/ + WraptFunctionWrapperBase_new, /*tp_new*/ 0, /*tp_free*/ 0, /*tp_is_gc*/ }; /* ------------------------------------------------------------------------- */ -static PyObject *WraptBoundFunctionWrapper_new(PyTypeObject *type, - PyObject *args, PyObject *kwds) -{ - WraptBoundFunctionWrapperObject *self; - - self = (WraptBoundFunctionWrapperObject *)WraptObjectProxy_new(type, - args, kwds); - - if (!self) - return NULL; - - self->instance = NULL; - self->wrapper = NULL; - self->wrapper_args = NULL; - self->wrapper_kwargs = NULL; - - return (PyObject *)self; -} - -/* ------------------------------------------------------------------------- */ - -static int WraptBoundFunctionWrapper_init( - WraptBoundFunctionWrapperObject *self, PyObject *args, PyObject *kwds) -{ - PyObject *wrapped = NULL; - PyObject *instance = NULL; - PyObject *wrapper = NULL; - PyObject *wrapper_args = NULL; - PyObject *wrapper_kwargs = NULL; - - PyObject *base_args = NULL; - PyObject *base_kwds = NULL; - - int result = 0; - - static char *kwlist[] = { "wrapped", "instance", "wrapper", - "args", "kwargs", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "OOO|OO:BoundFunctionWrapper", kwlist, &wrapped, &instance, - &wrapper, &wrapper_args, &wrapper_kwargs)) { - return -1; - } - - Py_XDECREF(self->instance); - Py_XDECREF(self->wrapper); - Py_XDECREF(self->wrapper_args); - Py_XDECREF(self->wrapper_kwargs); - - self->instance = NULL; - self->wrapper = NULL; - self->wrapper_args = NULL; - self->wrapper_kwargs = NULL; - - base_args = PyTuple_Pack(1, wrapped); - base_kwds = PyDict_New(); - - result = WraptObjectProxy_init((WraptObjectProxyObject *)self, - base_args, base_kwds); - - if (result == 0) { - Py_INCREF(instance); - self->instance = instance; - - Py_INCREF(wrapper); - self->wrapper = wrapper; - - if (wrapper_args) { - Py_INCREF(wrapper_args); - self->wrapper_args = wrapper_args; - } - else - self->wrapper_args = PyTuple_New(0); - - if (wrapper_kwargs) { - Py_INCREF(wrapper_kwargs); - self->wrapper_kwargs = wrapper_kwargs; - } - else - self->wrapper_kwargs = PyDict_New(); - } - - Py_DECREF(base_args); - Py_DECREF(base_kwds); - - return result; -} - -/* ------------------------------------------------------------------------- */ - -static void WraptBoundFunctionWrapper_dealloc( - WraptBoundFunctionWrapperObject *self) -{ - Py_XDECREF(self->instance); - Py_XDECREF(self->wrapper); - Py_XDECREF(self->wrapper_args); - Py_XDECREF(self->wrapper_kwargs); - - WraptObjectProxy_dealloc((WraptObjectProxyObject *)self); -} - -/* ------------------------------------------------------------------------- */ - static PyObject *WraptBoundFunctionWrapper_call( - WraptBoundFunctionWrapperObject *self, PyObject *args, PyObject *kwds) + WraptFunctionWrapperObject *self, PyObject *args, PyObject *kwds) { PyObject *call_args = NULL; PyObject *param_kwds = NULL; @@ -1791,85 +1728,21 @@ static PyObject *WraptBoundFunctionWrapper_call( /* ------------------------------------------------------------------------- */ -static PyObject *WraptBoundFunctionWrapper_get_self_instance( - WraptBoundFunctionWrapperObject *self, void *closure) -{ - if (!self->instance) { - Py_INCREF(Py_None); - return Py_None; - } - - Py_INCREF(self->instance); - return self->instance; -} - -/* ------------------------------------------------------------------------- */ - -static PyObject *WraptBoundFunctionWrapper_get_self_wrapper( - WraptBoundFunctionWrapperObject *self, void *closure) -{ - if (!self->wrapper) { - Py_INCREF(Py_None); - return Py_None; - } - - Py_INCREF(self->wrapper); - return self->wrapper; -} - -/* ------------------------------------------------------------------------- */ - -static PyObject *WraptBoundFunctionWrapper_get_self_wrapper_args( - WraptBoundFunctionWrapperObject *self, void *closure) -{ - if (!self->wrapper_args) { - Py_INCREF(Py_None); - return Py_None; - } - - Py_INCREF(self->wrapper_args); - return self->wrapper_args; -} - -/* ------------------------------------------------------------------------- */ - -static PyObject *WraptBoundFunctionWrapper_get_self_wrapper_kwargs( - WraptBoundFunctionWrapperObject *self, void *closure) -{ - if (!self->wrapper_kwargs) { - Py_INCREF(Py_None); - return Py_None; - } - - Py_INCREF(self->wrapper_kwargs); - return self->wrapper_kwargs; -} - -/* ------------------------------------------------------------------------- */; - static PyGetSetDef WraptBoundFunctionWrapper_getset[] = { { "__module__", (getter)WraptObjectProxy_get_module, (setter)WraptObjectProxy_set_module, 0 }, { "__doc__", (getter)WraptObjectProxy_get_doc, (setter)WraptObjectProxy_set_doc, 0 }, - { "_self_instance", (getter)WraptBoundFunctionWrapper_get_self_instance, - NULL, 0 }, - { "_self_wrapper", (getter)WraptBoundFunctionWrapper_get_self_wrapper, - NULL, 0 }, - { "_self_wrapper_args", (getter)WraptBoundFunctionWrapper_get_self_wrapper_args, - NULL, 0 }, - { "_self_wrapper_kwargs", (getter)WraptBoundFunctionWrapper_get_self_wrapper_kwargs, - NULL, 0 }, { NULL }, }; PyTypeObject WraptBoundFunctionWrapper_Type = { PyVarObject_HEAD_INIT(NULL, 0) - "_wrappers.BoundFunctionWrapper", /*tp_name*/ - sizeof(WraptBoundFunctionWrapperObject), /*tp_basicsize*/ + "_BoundFunctionWrapper", /*tp_name*/ + sizeof(WraptFunctionWrapperObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ - (destructor)WraptBoundFunctionWrapper_dealloc, /*tp_dealloc*/ + 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ @@ -1904,120 +1777,17 @@ PyTypeObject WraptBoundFunctionWrapper_Type = { 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ - (initproc)WraptBoundFunctionWrapper_init, /*tp_init*/ + 0, /*tp_init*/ 0, /*tp_alloc*/ - WraptBoundFunctionWrapper_new, /*tp_new*/ + 0, /*tp_new*/ 0, /*tp_free*/ 0, /*tp_is_gc*/ }; /* ------------------------------------------------------------------------- */ -static PyObject *WraptBoundMethodWrapper_new(PyTypeObject *type, - PyObject *args, PyObject *kwds) -{ - WraptBoundMethodWrapperObject *self; - - self = (WraptBoundMethodWrapperObject *)WraptObjectProxy_new(type, - args, kwds); - - if (!self) - return NULL; - - self->instance = NULL; - self->wrapper = NULL; - self->wrapper_args = NULL; - self->wrapper_kwargs = NULL; - - return (PyObject *)self; -} - -/* ------------------------------------------------------------------------- */ - -static int WraptBoundMethodWrapper_init( - WraptBoundMethodWrapperObject *self, PyObject *args, PyObject *kwds) -{ - PyObject *wrapped = NULL; - PyObject *instance = NULL; - PyObject *wrapper = NULL; - PyObject *wrapper_args = NULL; - PyObject *wrapper_kwargs = NULL; - - PyObject *base_args = NULL; - PyObject *base_kwds = NULL; - - int result = 0; - - static char *kwlist[] = { "wrapped", "instance", "wrapper", - "args", "kwargs", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "OOO|OO:BoundMethodWrapper", kwlist, &wrapped, &instance, - &wrapper, &wrapper_args, &wrapper_kwargs)) { - return -1; - } - - Py_XDECREF(self->instance); - Py_XDECREF(self->wrapper); - Py_XDECREF(self->wrapper_args); - Py_XDECREF(self->wrapper_kwargs); - - self->instance = NULL; - self->wrapper = NULL; - self->wrapper_args = NULL; - self->wrapper_kwargs = NULL; - - base_args = PyTuple_Pack(1, wrapped); - base_kwds = PyDict_New(); - - result = WraptObjectProxy_init((WraptObjectProxyObject *)self, - base_args, base_kwds); - - if (result == 0) { - Py_INCREF(instance); - self->instance = instance; - - Py_INCREF(wrapper); - self->wrapper = wrapper; - - if (wrapper_args) { - Py_INCREF(wrapper_args); - self->wrapper_args = wrapper_args; - } - else - self->wrapper_args = PyTuple_New(0); - - if (wrapper_kwargs) { - Py_INCREF(wrapper_kwargs); - self->wrapper_kwargs = wrapper_kwargs; - } - else - self->wrapper_kwargs = PyDict_New(); - } - - Py_DECREF(base_args); - Py_DECREF(base_kwds); - - return result; -} - -/* ------------------------------------------------------------------------- */ - -static void WraptBoundMethodWrapper_dealloc( - WraptBoundMethodWrapperObject *self) -{ - Py_XDECREF(self->instance); - Py_XDECREF(self->wrapper); - Py_XDECREF(self->wrapper_args); - Py_XDECREF(self->wrapper_kwargs); - - WraptObjectProxy_dealloc((WraptObjectProxyObject *)self); -} - -/* ------------------------------------------------------------------------- */ - static PyObject *WraptBoundMethodWrapper_call( - WraptBoundMethodWrapperObject *self, PyObject *args, PyObject *kwds) + WraptFunctionWrapperObject *self, PyObject *args, PyObject *kwds) { PyObject *call_args = NULL; PyObject *param_args = NULL; @@ -2117,85 +1887,21 @@ static PyObject *WraptBoundMethodWrapper_call( /* ------------------------------------------------------------------------- */ -static PyObject *WraptBoundMethodWrapper_get_self_instance( - WraptBoundMethodWrapperObject *self, void *closure) -{ - if (!self->instance) { - Py_INCREF(Py_None); - return Py_None; - } - - Py_INCREF(self->instance); - return self->instance; -} - -/* ------------------------------------------------------------------------- */ - -static PyObject *WraptBoundMethodWrapper_get_self_wrapper( - WraptBoundMethodWrapperObject *self, void *closure) -{ - if (!self->wrapper) { - Py_INCREF(Py_None); - return Py_None; - } - - Py_INCREF(self->wrapper); - return self->wrapper; -} - -/* ------------------------------------------------------------------------- */ - -static PyObject *WraptBoundMethodWrapper_get_self_wrapper_args( - WraptBoundMethodWrapperObject *self, void *closure) -{ - if (!self->wrapper_args) { - Py_INCREF(Py_None); - return Py_None; - } - - Py_INCREF(self->wrapper_args); - return self->wrapper_args; -} - -/* ------------------------------------------------------------------------- */ - -static PyObject *WraptBoundMethodWrapper_get_self_wrapper_kwargs( - WraptBoundMethodWrapperObject *self, void *closure) -{ - if (!self->wrapper_kwargs) { - Py_INCREF(Py_None); - return Py_None; - } - - Py_INCREF(self->wrapper_kwargs); - return self->wrapper_kwargs; -} - -/* ------------------------------------------------------------------------- */; - static PyGetSetDef WraptBoundMethodWrapper_getset[] = { { "__module__", (getter)WraptObjectProxy_get_module, (setter)WraptObjectProxy_set_module, 0 }, { "__doc__", (getter)WraptObjectProxy_get_doc, (setter)WraptObjectProxy_set_doc, 0 }, - { "_self_instance", (getter)WraptBoundMethodWrapper_get_self_instance, - NULL, 0 }, - { "_self_wrapper", (getter)WraptBoundMethodWrapper_get_self_wrapper, - NULL, 0 }, - { "_self_wrapper_args", (getter)WraptBoundMethodWrapper_get_self_wrapper_args, - NULL, 0 }, - { "_self_wrapper_kwargs", (getter)WraptBoundMethodWrapper_get_self_wrapper_kwargs, - NULL, 0 }, { NULL }, }; PyTypeObject WraptBoundMethodWrapper_Type = { PyVarObject_HEAD_INIT(NULL, 0) - "_wrappers.BoundMethodWrapper", /*tp_name*/ - sizeof(WraptBoundMethodWrapperObject), /*tp_basicsize*/ + "_BoundMethodWrapper", /*tp_name*/ + sizeof(WraptFunctionWrapperObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ - (destructor)WraptBoundMethodWrapper_dealloc, /*tp_dealloc*/ + 0, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ @@ -2230,9 +1936,120 @@ PyTypeObject WraptBoundMethodWrapper_Type = { 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ - (initproc)WraptBoundMethodWrapper_init, /*tp_init*/ + 0, /*tp_init*/ 0, /*tp_alloc*/ - WraptBoundMethodWrapper_new, /*tp_new*/ + 0, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ +}; + +/* ------------------------------------------------------------------------- */ + +static int WraptFunctionWrapper_init(WraptFunctionWrapperObject *self, + PyObject *args, PyObject *kwds) +{ + PyObject *wrapped = NULL; + PyObject *wrapper = NULL; + PyObject *wrapper_args = NULL; + PyObject *wrapper_kwargs = NULL; + PyObject *adapter = Py_None; + PyObject *bound_type = NULL; + + int result = 0; + + static char *kwlist[] = { "wrapped", "wrapper", "wrapper_args", + "wrapper_kwargs", "adapter", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|OOO:FunctionWrapper", + kwlist, &wrapped, &wrapper, &wrapper_args, &wrapper_kwargs, + &adapter)) { + return -1; + } + + if (PyObject_IsInstance(wrapped, + (PyObject *)&PyClassMethod_Type) || PyObject_IsInstance( + wrapped, (PyObject *)&PyStaticMethod_Type)) { + Py_INCREF((PyObject *)&WraptBoundFunctionWrapper_Type); + bound_type = (PyObject *)&WraptBoundFunctionWrapper_Type; + } + else { + Py_INCREF((PyObject *)&WraptBoundMethodWrapper_Type); + bound_type = (PyObject *)&WraptBoundMethodWrapper_Type; + } + + if (!wrapper_args) + wrapper_args = PyTuple_New(0); + else + Py_INCREF(wrapper_args); + + if (!wrapper_kwargs) + wrapper_kwargs = PyDict_New(); + else + Py_INCREF(wrapper_kwargs); + + result = WraptFunctionWrapperBase_raw_init(self, wrapped, Py_None, + wrapper, wrapper_args, wrapper_kwargs, adapter, bound_type); + + Py_DECREF(wrapper_args); + Py_DECREF(wrapper_kwargs); + + return result; +} + +/* ------------------------------------------------------------------------- */; + +static PyGetSetDef WraptFunctionWrapper_getset[] = { + { "__module__", (getter)WraptObjectProxy_get_module, + (setter)WraptObjectProxy_set_module, 0 }, + { "__doc__", (getter)WraptObjectProxy_get_doc, + (setter)WraptObjectProxy_set_doc, 0 }, + { NULL }, +}; + +PyTypeObject WraptFunctionWrapper_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "FunctionWrapper", /*tp_name*/ + sizeof(WraptFunctionWrapperObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ +#if PY_MAJOR_VERSION < 3 + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/ +#else + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ +#endif + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + WraptFunctionWrapper_getset, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + (initproc)WraptFunctionWrapper_init, /*tp_init*/ + 0, /*tp_alloc*/ + 0, /*tp_new*/ 0, /*tp_free*/ 0, /*tp_is_gc*/ }; @@ -2272,16 +2089,19 @@ moduleinit(void) /* Ensure that inheritence relationships specified. */ - WraptFunctionWrapper_Type.tp_base = &WraptObjectProxy_Type; - WraptBoundFunctionWrapper_Type.tp_base = &WraptObjectProxy_Type; - WraptBoundMethodWrapper_Type.tp_base = &WraptObjectProxy_Type; + WraptFunctionWrapperBase_Type.tp_base = &WraptObjectProxy_Type; + WraptBoundFunctionWrapper_Type.tp_base = &WraptFunctionWrapperBase_Type; + WraptBoundMethodWrapper_Type.tp_base = &WraptFunctionWrapperBase_Type; + WraptFunctionWrapper_Type.tp_base = &WraptFunctionWrapperBase_Type; - if (PyType_Ready(&WraptFunctionWrapper_Type) < 0) + if (PyType_Ready(&WraptFunctionWrapperBase_Type) < 0) return NULL; if (PyType_Ready(&WraptBoundFunctionWrapper_Type) < 0) return NULL; if (PyType_Ready(&WraptBoundMethodWrapper_Type) < 0) return NULL; + if (PyType_Ready(&WraptFunctionWrapper_Type) < 0) + return NULL; Py_INCREF(&WraptObjectProxy_Type); PyModule_AddObject(module, "ObjectProxy", diff --git a/src/decorators.py b/src/decorators.py index 14aa6e0..880e4ed 100644 --- a/src/decorators.py +++ b/src/decorators.py @@ -133,21 +133,6 @@ def _validate_parameters(func, spec, *positional, **named): _missing_arguments(f_name, kwonlyargs, False, arg2value) return arg2value -# Copy name attributes from a wrapped function onto an wrapper. This is -# only used in mapping the name from the final wrapped function to which -# an adapter is applied onto the adapter itself. All other details come -# from the adapter function via the function wrapper so we don't update -# __dict__ or __wrapped__. - -def _update_adapter(wrapper, target): - for attr in ('__module__', '__name__', '__qualname__'): - try: - value = getattr(target, attr) - except AttributeError: - pass - else: - setattr(wrapper, attr, value) - # Decorators for creating other decorators. These decorators and the # wrappers which they use are designed to properly preserve any name # attributes, function signatures etc, in addition to the wrappers @@ -157,16 +142,19 @@ def _update_adapter(wrapper, target): WRAPPER_ARGLIST = ('wrapped', 'instance', 'args', 'kwargs') -def decorator(wrapper=None, target=None, validate=True): +def decorator(wrapper=None, adapter=None, validate=True): # The decorator takes some optional keyword parameters to change its # behaviour. The decorator works out whether parameters have been # passed based on whether the first positional argument, which is # the wrapper which implements the user decorator, has been - # supplied. The 'target' argument is used to optionally denote a - # function which is wrapped by an adapter decorator. In that case - # the name attributes are copied from the target function rather - # than those of the adapter function. The 'validate' argument, which - # defaults to True, indicates whether validation of decorator + # supplied. The 'adapter' argument is used to optionally denote a + # separate function which is notionally used by an adapter + # decorator. In that case the function '__code__' and '__defaults__' + # attributes are used from the adapter function rather than those of + # the wrapped function. This allows for the argument specification + # from inspect.getargspec() to be overridden with a prototype for a + # different function than what was wrapped. The 'validate' argument, + # which defaults to True, indicates whether validation of decorator # parameters should be validated at the time the decorator is # applied, or whether a failure is allow to occur only when the # wrapped function is later called and the user wrapper function @@ -210,10 +198,9 @@ def decorator(wrapper=None, target=None, validate=True): def _wrapper(func): result = FunctionWrapper(wrapped=func, - wrapper=wrapper, args=decorator_args, - kwargs=decorator_kwargs) - if target: - _update_adapter(result, target) + wrapper=wrapper, wrapper_args=decorator_args, + wrapper_kwargs=decorator_kwargs, + adapter=adapter) return result return _wrapper @@ -228,9 +215,8 @@ def decorator(wrapper=None, target=None, validate=True): @wraps(wrapper) def _wrapper(func): - result = FunctionWrapper(wrapped=func, wrapper=wrapper) - if target: - _update_adapter(result, target) + result = FunctionWrapper(wrapped=func, wrapper=wrapper, + adapter=adapter) return result return _wrapper @@ -241,10 +227,4 @@ def decorator(wrapper=None, target=None, validate=True): # a partial using the collected default parameters and the # adapter function if one is being used. - return partial(decorator, target=target, validate=validate) - -def adapter(target): - @decorator(target=target) - def wrapper(wrapped, instance, args, kwargs): - return wrapped(*args, **kwargs) - return wrapper + return partial(decorator, adapter=adapter, validate=validate) diff --git a/src/wrappers.py b/src/wrappers.py index a61b7ac..e1cdc21 100644 --- a/src/wrappers.py +++ b/src/wrappers.py @@ -51,7 +51,7 @@ class _ObjectProxyMetaType(type): class ObjectProxy(six.with_metaclass(_ObjectProxyMetaType)): def __init__(self, wrapped): - self._self_wrapped = wrapped + object.__setattr__(self, '_self_wrapped', wrapped) # Python 3.2+ has the __qualname__ attribute, but it does not # allow it to be overridden using a property and it must instead @@ -360,14 +360,67 @@ class ObjectProxy(six.with_metaclass(_ObjectProxyMetaType)): def __call__(self, *args, **kwargs): return self._self_wrapped(*args, **kwargs) -class _BoundFunctionWrapper(ObjectProxy): +class _FunctionWrapperBase(ObjectProxy): - def __init__(self, wrapped, instance, wrapper, args=(), kwargs={}): - super(_BoundFunctionWrapper, self).__init__(wrapped) - self._self_instance = instance - self._self_wrapper = wrapper - self._self_wrapper_args = args - self._self_wrapper_kwargs = kwargs + def __init__(self, wrapped, instance, wrapper, wrapper_args=(), + wrapper_kwargs={}, adapter=None, bound_type=None): + + super(_FunctionWrapperBase, self).__init__(wrapped) + + object.__setattr__(self, '_self_instance', instance) + object.__setattr__(self, '_self_wrapper', wrapper) + object.__setattr__(self, '_self_wrapper_args', wrapper_args) + object.__setattr__(self, '_self_wrapper_kwargs', wrapper_kwargs) + object.__setattr__(self, '_self_adapter', adapter) + object.__setattr__(self, '_self_bound_type', bound_type) + + def __get__(self, instance, owner): + # If we have already been bound to an instance of something, we + # do not do it again and return ourselves again. This appears to + # mirror what Python itself does. + + if self._self_bound_type is None: + return self + + descriptor = self._self_wrapped.__get__(instance, owner) + + return self._self_bound_type(descriptor, instance, self._self_wrapper, + self._self_wrapper_args, self._self_wrapper_kwargs, + self._self_adapter) + + def __call__(self, *args, **kwargs): + # This is generally invoked when the wrapped function is being + # called as a normal function and is not bound to a class as an + # instance method. This is also invoked in the case where the + # wrapped function was a method, but this wrapper was in turn + # wrapped using the staticmethod decorator. + + return self._self_wrapper(self._self_wrapped, self._self_instance, + args, kwargs, *self._self_wrapper_args, + **self._self_wrapper_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._self_wrapped.__code__ + + @property + def __defaults__(self): + if self._self_adapter: + return self._self_adapter.__defaults__ + return self._self_wrapped.__defaults__ + + if six.PY2: + func_code = __code__ + func_defaults = __defaults__ + +class _BoundFunctionWrapper(_FunctionWrapperBase): def __call__(self, *args, **kwargs): # As in this case we would be dealing with a classmethod or @@ -389,14 +442,7 @@ class _BoundFunctionWrapper(ObjectProxy): args, kwargs, *self._self_wrapper_args, **self._self_wrapper_kwargs) -class _BoundMethodWrapper(ObjectProxy): - - def __init__(self, wrapped, instance, wrapper, args=(), kwargs={}): - super(_BoundMethodWrapper, self).__init__(wrapped) - self._self_instance = instance - self._self_wrapper = wrapper - self._self_wrapper_args = args - self._self_wrapper_kwargs = kwargs +class _BoundMethodWrapper(_FunctionWrapperBase): def __call__(self, *args, **kwargs): if self._self_instance is None: @@ -416,13 +462,10 @@ class _BoundMethodWrapper(ObjectProxy): args, kwargs, *self._self_wrapper_args, **self._self_wrapper_kwargs) -class FunctionWrapper(ObjectProxy): +class FunctionWrapper(_FunctionWrapperBase): - def __init__(self, wrapped, wrapper, args=(), kwargs={}): - super(FunctionWrapper, self).__init__(wrapped) - self._self_wrapper = wrapper - self._self_wrapper_args = args - self._self_wrapper_kwargs = kwargs + def __init__(self, wrapped, wrapper, wrapper_args=(), wrapper_kwargs={}, + adapter=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 @@ -434,10 +477,7 @@ class FunctionWrapper(ObjectProxy): # Note that there isn't strictly a fool proof method of knowing # which is occuring because if a decorator using this code wraps # other decorators and they are poorly implemented they can - # throw away important information needed to determine it. Some - # ways that it could be determined in Python 2 are also not - # possible in Python 3 due to the concept of unbound methods - # being done away with. + # throw away important information needed to determine it. # # Anyway, the best we can do is look at the original type of the # object which was wrapped prior to any binding being done and @@ -453,26 +493,13 @@ class FunctionWrapper(ObjectProxy): # that those other decorators be fixed. It is also only an issue # if a decorator wants to actually do things with the arguments. - if isinstance(self._self_wrapped, (classmethod, staticmethod)): - self._self_bound_type = _BoundFunctionWrapper + if isinstance(wrapped, (classmethod, staticmethod)): + bound_type = _BoundFunctionWrapper else: - self._self_bound_type = _BoundMethodWrapper + bound_type = _BoundMethodWrapper - def __get__(self, instance, owner): - descriptor = self._self_wrapped.__get__(instance, owner) - - return self._self_bound_type(descriptor, instance, self._self_wrapper, - self._self_wrapper_args, self._self_wrapper_kwargs) - - def __call__(self, *args, **kwargs): - # This is invoked when the wrapped function is being called as a - # normal function and is not bound to a class as an instance - # method. This is also invoked in the case where the wrapped - # function was a method, but this wrapper was in turn wrapped - # using the staticmethod decorator. - - return self._self_wrapper(self._self_wrapped, None, args, - kwargs, *self._self_wrapper_args, **self._self_wrapper_kwargs) + super(FunctionWrapper, self).__init__(wrapped, None, wrapper, + wrapper_args, wrapper_kwargs, adapter, bound_type) try: from ._wrappers import ObjectProxy as C_ObjectProxy diff --git a/tests/test_adapter.py b/tests/test_adapter.py index a2d337c..1e841b0 100644 --- a/tests/test_adapter.py +++ b/tests/test_adapter.py @@ -11,12 +11,11 @@ from wrapt import six DECORATORS_CODE = """ import wrapt -def adapter1(func): - @wrapt.adapter(target=func) - def _adapter(arg): - '''adapter documentation''' - return func(arg, arg) - return _adapter +def prototype(arg): pass +@wrapt.decorator(adapter=prototype) +def adapter1(wrapped, instance, args, kwargs): + '''adapter documentation''' + return wrapped(*args, **kwargs) """ decorators = imp.new_module('decorators') @@ -58,14 +57,16 @@ class TestNamingAdapter(unittest.TestCase): self.assertEqual(function1d.__module__, __name__) def test_doc_string(self): - # Test preservation of function __doc__ attribute from the - # adapter rather than from the original target wrapped function. + # Test preservation of function __doc__ attribute. It is + # still the documentation from the wrapped function, not + # of the adapter. - self.assertEqual(function1d.__doc__, 'adapter documentation') + self.assertEqual(function1d.__doc__, 'documentation') def test_argspec(self): # Test preservation of function argument specification. It - # actually needs to match that of the adapter function. + # actually needs to match that of the adapter function the + # prototype of which was supplied via the dummy function. def _adapter(arg): pass @@ -78,61 +79,5 @@ class TestNamingAdapter(unittest.TestCase): self.assertTrue(isinstance(function1d, type(function1o))) -class TestAdapter(unittest.TestCase): - - def test_no_arguments(self): - events = [] - - def _adapter(events): - def _trace(func): - @wrapt.adapter(target=func) - def _wrapper(): - if events is not None: - events.append('in') - try: - return func() - finally: - if events is not None: - events.append('out') - return _wrapper - return _trace - - @_adapter(events=events) - def _function(): - '''documentation''' - events.append('call') - - _function() - - self.assertEqual(events, ['in', 'call', 'out']) - - def test_add_argument(self): - events = [] - - def _adapter(events): - def _trace(func): - @wrapt.adapter(target=func) - def _wrapper(): - if events is not None: - events.append('in') - try: - return func(1) - finally: - if events is not None: - events.append('out') - return _wrapper - return _trace - - @_adapter(events=events) - def _function(*args): - '''documentation''' - events.append('call') - return args - - result = _function() - - self.assertEqual(result, (1,)) - self.assertEqual(events, ['in', 'call', 'out']) - if __name__ == '__main__': unittest.main()