Skip to content

Commit 3a79210

Browse files
committed
gh-108444: Add PyLong_AsInt() public function
* Rename _PyLong_AsInt() to PyLong_AsInt(). * Add documentation. * Add test. * For now, keep _PyLong_AsInt() as an alias to PyLong_AsInt().
1 parent 480a337 commit 3a79210

File tree

13 files changed

+88
-3
lines changed

13 files changed

+88
-3
lines changed

Doc/c-api/long.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,14 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
136136
This function will no longer use :meth:`~object.__int__`.
137137
138138
139+
.. c:function:: int PyLong_AsInt(PyObject *obj)
140+
141+
Similar to :c:func:`PyLong_AsLong`, but store the result in a C
142+
:c:expr:`int` instead of a C :c:expr:`long`.
143+
144+
.. versionadded:: 3.13
145+
146+
139147
.. c:function:: long PyLong_AsLongAndOverflow(PyObject *obj, int *overflow)
140148
141149
Return a C :c:expr:`long` representation of *obj*. If *obj* is not an

Doc/data/stable_abi.dat

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Doc/whatsnew/3.13.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,12 @@ New Features
871871
:term:`shutting down <interpreter shutdown>`.
872872
(Contributed by Victor Stinner in :gh:`108014`.)
873873

874+
* Add :c:func:`PyLong_AsInt` function: similar to :c:func:`PyLong_AsLong`, but
875+
store the result in a C :c:expr:`int` instead of a C :c:expr:`long`.
876+
Previously, it was known as the the private function :c:func:`!_PyLong_AsInt`
877+
(with an underscore prefix).
878+
(Contributed by Victor Stinner in :gh:`108014`.)
879+
874880
Porting to Python 3.13
875881
----------------------
876882

Include/cpython/longobject.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
# error "this header file must not be included directly"
33
#endif
44

5-
PyAPI_FUNC(int) _PyLong_AsInt(PyObject *);
5+
// Alias for backport compatibility
6+
#define _PyLong_AsInt PyLong_AsInt
67

78
PyAPI_FUNC(int) _PyLong_UnsignedShort_Converter(PyObject *, void *);
89
PyAPI_FUNC(int) _PyLong_UnsignedInt_Converter(PyObject *, void *);

Include/longobject.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,18 @@ PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLong(unsigned long);
1818
PyAPI_FUNC(PyObject *) PyLong_FromSize_t(size_t);
1919
PyAPI_FUNC(PyObject *) PyLong_FromSsize_t(Py_ssize_t);
2020
PyAPI_FUNC(PyObject *) PyLong_FromDouble(double);
21+
2122
PyAPI_FUNC(long) PyLong_AsLong(PyObject *);
2223
PyAPI_FUNC(long) PyLong_AsLongAndOverflow(PyObject *, int *);
2324
PyAPI_FUNC(Py_ssize_t) PyLong_AsSsize_t(PyObject *);
2425
PyAPI_FUNC(size_t) PyLong_AsSize_t(PyObject *);
2526
PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLong(PyObject *);
2627
PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLongMask(PyObject *);
28+
29+
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000
30+
PyAPI_FUNC(int) PyLong_AsInt(PyObject *);
31+
#endif
32+
2733
PyAPI_FUNC(PyObject *) PyLong_GetInfo(void);
2834

2935
/* It may be useful in the future. I've added it in the PyInt -> PyLong

Lib/test/test_capi/test_long.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,28 @@ def test_compact_known(self):
3434
self.assertEqual(_testcapi.call_long_compact_api(sys.maxsize),
3535
(False, -1))
3636

37+
def test_long_asint(self):
38+
PyLong_AsInt = _testcapi.PyLong_AsInt
39+
INT_MIN = _testcapi.INT_MIN
40+
INT_MAX = _testcapi.INT_MAX
41+
42+
# round trip (object -> int -> object)
43+
for value in (INT_MIN, INT_MAX, -1, 0, 1, 123):
44+
with self.subTest(value=value):
45+
self.assertEqual(PyLong_AsInt(value), value)
46+
47+
# bound checking
48+
with self.assertRaises(OverflowError):
49+
PyLong_AsInt(INT_MIN - 1)
50+
with self.assertRaises(OverflowError):
51+
PyLong_AsInt(INT_MAX + 1)
52+
53+
# invalid type
54+
for value in (1.0, b'2', '3'):
55+
with self.subTest(value=value):
56+
with self.assertRaises(TypeError):
57+
PyLong_AsInt(value)
58+
3759

3860
if __name__ == "__main__":
3961
unittest.main()

Lib/test/test_stable_abi_ctypes.py

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Add :c:func:`PyLong_AsInt` function: similar to :c:func:`PyLong_AsLong`, but
2+
store the result in a C :c:expr:`int` instead of a C :c:expr:`long`.
3+
Previously, it was known as the the private function :c:func:`!_PyLong_AsInt`
4+
(with an underscore prefix). Patch by by Victor Stinner.

Misc/stable_abi.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2450,3 +2450,5 @@
24502450
added = '3.13'
24512451
[function.PyDict_GetItemStringRef]
24522452
added = '3.13'
2453+
[function.PyLong_AsInt]
2454+
added = '3.13'

Modules/_testcapi/clinic/long.c.h

Lines changed: 9 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)