]> granicus.if.org Git - python/commitdiff
Buffer objects would return the read or write buffer for a wrapped object when
authorBrett Cannon <bcannon@gmail.com>
Thu, 8 Jun 2006 17:00:45 +0000 (17:00 +0000)
committerBrett Cannon <bcannon@gmail.com>
Thu, 8 Jun 2006 17:00:45 +0000 (17:00 +0000)
the char buffer was requested.  Now it actually returns the char buffer if
available or raises a TypeError if it isn't (as is raised for the other buffer
types if they are not present but requested).

Not a backport candidate since it does change semantics of the buffer object
(although it could be argued this is enough of a bug to bother backporting).

Lib/test/test_types.py
Misc/NEWS
Modules/arraymodule.c
Objects/bufferobject.c

index c575c0c931794cf2ac6e5dd0a436488249d3a24f..f0bdfdebf7291c88284b061cb0678bcfdd4d0975 100644 (file)
@@ -276,3 +276,10 @@ else: raise TestFailed, "buffer assignment should raise TypeError"
 try: a[0:1] = 'g'
 except TypeError: pass
 else: raise TestFailed, "buffer slice assignment should raise TypeError"
+
+# array.array() returns an object that does not implement a char buffer,
+# something which int() uses for conversion.
+import array
+try: int(buffer(array.array('c')))
+except TypeError :pass
+else: raise TestFailed, "char buffer (at C level) not working"
index 6c1fddbc17b688c06e58d700b9cb5f8e3e0ed0cc..73406070d6f97ed44af2648782fb528c568444f0 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,12 @@ What's New in Python 2.5 beta 1?
 Core and builtins
 -----------------
 
+- Buffer objects, at the C level, never used the char buffer
+  implementation even when the char buffer for the wrapped object was
+  explicitly requested (originally returned the read or write buffer).
+  Now a TypeError is raised if the char buffer is not present but is
+  requested.
+
 - Patch #1346214: Statements like "if 0: suite" are now again optimized
   away like they were in Python 2.4.
 
index af1276949c8434da9f408e7ea62a41d5a77cfc26..eb6ceefc7a711777c17e554d835ffe46b17ca722 100644 (file)
@@ -1787,6 +1787,7 @@ static PyBufferProcs array_as_buffer = {
        (readbufferproc)array_buffer_getreadbuf,
        (writebufferproc)array_buffer_getwritebuf,
        (segcountproc)array_buffer_getsegcount,
+       NULL,
 };
 
 static PyObject *
index d2597b9ee45ef1fde759c8e7846662c2a0325e73..977e7d2bd11a39024156f6ce51ca579101225c45 100644 (file)
@@ -15,8 +15,16 @@ typedef struct {
 } PyBufferObject;
 
 
+enum buffer_t {
+    READBUFFER,
+    WRITEBUFFER,
+    CHARBUFFER,
+    ANY_BUFFER,
+};
+
 static int
-get_buf(PyBufferObject *self, void **ptr, Py_ssize_t *size)
+get_buf(PyBufferObject *self, void **ptr, Py_ssize_t *size,
+       enum buffer_t buffer_type)
 {
        if (self->b_base == NULL) {
                assert (ptr != NULL);
@@ -32,10 +40,42 @@ get_buf(PyBufferObject *self, void **ptr, Py_ssize_t *size)
                                "single-segment buffer object expected");
                        return 0;
                }
-               if (self->b_readonly)
-                       proc = bp->bf_getreadbuffer;
-               else
-                       proc = (readbufferproc)bp->bf_getwritebuffer;
+               if ((buffer_type == READBUFFER) ||
+                       ((buffer_type == ANY_BUFFER) && self->b_readonly))
+                   proc = bp->bf_getreadbuffer;
+               else if ((buffer_type == WRITEBUFFER) ||
+                       (buffer_type == ANY_BUFFER))
+                   proc = (readbufferproc)bp->bf_getwritebuffer;
+               else if (buffer_type == CHARBUFFER) {
+                   if (!PyType_HasFeature(self->ob_type,
+                               Py_TPFLAGS_HAVE_GETCHARBUFFER)) {
+                       PyErr_SetString(PyExc_TypeError,
+                               "Py_TPFLAGS_HAVE_GETCHARBUFFER needed");
+                       return 0;
+                   }
+                   proc = (readbufferproc)bp->bf_getcharbuffer;
+               }
+               if (!proc) {
+                   char *buffer_type_name;
+                   switch (buffer_type) {
+                       case READBUFFER:
+                           buffer_type_name = "read";
+                           break;
+                       case WRITEBUFFER:
+                           buffer_type_name = "write";
+                           break;
+                       case CHARBUFFER:
+                           buffer_type_name = "char";
+                           break;
+                       default:
+                           buffer_type_name = "no";
+                           break;
+                   }
+                   PyErr_Format(PyExc_TypeError,
+                           "%s buffer type not available",
+                           buffer_type_name);
+                   return 0;
+               }
                if ((count = (*proc)(self->b_base, 0, ptr)) < 0)
                        return 0;
                /* apply constraints to the start/end */
@@ -224,9 +264,9 @@ buffer_compare(PyBufferObject *self, PyBufferObject *other)
        Py_ssize_t len_self, len_other, min_len;
        int cmp;
 
-       if (!get_buf(self, &p1, &len_self))
+       if (!get_buf(self, &p1, &len_self, ANY_BUFFER))
                return -1;
