]> granicus.if.org Git - python/commitdiff
Issue #8850: Remove "w" and "w#" formats from PyArg_Parse*() functions, use
authorVictor Stinner <victor.stinner@haypocalc.com>
Fri, 25 Jun 2010 00:02:38 +0000 (00:02 +0000)
committerVictor Stinner <victor.stinner@haypocalc.com>
Fri, 25 Jun 2010 00:02:38 +0000 (00:02 +0000)
"w*" format instead. Add tests for "w*" format.

Doc/c-api/arg.rst
Doc/whatsnew/3.2.rst
Lib/test/test_getargs2.py
Misc/NEWS
Modules/_testcapimodule.c
Python/getargs.c

index 158397af8cc4d53369aa816d23834ffd4cbaa622..29d336819309092a19d999f1ae772d413d406b0e 100644 (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
    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]
-   This is to ``w`` what ``y*`` is to ``y``.
-
-``w#`` (:class:`bytearray` or read-write character buffer) [char \*, int]
-   Like ``y#``, but accepts any object which implements the read-write 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.
+   This format accepts any object which implements the read-write buffer
+   interface. It fills a :ctype:`Py_buffer` structure provided by the caller.
+   The buffer may contain embedded null bytes. The caller have to call
+   :cfunc:`PyBuffer_Release` when it is done with the buffer.
 
 ``es`` (:class:`str`) [const char \*encoding, char \*\*buffer]
    This variant on ``s`` is used for encoding Unicode into a character buffer.
index 14f9215e8b999bbeb1639bd420bf47a0e9b55f10..f2d50b51086621b68fac2615837d7e8d08f88874 100644 (file)
@@ -173,7 +173,8 @@ that may require changes to your code:
 
 * 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*"
-  instead
+* PyArg_Parse*() functions:
+
+  * "t#" format has been removed: use "s#" or "s*" instead
+  * "w" and "w#" formats has been removed: use "w*" instead
 
-* Stub
index 5ade2b43e6c1ea933c3b623b324f27bba1c666cf..d751c1ac2437cd2297cd40a8a106b12adaa9efb0 100644 (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, 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):
     def test_u(self):
index c6a8c6ebbb5dd0d4f7084aabd2527e78c021fc92..1073cd6b57925020840163c26b623078b1b0b721 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -29,6 +29,9 @@ Core and Builtins
   error handlers, the decoder only supports "strict" and "ignore" error
   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"
   formats if the string contains a null byte/character. Write unit tests for
   string formats.
index 7bcc1d8cecb2a5d904bf994f742e6f2c74418da1..acbff344fe33773e097b917ccece3fd087672887 100644 (file)
@@ -1385,6 +1385,28 @@ test_widechar(PyObject *self)
     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 *
 test_empty_argparse(PyObject *self)
 {
@@ -2227,6 +2249,7 @@ static PyMethodDef TestMethods[] = {
     {"getargs_u_hash",          getargs_u_hash,                  METH_VARARGS},
     {"getargs_Z",               getargs_Z,                       METH_VARARGS},
     {"getargs_Z_hash",          getargs_Z_hash,                  METH_VARARGS},
+    {"getargs_w_star",          getargs_w_star,                  METH_VARARGS},
     {"codec_incrementalencoder",
      (PyCFunction)codec_incrementalencoder,      METH_VARARGS},
     {"codec_incrementaldecoder",
index 41b4af56cf472d60ebebaa944e7924387a5c8b71..7b929481d25ef03ec1d9e3fe4d320af051cf98d9 100644 (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 **);
-        PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
-        Py_ssize_t count;
-        int temp=-1;
-        Py_buffer view;
-
-        if (pb && pb->bf_releasebuffer && *format != '*')
-            /* Buffer must be released, yet caller does not use
-               the Py_buffer protocol. */
-            return converterr("pinned buffer", arg, msgbuf, bufsize);
 
+        if (*format != '*')
+            return converterr(
+                "invalid use of 'w' format character",
+                arg, msgbuf, bufsize);
+        format++;
 
-        if (pb && pb->bf_getbuffer && *format == '*') {
-            /* Caller is interested in Py_buffer, and the object
-               supports it directly. */
-            format++;
-            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;
-        }
-
-        /* Here we have processed w*, only w and w# remain. */
-        if (pb == NULL ||
-            pb->bf_getbuffer == NULL ||
-            ((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);
+        /* Caller is interested in Py_buffer, and the object
+           supports it directly. */
+        if (PyObject_GetBuffer(arg, (Py_buffer*)p, PyBUF_WRITABLE) < 0) {
+            PyErr_Clear();
+            return converterr("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 (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;
     }