mirror of https://github.com/python/cpython
gh-108444: Add PyLong_AsInt() public function (#108445)
* Rename _PyLong_AsInt() to PyLong_AsInt(). * Add documentation. * Add test. * For now, keep _PyLong_AsInt() as an alias to PyLong_AsInt().
This commit is contained in:
parent
feb9a49c9c
commit
be436e08b8
|
@ -136,6 +136,14 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
|
||||||
This function will no longer use :meth:`~object.__int__`.
|
This function will no longer use :meth:`~object.__int__`.
|
||||||
|
|
||||||
|
|
||||||
|
.. c:function:: int PyLong_AsInt(PyObject *obj)
|
||||||
|
|
||||||
|
Similar to :c:func:`PyLong_AsLong`, but store the result in a C
|
||||||
|
:c:expr:`int` instead of a C :c:expr:`long`.
|
||||||
|
|
||||||
|
.. versionadded:: 3.13
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: long PyLong_AsLongAndOverflow(PyObject *obj, int *overflow)
|
.. c:function:: long PyLong_AsLongAndOverflow(PyObject *obj, int *overflow)
|
||||||
|
|
||||||
Return a C :c:expr:`long` representation of *obj*. If *obj* is not an
|
Return a C :c:expr:`long` representation of *obj*. If *obj* is not an
|
||||||
|
|
|
@ -347,6 +347,7 @@ var,PyList_Type,3.2,,
|
||||||
type,PyLongObject,3.2,,opaque
|
type,PyLongObject,3.2,,opaque
|
||||||
var,PyLongRangeIter_Type,3.2,,
|
var,PyLongRangeIter_Type,3.2,,
|
||||||
function,PyLong_AsDouble,3.2,,
|
function,PyLong_AsDouble,3.2,,
|
||||||
|
function,PyLong_AsInt,3.13,,
|
||||||
function,PyLong_AsLong,3.2,,
|
function,PyLong_AsLong,3.2,,
|
||||||
function,PyLong_AsLongAndOverflow,3.2,,
|
function,PyLong_AsLongAndOverflow,3.2,,
|
||||||
function,PyLong_AsLongLong,3.2,,
|
function,PyLong_AsLongLong,3.2,,
|
||||||
|
|
|
@ -871,6 +871,12 @@ New Features
|
||||||
:term:`shutting down <interpreter shutdown>`.
|
:term:`shutting down <interpreter shutdown>`.
|
||||||
(Contributed by Victor Stinner in :gh:`108014`.)
|
(Contributed by Victor Stinner in :gh:`108014`.)
|
||||||
|
|
||||||
|
* Add :c:func:`PyLong_AsInt` function: similar to :c:func:`PyLong_AsLong`, but
|
||||||
|
store the result in a C :c:expr:`int` instead of a C :c:expr:`long`.
|
||||||
|
Previously, it was known as the private function :c:func:`!_PyLong_AsInt`
|
||||||
|
(with an underscore prefix).
|
||||||
|
(Contributed by Victor Stinner in :gh:`108014`.)
|
||||||
|
|
||||||
Porting to Python 3.13
|
Porting to Python 3.13
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
# error "this header file must not be included directly"
|
# error "this header file must not be included directly"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PyAPI_FUNC(int) _PyLong_AsInt(PyObject *);
|
// Alias for backport compatibility
|
||||||
|
#define _PyLong_AsInt PyLong_AsInt
|
||||||
|
|
||||||
PyAPI_FUNC(int) _PyLong_UnsignedShort_Converter(PyObject *, void *);
|
PyAPI_FUNC(int) _PyLong_UnsignedShort_Converter(PyObject *, void *);
|
||||||
PyAPI_FUNC(int) _PyLong_UnsignedInt_Converter(PyObject *, void *);
|
PyAPI_FUNC(int) _PyLong_UnsignedInt_Converter(PyObject *, void *);
|
||||||
|
|
|
@ -18,12 +18,18 @@ PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLong(unsigned long);
|
||||||
PyAPI_FUNC(PyObject *) PyLong_FromSize_t(size_t);
|
PyAPI_FUNC(PyObject *) PyLong_FromSize_t(size_t);
|
||||||
PyAPI_FUNC(PyObject *) PyLong_FromSsize_t(Py_ssize_t);
|
PyAPI_FUNC(PyObject *) PyLong_FromSsize_t(Py_ssize_t);
|
||||||
PyAPI_FUNC(PyObject *) PyLong_FromDouble(double);
|
PyAPI_FUNC(PyObject *) PyLong_FromDouble(double);
|
||||||
|
|
||||||
PyAPI_FUNC(long) PyLong_AsLong(PyObject *);
|
PyAPI_FUNC(long) PyLong_AsLong(PyObject *);
|
||||||
PyAPI_FUNC(long) PyLong_AsLongAndOverflow(PyObject *, int *);
|
PyAPI_FUNC(long) PyLong_AsLongAndOverflow(PyObject *, int *);
|
||||||
PyAPI_FUNC(Py_ssize_t) PyLong_AsSsize_t(PyObject *);
|
PyAPI_FUNC(Py_ssize_t) PyLong_AsSsize_t(PyObject *);
|
||||||
PyAPI_FUNC(size_t) PyLong_AsSize_t(PyObject *);
|
PyAPI_FUNC(size_t) PyLong_AsSize_t(PyObject *);
|
||||||
PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLong(PyObject *);
|
PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLong(PyObject *);
|
||||||
PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLongMask(PyObject *);
|
PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLongMask(PyObject *);
|
||||||
|
|
||||||
|
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000
|
||||||
|
PyAPI_FUNC(int) PyLong_AsInt(PyObject *);
|
||||||
|
#endif
|
||||||
|
|
||||||
PyAPI_FUNC(PyObject *) PyLong_GetInfo(void);
|
PyAPI_FUNC(PyObject *) PyLong_GetInfo(void);
|
||||||
|
|
||||||
/* It may be useful in the future. I've added it in the PyInt -> PyLong
|
/* It may be useful in the future. I've added it in the PyInt -> PyLong
|
||||||
|
|
|
@ -34,6 +34,36 @@ class LongTests(unittest.TestCase):
|
||||||
self.assertEqual(_testcapi.call_long_compact_api(sys.maxsize),
|
self.assertEqual(_testcapi.call_long_compact_api(sys.maxsize),
|
||||||
(False, -1))
|
(False, -1))
|
||||||
|
|
||||||
|
def test_long_asint(self):
|
||||||
|
PyLong_AsInt = _testcapi.PyLong_AsInt
|
||||||
|
INT_MIN = _testcapi.INT_MIN
|
||||||
|
INT_MAX = _testcapi.INT_MAX
|
||||||
|
|
||||||
|
# round trip (object -> int -> object)
|
||||||
|
for value in (INT_MIN, INT_MAX, -1, 0, 1, 123):
|
||||||
|
with self.subTest(value=value):
|
||||||
|
self.assertEqual(PyLong_AsInt(value), value)
|
||||||
|
|
||||||
|
# use __index__(), not __int__()
|
||||||
|
class MyIndex:
|
||||||
|
def __index__(self):
|
||||||
|
return 10
|
||||||
|
def __int__(self):
|
||||||
|
return 22
|
||||||
|
self.assertEqual(PyLong_AsInt(MyIndex()), 10)
|
||||||
|
|
||||||
|
# bound checking
|
||||||
|
with self.assertRaises(OverflowError):
|
||||||
|
PyLong_AsInt(INT_MIN - 1)
|
||||||
|
with self.assertRaises(OverflowError):
|
||||||
|
PyLong_AsInt(INT_MAX + 1)
|
||||||
|
|
||||||
|
# invalid type
|
||||||
|
for value in (1.0, b'2', '3'):
|
||||||
|
with self.subTest(value=value):
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
PyLong_AsInt(value)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -375,6 +375,7 @@ SYMBOL_NAMES = (
|
||||||
"PyList_Type",
|
"PyList_Type",
|
||||||
"PyLongRangeIter_Type",
|
"PyLongRangeIter_Type",
|
||||||
"PyLong_AsDouble",
|
"PyLong_AsDouble",
|
||||||
|
"PyLong_AsInt",
|
||||||
"PyLong_AsLong",
|
"PyLong_AsLong",
|
||||||
"PyLong_AsLongAndOverflow",
|
"PyLong_AsLongAndOverflow",
|
||||||
"PyLong_AsLongLong",
|
"PyLong_AsLongLong",
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Add :c:func:`PyLong_AsInt` function: similar to :c:func:`PyLong_AsLong`, but
|
||||||
|
store the result in a C :c:expr:`int` instead of a C :c:expr:`long`.
|
||||||
|
Previously, it was known as the the private function :c:func:`!_PyLong_AsInt`
|
||||||
|
(with an underscore prefix). Patch by Victor Stinner.
|
|
@ -2450,3 +2450,5 @@
|
||||||
added = '3.13'
|
added = '3.13'
|
||||||
[function.PyDict_GetItemStringRef]
|
[function.PyDict_GetItemStringRef]
|
||||||
added = '3.13'
|
added = '3.13'
|
||||||
|
[function.PyLong_AsInt]
|
||||||
|
added = '3.13'
|
||||||
|
|
|
@ -163,4 +163,12 @@ PyDoc_STRVAR(_testcapi_call_long_compact_api__doc__,
|
||||||
|
|
||||||
#define _TESTCAPI_CALL_LONG_COMPACT_API_METHODDEF \
|
#define _TESTCAPI_CALL_LONG_COMPACT_API_METHODDEF \
|
||||||
{"call_long_compact_api", (PyCFunction)_testcapi_call_long_compact_api, METH_O, _testcapi_call_long_compact_api__doc__},
|
{"call_long_compact_api", (PyCFunction)_testcapi_call_long_compact_api, METH_O, _testcapi_call_long_compact_api__doc__},
|
||||||
/*[clinic end generated code: output=d000a1b58fa81eab input=a9049054013a1b77]*/
|
|
||||||
|
PyDoc_STRVAR(_testcapi_PyLong_AsInt__doc__,
|
||||||
|
"PyLong_AsInt($module, arg, /)\n"
|
||||||
|
"--\n"
|
||||||
|
"\n");
|
||||||
|
|
||||||
|
#define _TESTCAPI_PYLONG_ASINT_METHODDEF \
|
||||||
|
{"PyLong_AsInt", (PyCFunction)_testcapi_PyLong_AsInt, METH_O, _testcapi_PyLong_AsInt__doc__},
|
||||||
|
/*[clinic end generated code: output=1631a18f1193486a input=a9049054013a1b77]*/
|
||||||
|
|
|
@ -37,6 +37,9 @@ raise_test_long_error(const char* msg)
|
||||||
return raiseTestError("test_long_api", msg);
|
return raiseTestError("test_long_api", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test PyLong_FromLong()/PyLong_AsLong()
|
||||||
|
// and PyLong_FromUnsignedLong()/PyLong_AsUnsignedLong().
|
||||||
|
|
||||||
#define TESTNAME test_long_api_inner
|
#define TESTNAME test_long_api_inner
|
||||||
#define TYPENAME long
|
#define TYPENAME long
|
||||||
#define F_S_TO_PY PyLong_FromLong
|
#define F_S_TO_PY PyLong_FromLong
|
||||||
|
@ -64,6 +67,9 @@ _testcapi_test_long_api_impl(PyObject *module)
|
||||||
#undef F_U_TO_PY
|
#undef F_U_TO_PY
|
||||||
#undef F_PY_TO_U
|
#undef F_PY_TO_U
|
||||||
|
|
||||||
|
// Test PyLong_FromLongLong()/PyLong_AsLongLong()
|
||||||
|
// and PyLong_FromUnsignedLongLong()/PyLong_AsUnsignedLongLong().
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
raise_test_longlong_error(const char* msg)
|
raise_test_longlong_error(const char* msg)
|
||||||
{
|
{
|
||||||
|
@ -595,6 +601,24 @@ _testcapi_call_long_compact_api(PyObject *module, PyObject *arg)
|
||||||
return Py_BuildValue("in", is_compact, value);
|
return Py_BuildValue("in", is_compact, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*[clinic input]
|
||||||
|
_testcapi.PyLong_AsInt
|
||||||
|
arg: object
|
||||||
|
/
|
||||||
|
[clinic start generated code]*/
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
_testcapi_PyLong_AsInt(PyObject *module, PyObject *arg)
|
||||||
|
/*[clinic end generated code: output=0df9f19de5fa575b input=9561b97105493a67]*/
|
||||||
|
{
|
||||||
|
assert(!PyErr_Occurred());
|
||||||
|
int value = PyLong_AsInt(arg);
|
||||||
|
if (value == -1 && PyErr_Occurred()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return PyLong_FromLong(value);
|
||||||
|
}
|
||||||
|
|
||||||
static PyMethodDef test_methods[] = {
|
static PyMethodDef test_methods[] = {
|
||||||
_TESTCAPI_TEST_LONG_AND_OVERFLOW_METHODDEF
|
_TESTCAPI_TEST_LONG_AND_OVERFLOW_METHODDEF
|
||||||
_TESTCAPI_TEST_LONG_API_METHODDEF
|
_TESTCAPI_TEST_LONG_API_METHODDEF
|
||||||
|
@ -605,6 +629,7 @@ static PyMethodDef test_methods[] = {
|
||||||
_TESTCAPI_TEST_LONG_NUMBITS_METHODDEF
|
_TESTCAPI_TEST_LONG_NUMBITS_METHODDEF
|
||||||
_TESTCAPI_TEST_LONGLONG_API_METHODDEF
|
_TESTCAPI_TEST_LONGLONG_API_METHODDEF
|
||||||
_TESTCAPI_CALL_LONG_COMPACT_API_METHODDEF
|
_TESTCAPI_CALL_LONG_COMPACT_API_METHODDEF
|
||||||
|
_TESTCAPI_PYLONG_ASINT_METHODDEF
|
||||||
{NULL},
|
{NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -549,7 +549,7 @@ PyLong_AsLong(PyObject *obj)
|
||||||
method. Return -1 and set an error if overflow occurs. */
|
method. Return -1 and set an error if overflow occurs. */
|
||||||
|
|
||||||
int
|
int
|
||||||
_PyLong_AsInt(PyObject *obj)
|
PyLong_AsInt(PyObject *obj)
|
||||||
{
|
{
|
||||||
int overflow;
|
int overflow;
|
||||||
long result = PyLong_AsLongAndOverflow(obj, &overflow);
|
long result = PyLong_AsLongAndOverflow(obj, &overflow);
|
||||||
|
|
|
@ -331,6 +331,7 @@ EXPORT_FUNC(PyList_SetSlice)
|
||||||
EXPORT_FUNC(PyList_Size)
|
EXPORT_FUNC(PyList_Size)
|
||||||
EXPORT_FUNC(PyList_Sort)
|
EXPORT_FUNC(PyList_Sort)
|
||||||
EXPORT_FUNC(PyLong_AsDouble)
|
EXPORT_FUNC(PyLong_AsDouble)
|
||||||
|
EXPORT_FUNC(PyLong_AsInt)
|
||||||
EXPORT_FUNC(PyLong_AsLong)
|
EXPORT_FUNC(PyLong_AsLong)
|
||||||
EXPORT_FUNC(PyLong_AsLongAndOverflow)
|
EXPORT_FUNC(PyLong_AsLongAndOverflow)
|
||||||
EXPORT_FUNC(PyLong_AsLongLong)
|
EXPORT_FUNC(PyLong_AsLongLong)
|
||||||
|
|
Loading…
Reference in New Issue