From 207a24ff7c1d9713cc041510e2c9ae95f31e446b Mon Sep 17 00:00:00 2001 From: RUANG Date: Mon, 28 Oct 2024 17:07:23 +0800 Subject: [PATCH 01/20] Add PyLong_IsPositive/Zero/Negative() functions --- Doc/c-api/long.rst | 36 +++++++++++++++++++ Doc/whatsnew/3.14.rst | 5 +++ Include/cpython/longobject.h | 18 ++++++++++ ...-10-28-15-56-03.gh-issue-126061.Py51_1.rst | 3 ++ Objects/longobject.c | 30 ++++++++++++++++ 5 files changed, 92 insertions(+) create mode 100644 Misc/NEWS.d/next/C_API/2024-10-28-15-56-03.gh-issue-126061.Py51_1.rst diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 30133a9c5cfa2f..ff3ea95c64d529 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -571,6 +571,42 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. versionadded:: 3.14 +.. c:function:: int PyLong_IsPositive(PyObject *obj) + + Check if the integer object *obj* is positive. + + On success, return 1 if *obj* is positive, and 0 otherwise. + + On failure, return -1 with an exception set. This function always succeeds + if *obj* is a :c:type:`PyLongObject` or its subtype. + + .. versionadded:: 3.14 + + +.. c:function:: int PyLong_IsNegative(PyObject *obj) + + Check if the integer object *obj* is negative. + + On success, return 1 if *obj* is negative, and 0 otherwise. + + On failure, return -1 with an exception set. This function always succeeds + if *obj* is a :c:type:`PyLongObject` or its subtype. + + .. versionadded:: 3.14 + + +.. c:function:: int PyLong_IsZero(PyObject *obj) + + Check if the integer object *obj* is zero. + + On success, return 1 if *obj* is zero, and 0 if it is non-zero. + + On failure, return -1 with an exception set. This function always succeeds + if *obj* is a :c:type:`PyLongObject` or its subtype. + + .. versionadded:: 3.14 + + .. c:function:: PyObject* PyLong_GetInfo(void) On success, return a read only :term:`named tuple`, that holds diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 83c13e6fb64d1d..4cd2476ac6fada 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -479,6 +479,11 @@ New Features an interned string and deallocate it during module shutdown. (Contribued by Eddie Elizondo in :gh:`113601`.) +* Add :c:func:`PyLong_IsPositive`, :c:func:`PyLong_IsNegative` + and :c:func:`PyLong_IsZero` for checking if :c:type:`PyLongObject` + is positive, negative, or zero. + (Contribued by James Roy in :gh:`126061`.) + * Add new functions to convert C ```` numbers from/to Python :class:`int`: diff --git a/Include/cpython/longobject.h b/Include/cpython/longobject.h index 82f8cc8a159c77..52872454a92f10 100644 --- a/Include/cpython/longobject.h +++ b/Include/cpython/longobject.h @@ -58,6 +58,24 @@ PyAPI_FUNC(PyObject*) PyLong_FromUnsignedNativeBytes(const void* buffer, PyAPI_FUNC(int) PyUnstable_Long_IsCompact(const PyLongObject* op); PyAPI_FUNC(Py_ssize_t) PyUnstable_Long_CompactValue(const PyLongObject* op); +/* PyLong_IsPositive. Check if the integer object is positive. + + - On success, return 1 if *obj is positive, and 0 otherwise. + - On failure, set an exception, and return -1. */ +PyAPI_FUNC(int) PyLong_IsPositive(PyObject *obj); + +/* PyLong_IsNegative. Check if the integer object is negative. + + - On success, return 1 if *obj is negative, and 0 otherwise. + - On failure, set an exception, and return -1. */ +PyAPI_FUNC(int) PyLong_IsNegative(PyObject *obj); + +/* PyLong_IsZero. Check if the integer object is zero. + + - On success, return 1 if *obj is zero, and 0 if it is non-zero. + - On failure, set an exception, and return -1. */ +PyAPI_FUNC(int) PyLong_IsZero(PyObject *obj); + /* PyLong_GetSign. Get the sign of an integer object: 0, -1 or +1 for zero, negative or positive integer, respectively. diff --git a/Misc/NEWS.d/next/C_API/2024-10-28-15-56-03.gh-issue-126061.Py51_1.rst b/Misc/NEWS.d/next/C_API/2024-10-28-15-56-03.gh-issue-126061.Py51_1.rst new file mode 100644 index 00000000000000..e1da2302ac691e --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2024-10-28-15-56-03.gh-issue-126061.Py51_1.rst @@ -0,0 +1,3 @@ +Add :c:func:`PyLong_IsPositive`, :c:func:`PyLong_IsNegative` +and :c:func:`PyLong_IsZero` for checking if :c:type:`PyLongObject` +is positive, negative, or zero. diff --git a/Objects/longobject.c b/Objects/longobject.c index d34c8b6d71ab3f..39cf5453614e11 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -769,6 +769,36 @@ PyLong_AsUnsignedLongMask(PyObject *op) return val; } +int +PyLong_IsPositive(PyObject *obj) +{ + if (!PyLong_Check(obj)) { + PyErr_Format(PyExc_TypeError, "expect int, got %T", obj); + return -1; + } + return _PyLong_IsPositive((PyLongObject *)obj); +} + +int +PyLong_IsNegative(PyObject *obj) +{ + if (!PyLong_Check(obj)) { + PyErr_Format(PyExc_TypeError, "expect int, got %T", obj); + return -1; + } + return _PyLong_IsNegative((PyLongObject *)obj); +} + +int +PyLong_IsZero(PyObject *obj) +{ + if (!PyLong_Check(obj)) { + PyErr_Format(PyExc_TypeError, "expect int, got %T", obj); + return -1; + } + return _PyLong_IsZero((PyLongObject *)obj); +} + int _PyLong_Sign(PyObject *vv) { From 6bbb376d5d406f77dc9b1c45f9ac86bb474c7895 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Tue, 29 Oct 2024 05:28:09 +0300 Subject: [PATCH 02/20] Apply suggestions from code review Co-authored-by: Peter Bierma --- Doc/c-api/long.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index ff3ea95c64d529..ae2c8c27d88021 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -580,7 +580,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. On failure, return -1 with an exception set. This function always succeeds if *obj* is a :c:type:`PyLongObject` or its subtype. - .. versionadded:: 3.14 + .. versionadded:: next .. c:function:: int PyLong_IsNegative(PyObject *obj) @@ -592,7 +592,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. On failure, return -1 with an exception set. This function always succeeds if *obj* is a :c:type:`PyLongObject` or its subtype. - .. versionadded:: 3.14 + .. versionadded:: next .. c:function:: int PyLong_IsZero(PyObject *obj) @@ -604,7 +604,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. On failure, return -1 with an exception set. This function always succeeds if *obj* is a :c:type:`PyLongObject` or its subtype. - .. versionadded:: 3.14 + .. versionadded:: next .. c:function:: PyObject* PyLong_GetInfo(void) From 74367521a1780cb4f1a52c9f805772919b47f06c Mon Sep 17 00:00:00 2001 From: "RUANG (James Roy)" Date: Tue, 29 Oct 2024 14:22:22 +0800 Subject: [PATCH 03/20] Add author --- Doc/whatsnew/3.14.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 4cd2476ac6fada..e002f9d36a7926 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -482,7 +482,7 @@ New Features * Add :c:func:`PyLong_IsPositive`, :c:func:`PyLong_IsNegative` and :c:func:`PyLong_IsZero` for checking if :c:type:`PyLongObject` is positive, negative, or zero. - (Contribued by James Roy in :gh:`126061`.) + (Contribued by James Roy and Sergey B Kirpichev in :gh:`126061`.) * Add new functions to convert C ```` numbers from/to Python :class:`int`: From 14608791d52cba937b7eadedbd8d6cc8d3cd6f3d Mon Sep 17 00:00:00 2001 From: RUANG Date: Tue, 29 Oct 2024 19:13:54 +0800 Subject: [PATCH 04/20] Add test --- Lib/test/test_capi/test_long.py | 32 +++++++++++++++++++++++++++++ Modules/_testcapi/long.c | 36 +++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/Lib/test/test_capi/test_long.py b/Lib/test/test_capi/test_long.py index 925fccd660bde3..251823d912b345 100644 --- a/Lib/test/test_capi/test_long.py +++ b/Lib/test/test_capi/test_long.py @@ -643,6 +643,38 @@ def test_long_getsign(self): # CRASHES getsign(NULL) + def test_long_ispositive(self): + ispositive = _testcapi.pylong_ispositive + self.assertEqual(ispositive(1), 1) + self.assertEqual(ispositive(123), 1) + self.assertEqual(ispositive(-1), 0) + self.assertEqual(ispositive(0), 0) + self.assertEqual(ispositive(True), 1) + self.assertEqual(ispositive(False), 0) + self.assertEqual(ispositive(IntSubclass(-1)), 0) + self.assertRaises(TypeError, ispositive, 1.0) + self.assertRaises(TypeError, ispositive, Index(123)) + + def test_long_isnegative(self): + isnegative = _testcapi.pylong_isnegative + self.assertEqual(isnegative(1), 0) + self.assertEqual(isnegative(123), 0) + self.assertEqual(isnegative(-1), 1) + self.assertEqual(isnegative(0), 0) + self.assertEqual(isnegative(True), 0) + self.assertEqual(isnegative(False), 0) + self.assertEqual(isnegative(IntSubclass(-1)), 1) + self.assertRaises(TypeError, isnegative, 1.0) + self.assertRaises(TypeError, isnegative, Index(123)) + + def test_long_iszero(self): + iszero = _testcapi.pylong_iszero + self.assertEqual(iszero(1), 0) + self.assertEqual(iszero(-1), 0) + self.assertEqual(iszero(0), 1) + self.assertRaises(TypeError, iszero, 1.0) + self.assertRaises(TypeError, iszero, Index(123)) + def test_long_asint32(self): # Test PyLong_AsInt32() and PyLong_FromInt32() to_int32 = _testlimitedcapi.pylong_asint32 diff --git a/Modules/_testcapi/long.c b/Modules/_testcapi/long.c index 2b5e85d5707522..a2dc41c44a5521 100644 --- a/Modules/_testcapi/long.c +++ b/Modules/_testcapi/long.c @@ -105,6 +105,39 @@ pylong_getsign(PyObject *module, PyObject *arg) } +static PyObject * +pylong_ispositive(PyObject *module, PyObject *arg) +{ + int s; + if ((s = PyLong_IsPositive(arg)) == -1) { + return NULL; + } + return PyLong_FromLong(s); +} + + +static PyObject * +pylong_isnegative(PyObject *module, PyObject *arg) +{ + int s; + if ((s = PyLong_IsNegative(arg)) == -1) { + return NULL; + } + return PyLong_FromLong(s); +} + + +static PyObject * +pylong_iszero(PyObject *module, PyObject *arg) +{ + int s; + if ((s = PyLong_IsZero(arg)) == -1) { + return NULL; + } + return PyLong_FromLong(s); +} + + static PyObject * pylong_aspid(PyObject *module, PyObject *arg) { @@ -124,6 +157,9 @@ static PyMethodDef test_methods[] = { {"pylong_fromnativebytes", pylong_fromnativebytes, METH_VARARGS}, {"pylong_getsign", pylong_getsign, METH_O}, {"pylong_aspid", pylong_aspid, METH_O}, + {"pylong_ispositive", pylong_ispositive, METH_O}, + {"pylong_isnegative", pylong_isnegative, METH_O}, + {"pylong_iszero", pylong_iszero, METH_O}, {NULL}, }; From b6a912626de9c8f294b7e35ebace094635c35e42 Mon Sep 17 00:00:00 2001 From: RUANG Date: Tue, 29 Oct 2024 19:16:41 +0800 Subject: [PATCH 05/20] Remove a space --- Modules/_testcapi/long.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_testcapi/long.c b/Modules/_testcapi/long.c index a2dc41c44a5521..ca8b741a1d54e9 100644 --- a/Modules/_testcapi/long.c +++ b/Modules/_testcapi/long.c @@ -123,7 +123,7 @@ pylong_isnegative(PyObject *module, PyObject *arg) if ((s = PyLong_IsNegative(arg)) == -1) { return NULL; } - return PyLong_FromLong(s); + return PyLong_FromLong(s); } From 71bf57b54c7effee9beba62cd49ed17ba4498092 Mon Sep 17 00:00:00 2001 From: RUANG Date: Tue, 29 Oct 2024 19:54:19 +0800 Subject: [PATCH 06/20] Change test --- Lib/test/test_capi/test_long.py | 13 +++++++++++++ Modules/_testcapi/long.c | 12 ++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_capi/test_long.py b/Lib/test/test_capi/test_long.py index 251823d912b345..737d299ad316e5 100644 --- a/Lib/test/test_capi/test_long.py +++ b/Lib/test/test_capi/test_long.py @@ -644,6 +644,7 @@ def test_long_getsign(self): # CRASHES getsign(NULL) def test_long_ispositive(self): + # Test PyLong_IsPositive() ispositive = _testcapi.pylong_ispositive self.assertEqual(ispositive(1), 1) self.assertEqual(ispositive(123), 1) @@ -655,7 +656,10 @@ def test_long_ispositive(self): self.assertRaises(TypeError, ispositive, 1.0) self.assertRaises(TypeError, ispositive, Index(123)) + # CRACHES ispositive(NULL) + def test_long_isnegative(self): + # Test PyLong_IsNegative() isnegative = _testcapi.pylong_isnegative self.assertEqual(isnegative(1), 0) self.assertEqual(isnegative(123), 0) @@ -667,14 +671,23 @@ def test_long_isnegative(self): self.assertRaises(TypeError, isnegative, 1.0) self.assertRaises(TypeError, isnegative, Index(123)) + # CRACHES isnegative(NULL) + def test_long_iszero(self): + # Test PyLong_IsZero() iszero = _testcapi.pylong_iszero self.assertEqual(iszero(1), 0) self.assertEqual(iszero(-1), 0) self.assertEqual(iszero(0), 1) + self.assertEqual(iszero(True), 0) + self.assertEqual(iszero(False), 1) + self.assertEqual(iszero(IntSubclass(-1)), 0) + self.assertEqual(iszero(IntSubclass(0)), 1) self.assertRaises(TypeError, iszero, 1.0) self.assertRaises(TypeError, iszero, Index(123)) + # CRACHES iszero(NULL) + def test_long_asint32(self): # Test PyLong_AsInt32() and PyLong_FromInt32() to_int32 = _testlimitedcapi.pylong_asint32 diff --git a/Modules/_testcapi/long.c b/Modules/_testcapi/long.c index ca8b741a1d54e9..93277b633fd8ca 100644 --- a/Modules/_testcapi/long.c +++ b/Modules/_testcapi/long.c @@ -108,8 +108,8 @@ pylong_getsign(PyObject *module, PyObject *arg) static PyObject * pylong_ispositive(PyObject *module, PyObject *arg) { - int s; - if ((s = PyLong_IsPositive(arg)) == -1) { + int s = PyLong_IsPositive(arg); + if (s == -1) { return NULL; } return PyLong_FromLong(s); @@ -119,8 +119,8 @@ pylong_ispositive(PyObject *module, PyObject *arg) static PyObject * pylong_isnegative(PyObject *module, PyObject *arg) { - int s; - if ((s = PyLong_IsNegative(arg)) == -1) { + int s = PyLong_IsNegative(arg); + if (s == -1) { return NULL; } return PyLong_FromLong(s); @@ -130,8 +130,8 @@ pylong_isnegative(PyObject *module, PyObject *arg) static PyObject * pylong_iszero(PyObject *module, PyObject *arg) { - int s; - if ((s = PyLong_IsZero(arg)) == -1) { + int s = PyLong_IsZero(arg); + if (s == -1) { return NULL; } return PyLong_FromLong(s); From 04b23c784617e6f0bd56b2b40411126a3a3c5892 Mon Sep 17 00:00:00 2001 From: RUANG Date: Wed, 30 Oct 2024 18:35:03 +0800 Subject: [PATCH 07/20] Change test --- Modules/_testcapi/long.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/Modules/_testcapi/long.c b/Modules/_testcapi/long.c index 93277b633fd8ca..5a60f41332da70 100644 --- a/Modules/_testcapi/long.c +++ b/Modules/_testcapi/long.c @@ -108,33 +108,21 @@ pylong_getsign(PyObject *module, PyObject *arg) static PyObject * pylong_ispositive(PyObject *module, PyObject *arg) { - int s = PyLong_IsPositive(arg); - if (s == -1) { - return NULL; - } - return PyLong_FromLong(s); + RETURN_INT(PyLong_IsPositive(arg)); } static PyObject * pylong_isnegative(PyObject *module, PyObject *arg) { - int s = PyLong_IsNegative(arg); - if (s == -1) { - return NULL; - } - return PyLong_FromLong(s); + RETURN_INT(PyLong_IsNegative(arg)); } static PyObject * pylong_iszero(PyObject *module, PyObject *arg) { - int s = PyLong_IsZero(arg); - if (s == -1) { - return NULL; - } - return PyLong_FromLong(s); + RETURN_INT(PyLong_IsZero(arg)); } From a30a7f1c39fb62dba5b2d022ae101ffbf8b53010 Mon Sep 17 00:00:00 2001 From: RUANG Date: Wed, 30 Oct 2024 18:35:10 +0800 Subject: [PATCH 08/20] Change docs --- Doc/c-api/long.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index ae2c8c27d88021..8c6205c5db5b24 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -575,9 +575,9 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Check if the integer object *obj* is positive. - On success, return 1 if *obj* is positive, and 0 otherwise. + On success, return ``1`` if *obj* is positive, and ``0`` otherwise. - On failure, return -1 with an exception set. This function always succeeds + On failure, return ``-1`` with an exception set. This function always succeeds if *obj* is a :c:type:`PyLongObject` or its subtype. .. versionadded:: next @@ -587,9 +587,9 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Check if the integer object *obj* is negative. - On success, return 1 if *obj* is negative, and 0 otherwise. + On success, return ``1`` if *obj* is negative, and ``0`` otherwise. - On failure, return -1 with an exception set. This function always succeeds + On failure, return ``-1`` with an exception set. This function always succeeds if *obj* is a :c:type:`PyLongObject` or its subtype. .. versionadded:: next @@ -599,9 +599,9 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Check if the integer object *obj* is zero. - On success, return 1 if *obj* is zero, and 0 if it is non-zero. + On success, return ``1`` if *obj* is zero, and ``0`` if it is non-zero. - On failure, return -1 with an exception set. This function always succeeds + On failure, return ``-1`` with an exception set. This function always succeeds if *obj* is a :c:type:`PyLongObject` or its subtype. .. versionadded:: next From b2f37624d6bef73b09e9d65940cef1a4dbe15c09 Mon Sep 17 00:00:00 2001 From: RUANG Date: Wed, 30 Oct 2024 18:42:20 +0800 Subject: [PATCH 09/20] Change docs --- Doc/c-api/long.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 8c6205c5db5b24..1ef7526842245a 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -573,7 +573,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: int PyLong_IsPositive(PyObject *obj) - Check if the integer object *obj* is positive. + Check if the integer object *obj* is strictly positive. On success, return ``1`` if *obj* is positive, and ``0`` otherwise. @@ -585,7 +585,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: int PyLong_IsNegative(PyObject *obj) - Check if the integer object *obj* is negative. + Check if the integer object *obj* is strictly negative. On success, return ``1`` if *obj* is negative, and ``0`` otherwise. From a18781f5e60ed004b558f331cd168c29316708aa Mon Sep 17 00:00:00 2001 From: "RUANG (James Roy)" Date: Wed, 30 Oct 2024 19:58:55 +0800 Subject: [PATCH 10/20] Change test --- Modules/_testcapi/long.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Modules/_testcapi/long.c b/Modules/_testcapi/long.c index 5a60f41332da70..ebea09080ef11c 100644 --- a/Modules/_testcapi/long.c +++ b/Modules/_testcapi/long.c @@ -108,6 +108,7 @@ pylong_getsign(PyObject *module, PyObject *arg) static PyObject * pylong_ispositive(PyObject *module, PyObject *arg) { + NULLABLE(arg); RETURN_INT(PyLong_IsPositive(arg)); } @@ -115,6 +116,7 @@ pylong_ispositive(PyObject *module, PyObject *arg) static PyObject * pylong_isnegative(PyObject *module, PyObject *arg) { + NULLABLE(arg); RETURN_INT(PyLong_IsNegative(arg)); } @@ -122,6 +124,7 @@ pylong_isnegative(PyObject *module, PyObject *arg) static PyObject * pylong_iszero(PyObject *module, PyObject *arg) { + NULLABLE(arg); RETURN_INT(PyLong_IsZero(arg)); } From c50d7a22c85d79090e5ca5e174b5cf89150e18be Mon Sep 17 00:00:00 2001 From: RUANG Date: Thu, 31 Oct 2024 12:02:46 +0800 Subject: [PATCH 11/20] Change typos --- Lib/test/test_capi/test_long.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_capi/test_long.py b/Lib/test/test_capi/test_long.py index 737d299ad316e5..a77094588a0edf 100644 --- a/Lib/test/test_capi/test_long.py +++ b/Lib/test/test_capi/test_long.py @@ -656,7 +656,7 @@ def test_long_ispositive(self): self.assertRaises(TypeError, ispositive, 1.0) self.assertRaises(TypeError, ispositive, Index(123)) - # CRACHES ispositive(NULL) + # CRASHES ispositive(NULL) def test_long_isnegative(self): # Test PyLong_IsNegative() @@ -671,7 +671,7 @@ def test_long_isnegative(self): self.assertRaises(TypeError, isnegative, 1.0) self.assertRaises(TypeError, isnegative, Index(123)) - # CRACHES isnegative(NULL) + # CRASHES isnegative(NULL) def test_long_iszero(self): # Test PyLong_IsZero() @@ -686,7 +686,7 @@ def test_long_iszero(self): self.assertRaises(TypeError, iszero, 1.0) self.assertRaises(TypeError, iszero, Index(123)) - # CRACHES iszero(NULL) + # CRASHES iszero(NULL) def test_long_asint32(self): # Test PyLong_AsInt32() and PyLong_FromInt32() From 63adaf60ed005679306eb1d6fa25562721bd1bf2 Mon Sep 17 00:00:00 2001 From: "RUANG (James Roy)" Date: Fri, 1 Nov 2024 10:18:42 +0800 Subject: [PATCH 12/20] expect rename to expected --- Objects/longobject.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 39cf5453614e11..62b37c1ff1dee9 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -773,7 +773,7 @@ int PyLong_IsPositive(PyObject *obj) { if (!PyLong_Check(obj)) { - PyErr_Format(PyExc_TypeError, "expect int, got %T", obj); + PyErr_Format(PyExc_TypeError, "expected int, got %T", obj); return -1; } return _PyLong_IsPositive((PyLongObject *)obj); @@ -783,7 +783,7 @@ int PyLong_IsNegative(PyObject *obj) { if (!PyLong_Check(obj)) { - PyErr_Format(PyExc_TypeError, "expect int, got %T", obj); + PyErr_Format(PyExc_TypeError, "expected int, got %T", obj); return -1; } return _PyLong_IsNegative((PyLongObject *)obj); @@ -793,7 +793,7 @@ int PyLong_IsZero(PyObject *obj) { if (!PyLong_Check(obj)) { - PyErr_Format(PyExc_TypeError, "expect int, got %T", obj); + PyErr_Format(PyExc_TypeError, "expected int, got %T", obj); return -1; } return _PyLong_IsZero((PyLongObject *)obj); From 5ec2379b5644c9a32d51a65f87ca2cc9073c0402 Mon Sep 17 00:00:00 2001 From: RUANG Date: Fri, 1 Nov 2024 13:55:55 +0800 Subject: [PATCH 13/20] Change docs --- Doc/c-api/long.rst | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 1ef7526842245a..1514193bd623a3 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -573,24 +573,22 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: int PyLong_IsPositive(PyObject *obj) - Check if the integer object *obj* is strictly positive. + Check if the integer object *obj* is positive. - On success, return ``1`` if *obj* is positive, and ``0`` otherwise. - - On failure, return ``-1`` with an exception set. This function always succeeds - if *obj* is a :c:type:`PyLongObject` or its subtype. + If *obj* is an instance of :c:type:`PyLongObject` or it's subtype, + return ``1`` when it's positive and ``0`` otherwise. Else set an + exception and return ``-1``. .. versionadded:: next .. c:function:: int PyLong_IsNegative(PyObject *obj) - Check if the integer object *obj* is strictly negative. + Check if the integer object *obj* is negative. - On success, return ``1`` if *obj* is negative, and ``0`` otherwise. - - On failure, return ``-1`` with an exception set. This function always succeeds - if *obj* is a :c:type:`PyLongObject` or its subtype. + If *obj* is an instance of :c:type:`PyLongObject` or it's subtype, + return ``1`` when it's positive and ``0`` otherwise. Else set an + exception and return ``-1``. .. versionadded:: next From 196cf3619c0b3f4ee595aa72dc846ea71ad45621 Mon Sep 17 00:00:00 2001 From: RUANG Date: Fri, 1 Nov 2024 14:04:37 +0800 Subject: [PATCH 14/20] Change docs --- Doc/c-api/long.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 1514193bd623a3..b80da880cc766c 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -587,7 +587,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Check if the integer object *obj* is negative. If *obj* is an instance of :c:type:`PyLongObject` or it's subtype, - return ``1`` when it's positive and ``0`` otherwise. Else set an + return ``1`` when it's negative and ``0`` otherwise. Else set an exception and return ``-1``. .. versionadded:: next @@ -597,10 +597,9 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Check if the integer object *obj* is zero. - On success, return ``1`` if *obj* is zero, and ``0`` if it is non-zero. - - On failure, return ``-1`` with an exception set. This function always succeeds - if *obj* is a :c:type:`PyLongObject` or its subtype. + If *obj* is an instance of :c:type:`PyLongObject` or it's subtype, + return ``1`` when it's zero and ``0`` otherwise. Else set an + exception and return ``-1``. .. versionadded:: next From 73e150d8d566e0829902ffde4fdc239da7147d33 Mon Sep 17 00:00:00 2001 From: "RUANG (James Roy)" Date: Sat, 2 Nov 2024 09:43:42 +0800 Subject: [PATCH 15/20] Change whatNEWS --- Doc/whatsnew/3.14.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index e002f9d36a7926..33cc189fc24fc4 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -481,7 +481,7 @@ New Features * Add :c:func:`PyLong_IsPositive`, :c:func:`PyLong_IsNegative` and :c:func:`PyLong_IsZero` for checking if :c:type:`PyLongObject` - is positive, negative, or zero. + is positive, negative, or zero, respectively. (Contribued by James Roy and Sergey B Kirpichev in :gh:`126061`.) * Add new functions to convert C ```` numbers from/to Python From 630bc01c669ddb6e2040bb600e4e6c17e6d18e65 Mon Sep 17 00:00:00 2001 From: "RUANG (James Roy)" Date: Sat, 2 Nov 2024 09:44:59 +0800 Subject: [PATCH 16/20] Change NEWS --- .../next/C_API/2024-10-28-15-56-03.gh-issue-126061.Py51_1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/C_API/2024-10-28-15-56-03.gh-issue-126061.Py51_1.rst b/Misc/NEWS.d/next/C_API/2024-10-28-15-56-03.gh-issue-126061.Py51_1.rst index e1da2302ac691e..318ea7a692d6e1 100644 --- a/Misc/NEWS.d/next/C_API/2024-10-28-15-56-03.gh-issue-126061.Py51_1.rst +++ b/Misc/NEWS.d/next/C_API/2024-10-28-15-56-03.gh-issue-126061.Py51_1.rst @@ -1,3 +1,3 @@ Add :c:func:`PyLong_IsPositive`, :c:func:`PyLong_IsNegative` and :c:func:`PyLong_IsZero` for checking if :c:type:`PyLongObject` -is positive, negative, or zero. +is positive, negative, or zero, respectively. From daecbc93c63eace02ff4576966151cf2f6d4513c Mon Sep 17 00:00:00 2001 From: "RUANG (James Roy)" Date: Tue, 5 Nov 2024 22:33:02 +0800 Subject: [PATCH 17/20] Change to its --- Doc/c-api/long.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index b80da880cc766c..f813a8d2eb0385 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -575,7 +575,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Check if the integer object *obj* is positive. - If *obj* is an instance of :c:type:`PyLongObject` or it's subtype, + If *obj* is an instance of :c:type:`PyLongObject` or its subtype, return ``1`` when it's positive and ``0`` otherwise. Else set an exception and return ``-1``. @@ -586,7 +586,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Check if the integer object *obj* is negative. - If *obj* is an instance of :c:type:`PyLongObject` or it's subtype, + If *obj* is an instance of :c:type:`PyLongObject` or its subtype, return ``1`` when it's negative and ``0`` otherwise. Else set an exception and return ``-1``. @@ -597,7 +597,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Check if the integer object *obj* is zero. - If *obj* is an instance of :c:type:`PyLongObject` or it's subtype, + If *obj* is an instance of :c:type:`PyLongObject` or its subtype, return ``1`` when it's zero and ``0`` otherwise. Else set an exception and return ``-1``. From b1b82ff8dee3ce4f4291a118014f89361bd7af1d Mon Sep 17 00:00:00 2001 From: RUANG Date: Thu, 7 Nov 2024 19:11:49 +0800 Subject: [PATCH 18/20] Add note (boom) --- Doc/c-api/long.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index f813a8d2eb0385..4565d72bab97d0 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -573,7 +573,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: int PyLong_IsPositive(PyObject *obj) - Check if the integer object *obj* is positive. + Check if the integer object *obj* is positive (``obj > 0``). If *obj* is an instance of :c:type:`PyLongObject` or its subtype, return ``1`` when it's positive and ``0`` otherwise. Else set an @@ -584,7 +584,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: int PyLong_IsNegative(PyObject *obj) - Check if the integer object *obj* is negative. + Check if the integer object *obj* is negative (``obj < 0``). If *obj* is an instance of :c:type:`PyLongObject` or its subtype, return ``1`` when it's negative and ``0`` otherwise. Else set an From 5e7e6cea1a4260148d426302ded9923eb30aa613 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 11 Nov 2024 17:09:51 +0300 Subject: [PATCH 19/20] Update Misc/NEWS.d/next/C_API/2024-10-28-15-56-03.gh-issue-126061.Py51_1.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- .../next/C_API/2024-10-28-15-56-03.gh-issue-126061.Py51_1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/C_API/2024-10-28-15-56-03.gh-issue-126061.Py51_1.rst b/Misc/NEWS.d/next/C_API/2024-10-28-15-56-03.gh-issue-126061.Py51_1.rst index 318ea7a692d6e1..0a4ad4ea2874cf 100644 --- a/Misc/NEWS.d/next/C_API/2024-10-28-15-56-03.gh-issue-126061.Py51_1.rst +++ b/Misc/NEWS.d/next/C_API/2024-10-28-15-56-03.gh-issue-126061.Py51_1.rst @@ -1,3 +1,3 @@ Add :c:func:`PyLong_IsPositive`, :c:func:`PyLong_IsNegative` -and :c:func:`PyLong_IsZero` for checking if :c:type:`PyLongObject` +and :c:func:`PyLong_IsZero` for checking if a :c:type:`PyLongObject` is positive, negative, or zero, respectively. From 43cfbb4aa1fa495f26c1da55c9d126fdb4f61a12 Mon Sep 17 00:00:00 2001 From: "RUANG (James Roy)" Date: Mon, 11 Nov 2024 22:29:38 +0800 Subject: [PATCH 20/20] Add assert --- Objects/longobject.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Objects/longobject.c b/Objects/longobject.c index 62b37c1ff1dee9..3ca7710e219486 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -772,6 +772,7 @@ PyLong_AsUnsignedLongMask(PyObject *op) int PyLong_IsPositive(PyObject *obj) { + assert(obj != NULL); if (!PyLong_Check(obj)) { PyErr_Format(PyExc_TypeError, "expected int, got %T", obj); return -1; @@ -782,6 +783,7 @@ PyLong_IsPositive(PyObject *obj) int PyLong_IsNegative(PyObject *obj) { + assert(obj != NULL); if (!PyLong_Check(obj)) { PyErr_Format(PyExc_TypeError, "expected int, got %T", obj); return -1; @@ -792,6 +794,7 @@ PyLong_IsNegative(PyObject *obj) int PyLong_IsZero(PyObject *obj) { + assert(obj != NULL); if (!PyLong_Check(obj)) { PyErr_Format(PyExc_TypeError, "expected int, got %T", obj); return -1;