https://github.com/python/cpython/commit/61d3ab32da92e70bb97a544d76ef2b837501024f
commit: 61d3ab32da92e70bb97a544d76ef2b837501024f
branch: main
author: Sergey B Kirpichev <skirpic...@gmail.com>
committer: vstinner <vstin...@python.org>
date: 2024-06-03T14:06:31+02:00
summary:

gh-116560: Add PyLong_GetSign() public function (#116561)

Co-authored-by: Victor Stinner <vstin...@python.org>

files:
A Misc/NEWS.d/next/C API/2024-03-10-14-55-51.gh-issue-116560.x2mZaO.rst
M Doc/c-api/long.rst
M Doc/whatsnew/3.14.rst
M Include/cpython/longobject.h
M Lib/test/test_capi/test_long.py
M Modules/_testcapi/long.c
M Objects/longobject.c

diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst
index 522c028cfb8d40..a0e111af5996d7 100644
--- a/Doc/c-api/long.rst
+++ b/Doc/c-api/long.rst
@@ -494,6 +494,19 @@ distinguished from a number.  Use :c:func:`PyErr_Occurred` 
to disambiguate.
    .. versionadded:: 3.13
 
 
+.. c:function:: int PyLong_GetSign(PyObject *obj, int *sign)
+
+   Get the sign of the integer object *obj*.
+
+   On success, set *\*sign* to the integer sign  (0, -1 or +1 for zero, 
negative or
+   positive integer, respectively) and return 0.
+
+   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 PyUnstable_Long_IsCompact(const PyLongObject* op)
 
    Return 1 if *op* is compact, 0 otherwise.
diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst
index 47f3e30942397f..b2dd80b64a691a 100644
--- a/Doc/whatsnew/3.14.rst
+++ b/Doc/whatsnew/3.14.rst
@@ -255,6 +255,9 @@ C API Changes
 New Features
 ------------
 
+* Add :c:func:`PyLong_GetSign` function to get the sign of :class:`int` 
objects.
+  (Contributed by Sergey B Kirpichev in :gh:`116560`.)
+
 Porting to Python 3.14
 ----------------------
 
diff --git a/Include/cpython/longobject.h b/Include/cpython/longobject.h
index 96815938c8277a..19a6722d07734a 100644
--- a/Include/cpython/longobject.h
+++ b/Include/cpython/longobject.h
@@ -55,9 +55,13 @@ 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_Sign.  Return 0 if v is 0, -1 if v < 0, +1 if v > 0.
-// v must not be NULL, and must be a normalized long.
-// There are no error cases.
+/* PyLong_GetSign.  Get the sign of an integer object:
+   0, -1 or +1 for zero, negative or positive integer, respectively.
+
+   - On success, set '*sign' to the integer sign, and return 0.
+   - On failure, set an exception, and return -1. */
+PyAPI_FUNC(int) PyLong_GetSign(PyObject *v, int *sign);
+
 PyAPI_FUNC(int) _PyLong_Sign(PyObject *v);
 
 /* _PyLong_NumBits.  Return the number of bits needed to represent the
diff --git a/Lib/test/test_capi/test_long.py b/Lib/test/test_capi/test_long.py
index 83f894e552f983..06a29b5a0505b4 100644
--- a/Lib/test/test_capi/test_long.py
+++ b/Lib/test/test_capi/test_long.py
@@ -721,6 +721,22 @@ def test_long_fromnativebytes(self):
                 self.assertEqual(expect_u, fromnativebytes(v_be, n, 4, 1),
                     f"PyLong_FromNativeBytes(buffer, {n}, <big|unsigned>)")
 
+    def test_long_getsign(self):
+        # Test PyLong_GetSign()
+        getsign = _testcapi.pylong_getsign
+        self.assertEqual(getsign(1), 1)
+        self.assertEqual(getsign(123456), 1)
+        self.assertEqual(getsign(-2), -1)
+        self.assertEqual(getsign(0), 0)
+        self.assertEqual(getsign(True), 1)
+        self.assertEqual(getsign(IntSubclass(-11)), -1)
+        self.assertEqual(getsign(False), 0)
+
+        self.assertRaises(TypeError, getsign, 1.0)
+        self.assertRaises(TypeError, getsign, Index(123))
+
+        # CRASHES getsign(NULL)
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/Misc/NEWS.d/next/C 
API/2024-03-10-14-55-51.gh-issue-116560.x2mZaO.rst b/Misc/NEWS.d/next/C 
API/2024-03-10-14-55-51.gh-issue-116560.x2mZaO.rst
new file mode 100644
index 00000000000000..9bcadfd9247f78
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2024-03-10-14-55-51.gh-issue-116560.x2mZaO.rst     
@@ -0,0 +1 @@
+Add :c:func:`PyLong_GetSign` function.  Patch by Sergey B Kirpichev.
diff --git a/Modules/_testcapi/long.c b/Modules/_testcapi/long.c
index 769c3909ea3fb1..2b5e85d5707522 100644
--- a/Modules/_testcapi/long.c
+++ b/Modules/_testcapi/long.c
@@ -92,6 +92,19 @@ pylong_fromnativebytes(PyObject *module, PyObject *args)
     return res;
 }
 
+
+static PyObject *
+pylong_getsign(PyObject *module, PyObject *arg)
+{
+    int sign;
+    NULLABLE(arg);
+    if (PyLong_GetSign(arg, &sign) == -1) {
+        return NULL;
+    }
+    return PyLong_FromLong(sign);
+}
+
+
 static PyObject *
 pylong_aspid(PyObject *module, PyObject *arg)
 {
@@ -109,6 +122,7 @@ static PyMethodDef test_methods[] = {
     {"pylong_fromunicodeobject",    pylong_fromunicodeobject,   METH_VARARGS},
     {"pylong_asnativebytes",        pylong_asnativebytes,       METH_VARARGS},
     {"pylong_fromnativebytes",      pylong_fromnativebytes,     METH_VARARGS},
+    {"pylong_getsign",              pylong_getsign,             METH_O},
     {"pylong_aspid",                pylong_aspid,               METH_O},
     {NULL},
 };
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 2dc2cb7a47b460..054689471e7aa9 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -770,6 +770,18 @@ _PyLong_Sign(PyObject *vv)
     return _PyLong_NonCompactSign(v);
 }
 
+int
+PyLong_GetSign(PyObject *vv, int *sign)
+{
+    if (!PyLong_Check(vv)) {
+        PyErr_Format(PyExc_TypeError, "expect int, got %T", vv);
+        return -1;
+    }
+
+    *sign = _PyLong_Sign(vv);
+    return 0;
+}
+
 static int
 bit_length_digit(digit x)
 {

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to