Issue #8850: Remove "w" and "w#" formats from PyArg_Parse*() functions, use

"w*" format instead. Add tests for "w*" format.
This commit is contained in:
Victor Stinner 2010-06-25 00:02:38 +00:00
parent 21e09487ac
commit 25e8ec4724
6 changed files with 61 additions and 64 deletions

View File

@ -150,21 +150,11 @@ Unless otherwise stated, buffers are not NUL-terminated.
any conversion. Raises :exc:`TypeError` if the object is not a Unicode any conversion. Raises :exc:`TypeError` if the object is not a Unicode
object. The C variable may also be declared as :ctype:`PyObject\*`. object. The C variable may also be declared as :ctype:`PyObject\*`.
``w`` (:class:`bytearray` or read-write character buffer) [char \*]
Similar to ``y``, but accepts any object which implements the read-write buffer
interface. The caller must determine the length of the buffer by other means,
or use ``w#`` instead. Only single-segment buffer objects are accepted;
:exc:`TypeError` is raised for all others.
``w*`` (:class:`bytearray` or read-write byte-oriented buffer) [Py_buffer] ``w*`` (:class:`bytearray` or read-write byte-oriented buffer) [Py_buffer]
This is to ``w`` what ``y*`` is to ``y``. This format accepts any object which implements the read-write buffer
interface. It fills a :ctype:`Py_buffer` structure provided by the caller.
``w#`` (:class:`bytearray` or read-write character buffer) [char \*, int] The buffer may contain embedded null bytes. The caller have to call
Like ``y#``, but accepts any object which implements the read-write buffer :cfunc:`PyBuffer_Release` when it is done with the buffer.
interface. The :ctype:`char \*` variable is set to point to the first byte
of the buffer, and the :ctype:`int` is set to the length of the buffer.
Only single-segment buffer objects are accepted; :exc:`TypeError` is raised
for all others.
``es`` (:class:`str`) [const char \*encoding, char \*\*buffer] ``es`` (:class:`str`) [const char \*encoding, char \*\*buffer]
This variant on ``s`` is used for encoding Unicode into a character buffer. This variant on ``s`` is used for encoding Unicode into a character buffer.

View File

@ -173,7 +173,8 @@ that may require changes to your code:
* bytearray objects cannot be used anymore as filenames: convert them to bytes * bytearray objects cannot be used anymore as filenames: convert them to bytes
* "t#" format of PyArg_Parse*() functions has been removed: use "s#" or "s*" * PyArg_Parse*() functions:
instead
* "t#" format has been removed: use "s#" or "s*" instead
* "w" and "w#" formats has been removed: use "w*" instead
* Stub

View File

@ -375,6 +375,16 @@ class Bytes_TestCase(unittest.TestCase):
self.assertRaises(TypeError, getargs_y_hash, memoryview(b'memoryview')) self.assertRaises(TypeError, getargs_y_hash, memoryview(b'memoryview'))
self.assertRaises(TypeError, getargs_y_hash, None) self.assertRaises(TypeError, getargs_y_hash, None)
def test_w_star(self):
# getargs_w_star() modifies first and last byte
from _testcapi import getargs_w_star
self.assertRaises(TypeError, getargs_w_star, 'abc\xe9')
self.assertRaises(TypeError, getargs_w_star, b'bytes')
self.assertRaises(TypeError, getargs_w_star, b'nul:\0')
self.assertEqual(getargs_w_star(bytearray(b'bytearray')), b'[ytearra]')
self.assertEqual(getargs_w_star(memoryview(b'memoryview')), b'[emoryvie]')
self.assertRaises(TypeError, getargs_w_star, None)
class Unicode_TestCase(unittest.TestCase): class Unicode_TestCase(unittest.TestCase):
def test_u(self): def test_u(self):

View File

@ -29,6 +29,9 @@ Core and Builtins
error handlers, the decoder only supports "strict" and "ignore" error error handlers, the decoder only supports "strict" and "ignore" error
handlers. Patch written by Mark Hammond. handlers. Patch written by Mark Hammond.
- Issue #8850: Remove "w" and "w#" formats from PyArg_Parse*() functions, use
"w*" format instead. Add tests for "w*" format.
- Issue #8592: PyArg_Parse*() functions raise a TypeError for "y", "u" and "Z" - Issue #8592: PyArg_Parse*() functions raise a TypeError for "y", "u" and "Z"
formats if the string contains a null byte/character. Write unit tests for formats if the string contains a null byte/character. Write unit tests for
string formats. string formats.

