-
-
Notifications
You must be signed in to change notification settings - Fork 30.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gh-126061: Add PyLong_IsPositive/Zero/Negative() functions #126065
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should have tests and an entry in Doc/whatsnew/3.14.rst
I'll get to reviewing this sometime today. |
@rruuaanng, please avoid force-pushes. |
Sorry, there are a lot of changes that need to be rolled back. I will pay attention. :( |
On Mon, Oct 28, 2024 at 02:55:40AM -0700, RUANG (James Roy) wrote:
Sorry, there are a lot of changes that need to be rolled back. I will pay
attention. :(
In the end - individual commits will be squashed anyway.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: Use op
for names, not obj
Given the number of comments,I'll reply here. I apologize for any inconvenience. The error handling implementation mentioned above was based on discussions in Capigroup, as Edit |
Yes, I'm not asking to change how errors are handled. I'm worried about the error message. |
Looking on other functions, rather |
Co-authored-by: Peter Bierma <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM in general. Please add tests. Look at Modules/_testcapi/long.c
and Lib/test/test_capi/test_long.py
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do see Serhiy's point of using the type name rather than the repr, but it's nice when "invalid type" errors are more unified, so I would prefer if it matched what was raised when using PyArg*
. AFAICS, the only other function using the current message is PyLong_GetSign
.
No. PyLong_AsNativeBytes, PyLong_AsUnsignedLongLong, PyLong_AsDouble, PyLong_AsSsize_t, etc. |
Ah, I see it in |
On Tue, Oct 29, 2024 at 04:40:08AM -0700, Peter Bierma wrote:
Ah, I see it in PyLong_AsNativeBytes, but that looks like the only other
location. Could you point me to where it's thrown in the other functions?
(GitHub search might be acting up.)
Correct phrase to grep is "an integer is required" ;)
|
Ok, so that's not |
I've made changes :) |
See |
@rruuaanng: What are you doing? You modified errnomodule.c!? I remove my approval. |
Sorry, there was something wrong with my terminal and it didn't update my current branch in real time after switching branches. I accidentally submitted another PR to my current branch. I rolled it back, oh :( |
git push --force was used after my approval
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is why we don't force push. It looks like the changes got rolled back, though.
This isn't what I expected. Actually, I didn't notice that this event occurred at first, but later I didn't receive any emails from my target branch. After using I apologize for the malfunction that occurred during the process. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@encukou, are you ok with current wording? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we update Doc/data/refcounts.dat
even though the file is not maintained anymore?
Misc/NEWS.d/next/C_API/2024-10-28-15-56-03.gh-issue-126061.Py51_1.rst
Outdated
Show resolved
Hide resolved
@@ -571,6 +571,39 @@ 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 (``obj > 0``). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAICT, obj
must not be NULL since otherwise it crashes (it's not the same as setting an exception). Other functions in this section mention when an input must not be NULL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think such details are documented for other functions.
But maybe we should add instead the NULL
check (like e.g. PyLong_AsNativeBytes). IIUC, there is no rule to do so for new functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think such details are documented for other functions.
There is: https://docs.python.org/3.14/c-api/long.html#c.PyLong_AsInt32. Those were recently added functions so that's why I suggested continuing specifying whether a NULL is allowed or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact, PyLong_AsInt32 doesn't crashes on NULL
. So, value must not be NULL
sentence is slightly redundant: in this case function set an exception and return -1
(exactly as specified right above).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, maybe I wasn't clear but value in this case is the output buffer which is then dereferenced without a NULL check. It's not the PyObject input. My point was that when we do not expect a NULL value (and don't check for it), we specify it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally (unless documented otherwise), the C API has undefined behaviour if you pass in a NULL PyObject *
. Usually it'll crash. Sometimes we assert
that it's not NULL: that would probably be best here. But we don't need an if
.
I advise against adding a note in the docs about NULL, since it could hint (to humans) that one could pass NULL to other functions.
PyLong_AsInt32
is different: there the pointer is an “output argument” that the function fills in. An explicit note makes more sense there. Generally, for many functions like that, it's sometimes useful to run other effects of a function without getting the result filled in, and so some functions like this do accept NULL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I advise against adding a note in the docs about NULL, since it could hint (to humans) that one could pass NULL to other functions.
I see your point here. The alternative is to specify it to other functions explicitly as well. But it's probably better to just do it in one docs PR later if needed. So I don't mind not specifying "do not pass NULL".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, no docs changes. I'll keep this comment unresolved, in case we want handle obj==NULL case in functions as suggested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added few suggestions to address @picnixz review.
@@ -769,6 +769,36 @@ PyLong_AsUnsignedLongMask(PyObject *op) | |||
return val; | |||
} | |||
|
|||
int | |||
PyLong_IsPositive(PyObject *obj) | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{ | |
{ | |
if (obj == NULL) { | |
PyErr_BadInternalCall(); | |
return -1; | |
} |
|
||
int | ||
PyLong_IsNegative(PyObject *obj) | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{ | |
{ | |
if (obj == NULL) { | |
PyErr_BadInternalCall(); | |
return -1; | |
} |
|
||
int | ||
PyLong_IsZero(PyObject *obj) | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{ | |
{ | |
if (obj == NULL) { | |
PyErr_BadInternalCall(); | |
return -1; | |
} |
|
||
# CRASHES ispositive(NULL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# CRASHES ispositive(NULL) | |
self.assertRaises(SystemError, ispositive, NULL) |
|
||
# CRASHES isnegative(NULL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# CRASHES isnegative(NULL) | |
self.assertRaises(SystemError, isnegative, NULL) |
|
||
# CRASHES iszero(NULL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# CRASHES iszero(NULL) | |
self.assertRaises(SystemError, iszero, NULL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@encukou, are you ok with current wording?
Yes.
Should we update Doc/data/refcounts.dat even though the file is not maintained anymore?
Yeah, ideally yes.
…1_1.rst Co-authored-by: Bénédikt Tran <[email protected]>
Merged, thanks @rruuaanng. I suggest to write a separated PR to update @skirpichev: I disagree with checking for NULL. I prefer to have undefined behavior for best performance and document that the argument must not be NULL. |
Thanks for the merger of @vstinner :)
Of course, for another PR, I will finish it. |
I'll prepare a backport for pythoncapi-compat. |
📚 Documentation preview 📚: https://cpython-previews--126065.org.readthedocs.build/