-       if (!get_buf(other, &p2, &len_other))
+       if (!get_buf(other, &p2, &len_other, ANY_BUFFER))
                return -1;
        min_len = (len_self < len_other) ? len_self : len_other;
        if (min_len > 0) {
@@ -284,7 +324,7 @@ buffer_hash(PyBufferObject *self)
                return -1;
        }
 
-       if (!get_buf(self, &ptr, &size))
+       if (!get_buf(self, &ptr, &size, ANY_BUFFER))
                return -1;
        p = (unsigned char *) ptr;
        len = size;
@@ -303,7 +343,7 @@ buffer_str(PyBufferObject *self)
 {
        void *ptr;
        Py_ssize_t size;
-       if (!get_buf(self, &ptr, &size))
+       if (!get_buf(self, &ptr, &size, ANY_BUFFER))
                return NULL;
        return PyString_FromStringAndSize((const char *)ptr, size);
 }
@@ -315,7 +355,7 @@ buffer_length(PyBufferObject *self)
 {
        void *ptr;
        Py_ssize_t size;
-       if (!get_buf(self, &ptr, &size))
+       if (!get_buf(self, &ptr, &size, ANY_BUFFER))
                return -1;
        return size;
 }
@@ -344,7 +384,7 @@ buffer_concat(PyBufferObject *self, PyObject *other)
                return NULL;
        }
 
-       if (!get_buf(self, &ptr1, &size))
+       if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
                return NULL;
  
        /* optimize special case */
@@ -380,7 +420,7 @@ buffer_repeat(PyBufferObject *self, Py_ssize_t count)
 
        if ( count < 0 )
                count = 0;
-       if (!get_buf(self, &ptr, &size))
+       if (!get_buf(self, &ptr, &size, ANY_BUFFER))
                return NULL;
        ob = PyString_FromStringAndSize(NULL, size * count);
        if ( ob == NULL )
@@ -404,7 +444,7 @@ buffer_item(PyBufferObject *self, Py_ssize_t idx)
 {
        void *ptr;
        Py_ssize_t size;
-       if (!get_buf(self, &ptr, &size))
+       if (!get_buf(self, &ptr, &size, ANY_BUFFER))
                return NULL;
        if ( idx < 0 || idx >= size ) {
                PyErr_SetString(PyExc_IndexError, "buffer index out of range");
@@ -418,7 +458,7 @@ buffer_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right)
 {
        void *ptr;
        Py_ssize_t size;
-       if (!get_buf(self, &ptr, &size))
+       if (!get_buf(self, &ptr, &size, ANY_BUFFER))
                return NULL;
        if ( left < 0 )
                left = 0;
@@ -446,7 +486,7 @@ buffer_ass_item(PyBufferObject *self, Py_ssize_t idx, PyObject *other)
                return -1;
        }
 
-       if (!get_buf(self, &ptr1, &size))
+       if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
                return -1;
 
        if (idx < 0 || idx >= size) {
@@ -513,7 +553,7 @@ buffer_ass_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right, PyObje
                                "single-segment buffer object expected");
                return -1;
        }
-       if (!get_buf(self, &ptr1, &size))
+       if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
                return -1;
        if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
                return -1;
@@ -552,7 +592,7 @@ buffer_getreadbuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
                                "accessing non-existent buffer segment");
                return -1;
        }
-       if (!get_buf(self, pp, &size))
+       if (!get_buf(self, pp, &size, READBUFFER))
                return -1;
        return size;
 }
@@ -560,12 +600,22 @@ buffer_getreadbuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
 static Py_ssize_t
 buffer_getwritebuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
 {
+       Py_ssize_t size;
+
        if ( self->b_readonly )
        {
                PyErr_SetString(PyExc_TypeError, "buffer is read-only");
                return -1;
        }
-       return buffer_getreadbuf(self, idx, pp);
+
+       if ( idx != 0 ) {
+               PyErr_SetString(PyExc_SystemError,
+                               "accessing non-existent buffer segment");
+               return -1;
+       }
+       if (!get_buf(self, pp, &size, WRITEBUFFER))
+               return -1;
+       return size;
 }
 
 static Py_ssize_t
@@ -573,7 +623,7 @@ buffer_getsegcount(PyBufferObject *self, Py_ssize_t *lenp)
 {
        void *ptr;
        Py_ssize_t size;
-       if (!get_buf(self, &ptr, &size))
+       if (!get_buf(self, &ptr, &size, ANY_BUFFER))
                return -1;
        if (lenp)
                *lenp = size;
@@ -590,13 +640,12 @@ buffer_getcharbuf(PyBufferObject *self, Py_ssize_t idx, const char **pp)
                                "accessing non-existent buffer segment");
                return -1;
        }
-       if (!get_buf(self, &ptr, &size))
+       if (!get_buf(self, &ptr, &size, CHARBUFFER))
                return -1;
        *pp = (const char *)ptr;
        return size;
 }
 
-
 static PySequenceMethods buffer_as_sequence = {
        (lenfunc)buffer_length, /*sq_length*/
        (binaryfunc)buffer_concat, /*sq_concat*/
@@ -635,7 +684,7 @@ PyTypeObject PyBuffer_Type = {
        PyObject_GenericGetAttr,                /* tp_getattro */
        0,                                      /* tp_setattro */
        &buffer_as_buffer,                      /* tp_as_buffer */
-       Py_TPFLAGS_DEFAULT,                     /* tp_flags */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GETCHARBUFFER, /* tp_flags */
        buffer_doc,                             /* tp_doc */
        0,                                      /* tp_traverse */
        0,                                      /* tp_clear */