Skip to content
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

Merged
merged 20 commits into from
Nov 12, 2024

Conversation

rruuaanng
Copy link
Contributor

@rruuaanng rruuaanng commented Oct 28, 2024

Copy link
Member

@skirpichev skirpichev left a 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

Doc/c-api/long.rst Outdated Show resolved Hide resolved
Doc/c-api/long.rst Outdated Show resolved Hide resolved
Include/longobject.h Outdated Show resolved Hide resolved
@ZeroIntensity
Copy link
Member

I'll get to reviewing this sometime today.

@skirpichev skirpichev self-requested a review October 28, 2024 09:51
@skirpichev
Copy link
Member

@rruuaanng, please avoid force-pushes.

@rruuaanng
Copy link
Contributor Author

rruuaanng commented Oct 28, 2024

Sorry, there are a lot of changes that need to be rolled back. I will pay attention. :(

@skirpichev
Copy link
Member

skirpichev commented Oct 28, 2024 via email

Copy link
Member

@ZeroIntensity ZeroIntensity left a 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

Objects/longobject.c Outdated Show resolved Hide resolved
Objects/longobject.c Outdated Show resolved Hide resolved
Objects/longobject.c Outdated Show resolved Hide resolved
Include/cpython/longobject.h Show resolved Hide resolved
Doc/whatsnew/3.14.rst Outdated Show resolved Hide resolved
Doc/c-api/long.rst Outdated Show resolved Hide resolved
Doc/c-api/long.rst Outdated Show resolved Hide resolved
Doc/c-api/long.rst Outdated Show resolved Hide resolved
@rruuaanng
Copy link
Contributor Author

rruuaanng commented Oct 29, 2024

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 victor expected. It'sItsavior should be consistent with GetSign. Regarding the comments, their style follows the format used in the same file. So, I apologize, but I may not make changes to them.

Edit
about the document, I'll change it.

@ZeroIntensity
Copy link
Member

The error handling implementation mentioned above was based on discussions in Capigroup

Yes, I'm not asking to change how errors are handled. I'm worried about the error message.

@skirpichev
Copy link
Member

Nitpick: Use op for names, not obj

Looking on other functions, rather v. But I don't think it's a big deal.

Copy link
Member

@serhiy-storchaka serhiy-storchaka left a 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.

Objects/longobject.c Outdated Show resolved Hide resolved
Doc/c-api/long.rst Outdated Show resolved Hide resolved
Copy link
Member

@ZeroIntensity ZeroIntensity left a 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.

@skirpichev
Copy link
Member

AFAICS, the only other function using the current message is PyLong_GetSign.

No. PyLong_AsNativeBytes, PyLong_AsUnsignedLongLong, PyLong_AsDouble, PyLong_AsSsize_t, etc.

@ZeroIntensity
Copy link
Member

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.)

Modules/_testcapi/long.c Outdated Show resolved Hide resolved
Modules/_testcapi/long.c Outdated Show resolved Hide resolved
Modules/_testcapi/long.c Outdated Show resolved Hide resolved
Lib/test/test_capi/test_long.py Show resolved Hide resolved
Lib/test/test_capi/test_long.py Show resolved Hide resolved
Lib/test/test_capi/test_long.py Show resolved Hide resolved
Lib/test/test_capi/test_long.py Show resolved Hide resolved
Lib/test/test_capi/test_long.py Show resolved Hide resolved
Lib/test/test_capi/test_long.py Show resolved Hide resolved
Lib/test/test_capi/test_long.py Show resolved Hide resolved
@skirpichev
Copy link
Member

skirpichev commented Oct 29, 2024 via email

@ZeroIntensity
Copy link
Member

Ok, so that's not expect int, got type. Let's change the error to an integer is required (or better yet an integer is required, but got %T)

@rruuaanng
Copy link
Contributor Author

I've made changes :)

@erlend-aasland
Copy link
Contributor

Ok, so that's not expect int, got type. Let's change the error to an integer is required (or better yet an integer is required, but got %T)

See git grep "expected.*got". I think it would be fine to just change the word "expect" to "expected".

@vstinner
Copy link
Member

vstinner commented Nov 7, 2024

@rruuaanng rruuaanng force-pushed the gh126061 branch from f5a2e49 to b1b82ff

@rruuaanng: What are you doing? You modified errnomodule.c!? I remove my approval.

@rruuaanng
Copy link
Contributor Author

rruuaanng commented Nov 7, 2024

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 :(

@vstinner vstinner dismissed their stale review November 7, 2024 13:29

git push --force was used after my approval

Copy link
Member

@ZeroIntensity ZeroIntensity left a 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.

@rruuaanng
Copy link
Contributor Author

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 checkout, my terminal still shows the name of the current PR branch instead of the target branch I wanted to switch to. This hasn't happened before, and I don't know why this event occurred (I will never use custom scripts from hackers again, it makes me feel very ashamed).

I apologize for the malfunction that occurred during the process.
:(

Copy link
Member

@vstinner vstinner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@skirpichev
Copy link
Member

@encukou, are you ok with current wording?

@LeoniClemente LeoniClemente mentioned this pull request Nov 11, 2024
Copy link
Contributor

@picnixz picnixz left a 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?

@@ -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``).
Copy link
Contributor

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.

Copy link
Member

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.

Copy link
Contributor

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.

Copy link
Member

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).

Copy link
Contributor

@picnixz picnixz Nov 11, 2024

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.

Copy link
Member

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.

Copy link
Contributor

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".

Copy link
Member

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.

Doc/c-api/long.rst Show resolved Hide resolved
Doc/c-api/long.rst Show resolved Hide resolved
Copy link
Member

@skirpichev skirpichev left a 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)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{
{
if (obj == NULL) {
PyErr_BadInternalCall();
return -1;
}


int
PyLong_IsNegative(PyObject *obj)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{
{
if (obj == NULL) {
PyErr_BadInternalCall();
return -1;
}


int
PyLong_IsZero(PyObject *obj)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{
{
if (obj == NULL) {
PyErr_BadInternalCall();
return -1;
}

Comment on lines +658 to +659

# CRASHES ispositive(NULL)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# CRASHES ispositive(NULL)
self.assertRaises(SystemError, ispositive, NULL)

Comment on lines +673 to +674

# CRASHES isnegative(NULL)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# CRASHES isnegative(NULL)
self.assertRaises(SystemError, isnegative, NULL)

Comment on lines +688 to +689

# CRASHES iszero(NULL)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# CRASHES iszero(NULL)
self.assertRaises(SystemError, iszero, NULL)

Copy link
Member

@encukou encukou left a 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.

@vstinner vstinner merged commit 8ff7efb into python:main Nov 12, 2024
39 checks passed
@vstinner
Copy link
Member

Merged, thanks @rruuaanng.

I suggest to write a separated PR to update Doc/data/refcounts.dat for these functions but also for other recently added functions. @rruuaanng: Do you want to write such PR?

@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.

@rruuaanng
Copy link
Contributor Author

Thanks for the merger of @vstinner :)

I suggest to write a separated PR to update Doc/data/refcounts.dat for these functions but also for other recently added functions. @rruuaanng: Do you want to write such PR?

Of course, for another PR, I will finish it.

@skirpichev
Copy link
Member

I'll prepare a backport for pythoncapi-compat.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants