Index: Python/getargs.c
===================================================================
--- Python/getargs.c (revision 57622)
+++ Python/getargs.c (working copy)
@@ -921,6 +921,34 @@
break;
}
+ case 'Z': {/* unicode, may be NULL (None) */
+ if (*format == '#') { /* any buffer-like object */
+ Py_UNICODE **p = va_arg(*p_va, Py_UNICODE **);
+ FETCH_SIZE;
+
+ if (arg == Py_None) {
+ *p = 0;
+ STORE_SIZE(0);
+ }
+ else if (PyUnicode_Check(arg)) {
+ *p = PyUnicode_AS_UNICODE(arg);
+ STORE_SIZE(PyUnicode_GET_SIZE(arg));
+ }
+ format++;
+ } else {
+ Py_UNICODE **p = va_arg(*p_va, Py_UNICODE **);
+
+ if (arg == Py_None)
+ *p = 0;
+ else if (PyUnicode_Check(arg))
+ *p = PyUnicode_AS_UNICODE(arg);
+ else
+ return converterr("string or None",
+ arg, msgbuf, bufsize);
+ }
+ break;
+ }
+
case 'e': {/* encoded string */
char **buffer;
const char *encoding;
Index: Doc/c-api/utilities.rst
===================================================================
--- Doc/c-api/utilities.rst (revision 57622)
+++ Doc/c-api/utilities.rst (working copy)
@@ -484,6 +484,13 @@
by interpreting their read-buffer pointer as pointer to a :ctype:`Py_UNICODE`
array.
+``Z`` (Unicode or ``None``) [Py_UNICODE \*]
+ Like ``s``, but the Python object may also be ``None``, in which case the C
+ pointer is set to *NULL*.
+
+``Z#`` (Unicode or ``None``) [Py_UNICODE \*, int]
+ This is to ``u#`` as ``Z`` is to ``u``.
+
``es`` (string, Unicode object or character buffer compatible object) [const char \*encoding, char \*\*buffer]
This variant on ``s`` is used for encoding Unicode and objects convertible to
Unicode into a character buffer. It only works for encoded data without embedded
Index: Modules/_fileio.c
===================================================================
--- Modules/_fileio.c (revision 57622)
+++ Modules/_fileio.c (working copy)
@@ -45,7 +45,7 @@
internal_close(PyFileIOObject *self)
{
int save_errno = 0;
- if (self->fd >= 0) {
+ if (self->fd >= 3) {
int fd = self->fd;
self->fd = -1;
Py_BEGIN_ALLOW_THREADS
Index: Modules/_testcapimodule.c
===================================================================
--- Modules/_testcapimodule.c (revision 57622)
+++ Modules/_testcapimodule.c (working copy)
@@ -497,7 +497,60 @@
return Py_None;
}
+/* Test Z and Z# codes for PyArg_ParseTuple */
static PyObject *
+test_Z_code(PyObject *self)
+{
+ PyObject *tuple, *obj;
+ Py_UNICODE *value1, *value2;
+ int len1, len2;
+
+ tuple = PyTuple_New(2);
+ if (tuple == NULL)
+ return NULL;
+
+ obj = PyUnicode_FromString("test");
+ PyTuple_SET_ITEM(tuple, 0, obj);
+ Py_INCREF(Py_None);
+ PyTuple_SET_ITEM(tuple, 1, Py_None);
+
+ /* swap values on purpose */
+ value1 = NULL;
+ value2 = PyUnicode_AS_UNICODE(obj);
+
+ /* Test Z for both values */
+ if (PyArg_ParseTuple(tuple, "ZZ:test_Z_code", &value1, &value2) < 0)
+ return NULL;
+ if (value1 != PyUnicode_AS_UNICODE(obj))
+ return raiseTestError("test_Z_code",
+ "Z code returned wrong value for 'test'");
+ if (value2 != NULL)
+ return raiseTestError("test_Z_code",
+ "Z code returned wrong value for None");
+
+ value1 = NULL;
+ value2 = PyUnicode_AS_UNICODE(obj);
+ len1 = -1;
+ len2 = -1;
+
+ /* Test Z# for both values */
+ if (PyArg_ParseTuple(tuple, "Z#Z#:test_Z_code", &value1, &len1,
+ &value2, &len2) < 0)
+ return NULL;
+ if (value1 != PyUnicode_AS_UNICODE(obj) ||
+ len1 != PyUnicode_GET_SIZE(obj))
+ return raiseTestError("test_Z_code",
+ "Z# code returned wrong values for 'test'");
+ if (value2 != NULL ||
+ len2 != 0)
+ return raiseTestError("test_Z_code",
+ "Z# code returned wrong values for None'");
+
+ Py_DECREF(tuple);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
codec_incrementalencoder(PyObject *self, PyObject *args)
{
const char *encoding, *errors = NULL;
@@ -862,6 +915,7 @@
(PyCFunction)codec_incrementaldecoder, METH_VARARGS},
#endif
{"test_u_code", (PyCFunction)test_u_code, METH_NOARGS},
+ {"test_Z_code", (PyCFunction)test_Z_code, METH_NOARGS},
#ifdef WITH_THREAD
{"_test_thread_state", test_thread_state, METH_VARARGS},
#endif