Handle name preservation for an adapter when creating the decorator rather than in the wrapper itself.

This commit is contained in:
Graham Dumpleton
2013-08-19 21:57:20 +10:00
parent 1fc4164750
commit 1bceb79e30
6 changed files with 203 additions and 213 deletions

View File

@@ -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, &params)) {
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O:FunctionWrapper",
kwlist, &wrapped, &wrapper, &params)) {
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, &params)) {
"OOO|O:BoundFunctionWrapper", kwlist, &wrapped, &instance,
&wrapper, &params)) {
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, &params)) {
"OOO|O:BoundMethodWrapper", kwlist, &wrapped, &instance,
&wrapper, &params)) {
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 },
};

View File

@@ -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:

View File

@@ -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

View File

@@ -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.

View File

@@ -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()

View File

@@ -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):