[Python-checkins] r46757 - in python/trunk: Lib/test/test_types.py Misc/NEWS Modules/arraymodule.c Objects/bufferobject.c

brett.cannon python-checkins at python.org
Thu Jun 8 19:00:49 CEST 2006


Author: brett.cannon
Date: Thu Jun  8 19:00:45 2006
New Revision: 46757

Modified:
   python/trunk/Lib/test/test_types.py
   python/trunk/Misc/NEWS
   python/trunk/Modules/arraymodule.c
   python/trunk/Objects/bufferobject.c
Log:
Buffer objects would return the read or write buffer for a wrapped object when
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).


Modified: python/trunk/Lib/test/test_types.py
==============================================================================
--- python/trunk/Lib/test/test_types.py	(original)
+++ python/trunk/Lib/test/test_types.py	Thu Jun  8 19:00:45 2006
@@ -276,3 +276,10 @@
 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"

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Thu Jun  8 19:00:45 2006
@@ -12,6 +12,12 @@
 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.
 

Modified: python/trunk/Modules/arraymodule.c
==============================================================================
--- python/trunk/Modules/arraymodule.c	(original)
+++ python/trunk/Modules/arraymodule.c	Thu Jun  8 19:00:45 2006
@@ -1787,6 +1787,7 @@
 	(readbufferproc)array_buffer_getreadbuf,
 	(writebufferproc)array_buffer_getwritebuf,
 	(segcountproc)array_buffer_getsegcount,
+	NULL,
 };
 
 static PyObject *

Modified: python/trunk/Objects/bufferobject.c
==============================================================================
--- python/trunk/Objects/bufferobject.c	(original)
+++ python/trunk/Objects/bufferobject.c	Thu Jun  8 19:00:45 2006
@@ -15,8 +15,16 @@
 } 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 @@
 				"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 @@
 	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 @@
 		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 @@
 {
 	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 @@
 {
 	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 @@
 		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 @@
 
 	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 @@
 {
 	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 @@
 {
 	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 @@
 		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 @@
 				"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 @@
 				"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 @@
 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 @@
 {
 	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 @@
 				"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 @@
 	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 */


More information about the Python-checkins mailing list