View File

@ -1385,6 +1385,28 @@ test_widechar(PyObject *self)
Py_RETURN_NONE; Py_RETURN_NONE;
} }
static PyObject *
getargs_w_star(PyObject *self, PyObject *args)
{
Py_buffer buffer;
PyObject *result;
char *str;
if (!PyArg_ParseTuple(args, "w*:getargs_w_star", &buffer))
return NULL;
if (2 <= buffer.len) {
str = buffer.buf;
str[0] = '[';
str[buffer.len-1] = ']';
}
result = PyBytes_FromStringAndSize(buffer.buf, buffer.len);
PyBuffer_Release(&buffer);
return result;
}
static PyObject * static PyObject *
test_empty_argparse(PyObject *self) test_empty_argparse(PyObject *self)
{ {
@ -2227,6 +2249,7 @@ static PyMethodDef TestMethods[] = {
{"getargs_u_hash", getargs_u_hash, METH_VARARGS}, {"getargs_u_hash", getargs_u_hash, METH_VARARGS},
{"getargs_Z", getargs_Z, METH_VARARGS}, {"getargs_Z", getargs_Z, METH_VARARGS},
{"getargs_Z_hash", getargs_Z_hash, METH_VARARGS}, {"getargs_Z_hash", getargs_Z_hash, METH_VARARGS},
{"getargs_w_star", getargs_w_star, METH_VARARGS},
{"codec_incrementalencoder", {"codec_incrementalencoder",
(PyCFunction)codec_incrementalencoder, METH_VARARGS}, (PyCFunction)codec_incrementalencoder, METH_VARARGS},
{"codec_incrementaldecoder", {"codec_incrementaldecoder",

View File

@ -1231,58 +1231,28 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
} }
case 'w': { /* memory buffer, read-write access */ case 'w': { /* "w*": memory buffer, read-write access */
void **p = va_arg(*p_va, void **); void **p = va_arg(*p_va, void **);
PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
Py_ssize_t count;
int temp=-1;
Py_buffer view;
if (pb && pb->bf_releasebuffer && *format != '*') if (*format != '*')
/* Buffer must be released, yet caller does not use return converterr(
the Py_buffer protocol. */ "invalid use of 'w' format character",
return converterr("pinned buffer", arg, msgbuf, bufsize); arg, msgbuf, bufsize);
format++;
/* Caller is interested in Py_buffer, and the object
if (pb && pb->bf_getbuffer && *format == '*') { supports it directly. */
/* Caller is interested in Py_buffer, and the object if (PyObject_GetBuffer(arg, (Py_buffer*)p, PyBUF_WRITABLE) < 0) {
supports it directly. */ PyErr_Clear();
format++; return converterr("read-write buffer", arg, msgbuf, bufsize);
if (PyObject_GetBuffer(arg, (Py_buffer*)p, PyBUF_WRITABLE) < 0) {
PyErr_Clear();
return converterr("read-write buffer", arg, msgbuf, bufsize);
}
if (addcleanup(p, freelist, cleanup_buffer)) {
return converterr(
"(cleanup problem)",
arg, msgbuf, bufsize);
}
if (!PyBuffer_IsContiguous((Py_buffer*)p, 'C'))
return converterr("contiguous buffer", arg, msgbuf, bufsize);
break;
} }
if (addcleanup(p, freelist, cleanup_buffer)) {
/* Here we have processed w*, only w and w# remain. */ return converterr(
if (pb == NULL || "(cleanup problem)",
pb->bf_getbuffer == NULL || arg, msgbuf, bufsize);
((temp = PyObject_GetBuffer(arg, &view,
PyBUF_SIMPLE)) != 0) ||
view.readonly == 1) {
if (temp==0) {
PyBuffer_Release(&view);
}
return converterr("single-segment read-write buffer",
arg, msgbuf, bufsize);
}
if ((count = view.len) < 0)
return converterr("(unspecified)", arg, msgbuf, bufsize);
*p = view.buf;
if (*format == '#') {
FETCH_SIZE;
STORE_SIZE(count);
format++;
} }
if (!PyBuffer_IsContiguous((Py_buffer*)p, 'C'))
return converterr("contiguous buffer", arg, msgbuf, bufsize);
break; break;
} }