Commit faf91e75 authored by Larry Hastings's avatar Larry Hastings

Issue #14705: Add 'p' format character to PyArg_ParseTuple* for bool support.

parent 6b03f2ce
...@@ -317,6 +317,15 @@ Other objects ...@@ -317,6 +317,15 @@ Other objects
.. versionchanged:: 3.1 .. versionchanged:: 3.1
``Py_CLEANUP_SUPPORTED`` was added. ``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*] ``(items)`` (:class:`tuple`) [*matching-items*]
The object must be a Python sequence whose length is the number of format units 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 in *items*. The C arguments must correspond to the individual format units in
......
...@@ -214,6 +214,36 @@ class LongLong_TestCase(unittest.TestCase): ...@@ -214,6 +214,36 @@ class LongLong_TestCase(unittest.TestCase):
self.assertEqual(VERY_LARGE & ULLONG_MAX, getargs_K(VERY_LARGE)) 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): class Tuple_TestCase(unittest.TestCase):
def test_tuple(self): def test_tuple(self):
...@@ -510,6 +540,7 @@ def test_main(): ...@@ -510,6 +540,7 @@ def test_main():
tests = [ tests = [
Signed_TestCase, Signed_TestCase,
Unsigned_TestCase, Unsigned_TestCase,
Boolean_TestCase,
Tuple_TestCase, Tuple_TestCase,
Keywords_TestCase, Keywords_TestCase,
KeywordOnly_TestCase, KeywordOnly_TestCase,
......
...@@ -916,6 +916,15 @@ getargs_n(PyObject *self, PyObject *args) ...@@ -916,6 +916,15 @@ getargs_n(PyObject *self, PyObject *args)
return PyLong_FromSsize_t(value); 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 #ifdef HAVE_LONG_LONG
static PyObject * static PyObject *
getargs_L(PyObject *self, PyObject *args) getargs_L(PyObject *self, PyObject *args)
...@@ -2439,6 +2448,7 @@ static PyMethodDef TestMethods[] = { ...@@ -2439,6 +2448,7 @@ static PyMethodDef TestMethods[] = {
{"getargs_i", getargs_i, METH_VARARGS}, {"getargs_i", getargs_i, METH_VARARGS},
{"getargs_l", getargs_l, METH_VARARGS}, {"getargs_l", getargs_l, METH_VARARGS},
{"getargs_n", getargs_n, METH_VARARGS}, {"getargs_n", getargs_n, METH_VARARGS},
{"getargs_p", getargs_p, METH_VARARGS},
#ifdef HAVE_LONG_LONG #ifdef HAVE_LONG_LONG
{"getargs_L", getargs_L, METH_VARARGS}, {"getargs_L", getargs_L, METH_VARARGS},
{"getargs_K", getargs_K, METH_VARARGS}, {"getargs_K", getargs_K, METH_VARARGS},
......
...@@ -814,6 +814,18 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, ...@@ -814,6 +814,18 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
break; 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 /* XXX WAAAAH! 's', 'y', 'z', 'u', 'Z', 'e', 'w' codes all
need to be cleaned up! */ need to be cleaned up! */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment