mirror of
https://github.com/python/cpython.git
synced 2024-11-28 20:33:54 +08:00
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:
parent
21e09487ac
commit
25e8ec4724
@ -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.
|
||||||
|
@ -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
|
|
||||||
|
@ -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):
|
||||||
|
@ -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.
|
||||||
|
@ -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",
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user