diff --git a/docs/changes.rst b/docs/changes.rst index ffb1efe..894cc29 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -22,7 +22,8 @@ Version 1.2.0 * When creating a custom proxy by deriving from ObjectProxy and the custom proxy needed to override __getattr__(), it was not possible to called the base class ObjectProxy.__getattr__() when the C implementation of - ObjectProxy was being used. + ObjectProxy was being used. The derived class __getattr__() could also + get ignored. Version 1.1.3 ------------- diff --git a/src/_wrappers.c b/src/_wrappers.c index b6ddbba..fde4b1c 100644 --- a/src/_wrappers.c +++ b/src/_wrappers.c @@ -1164,6 +1164,9 @@ static PyObject *WraptObjectProxy_getattro( WraptObjectProxyObject *self, PyObject *name) { PyObject *object = NULL; + PyObject *result = NULL; + + static PyObject *getattr_str = NULL; object = PyObject_GenericGetAttr((PyObject *)self, name); @@ -1172,12 +1175,24 @@ static PyObject *WraptObjectProxy_getattro( PyErr_Clear(); - if (!self->wrapped) { - PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); - return NULL; + if (!getattr_str) { +#if PY_MAJOR_VERSION >= 3 + getattr_str = PyUnicode_InternFromString("__getattr__"); +#else + getattr_str = PyString_InternFromString("__getattr__"); +#endif } - return PyObject_GetAttr(self->wrapped, name); + object = PyObject_GenericGetAttr((PyObject *)self, getattr_str); + + if (!object) + return NULL; + + result = PyObject_CallFunction(object, "(O)", name); + + Py_DECREF(object); + + return result; } /* ------------------------------------------------------------------------- */ @@ -1195,7 +1210,12 @@ static PyObject *WraptObjectProxy_getattr( return NULL; #endif - return WraptObjectProxy_getattro(self, name); + if (!self->wrapped) { + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + return NULL; + } + + return PyObject_GetAttr(self->wrapped, name); } /* ------------------------------------------------------------------------- */ diff --git a/tests/test_object_proxy.py b/tests/test_object_proxy.py index 5f68491..9696b02 100644 --- a/tests/test_object_proxy.py +++ b/tests/test_object_proxy.py @@ -1292,17 +1292,6 @@ class TestDerivedClassCreation(unittest.TestCase): class DerivedClassAttributes(unittest.TestCase): - def test_attr_functions(self): - - def function(): - pass - - proxy = wrapt.ObjectProxy(function) - - self.assertTrue(hasattr(proxy, '__getattr__')) - self.assertTrue(hasattr(proxy, '__setattr__')) - self.assertTrue(hasattr(proxy, '__delattr__')) - def test_setup_class_attributes(self): def function(): @@ -1397,5 +1386,42 @@ class DerivedClassAttributes(unittest.TestCase): self.assertFalse(hasattr(obj, 'ATTRIBUTE')) self.assertFalse(hasattr(function, 'ATTRIBUTE')) +class OverrideAttributeAccess(unittest.TestCase): + + def test_attr_functions(self): + + def function(): + pass + + proxy = wrapt.ObjectProxy(function) + + self.assertTrue(hasattr(proxy, '__getattr__')) + self.assertTrue(hasattr(proxy, '__setattr__')) + self.assertTrue(hasattr(proxy, '__delattr__')) + + def test_override_getattr(self): + + def function(): + pass + + accessed = [] + + class DerivedObjectProxy(wrapt.ObjectProxy): + def __getattr__(self, name): + accessed.append(name) + try: + __getattr__ = super(DerivedObjectProxy, self).__getattr__ + except AttributeError as e: + raise RuntimeError(str(e)) + return __getattr__(name) + + function.attribute = 1 + + proxy = DerivedObjectProxy(function) + + self.assertEqual(proxy.attribute, 1) + + self.assertTrue('attribute' in accessed) + if __name__ == '__main__': unittest.main()