diff --git a/src/_wrappers.c b/src/_wrappers.c index c501d32..f4a9fae 100644 --- a/src/_wrappers.c +++ b/src/_wrappers.c @@ -14,7 +14,6 @@ typedef struct { PyObject_HEAD PyObject *dict; PyObject *wrapped; - PyObject *target; } WraptObjectProxyObject; PyTypeObject WraptObjectProxy_Type; @@ -23,7 +22,7 @@ typedef struct { WraptObjectProxyObject object_proxy; PyObject *wrapper; PyObject *params; - PyObject *wrapper_type; + PyObject *bound_type; } WraptFunctionWrapperObject; PyTypeObject WraptFunctionWrapper_Type; @@ -60,7 +59,6 @@ static PyObject *WraptObjectProxy_new(PyTypeObject *type, self->dict = NULL; self->wrapped = NULL; - self->target = NULL; return (PyObject *)self; } @@ -71,21 +69,19 @@ static int WraptObjectProxy_init(WraptObjectProxyObject *self, PyObject *args, PyObject *kwds) { PyObject *wrapped = NULL; - PyObject *target = NULL;; PyObject *name = NULL; PyObject *object = NULL; - static char *kwlist[] = { "wrapped", "target", NULL }; + static char *kwlist[] = { "wrapped", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:ObjectProxy", - kwlist, &wrapped, &target)) { + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:ObjectProxy", + kwlist, &wrapped)) { return -1; } Py_XDECREF(self->dict); Py_XDECREF(self->wrapped); - Py_XDECREF(self->target); self->dict = PyDict_New(); @@ -93,86 +89,35 @@ static int WraptObjectProxy_init(WraptObjectProxyObject *self, self->wrapped = wrapped; - if (!target || target == Py_None) { - object = PyObject_GetAttrString(wrapped, "__wrapped__"); + object = PyObject_GetAttrString(wrapped, "__name__"); - if (object) { - self->target = object; - } - else { - PyErr_Clear(); - - Py_INCREF(wrapped); - self->target = wrapped; - } - - object = PyObject_GetAttrString(wrapped, "__name__"); - - if (object) { + if (object) { #if PY_MAJOR_VERSION >= 3 - name = PyUnicode_FromString("__name__"); + name = PyUnicode_FromString("__name__"); #else - name = PyString_FromString("__name__"); + name = PyString_FromString("__name__"); #endif - PyObject_GenericSetAttr((PyObject *)self, name, object); - Py_DECREF(name); - Py_DECREF(object); - } - else - PyErr_Clear(); - - object = PyObject_GetAttrString(wrapped, "__qualname__"); - - if (object) { -#if PY_MAJOR_VERSION >= 3 - name = PyUnicode_FromString("__qualname__"); -#else - name = PyString_FromString("__qualname__"); -#endif - PyObject_GenericSetAttr((PyObject *)self, name, object); - Py_DECREF(name); - Py_DECREF(object); - } - else - PyErr_Clear(); + PyObject_GenericSetAttr((PyObject *)self, name, object); + Py_DECREF(name); + Py_DECREF(object); } - else { - if (!target) - target = Py_None; + else + PyErr_Clear(); - Py_INCREF(target); - self->target = target; + object = PyObject_GetAttrString(wrapped, "__qualname__"); - object = PyObject_GetAttrString(target, "__name__"); - - if (object) { + if (object) { #if PY_MAJOR_VERSION >= 3 - name = PyUnicode_FromString("__name__"); + name = PyUnicode_FromString("__qualname__"); #else - name = PyString_FromString("__name__"); + name = PyString_FromString("__qualname__"); #endif - PyObject_GenericSetAttr((PyObject *)self, name, object); - Py_DECREF(name); - Py_DECREF(object); - } - else - PyErr_Clear(); - - object = PyObject_GetAttrString(target, "__qualname__"); - - if (object) { -#if PY_MAJOR_VERSION >= 3 - name = PyUnicode_FromString("__qualname__"); -#else - name = PyString_FromString("__qualname__"); -#endif - PyObject_GenericSetAttr((PyObject *)self, name, object); - Py_DECREF(name); - Py_DECREF(object); - } - else - PyErr_Clear(); + PyObject_GenericSetAttr((PyObject *)self, name, object); + Py_DECREF(name); + Py_DECREF(object); } + else + PyErr_Clear(); return 0; } @@ -183,7 +128,6 @@ static void WraptObjectProxy_dealloc(WraptObjectProxyObject *self) { Py_XDECREF(self->dict); Py_XDECREF(self->wrapped); - Py_XDECREF(self->target); Py_TYPE(self)->tp_free(self); } @@ -343,6 +287,41 @@ static PyObject *WraptObjectProxy_get_class( /* ------------------------------------------------------------------------- */ +static PyObject *WraptObjectProxy_get_wrapped( + WraptObjectProxyObject *self) +{ + PyObject *result = NULL; + + if (!self->wrapped) { + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + return NULL; + } + + result = PyObject_GetAttrString(self->wrapped, "__wrapped__"); + + if (!result) { + Py_INCREF(self->wrapped); + result = self->wrapped; + } + + return result; +} + +/* ------------------------------------------------------------------------- */ + +static int WraptObjectProxy_set_wrapped(WraptObjectProxyObject *self, + PyObject *value) +{ + if (!self->wrapped) { + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + return -1; + } + + return PyObject_SetAttrString(self->wrapped, "__wrapped__", value); +} + +/* ------------------------------------------------------------------------- */ + static PyObject *WraptObjectProxy_get_annotations( WraptObjectProxyObject *self) { @@ -369,7 +348,7 @@ static int WraptObjectProxy_set_annotations(WraptObjectProxyObject *self, /* ------------------------------------------------------------------------- */ -static PyObject *WraptObjectProxy_get_wrapped( +static PyObject *WraptObjectProxy_get_self_wrapped( WraptObjectProxyObject *self, void *closure) { if (!self->wrapped) { @@ -383,20 +362,6 @@ static PyObject *WraptObjectProxy_get_wrapped( /* ------------------------------------------------------------------------- */ -static PyObject *WraptObjectProxy_get_target( - WraptObjectProxyObject *self, void *closure) -{ - if (!self->target) { - Py_INCREF(Py_None); - return Py_None; - } - - Py_INCREF(self->target); - return self->target; -} - -/* ------------------------------------------------------------------------- */ - static PyObject *WraptObjectProxy_getattro( WraptObjectProxyObject *self, PyObject *name) { @@ -512,9 +477,9 @@ static PyGetSetDef WraptObjectProxy_getset[] = { NULL, 0 }, { "__annotations__", (getter)WraptObjectProxy_get_annotations, (setter)WraptObjectProxy_set_annotations, 0 }, - { "_self_wrapped", (getter)WraptObjectProxy_get_wrapped, - NULL, 0 }, - { "_self_target", (getter)WraptObjectProxy_get_target, + { "__wrapped__", (getter)WraptObjectProxy_get_wrapped, + (setter)WraptObjectProxy_set_wrapped, 0 }, + { "_self_wrapped", (getter)WraptObjectProxy_get_self_wrapped, NULL, 0 }, { NULL }, }; @@ -579,7 +544,7 @@ static PyObject *WraptFunctionWrapper_new(PyTypeObject *type, self->wrapper = NULL; self->params = NULL; - self->wrapper_type = NULL; + self->bound_type = NULL; return (PyObject *)self; } @@ -591,7 +556,6 @@ static int WraptFunctionWrapper_init(WraptFunctionWrapperObject *self, { PyObject *wrapped = NULL; PyObject *wrapper = NULL; - PyObject *target = NULL; PyObject *params = NULL; PyObject *base_args = NULL; @@ -599,26 +563,22 @@ static int WraptFunctionWrapper_init(WraptFunctionWrapperObject *self, int result = 0; - static char *kwlist[] = { "wrapped", "wrapper", "target", "params", - NULL }; + static char *kwlist[] = { "wrapped", "wrapper", "params", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO:FunctionWrapper", - kwlist, &wrapped, &wrapper, &target, ¶ms)) { + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O:FunctionWrapper", + kwlist, &wrapped, &wrapper, ¶ms)) { return -1; } Py_XDECREF(self->wrapper); Py_XDECREF(self->params); - Py_XDECREF(self->wrapper_type); + Py_XDECREF(self->bound_type); self->wrapper = NULL; self->params = NULL; - self->wrapper_type = NULL; + self->bound_type = NULL; - if (!target) - target = Py_None; - - base_args = PyTuple_Pack(2, wrapped, target); + base_args = PyTuple_Pack(1, wrapped); base_kwds = PyDict_New(); result = WraptObjectProxy_init((WraptObjectProxyObject *)self, @@ -639,11 +599,11 @@ static int WraptFunctionWrapper_init(WraptFunctionWrapperObject *self, (PyObject *)&PyClassMethod_Type) || PyObject_IsInstance( wrapped, (PyObject *)&PyStaticMethod_Type)) { Py_INCREF((PyObject *)&WraptBoundFunctionWrapper_Type); - self->wrapper_type = (PyObject *)&WraptBoundFunctionWrapper_Type; + self->bound_type = (PyObject *)&WraptBoundFunctionWrapper_Type; } else { Py_INCREF((PyObject *)&WraptBoundMethodWrapper_Type); - self->wrapper_type = (PyObject *)&WraptBoundMethodWrapper_Type; + self->bound_type = (PyObject *)&WraptBoundMethodWrapper_Type; } } @@ -659,7 +619,7 @@ static void WraptFunctionWrapper_dealloc(WraptFunctionWrapperObject *self) { Py_XDECREF(self->wrapper); Py_XDECREF(self->params); - Py_XDECREF(self->wrapper_type); + Py_XDECREF(self->bound_type); WraptObjectProxy_dealloc((WraptObjectProxyObject *)self); } @@ -708,9 +668,8 @@ static PyObject *WraptFunctionWrapper_descr_get( type = Py_None; if (descriptor) { - result = PyObject_CallFunction(self->wrapper_type, "(OOOOO)", - descriptor, obj, self->wrapper, self->object_proxy.target, - self->params); + result = PyObject_CallFunction(self->bound_type, "(OOOO)", + descriptor, obj, self->wrapper, self->params); } Py_XDECREF(descriptor); @@ -720,7 +679,7 @@ static PyObject *WraptFunctionWrapper_descr_get( /* ------------------------------------------------------------------------- */ -static PyObject *WraptFunctionWrapper_get_wrapper( +static PyObject *WraptFunctionWrapper_get_self_wrapper( WraptFunctionWrapperObject *self, void *closure) { if (!self->wrapper) { @@ -734,7 +693,7 @@ static PyObject *WraptFunctionWrapper_get_wrapper( /* ------------------------------------------------------------------------- */ -static PyObject *WraptFunctionWrapper_get_params( +static PyObject *WraptFunctionWrapper_get_self_params( WraptFunctionWrapperObject *self, void *closure) { if (!self->params) { @@ -748,16 +707,16 @@ static PyObject *WraptFunctionWrapper_get_params( /* ------------------------------------------------------------------------- */ -static PyObject *WraptFunctionWrapper_get_wrapper_type( +static PyObject *WraptFunctionWrapper_get_self_bound_type( WraptFunctionWrapperObject *self, void *closure) { - if (!self->wrapper_type) { + if (!self->bound_type) { Py_INCREF(Py_None); return Py_None; } - Py_INCREF(self->wrapper_type); - return self->wrapper_type; + Py_INCREF(self->bound_type); + return self->bound_type; } /* ------------------------------------------------------------------------- */; @@ -767,11 +726,11 @@ static PyGetSetDef WraptFunctionWrapper_getset[] = { (setter)WraptObjectProxy_set_module, 0 }, { "__doc__", (getter)WraptObjectProxy_get_doc, (setter)WraptObjectProxy_set_doc, 0 }, - { "_self_wrapper", (getter)WraptFunctionWrapper_get_wrapper, + { "_self_wrapper", (getter)WraptFunctionWrapper_get_self_wrapper, NULL, 0 }, - { "_self_params", (getter)WraptFunctionWrapper_get_params, + { "_self_params", (getter)WraptFunctionWrapper_get_self_params, NULL, 0 }, - { "_self_wrapper_type", (getter)WraptFunctionWrapper_get_wrapper_type, + { "_self_bound_type", (getter)WraptFunctionWrapper_get_self_bound_type, NULL, 0 }, { NULL }, }; @@ -849,7 +808,6 @@ static int WraptBoundFunctionWrapper_init( PyObject *wrapped = NULL; PyObject *instance = NULL; PyObject *wrapper = NULL; - PyObject *target = NULL; PyObject *params = NULL; PyObject *base_args = NULL; @@ -858,11 +816,11 @@ static int WraptBoundFunctionWrapper_init( int result = 0; static char *kwlist[] = { "wrapped", "instance", "wrapper", - "target", "params", NULL }; + "params", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwds, - "OOO|OO:BoundFunctionWrapper", kwlist, &wrapped, &instance, - &wrapper, &target, ¶ms)) { + "OOO|O:BoundFunctionWrapper", kwlist, &wrapped, &instance, + &wrapper, ¶ms)) { return -1; } @@ -874,10 +832,7 @@ static int WraptBoundFunctionWrapper_init( self->wrapper = NULL; self->params = NULL; - if (!target) - target = Py_None; - - base_args = PyTuple_Pack(2, wrapped, target); + base_args = PyTuple_Pack(1, wrapped); base_kwds = PyDict_New(); result = WraptObjectProxy_init((WraptObjectProxyObject *)self, @@ -945,7 +900,7 @@ static PyObject *WraptBoundFunctionWrapper_call( /* ------------------------------------------------------------------------- */ -static PyObject *WraptBoundFunctionWrapper_get_instance( +static PyObject *WraptBoundFunctionWrapper_get_self_instance( WraptBoundFunctionWrapperObject *self, void *closure) { if (!self->instance) { @@ -959,7 +914,7 @@ static PyObject *WraptBoundFunctionWrapper_get_instance( /* ------------------------------------------------------------------------- */ -static PyObject *WraptBoundFunctionWrapper_get_wrapper( +static PyObject *WraptBoundFunctionWrapper_get_self_wrapper( WraptBoundFunctionWrapperObject *self, void *closure) { if (!self->wrapper) { @@ -973,7 +928,7 @@ static PyObject *WraptBoundFunctionWrapper_get_wrapper( /* ------------------------------------------------------------------------- */ -static PyObject *WraptBoundFunctionWrapper_get_params( +static PyObject *WraptBoundFunctionWrapper_get_self_params( WraptBoundFunctionWrapperObject *self, void *closure) { if (!self->params) { @@ -992,11 +947,11 @@ static PyGetSetDef WraptBoundFunctionWrapper_getset[] = { (setter)WraptObjectProxy_set_module, 0 }, { "__doc__", (getter)WraptObjectProxy_get_doc, (setter)WraptObjectProxy_set_doc, 0 }, - { "_self_instance", (getter)WraptBoundFunctionWrapper_get_instance, + { "_self_instance", (getter)WraptBoundFunctionWrapper_get_self_instance, NULL, 0 }, - { "_self_wrapper", (getter)WraptBoundFunctionWrapper_get_wrapper, + { "_self_wrapper", (getter)WraptBoundFunctionWrapper_get_self_wrapper, NULL, 0 }, - { "_self_params", (getter)WraptBoundFunctionWrapper_get_params, + { "_self_params", (getter)WraptBoundFunctionWrapper_get_self_params, NULL, 0 }, { NULL }, }; @@ -1074,7 +1029,6 @@ static int WraptBoundMethodWrapper_init( PyObject *wrapped = NULL; PyObject *instance = NULL; PyObject *wrapper = NULL; - PyObject *target = NULL; PyObject *params = NULL; PyObject *base_args = NULL; @@ -1083,11 +1037,11 @@ static int WraptBoundMethodWrapper_init( int result = 0; static char *kwlist[] = { "wrapped", "instance", "wrapper", - "target", "params", NULL }; + "params", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwds, - "OOO|OO:BoundMethodWrapper", kwlist, &wrapped, &instance, - &wrapper, &target, ¶ms)) { + "OOO|O:BoundMethodWrapper", kwlist, &wrapped, &instance, + &wrapper, ¶ms)) { return -1; } @@ -1099,10 +1053,7 @@ static int WraptBoundMethodWrapper_init( self->wrapper = NULL; self->params = NULL; - if (!target) - target = Py_None; - - base_args = PyTuple_Pack(2, wrapped, target); + base_args = PyTuple_Pack(1, wrapped); base_kwds = PyDict_New(); result = WraptObjectProxy_init((WraptObjectProxyObject *)self, @@ -1222,7 +1173,7 @@ static PyObject *WraptBoundMethodWrapper_call( /* ------------------------------------------------------------------------- */ -static PyObject *WraptBoundMethodWrapper_get_instance( +static PyObject *WraptBoundMethodWrapper_get_self_instance( WraptBoundMethodWrapperObject *self, void *closure) { if (!self->instance) { @@ -1236,7 +1187,7 @@ static PyObject *WraptBoundMethodWrapper_get_instance( /* ------------------------------------------------------------------------- */ -static PyObject *WraptBoundMethodWrapper_get_wrapper( +static PyObject *WraptBoundMethodWrapper_get_self_wrapper( WraptBoundMethodWrapperObject *self, void *closure) { if (!self->wrapper) { @@ -1250,7 +1201,7 @@ static PyObject *WraptBoundMethodWrapper_get_wrapper( /* ------------------------------------------------------------------------- */ -static PyObject *WraptBoundMethodWrapper_get_params( +static PyObject *WraptBoundMethodWrapper_get_self_params( WraptBoundMethodWrapperObject *self, void *closure) { if (!self->params) { @@ -1269,11 +1220,11 @@ static PyGetSetDef WraptBoundMethodWrapper_getset[] = { (setter)WraptObjectProxy_set_module, 0 }, { "__doc__", (getter)WraptObjectProxy_get_doc, (setter)WraptObjectProxy_set_doc, 0 }, - { "_self_instance", (getter)WraptBoundMethodWrapper_get_instance, + { "_self_instance", (getter)WraptBoundMethodWrapper_get_self_instance, NULL, 0 }, - { "_self_wrapper", (getter)WraptBoundMethodWrapper_get_wrapper, + { "_self_wrapper", (getter)WraptBoundMethodWrapper_get_self_wrapper, NULL, 0 }, - { "_self_params", (getter)WraptBoundMethodWrapper_get_params, + { "_self_params", (getter)WraptBoundMethodWrapper_get_self_params, NULL, 0 }, { NULL }, }; diff --git a/src/decorators.py b/src/decorators.py index 57e8103..854c4ca 100644 --- a/src/decorators.py +++ b/src/decorators.py @@ -9,16 +9,38 @@ from .wrappers import FunctionWrapper from .exceptions import (UnexpectedDefaultParameters, MissingDefaultParameter, UnexpectedParameters) +# 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 +# themselves acting like a transparent proxy for the original wrapped +# function so they the wrapper is effectively indistinguishable from +# the original wrapped function. + WRAPPER_ARGLIST = ('wrapped', 'instance', 'args', 'kwargs') def decorator(wrapper=None, target=None, **default_params): # The decorator works out whether the user decorator will have its # own parameters. Parameters for the user decorator must always # be specified using keyword arguments and must always have - # defaults. The user cannot use 'wrapper' or 'adapter' for their + # defaults. The user cannot use 'wrapper' or 'target' for their # own parameters as we use them ourselves and so they are # effectively reserved. The 'wrapper' argument being how the - # user's wrapper function is passed in. The 'adapter' argument + # user's wrapper function is passed in. The 'target' argument # is used to optionally denote a function which is an adapter, # which changes the effective prototype of the wrapped function. # The latter is used to ensure that any function argument @@ -111,8 +133,11 @@ def decorator(wrapper=None, target=None, **default_params): # combines the parameters with the wrapped function. def _wrapper(func): - return FunctionWrapper(wrapped=func, wrapper=wrapper, - target=target, params=complete_params) + result = FunctionWrapper(wrapped=func, wrapper=wrapper, + params=complete_params) + if target: + _update_adapter(result, target) + return result return _wrapper # Here is where the partial wrapper is returned. This is @@ -126,8 +151,10 @@ def decorator(wrapper=None, target=None, **default_params): @wraps(wrapper) def _wrapper(func): - return FunctionWrapper(wrapped=func, wrapper=wrapper, - target=target) + result = FunctionWrapper(wrapped=func, wrapper=wrapper) + if target: + _update_adapter(result, target) + return result return _wrapper else: diff --git a/src/wrappers.py b/src/wrappers.py index 0b4c6f9..33de4fb 100644 --- a/src/wrappers.py +++ b/src/wrappers.py @@ -49,33 +49,15 @@ class _ObjectProxyMetaType(type): class ObjectProxy(six.with_metaclass(_ObjectProxyMetaType)): - def __init__(self, wrapped, target=None): + def __init__(self, wrapped): self._self_wrapped = wrapped - # Python 3.2+ has the __wrapped__ attribute which is meant to - # hold a reference to the inner most wrapped object when there - # are multiple decorators. We handle __wrapped__ and also - # duplicate that functionality for Python 2, although it will - # only go as far as what is below our own wrappers when there is - # more than one for Python 2. - - if target is None: - try: - self._self_target = wrapped.__wrapped__ - except AttributeError: - self._self_target = wrapped - else: - self._self_target = target - # Python 3.2+ has the __qualname__ attribute, but it does not # allow it to be overridden using a property and it must instead # be an actual string object instead. try: - if target is None: - object.__setattr__(self, '__qualname__', wrapped.__qualname__) - else: - object.__setattr__(self, '__qualname__', target.__qualname__) + object.__setattr__(self, '__qualname__', wrapped.__qualname__) except AttributeError: pass @@ -85,10 +67,7 @@ class ObjectProxy(six.with_metaclass(_ObjectProxyMetaType)): # if overriding it as a property is sufficient in all cases. try: - if target is None: - object.__setattr__(self, '__name__', wrapped.__name__) - else: - object.__setattr__(self, '__name__', target.__name__) + object.__setattr__(self, '__name__', wrapped.__name__) except AttributeError: pass @@ -122,7 +101,10 @@ class ObjectProxy(six.with_metaclass(_ObjectProxyMetaType)): @property def __wrapped__(self): - return self._self_target + try: + return self._self_wrapped.__wrapped__ + except AttributeError: + return self._self_wrapped @__wrapped__.setter def __wrapped__(self, value): @@ -169,8 +151,8 @@ class ObjectProxy(six.with_metaclass(_ObjectProxyMetaType)): class _BoundFunctionWrapper(ObjectProxy): - def __init__(self, wrapped, instance, wrapper, target=None, params={}): - super(_BoundFunctionWrapper, self).__init__(wrapped, target) + def __init__(self, wrapped, instance, wrapper, params={}): + super(_BoundFunctionWrapper, self).__init__(wrapped) self._self_instance = instance self._self_wrapper = wrapper self._self_params = params @@ -181,8 +163,8 @@ class _BoundFunctionWrapper(ObjectProxy): class _BoundMethodWrapper(ObjectProxy): - def __init__(self, wrapped, instance, wrapper, target=None, params={}): - super(_BoundMethodWrapper, self).__init__(wrapped, target) + def __init__(self, wrapped, instance, wrapper, params={}): + super(_BoundMethodWrapper, self).__init__(wrapped) self._self_instance = instance self._self_wrapper = wrapper self._self_params = params @@ -206,8 +188,8 @@ class _BoundMethodWrapper(ObjectProxy): class FunctionWrapper(ObjectProxy): - def __init__(self, wrapped, wrapper, target=None, params={}): - super(FunctionWrapper, self).__init__(wrapped, target) + def __init__(self, wrapped, wrapper, params={}): + super(FunctionWrapper, self).__init__(wrapped) self._self_wrapper = wrapper self._self_params = params @@ -244,15 +226,15 @@ class FunctionWrapper(ObjectProxy): # later. if isinstance(self._self_wrapped, (classmethod, staticmethod)): - self._self_wrapper_type = _BoundFunctionWrapper + self._self_bound_type = _BoundFunctionWrapper else: - self._self_wrapper_type = _BoundMethodWrapper + self._self_bound_type = _BoundMethodWrapper def __get__(self, instance, owner): descriptor = self._self_wrapped.__get__(instance, owner) - return self._self_wrapper_type(descriptor, instance, - self._self_wrapper, self._self_target, self._self_params) + return self._self_bound_type(descriptor, instance, self._self_wrapper, + self._self_params) def __call__(self, *args, **kwargs): # This is invoked when the wrapped function is being called as a diff --git a/tests/test_adapter.py b/tests/test_adapter.py index 5fc6897..a2d337c 100644 --- a/tests/test_adapter.py +++ b/tests/test_adapter.py @@ -2,26 +2,36 @@ from __future__ import print_function import unittest import inspect +import imp import wrapt -def function1(arg): - '''documentation''' - return arg +from wrapt import six -function1o = function1 +DECORATORS_CODE = """ +import wrapt def adapter1(func): @wrapt.adapter(target=func) def _adapter(arg): - """adapter documentation""" - return func() + '''adapter documentation''' + return func(arg, arg) return _adapter +""" -@adapter1 -def function1(arg): +decorators = imp.new_module('decorators') +six.exec_(DECORATORS_CODE, decorators.__dict__, decorators.__dict__) + +def function1(arg1, arg2): '''documentation''' - return arg + return arg1, arg2 + +function1o = function1 + +@decorators.adapter1 +def function1(arg1, arg2): + '''documentation''' + return arg1, arg2 function1d = function1 @@ -54,11 +64,14 @@ class TestNamingAdapter(unittest.TestCase): self.assertEqual(function1d.__doc__, 'adapter documentation') def test_argspec(self): - # Test preservation of function argument specification. + # Test preservation of function argument specification. It + # actually needs to match that of the adapter function. - function1o_argspec = inspect.getargspec(function1o) + def _adapter(arg): pass + + function1a_argspec = inspect.getargspec(_adapter) function1d_argspec = inspect.getargspec(function1d) - self.assertEqual(function1o_argspec, function1d_argspec) + self.assertEqual(function1a_argspec, function1d_argspec) def test_isinstance(self): # Test preservation of isinstance() checks. diff --git a/tests/test_function_wrapper.py b/tests/test_function_wrapper.py index 3d27e8e..809f65f 100644 --- a/tests/test_function_wrapper.py +++ b/tests/test_function_wrapper.py @@ -89,9 +89,8 @@ class TestAttributeAccess(unittest.TestCase): self.assertEqual(function2._self_wrapped, function1) self.assertEqual(function2._self_wrapper, decorator1) - self.assertEqual(function2._self_target, function1) self.assertEqual(function2._self_params, {}) - self.assertNotEqual(function2._self_wrapper_type, None) + self.assertNotEqual(function2._self_bound_type, None) def test_instancemethod_attributes(self): def decorator1(wrapped, instance, args, kwargs): @@ -105,9 +104,8 @@ class TestAttributeAccess(unittest.TestCase): self.assertEqual(function2._self_wrapped, function1) self.assertEqual(function2._self_wrapper, decorator1) - self.assertEqual(function2._self_target, function1) self.assertEqual(function2._self_params, {}) - self.assertNotEqual(function2._self_wrapper_type, None) + self.assertNotEqual(function2._self_bound_type, None) instance = Class() @@ -129,9 +127,8 @@ class TestAttributeAccess(unittest.TestCase): self.assertEqual(function2._self_wrapped, function1) self.assertEqual(function2._self_wrapper, decorator1) - self.assertEqual(function2._self_target, function1) self.assertEqual(function2._self_params, {}) - self.assertNotEqual(function2._self_wrapper_type, None) + self.assertNotEqual(function2._self_bound_type, None) instance = Class() @@ -153,9 +150,8 @@ class TestAttributeAccess(unittest.TestCase): self.assertEqual(function2._self_wrapped, function1) self.assertEqual(function2._self_wrapper, decorator1) - self.assertEqual(function2._self_target, function1) self.assertEqual(function2._self_params, {}) - self.assertNotEqual(function2._self_wrapper_type, None) + self.assertNotEqual(function2._self_bound_type, None) instance = Class() diff --git a/tests/test_object_proxy.py b/tests/test_object_proxy.py index fc0b880..233ee1b 100644 --- a/tests/test_object_proxy.py +++ b/tests/test_object_proxy.py @@ -27,7 +27,28 @@ class TestAttributeAccess(unittest.TestCase): function2 = wrapt.ObjectProxy(function1) self.assertEqual(function2._self_wrapped, function1) - self.assertEqual(function2._self_target, function1) + + def test_get_wrapped(self): + def function1(*args, **kwargs): + return args, kwargs + function2 = wrapt.ObjectProxy(function1) + + self.assertEqual(function2.__wrapped__, function1) + + function3 = wrapt.ObjectProxy(function2) + + self.assertEqual(function3.__wrapped__, function1) + + def test_set_wrapped(self): + def function1(*args, **kwargs): + return args, kwargs + function2 = wrapt.ObjectProxy(function1) + + self.assertEqual(function2.__wrapped__, function1) + + function2.__wrapped__ = None + + self.assertEqual(function2.__wrapped__, None) class TestNamingObjectProxy(unittest.TestCase):