Implement inheritance between C implementations of wrapper classes and object proxy.

This commit is contained in:
Graham Dumpleton
2013-08-14 22:23:25 +08:00
parent c18581be36
commit 7a24950da0
3 changed files with 260 additions and 99 deletions

View File

@@ -216,47 +216,6 @@ static PyObject *WraptObjectProxy_dir(
/* ------------------------------------------------------------------------- */
static PyObject *WraptObjectProxy_get_wrapped(
WraptObjectProxyObject *self, void *closure)
{
if (!self->wrapped) {
Py_INCREF(Py_None);
return Py_None;
}
Py_INCREF(self->wrapped);
return self->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_get_class(
WraptObjectProxyObject *self)
{
if (!self->wrapped) {
PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised");
return NULL;
}
return PyObject_GetAttrString(self->wrapped, "__class__");
}
/* ------------------------------------------------------------------------- */
static PyObject *WraptObjectProxy_get_module(
WraptObjectProxyObject *self)
{
@@ -309,6 +268,19 @@ static int WraptObjectProxy_set_doc(WraptObjectProxyObject *self,
/* ------------------------------------------------------------------------- */
static PyObject *WraptObjectProxy_get_class(
WraptObjectProxyObject *self)
{
if (!self->wrapped) {
PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised");
return NULL;
}
return PyObject_GetAttrString(self->wrapped, "__class__");
}
/* ------------------------------------------------------------------------- */
static PyObject *WraptObjectProxy_get_annotations(
WraptObjectProxyObject *self)
{
@@ -335,6 +307,34 @@ static int WraptObjectProxy_set_annotations(WraptObjectProxyObject *self,
/* ------------------------------------------------------------------------- */
static PyObject *WraptObjectProxy_get_wrapped(
WraptObjectProxyObject *self, void *closure)
{
if (!self->wrapped) {
Py_INCREF(Py_None);
return Py_None;
}
Py_INCREF(self->wrapped);
return self->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)
{
@@ -425,18 +425,18 @@ static PyMethodDef WraptObjectProxy_methods[] = {
};
static PyGetSetDef WraptObjectProxy_getset[] = {
{ "_self_wrapped", (getter)WraptObjectProxy_get_wrapped,
NULL, 0 },
{ "_self_target", (getter)WraptObjectProxy_get_target,
NULL, 0 },
{ "__class__", (getter)WraptObjectProxy_get_class,
NULL, 0 },
{ "__module__", (getter)WraptObjectProxy_get_module,
(setter)WraptObjectProxy_set_module, 0 },
{ "__doc__", (getter)WraptObjectProxy_get_doc,
(setter)WraptObjectProxy_set_doc, 0 },
{ "__class__", (getter)WraptObjectProxy_get_class,
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,
NULL, 0 },
{ NULL },
};
@@ -684,24 +684,16 @@ static PyObject *WraptFunctionWrapper_get_wrapper_type(
/* ------------------------------------------------------------------------- */;
static PyGetSetDef WraptFunctionWrapper_getset[] = {
{ "_self_wrapped", (getter)WraptObjectProxy_get_wrapped,
NULL, 0 },
{ "__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_wrapper,
NULL, 0 },
{ "_self_target", (getter)WraptObjectProxy_get_target,
NULL, 0 },
{ "_self_params", (getter)WraptFunctionWrapper_get_params,
NULL, 0 },
{ "_self_wrapper_type", (getter)WraptFunctionWrapper_get_wrapper_type,
NULL, 0 },
{ "__class__", (getter)WraptObjectProxy_get_class,
NULL, 0 },
{ "__module__", (getter)WraptObjectProxy_get_module,
(setter)WraptObjectProxy_set_module, 0 },
{ "__doc__", (getter)WraptObjectProxy_get_doc,
(setter)WraptObjectProxy_set_doc, 0 },
{ "__annotations__", (getter)WraptObjectProxy_get_annotations,
(setter)WraptObjectProxy_set_annotations, 0 },
{ NULL },
};
@@ -723,8 +715,8 @@ PyTypeObject WraptFunctionWrapper_Type = {
0, /*tp_hash*/
(ternaryfunc)WraptFunctionWrapper_call, /*tp_call*/
0, /*tp_str*/
(getattrofunc)WraptObjectProxy_getattro, /*tp_getattro*/
(setattrofunc)WraptObjectProxy_setattro, /*tp_setattro*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT |
Py_TPFLAGS_BASETYPE, /*tp_flags*/
@@ -733,7 +725,7 @@ PyTypeObject WraptFunctionWrapper_Type = {
0, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
(getiterfunc)WraptObjectProxy_iter, /*tp_iter*/
0, /*tp_iter*/
0, /*tp_iternext*/
0, /*tp_methods*/
0, /*tp_members*/
@@ -742,7 +734,7 @@ PyTypeObject WraptFunctionWrapper_Type = {
0, /*tp_dict*/
(descrgetfunc)WraptFunctionWrapper_descr_get, /*tp_descr_get*/
0, /*tp_descr_set*/
offsetof(WraptObjectProxyObject, dict), /*tp_dictoffset*/
0, /*tp_dictoffset*/
(initproc)WraptFunctionWrapper_init, /*tp_init*/
0, /*tp_alloc*/
WraptFunctionWrapper_new, /*tp_new*/
@@ -917,24 +909,16 @@ static PyObject *WraptBoundFunctionWrapper_get_params(
/* ------------------------------------------------------------------------- */;
static PyGetSetDef WraptBoundFunctionWrapper_getset[] = {
{ "_self_wrapped", (getter)WraptObjectProxy_get_wrapped,
NULL, 0 },
{ "_self_instance", (getter)WraptBoundFunctionWrapper_get_instance,
NULL, 0 },
{ "_self_wrapper", (getter)WraptBoundFunctionWrapper_get_wrapper,
NULL, 0 },
{ "_self_target", (getter)WraptObjectProxy_get_target,
NULL, 0 },
{ "_self_params", (getter)WraptBoundFunctionWrapper_get_params,
NULL, 0 },
{ "__class__", (getter)WraptObjectProxy_get_class,
NULL, 0 },
{ "__module__", (getter)WraptObjectProxy_get_module,
(setter)WraptObjectProxy_set_module, 0 },
{ "__doc__", (getter)WraptObjectProxy_get_doc,
(setter)WraptObjectProxy_set_doc, 0 },
{ "__annotations__", (getter)WraptObjectProxy_get_annotations,
(setter)WraptObjectProxy_set_annotations, 0 },
{ "_self_instance", (getter)WraptBoundFunctionWrapper_get_instance,
NULL, 0 },
{ "_self_wrapper", (getter)WraptBoundFunctionWrapper_get_wrapper,
NULL, 0 },
{ "_self_params", (getter)WraptBoundFunctionWrapper_get_params,
NULL, 0 },
{ NULL },
};
@@ -956,8 +940,8 @@ PyTypeObject WraptBoundFunctionWrapper_Type = {
0, /*tp_hash*/
(ternaryfunc)WraptBoundFunctionWrapper_call, /*tp_call*/
0, /*tp_str*/
(getattrofunc)WraptObjectProxy_getattro, /*tp_getattro*/
(setattrofunc)WraptObjectProxy_setattro, /*tp_setattro*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT |
Py_TPFLAGS_BASETYPE, /*tp_flags*/
@@ -966,7 +950,7 @@ PyTypeObject WraptBoundFunctionWrapper_Type = {
0, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
(getiterfunc)WraptObjectProxy_iter, /*tp_iter*/
0, /*tp_iter*/
0, /*tp_iternext*/
0, /*tp_methods*/
0, /*tp_members*/
@@ -975,7 +959,7 @@ PyTypeObject WraptBoundFunctionWrapper_Type = {
0, /*tp_dict*/
0, /*tp_descr_get*/
0, /*tp_descr_set*/
offsetof(WraptObjectProxyObject, dict), /*tp_dictoffset*/
0, /*tp_dictoffset*/
(initproc)WraptBoundFunctionWrapper_init, /*tp_init*/
0, /*tp_alloc*/
WraptBoundFunctionWrapper_new, /*tp_new*/
@@ -1202,24 +1186,16 @@ static PyObject *WraptBoundMethodWrapper_get_params(
/* ------------------------------------------------------------------------- */;
static PyGetSetDef WraptBoundMethodWrapper_getset[] = {
{ "_self_wrapped", (getter)WraptObjectProxy_get_wrapped,
NULL, 0 },
{ "_self_instance", (getter)WraptBoundMethodWrapper_get_instance,
NULL, 0 },
{ "_self_wrapper", (getter)WraptBoundMethodWrapper_get_wrapper,
NULL, 0 },
{ "_self_target", (getter)WraptObjectProxy_get_target,
NULL, 0 },
{ "_self_params", (getter)WraptBoundMethodWrapper_get_params,
NULL, 0 },
{ "__class__", (getter)WraptObjectProxy_get_class,
NULL, 0 },
{ "__module__", (getter)WraptObjectProxy_get_module,
(setter)WraptObjectProxy_set_module, 0 },
{ "__doc__", (getter)WraptObjectProxy_get_doc,
(setter)WraptObjectProxy_set_doc, 0 },
{ "__annotations__", (getter)WraptObjectProxy_get_annotations,
(setter)WraptObjectProxy_set_annotations, 0 },
{ "_self_instance", (getter)WraptBoundMethodWrapper_get_instance,
NULL, 0 },
{ "_self_wrapper", (getter)WraptBoundMethodWrapper_get_wrapper,
NULL, 0 },
{ "_self_params", (getter)WraptBoundMethodWrapper_get_params,
NULL, 0 },
{ NULL },
};
@@ -1241,8 +1217,8 @@ PyTypeObject WraptBoundMethodWrapper_Type = {
0, /*tp_hash*/
(ternaryfunc)WraptBoundMethodWrapper_call, /*tp_call*/
0, /*tp_str*/
(getattrofunc)WraptObjectProxy_getattro, /*tp_getattro*/
(setattrofunc)WraptObjectProxy_setattro, /*tp_setattro*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT |
Py_TPFLAGS_BASETYPE, /*tp_flags*/
@@ -1251,7 +1227,7 @@ PyTypeObject WraptBoundMethodWrapper_Type = {
0, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
(getiterfunc)WraptObjectProxy_iter, /*tp_iter*/
0, /*tp_iter*/
0, /*tp_iternext*/
0, /*tp_methods*/
0, /*tp_members*/
@@ -1260,7 +1236,7 @@ PyTypeObject WraptBoundMethodWrapper_Type = {
0, /*tp_dict*/
0, /*tp_descr_get*/
0, /*tp_descr_set*/
offsetof(WraptObjectProxyObject, dict), /*tp_dictoffset*/
0, /*tp_dictoffset*/
(initproc)WraptBoundMethodWrapper_init, /*tp_init*/
0, /*tp_alloc*/
WraptBoundMethodWrapper_new, /*tp_new*/
@@ -1300,6 +1276,13 @@ moduleinit(void)
if (PyType_Ready(&WraptObjectProxy_Type) < 0)
return NULL;
/* Ensure that inheritence relationships specified. */
WraptFunctionWrapper_Type.tp_base = &WraptObjectProxy_Type;
WraptBoundFunctionWrapper_Type.tp_base = &WraptObjectProxy_Type;
WraptBoundMethodWrapper_Type.tp_base = &WraptObjectProxy_Type;
if (PyType_Ready(&WraptFunctionWrapper_Type) < 0)
return NULL;
if (PyType_Ready(&WraptBoundFunctionWrapper_Type) < 0)

View File

@@ -0,0 +1,168 @@
from __future__ import print_function
import unittest
import wrapt
from wrapt import six
class TestClassInheritence(unittest.TestCase):
def test_function_type_inheritence(self):
@wrapt.decorator
def _decorator(wrapped, instance, args, kwargs):
return wrapped(*args, **kwargs)
@_decorator
def _function(*args, **kwargs):
return args, kwargs
self.assertTrue(isinstance(_function, wrapt.FunctionWrapper))
self.assertTrue(isinstance(_function, wrapt.ObjectProxy))
def test_instancemethod_type_inheritence(self):
@wrapt.decorator
def _decorator(wrapped, instance, args, kwargs):
return wrapped(*args, **kwargs)
class Class(object):
@_decorator
def function(self, args, **kwargs):
return args, kwargs
self.assertTrue(isinstance(function, wrapt.FunctionWrapper))
self.assertTrue(isinstance(function, wrapt.ObjectProxy))
instance = Class()
self.assertFalse(isinstance(instance.function, wrapt.FunctionWrapper))
self.assertTrue(isinstance(instance.function, wrapt.ObjectProxy))
def test_classmethod_type_inheritence(self):
@wrapt.decorator
def _decorator(wrapped, instance, args, kwargs):
return wrapped(*args, **kwargs)
class Class(object):
@_decorator
@classmethod
def function(cls, *args, **kwargs):
return args, kwargs
self.assertTrue(isinstance(function, wrapt.FunctionWrapper))
self.assertTrue(isinstance(function, wrapt.ObjectProxy))
instance = Class()
self.assertFalse(isinstance(instance.function, wrapt.FunctionWrapper))
self.assertTrue(isinstance(instance.function, wrapt.ObjectProxy))
def test_staticmethod_type_inheritence(self):
@wrapt.decorator
def _decorator(wrapped, instance, args, kwargs):
return wrapped(*args, **kwargs)
class Class(object):
@_decorator
@staticmethod
def function(*args, **kwargs):
return args, kwargs
self.assertTrue(isinstance(function, wrapt.FunctionWrapper))
self.assertTrue(isinstance(function, wrapt.ObjectProxy))
instance = Class()
self.assertFalse(isinstance(instance.function, wrapt.FunctionWrapper))
self.assertTrue(isinstance(instance.function, wrapt.ObjectProxy))
class TestAttributeAccess(unittest.TestCase):
def test_function_attributes(self):
def decorator1(wrapped, instance, args, kwargs):
return wrapped(*args, **kwargs)
decorator2 = wrapt.decorator(decorator1)
def function1(*args, **kwargs):
return args, kwargs
function2 = decorator2(function1)
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)
def test_instancemethod_attributes(self):
def decorator1(wrapped, instance, args, kwargs):
return wrapped(*args, **kwargs)
decorator2 = wrapt.decorator(decorator1)
class Class(object):
def function1(self, *args, **kwargs):
return args, kwargs
function2 = decorator2(function1)
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)
instance = Class()
self.assertEqual(instance.function2._self_wrapped, instance.function1)
self.assertEqual(instance.function2._self_instance, instance)
self.assertEqual(instance.function2._self_wrapper, decorator1)
self.assertEqual(instance.function2._self_params, {})
def test_classmethod_attributes(self):
def decorator1(wrapped, instance, args, kwargs):
return wrapped(*args, **kwargs)
decorator2 = wrapt.decorator(decorator1)
class Class(object):
@classmethod
def function1(cls, *args, **kwargs):
return args, kwargs
function2 = decorator2(function1)
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)
instance = Class()
self.assertEqual(instance.function2._self_wrapped, instance.function1)
self.assertEqual(instance.function2._self_instance, instance)
self.assertEqual(instance.function2._self_wrapper, decorator1)
self.assertEqual(instance.function2._self_params, {})
def test_staticmethod_attributes(self):
def decorator1(wrapped, instance, args, kwargs):
return wrapped(*args, **kwargs)
decorator2 = wrapt.decorator(decorator1)
class Class(object):
@staticmethod
def function1(*args, **kwargs):
return args, kwargs
function2 = decorator2(function1)
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)
instance = Class()
self.assertEqual(instance.function2._self_wrapped, instance.function1)
self.assertEqual(instance.function2._self_instance, instance)
self.assertEqual(instance.function2._self_wrapper, decorator1)
self.assertEqual(instance.function2._self_params, {})
if __name__ == '__main__':
unittest.main()

View File

@@ -19,6 +19,16 @@ def target():
objects = imp.new_module('objects')
six.exec_(OBJECTS_CODE, objects.__dict__, objects.__dict__)
class TestAttributeAccess(unittest.TestCase):
def test_attributes(self):
def function1(*args, **kwargs):
return args, kwargs
function2 = wrapt.ObjectProxy(function1)
self.assertEqual(function2._self_wrapped, function1)
self.assertEqual(function2._self_target, function1)
class TestNamingObjectProxy(unittest.TestCase):
def test_class_object_name(self):