Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Lib/test/test_capi.py
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,20 @@ def test_c_subclass_of_heap_ctype_with_del_modifying_dunder_class_only_decrefs_o
# Test that subtype_dealloc decref the newly assigned __class__ only once
self.assertEqual(new_type_refcnt, sys.getrefcount(_testcapi.HeapCTypeSubclass))

def test_pynumber_tobase(self):
from _testcapi import pynumber_tobase
self.assertEqual(pynumber_tobase(123, 2), '0b1111011')
self.assertEqual(pynumber_tobase(123, 8), '0o173')
self.assertEqual(pynumber_tobase(123, 10), '123')
self.assertEqual(pynumber_tobase(123, 16), '0x7b')
self.assertEqual(pynumber_tobase(-123, 2), '-0b1111011')
self.assertEqual(pynumber_tobase(-123, 8), '-0o173')
self.assertEqual(pynumber_tobase(-123, 10), '-123')
self.assertEqual(pynumber_tobase(-123, 16), '-0x7b')
self.assertRaises(TypeError, pynumber_tobase, 123.0, 10)
self.assertRaises(TypeError, pynumber_tobase, '123', 10)
self.assertRaises(SystemError, pynumber_tobase, 123, 0)


class TestPendingCalls(unittest.TestCase):

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:c:func:`PyNumber_ToBase` now raises a :exc:`SystemError` instead of
crashing when called with invalid base.
14 changes: 14 additions & 0 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -5063,6 +5063,19 @@ test_write_unraisable_exc(PyObject *self, PyObject *args)
}


static PyObject*
pynumber_tobase(PyObject *module, PyObject *args)
{
PyObject *obj;
int base;
if (!PyArg_ParseTuple(args, "Oi:pynumber_tobase",
&obj, &base)) {
return NULL;
}
return PyNumber_ToBase(obj, base);
}


static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *);

static PyMethodDef TestMethods[] = {
Expand Down Expand Up @@ -5309,6 +5322,7 @@ static PyMethodDef TestMethods[] = {
{"negative_refcount", negative_refcount, METH_NOARGS},
#endif
{"write_unraisable_exc", test_write_unraisable_exc, METH_VARARGS},
{"pynumber_tobase", pynumber_tobase, METH_VARARGS},
{NULL, NULL} /* sentinel */
};

Expand Down
15 changes: 6 additions & 9 deletions Objects/abstract.c
Original file line number Diff line number Diff line change
Expand Up @@ -1509,18 +1509,15 @@ PyNumber_Float(PyObject *o)
PyObject *
PyNumber_ToBase(PyObject *n, int base)
{
PyObject *res = NULL;
if (!(base == 2 || base == 8 || base == 10 || base == 16)) {
PyErr_SetString(PyExc_SystemError,
"PyNumber_ToBase: base must be 2, 8, 10 or 16");
return NULL;
}
PyObject *index = PyNumber_Index(n);

if (!index)
return NULL;
if (PyLong_Check(index))
res = _PyLong_Format(index, base);
else
/* It should not be possible to get here, as
PyNumber_Index already has a check for the same
condition */
PyErr_SetString(PyExc_ValueError, "PyNumber_ToBase: index not int");
PyObject *res = _PyLong_Format(index, base);
Py_DECREF(index);
return res;
}
Expand Down