Commits

Lenard Lindstrom  committed e9bccdc

Port pygame.bufferproxy.BufferProxy properties to pygame._view.View. Enable View subclassing.

For backward compatibility, add __dict__, raw, and length properties to
pygame._view.View. Since the BufferProxy dictionary (__dict__) is for use by
BufferProxy subclass instances, also allow View to be subclassed.

  • Participants
  • Parent commits a486afc

Comments (0)

Files changed (3)

     PyObject *pyprelude;                  /* Python lock callable             */
     PyObject *pypostscript;               /* Python release callback          */
     int global_release;                   /* dealloc callback flag            */
+    PyObject *dict;                       /* Allow arbitrary attributes       */
     PyObject *weakrefs;                   /* There can be reference cycles    */
 } PgViewObject;
 
     if (!format) {
         format = self->cmem;
     }
+    self->dict = 0;
     self->weakrefs = 0;
     memcpy(&(self->bufview), bufview, sizeof(Py_buffer));
     self->bufview.format = format;
     PyObject *pyprelude = 0;
     PyObject *pypostscript = 0;
     PyObject *self = 0;
+    int i;
     /* The argument evaluation order is important: strides must follow shape. */
     char *keywords[] = {"shape", "typestr", "data", "strides", "parent",
                         "prelude", "postscript", 0};
         pypostscript = 0;
     }
     Py_XINCREF((PyObject *)bufview.obj);
+    bufview.len = bufview.itemsize;
+    for (i = 0; i < bufview.ndim; ++i) {
+        bufview.len *= bufview.shape[i];
+    }
     self = _view_new_from_type(type, &bufview, 0,
                                0, 0, pyprelude, pypostscript);
     _free_bufview(&bufview);
     Py_XDECREF((PyObject *)self->bufview.obj);
     Py_XDECREF(self->pyprelude);
     Py_XDECREF(self->pypostscript);
+    Py_XDECREF(self->dict);
     if (self->weakrefs) {
         PyObject_ClearWeakRefs((PyObject *)self);
     }
     return parent;
 }
 
+static PyObject *
+_view_get___dict__(PgViewObject *self, PyObject *closure)
+{
+    if (!self->dict) {
+	self->dict = PyDict_New();
+        if (!self->dict) {
+            return 0;
+        }
+    }
+
+    Py_INCREF(self->dict);
+    return self->dict;
+}
+
+static PyObject *
+_view_get_raw(PgViewObject *self, PyObject *closure)
+{
+    if (!(self->flags & VIEW_CONTIGUOUS)) {
+        PyErr_SetString(PyExc_ValueError, "the bytes are not contiguous");
+        return 0;
+    }
+
+    return Bytes_FromStringAndSize((char *)self->bufview.buf,
+                                   self->bufview.len);
+}
+
+static PyObject *
+_view_get_length(PgViewObject *self, PyObject *closure)
+{
+    return PyInt_FromSsize_t(self->bufview.len);
+}
+
 /**** Methods ****/
 
 /**
     {"__array_struct__", (getter)_view_get_arraystruct, 0, 0, 0},
     {"__array_interface__", (getter)_view_get_arrayinterface, 0, 0, 0},
     {"parent", (getter)_view_get_parent, 0, 0, 0},
+    {"__dict__", (getter)_view_get___dict__, 0, 0, 0},
+    {"raw", (getter)_view_get_raw, 0, 0, 0},
+    {"length", (getter)_view_get_length, 0, 0, 0},
     {0, 0, 0, 0, 0}
 };
 
 #else
     0,                          /* tp_as_buffer */
 #endif
-    Py_TPFLAGS_DEFAULT,         /* tp_flags */
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /* tp_flags */
     "Object view as an array struct\n",
     0,                          /* tp_traverse */
     0,                          /* tp_clear */
     0,                          /* tp_dict */
     0,                          /* tp_descr_get */
     0,                          /* tp_descr_set */
-    0,                          /* tp_dictoffset */
+    offsetof(PgViewObject, dict), /* tp_dictoffset */
     0,                          /* tp_init */
     0,                          /* tp_alloc */
     _view_new,                  /* tp_new */

File src/pgcompat.h

 /* Python 2.4 (PEP 353) ssize_t */
 #if PY_VERSION_HEX < 0x02050000
 #define PyInt_AsSsize_t PyInt_AsLong
+#define PyInt_FromSsizt_t PyInt_FromLong
 #endif
 
 /* Python 2.5 and earlier (PEP 3118) Py_buffer */

File test/_view_test.py

 import re
 import weakref
 import gc
+import ctypes
 if __name__ == '__main__':
     import os
     pkg_dir = os.path.split(os.path.abspath(__file__))[0]
     from test.test_utils import test_not_implemented, unittest
 import pygame
 from pygame._view import View
+from pygame.compat import as_bytes
 
 class ViewTest(unittest.TestCase):
     view_keywords = {'shape': (5, 4, 3),
         self.assertEqual(r[:2], '*<')
         self.assertEqual(r[-2:], '>*')
 
+class BufferProxyLegacyTest(unittest.TestCase):
+    content = as_bytes('\x01\x00\x00\x02') * 12
+    buffer = ctypes.create_string_buffer(content)
+    data = (ctypes.addressof(buffer), True)
+
+    def test_length(self):
+
+        # __doc__ (as of 2008-08-02) for pygame.bufferproxy.BufferProxy.length:
+
+          # The size of the buffer data in bytes.
+        bf = View(shape=(3, 4),
+                  typestr='|u4',
+                  data=self.data,
+                  strides=(12, 4))
+        self.assertEqual(bf.length, len(self.content))
+        bf = View(shape=(3, 3),
+                  typestr='|u4',
+                  data=self.data,
+                  strides=(12, 4))
+        self.assertEqual(bf.length, 3*3*4)
+
+    def todo_test_raw(self):
+
+        # __doc__ (as of 2008-08-02) for pygame.bufferproxy.BufferProxy.raw:
+
+          # The raw buffer data as string. The string may contain NUL bytes.
+
+        self.fail() 
+
+    def todo_test_write(self):
+
+        # __doc__ (as of 2008-08-02) for pygame.bufferproxy.BufferProxy.write:
+
+          # B.write (bufferproxy, buffer, offset) -> None
+          # 
+          # Writes raw data to the bufferproxy.
+          # 
+          # Writes the raw data from buffer to the BufferProxy object, starting
+          # at the specified offset within the BufferProxy.
+          # If the length of the passed buffer exceeds the length of the
+          # BufferProxy (reduced by the offset), an IndexError will be raised.
+
+        self.fail() 
+        
+
 if __name__ == '__main__':
     unittest.main()