Skip to content

gh-128509: Add PyUnstable_IsImmortal for finding immortal objects #129182

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

Merged
merged 16 commits into from
Jan 27, 2025

Conversation

ZeroIntensity
Copy link
Member

@ZeroIntensity ZeroIntensity commented Jan 22, 2025

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.

@ZeroIntensity
Copy link
Member Author

I think @encukou's review would also be helpful.

static PyObject *
is_immortal(PyObject *self, PyObject *op)
{
return PyBool_FromLong(PyUnstable_IsImmortal(op));
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
return PyBool_FromLong(PyUnstable_IsImmortal(op));
NULLABLE(op)
return PyLong_FromLong(PyUnstable_IsImmortal(op));

This allows to test with NULL, and check if the result is not 0 or 1.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it makes sense to crash with NULL.

for non_immortal in non_immortals:
with self.subTest(non_immortal=non_immortal):
self.assertFalse(_testcapi.is_immortal(non_immortal))

Copy link
Member

Choose a reason for hiding this comment

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

Does _testcapi.is_immortal(NULL) crash? If yes, add a comment, otherwise add a test.

Copy link
Member

Choose a reason for hiding this comment

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

If yes, add a comment

And ideally an assert to the implementation (as “executable documentation”).

for non_immortal in non_immortals:
with self.subTest(non_immortal=non_immortal):
self.assertFalse(_testcapi.is_immortal(non_immortal))

Copy link
Member

Choose a reason for hiding this comment

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

If yes, add a comment

And ideally an assert to the implementation (as “executable documentation”).

ZeroIntensity and others added 4 commits January 23, 2025 08:03
Co-authored-by: Serhiy Storchaka <[email protected]>
Co-authored-by: Petr Viktorin <[email protected]>
This reverts commit 6014587.
with self.subTest(non_immortal=non_immortal):
self.assertFalse(_testcapi.is_immortal(non_immortal))

# CRASHES _testcapi.is_immortal(NULL)
Copy link
Member

Choose a reason for hiding this comment

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

Did you test this?

Copy link
Member

Choose a reason for hiding this comment

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

is_immortal(None) checks if None is immortal, it doesn't crash.

I suggest to remove this comment. I don't think that it's worth it to bother with testing NULL, PyUnstable_IsImmortal() now starts with assert(op != NULL);. And it's interesting to test if None is immortal 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.

I suggest to apply my suggestions to be able to test with NULL.

Copy link
Member Author

Choose a reason for hiding this comment

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

That would break the test with None. I think as long as we have the assertion there, it's not worth explicitly testing it.

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.

class TestCAPI(unittest.TestCase):
    def test_immortal_builtins(self):
        _testcapi.test_immortal_builtins()
    def test_immortal_small_ints(self):
_testcapi.test_immortal_small_ints()

There is a problem with existing tests: all methods called test_xxx are run automatically by test_capi.test_misc:

vstinner@mona$ ./python -m test test_capi -v -m test_immortal_small_ints
(...)
test_immortal_small_ints (test.test_capi.test_immortal.TestCAPI.test_immortal_small_ints) ... ok
test_immortal_small_ints (test.test_capi.test_misc.Test_testcapi.test_immortal_small_ints) ... ok
(...)

Tests are run twice. Can you fix these tests as part of your PR? Just use a different function name prefix, such as check_xxx.

@@ -131,13 +131,22 @@ pyobject_enable_deferred_refcount(PyObject *self, PyObject *obj)
return PyLong_FromLong(result);
}


static PyObject *
is_immortal(PyObject *self, PyObject *op)
Copy link
Member

Choose a reason for hiding this comment

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

Oh, I didn't know that Modules/_testcapi/immortal.c exists. Maybe put the new function there?

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

@encukou encukou merged commit 3fb5f6e into python:main Jan 27, 2025
41 checks passed
@ZeroIntensity ZeroIntensity deleted the unstable-is-immortal branch January 27, 2025 15:42
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.

4 participants