Skip to content

Commit 3e3eacb

Browse files
committed
Fixed "u#" parser marker to pass through Unicode objects as-is without
going through the buffer interface API. Added tests for this to the _testcapi module and updated docs.
1 parent e0b1e6a commit 3e3eacb

4 files changed

Lines changed: 61 additions & 2 deletions

File tree

Doc/ext/extending.tex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,8 @@ \section{Extracting Parameters in Extension Functions
669669
\item[\samp{u\#} (Unicode object) {[Py_UNICODE *, int]}]
670670
This variant on \samp{u} stores into two C variables, the first one
671671
a pointer to a Unicode data buffer, the second one its length.
672+
Non-Unicode objects are handled by interpreting their read buffer
673+
pointer as pointer to a Py_UNICODE array.
672674

673675
\item[\samp{es} (string, Unicode object or character buffer compatible
674676
object) {[const char *encoding, char **buffer]}]

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ Build
2828

2929
C API
3030

31+
- The "u#" parser marker will now pass through Unicode object as-is
32+
without going through the buffer API.
33+
3134
- The enumerators of cmp_op have been renamed to use the prefix PyCmp_.
3235

3336
- An old #define of ANY as void has been removed from pyport.h. This

Modules/_testcapimodule.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,53 @@ test_L_code(PyObject *self, PyObject *args)
307307

308308
#endif /* ifdef HAVE_LONG_LONG */
309309

310+
#ifdef Py_USING_UNICODE
311+
312+
/* Test the u and u# codes for PyArg_ParseTuple. May leak memory in case
313+
of an error.
314+
*/
315+
static PyObject *
316+
test_u_code(PyObject *self, PyObject *args)
317+
{
318+
PyObject *tuple, *obj;
319+
Py_UNICODE *value;
320+
int len;
321+
322+
if (!PyArg_ParseTuple(args, ":test_u_code"))
323+
return NULL;
324+
325+
tuple = PyTuple_New(1);
326+
if (tuple == NULL)
327+
return NULL;
328+
329+
obj = PyUnicode_Decode("test", strlen("test"),
330+
"ascii", NULL);
331+
if (obj == NULL)
332+
return NULL;
333+
334+
PyTuple_SET_ITEM(tuple, 0, obj);
335+
336+
value = 0;
337+
if (PyArg_ParseTuple(tuple, "u:test_u_code", &value) < 0)
338+
return NULL;
339+
if (value != PyUnicode_AS_UNICODE(obj))
340+
return raiseTestError("test_u_code",
341+
"u code returned wrong value for u'test'");
342+
value = 0;
343+
if (PyArg_ParseTuple(tuple, "u#:test_u_code", &value, &len) < 0)
344+
return NULL;
345+
if (value != PyUnicode_AS_UNICODE(obj) ||
346+
len != PyUnicode_GET_SIZE(obj))
347+
return raiseTestError("test_u_code",
348+
"u# code returned wrong values for u'test'");
349+
350+
Py_DECREF(tuple);
351+
Py_INCREF(Py_None);
352+
return Py_None;
353+
}
354+
355+
#endif
356+
310357
static PyObject *
311358
raise_exception(PyObject *self, PyObject *args)
312359
{
@@ -342,6 +389,9 @@ static PyMethodDef TestMethods[] = {
342389
#ifdef HAVE_LONG_LONG
343390
{"test_longlong_api", test_longlong_api, METH_VARARGS},
344391
{"test_L_code", test_L_code, METH_VARARGS},
392+
#endif
393+
#ifdef Py_USING_UNICODE
394+
{"test_u_code", test_u_code, METH_VARARGS},
345395
#endif
346396
{NULL, NULL} /* sentinel */
347397
};

Python/getargs.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -838,16 +838,20 @@ convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf,
838838
if (*format == '#') { /* any buffer-like object */
839839
void **p = (void **)va_arg(*p_va, char **);
840840
int *q = va_arg(*p_va, int *);
841+
if (PyUnicode_Check(arg)) {
842+
*p = PyUnicode_AS_UNICODE(arg);
843+
*q = PyUnicode_GET_SIZE(arg);
844+
}
845+
else {
841846
char *buf;
842847
int count = convertbuffer(arg, p, &buf);
843-
844848
if (count < 0)
845849
return converterr(buf, arg, msgbuf, bufsize);
846850
*q = count/(sizeof(Py_UNICODE));
851+
}
847852
format++;
848853
} else {
849854
Py_UNICODE **p = va_arg(*p_va, Py_UNICODE **);
850-
851855
if (PyUnicode_Check(arg))
852856
*p = PyUnicode_AS_UNICODE(arg);
853857
else

0 commit comments

Comments
 (0)