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).
This commit is contained in:
parent
6ee7d01c05
commit
de3b052216
|
@ -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"
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -1787,6 +1787,7 @@ static PyBufferProcs array_as_buffer = {
|
|||
(readbufferproc)array_buffer_getreadbuf,
|
||||
(writebufferproc)array_buffer_getwritebuf,
|
||||
(segcountproc)array_buffer_getsegcount,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue