Repository navigation
[C API] Add PyLong_GetNumBits() function #119714
Description
Activity
- addedtype-featureA feature request or enhancementA feature request or enhancement
on May 29, 2024 Why not return
(size_t)-1as indicator of error? It would be more consisting with the existing C API.Reacted by Petr ViktorinWe have a size type that can be negative to express errors. IMO, this should be
Py_ssize_t PyLong_GetNumBits(PyObject *obj);.Can we first add the underscored version back? IMO, we should design the API first, and only then start removing a function that's been there since 2003 and is used in popular software like mariadb or panda3d.
I see no reason to break people's working code. We have a better deprecation mechanism coming up in PEP-743.Can we first add the underscored version back?
The revert is discussed in a separated issue: #119336 I just enabled automerge on its PR: #119418.
First, I wasn't sure that it's worth it to restore it if a single project uses it, since you can easily call
PyObject_CallMethod(obj, "bit_length", NULL)in C to get the same value. Since I discovered more projects using it, I proposed to add a public function.Reacted by Petr ViktorinWhy not return (size_t)-1 as indicator of error? It would be more consisting with the existing C API.
We have a size type that can be negative to express errors. IMO, this should be Py_ssize_t PyLong_GetNumBits(PyObject *obj);.
I prefer to return an
intto indicate success or error. But since you both prefer to reuse the return value to also indicate an error, I changed the return type toPy_ssize_t(which was my first idea in fact).I wrote the PR #119715 to implement the function.
Py_ssize_thas a range twice smaller thansize_t. Usually this is not a problem if used for size or index, because no object can be larger thanPY_SSIZE_T_MAXbytes. But you can create an integer having more than2**31bits on 32-bit platform, and even more than2**32bits. It is not accident that_PyLong_NumBitsusessize_tinstead ofPy_ssize_t.It is still limited. This is why
int.bit_lengthdoes not use it. And this is the reason of not adding the public C API earlier -- it does not support all int objects.Perhaps returning a 64-bit integer, even on 32-bit platform, can solve the issue. In this case it does not matter whether the return type is signed or unsigned.
IMO 2**31 limit on a 32-bit system is a reasonable limitation, since Python is slow to manage such very large number. The OverflowError is already documented in the API documentation, we can also suggest calling
bit_length()for very large integer.Reacted by Petr Viktorinwe can also suggest calling bit_length() for very large integer
Done in the PR.
I created a ticket in the C API Working Group: capi-workgroup/decisions#28
See also previous slightly related discussion:
- added a commit that references this issue
on Jun 3, 2024 The C API Working Group rejected this API:
PyLong_AsNativeBytes()should be used instead.
Feature or enhancement
In Python 3.13 alpha1, I removed the private _PyLong_NumBits() function. It seems like this function is used by pywin32 and MariaDB projects: see issue gh-119336.
I propose to add a public function to replace it:
-1on error.OverflowErrorexception, and return-1if the number of bits doesn't fit intoPy_ssize_t.The C function is similar to the Python
int.bit_length()method.See also the proposed PyLong_GetSign() function.
Linked PRs