Skip to content

Commit

Permalink
Add PyLong_AsInt() function (#72)
Browse files Browse the repository at this point in the history
  • Loading branch information
vstinner committed Aug 24, 2023
1 parent 4734c8e commit 8109811
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 0 deletions.
8 changes: 8 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ Python 3.13
See `Py_IsFinalizing() documentation <https://docs.python.org/dev/c-api/init.html#c.Py_IsFinalizing>`__.
.. c:function:: int PyDict_ContainsString(PyObject *p, const char *key)
See `PyDict_ContainsString() documentation <https://docs.python.org/dev/c-api/dict.html#c.PyDict_ContainsString>`__.
.. c:function:: int PyLong_AsInt(PyObject *obj)
See `PyLong_AsInt() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLong_AsInt>`__.
Python 3.12
-----------
Expand Down
1 change: 1 addition & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
Changelog
=========

* 2023-08-25: Add ``PyDict_ContainsString()`` and ``PyLong_AsInt()`` functions.
* 2023-08-21: Remove support for Python 2.7, Python 3.4 and older.
* 2023-08-16: Add ``Py_IsFinalizing()`` function.
* 2023-07-21: Add ``PyDict_GetItemRef()`` function.
Expand Down
22 changes: 22 additions & 0 deletions pythoncapi_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,28 @@ static inline int PyDict_ContainsString(PyObject *op, const char *key)
#endif


// gh-108445 added PyLong_AsInt() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
static inline int PyLong_AsInt(PyObject *obj)
{
#ifdef PYPY_VERSION
long value = PyLong_AsLong(obj);
if (value == -1 && PyErr_Occurred()) {
return -1;
}
if (value < (long)INT_MIN || (long)INT_MAX < value) {
PyErr_SetString(PyExc_OverflowError,
"Python int too large to convert to C int");
return -1;
}
return (int)value;
#else
return _PyLong_AsInt(obj);
#endif
}
#endif


#ifdef __cplusplus
}
#endif
Expand Down
30 changes: 30 additions & 0 deletions tests/test_pythoncapi_compat_cext.c
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,35 @@ test_dict_api(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
}


static PyObject *
test_long_api(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
{
// test PyLong_AsInt()
assert(!PyErr_Occurred());
PyObject *obj = PyLong_FromLong(123);
if (obj == NULL) {
return NULL;
}
int value = PyLong_AsInt(obj);
assert(value == 123);
assert(!PyErr_Occurred());
Py_DECREF(obj);

// test PyLong_AsInt() with overflow
PyObject *obj2 = PyLong_FromLongLong((long long)INT_MAX + 1);
if (obj2 == NULL) {
return NULL;
}
value = PyLong_AsInt(obj2);
assert(value == -1);
assert(PyErr_ExceptionMatches(PyExc_OverflowError));
PyErr_Clear();
Py_DECREF(obj2);

Py_RETURN_NONE;
}


static struct PyMethodDef methods[] = {
{"test_object", test_object, METH_NOARGS, _Py_NULL},
{"test_py_is", test_py_is, METH_NOARGS, _Py_NULL},
Expand All @@ -1234,6 +1263,7 @@ static struct PyMethodDef methods[] = {
{"test_getattr", test_getattr, METH_NOARGS, _Py_NULL},
{"test_getitem", test_getitem, METH_NOARGS, _Py_NULL},
{"test_dict_api", test_dict_api, METH_NOARGS, _Py_NULL},
{"test_long_api", test_long_api, METH_NOARGS, _Py_NULL},
{_Py_NULL, _Py_NULL, 0, _Py_NULL}
};

Expand Down

0 comments on commit 8109811

Please sign in to comment.