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

bugfix: fixes a test suite bug in the __new__ example #4698

Merged

Conversation

Skylion007
Copy link
Collaborator

Description

Fixes a test suite bug for new pointed out by @XuehaiPan in #4549

@Skylion007 Skylion007 marked this pull request as ready for review June 11, 2023 18:42
@@ -85,7 +85,7 @@ TEST_SUBMODULE(class_, m) {
.def_static("new_instance", &NoConstructor::new_instance, "Return an instance");

py::class_<NoConstructorNew>(m, "NoConstructorNew")
.def(py::init([](const NoConstructorNew &self) { return self; })) // Need a NOOP __init__
.def(py::init<>()) // Need a NOOP __init__
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is the usual default ctor. Is this still the NOOP __init__ you wanted in #3265 (and is suggested by the NoConstructor... name)?

I don't fully understand the mechanics behind __new__ and __init__, so I resorted to limited trial and error. Long story short, this works:

.def(py::init([]() { return nullptr; }))

It passes with asan, msan, ubsan (Google toolchain).

FWIW

Before I settled on the above I tried:

.def("__init__", [](NoConstructorNew *) {}) // Need a NOOP __init__

This runs if NDEBUG is defined, but not otherwise (using Python 3.10):

assert.h assertion failed at third_party/python_runtime/v3_10/Objects/typeobject.c:3823 in PyObject *_PyType_Lookup(PyTypeObject *, PyObject *): !PyErr_Occurred()

On Sep 20, 2021 @Skylion007 wrote:

I also wish there was a cleaner way to not have to implement init if new is defined, but I can't figure out how to hack to the metaclass not to complain.

I confirmed that we need one of the __init__ alternatives to avoid this error:

>       instance = m.NoConstructorNew()  # .__new__(m.NoConstructor.__class__)
E       TypeError: pybind11_tests.class_.NoConstructorNew: No constructor defined!

I also confirmed that the existing code and the usual default ctor don't leak memory.

I'm really unsure TBH what's "right", strictly speaking, but the suggested code is the alternative that seems closest to an actual NOOP.

For completeness:

With the suggested code, this passes:

assert m.NoConstructorNew.__init__.__doc__.strip() == "__init__(self: pybind11_tests.class_.NoConstructorNew) -> None"

But l think it's best not to add this assert. This is just to report what the new __doc__ is, because IIUC the existing __doc__ led @XuehaiPan to suspect there is a bug.

@rwgk
Copy link
Collaborator

rwgk commented Jul 12, 2023

I went ahead and updated this PR, based on the work reported under #4698 (comment).

@rwgk
Copy link
Collaborator

rwgk commented Jul 12, 2023

@Skylion007 all tests pass. Could you please merge if this looks good to you?

@Skylion007
Copy link
Collaborator Author

@rwgk Looks good to me. Let's merge

@rwgk rwgk merged commit b33d06f into pybind:master Jul 12, 2023
@github-actions github-actions bot added the needs changelog Possibly needs a changelog entry label Jul 12, 2023
@henryiii henryiii removed the needs changelog Possibly needs a changelog entry label Jul 13, 2023
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.

3 participants