Commits

Lenard Lindstrom committed 648fe1a

Remove default BufferMixin methods _get_buffer and _release_buffer

These default methods caused problems with multiple inheritance. For a subclass
with multiple base classes to inherit the new buffer interface from BufferMixin,
BufferMixin must be first in the subclass's inheritance list. If the subclass's _get_buffer and _release_buffer methods were inherited from another base class, the BufferMixin defaults hid them.

Comments (0)

Files changed (2)

     return BufferSubtype_New(&Py_buffer_Type, view_p, filled, preserve);
 }
 
-static PyObject *
-mixin__get_buffer(PyObject *self, PyObject *args)
-{
-    PyErr_SetString(PyExc_NotImplementedError, "abstract method");
-    return 0;
-}
-
-static PyObject *
-mixin__release_buffer(PyObject *self, PyObject *arg)
-{
-    Py_RETURN_NONE;
-}
-
-static PyMethodDef mixin_methods[] = {
-    {"_get_buffer", (PyCFunction)mixin__get_buffer, METH_VARARGS,
-     "new buffer protocol default bf_getbuffer handler"},
-    {"_release_buffer", (PyCFunction)mixin__release_buffer, METH_O,
-     "new buffer protocol default bf_releasebuffer handler"},
-    {0, 0, 0, 0}
-};
-
 static int
 mixin_getbuffer(PyObject *self, Py_buffer *view_p, int flags)
 {
     PyObject *py_view = Buffer_New(view_p, 0, 1);
+    PyObject *py_method = 0;
     PyObject *py_rval = 0;
-    int rval = -1;
 
-    if (py_view) {
-        py_rval = PyObject_CallMethod(self, "_get_buffer", "(Oi)",
-                                      py_view, flags);
-        Buffer_Reset((BufferObject *)py_view);
+    if (!py_view) {
+        return -1;
+    }
+    py_method = PyObject_GetAttrString(self, "_get_buffer");
+    if (!py_method) {
         Py_DECREF(py_view);
-        if (py_rval == Py_None) {
-            rval = 0;
-            Py_DECREF(py_rval);
-        }
-        else if (py_rval) {
-            PyErr_SetString(PyExc_ValueError,
-                            "_get_buffer method return value was not None");
-            Py_DECREF(py_rval);
-        }
+        PyErr_Clear();
+        PyErr_SetString(PyExc_NotImplementedError, "abstract method");
+        return -1;
     }
-    return rval;
+    py_rval = PyObject_CallFunction(py_method, "(Oi)", py_view, flags);
+    Py_DECREF(py_method);
+    Buffer_Reset((BufferObject *)py_view);
+    Py_DECREF(py_view);
+    if (py_rval == Py_None) {
+        Py_DECREF(py_rval);
+    }
+    else if (py_rval) {
+        PyErr_SetString(PyExc_ValueError,
+                        "_get_buffer method return value was not None");
+        Py_DECREF(py_rval);
+        return -1;
+    }
+    else {
+        return -1;
+    }
+    return 0;
 }
 
 static void
     0,                          /* tp_weaklistoffset */
     0,                          /* tp_iter */
     0,                          /* tp_iternext */
-    mixin_methods,              /* tp_methods */
+    0,                          /* tp_methods */
     0,                          /* tp_members */
     0,                          /* tp_getset */
     0,                          /* tp_base */

newbuffer_test.py

         self.assertRaises(ValueError, m.get_buffer, B())
 
     def test_default_method(self):
-        """verify the default _get_buffer method is abstract"""
+        """verify the _get_buffer method is required"""
         m = Py_buffer()
-        self.assertTrue(hasattr(BufferMixin, '_get_buffer'))
         self.assertRaises(NotImplementedError, m.get_buffer, BufferMixin())
 
 class BufferMixinReleaseBufferTest(unittest.TestCase):
     """BufferMixin._release_buffer verification"""
-    def test_default_method(self):
-        """verify the default _release_buffer method exists"""
-        self.assertTrue(hasattr(BufferMixin, '_release_buffer'))
-        # It just returns without doing anything
-        b = BufferMixin()
-        self.assertTrue(b._release_buffer(None) is None)
-
     class B(BufferMixin):
         def __init__(self):
             self.is_called = False
         m.release_buffer()
         self.assertTrue(b.released)
 
+    def test_multiple_inheritance(self):
+        class A(object):
+            def _get_buffer(self, view, flags):
+                view.obj = self
+        class B(BufferMixin, A):
+            pass
+        b = B()
+        m = Py_buffer()
+        m.get_buffer(b, PyBUF_SIMPLE)
+        self.assertTrue(m.obj is b)
+
 class ModuleConstantsTest(unittest.TestCase):
     """verify module constants"""
     def test_PyBUF_x(self):