From faf91e75ab287ae6c377b05b7eb91d7f5274fbc5 Mon Sep 17 00:00:00 2001 From: Larry Hastings Date: Sat, 5 May 2012 16:54:29 -0700 Subject: [PATCH] Issue #14705: Add 'p' format character to PyArg_ParseTuple* for bool support. --- Doc/c-api/arg.rst | 9 +++++++++ Lib/test/test_getargs2.py | 31 +++++++++++++++++++++++++++++++ Modules/_testcapimodule.c | 10 ++++++++++ Python/getargs.c | 12 ++++++++++++ 4 files changed, 62 insertions(+) diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index f33714e1b72..2bcbbadf346 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -317,6 +317,15 @@ Other objects .. versionchanged:: 3.1 ``Py_CLEANUP_SUPPORTED`` was added. +``p`` (:class:`bool`) [int] + Tests the value passed in for truth (a boolean **p**\redicate) and converts + the result to its equivalent C true/false integer value. + Sets the int to 1 if the expression was true and 0 if it was false. + This accepts any valid Python value. See :ref:`truth` for more + information about how Python tests values for truth. + + .. versionchanged:: 3.3 + ``(items)`` (:class:`tuple`) [*matching-items*] The object must be a Python sequence whose length is the number of format units in *items*. The C arguments must correspond to the individual format units in diff --git a/Lib/test/test_getargs2.py b/Lib/test/test_getargs2.py index fe1e7ce50e4..48ca94ee381 100644 --- a/Lib/test/test_getargs2.py +++ b/Lib/test/test_getargs2.py @@ -214,6 +214,36 @@ class LongLong_TestCase(unittest.TestCase): self.assertEqual(VERY_LARGE & ULLONG_MAX, getargs_K(VERY_LARGE)) +class Paradox: + "This statement is false." + def __bool__(self): + raise NotImplementedError + +class Boolean_TestCase(unittest.TestCase): + def test_p(self): + from _testcapi import getargs_p + self.assertEqual(0, getargs_p(False)) + self.assertEqual(0, getargs_p(None)) + self.assertEqual(0, getargs_p(0)) + self.assertEqual(0, getargs_p(0.0)) + self.assertEqual(0, getargs_p(0j)) + self.assertEqual(0, getargs_p('')) + self.assertEqual(0, getargs_p(())) + self.assertEqual(0, getargs_p([])) + self.assertEqual(0, getargs_p({})) + + self.assertEqual(1, getargs_p(True)) + self.assertEqual(1, getargs_p(1)) + self.assertEqual(1, getargs_p(1.0)) + self.assertEqual(1, getargs_p(1j)) + self.assertEqual(1, getargs_p('x')) + self.assertEqual(1, getargs_p((1,))) + self.assertEqual(1, getargs_p([1])) + self.assertEqual(1, getargs_p({1:2})) + self.assertEqual(1, getargs_p(unittest.TestCase)) + + self.assertRaises(NotImplementedError, getargs_p, Paradox()) + class Tuple_TestCase(unittest.TestCase): def test_tuple(self): @@ -510,6 +540,7 @@ def test_main(): tests = [ Signed_TestCase, Unsigned_TestCase, + Boolean_TestCase, Tuple_TestCase, Keywords_TestCase, KeywordOnly_TestCase, diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 471d66d659e..bdc465ad931 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -916,6 +916,15 @@ getargs_n(PyObject *self, PyObject *args) return PyLong_FromSsize_t(value); } +static PyObject * +getargs_p(PyObject *self, PyObject *args) +{ + int value; + if (!PyArg_ParseTuple(args, "p", &value)) + return NULL; + return PyLong_FromLong(value); +} + #ifdef HAVE_LONG_LONG static PyObject * getargs_L(PyObject *self, PyObject *args) @@ -2439,6 +2448,7 @@ static PyMethodDef TestMethods[] = { {"getargs_i", getargs_i, METH_VARARGS}, {"getargs_l", getargs_l, METH_VARARGS}, {"getargs_n", getargs_n, METH_VARARGS}, + {"getargs_p", getargs_p, METH_VARARGS}, #ifdef HAVE_LONG_LONG {"getargs_L", getargs_L, METH_VARARGS}, {"getargs_K", getargs_K, METH_VARARGS}, diff --git a/Python/getargs.c b/Python/getargs.c index 8ec71106104..9e9695f4d21 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -814,6 +814,18 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, break; } + case 'p': {/* boolean *p*redicate */ + int *p = va_arg(*p_va, int *); + int val = PyObject_IsTrue(arg); + if (val > 0) + *p = 1; + else if (val == 0) + *p = 0; + else + RETURN_ERR_OCCURRED; + break; + } + /* XXX WAAAAH! 's', 'y', 'z', 'u', 'Z', 'e', 'w' codes all need to be cleaned up! */