Repository navigation
Conversation
pybind11_static_property, the pybind11_type metaclass, pybind11_object and the classes from make_new_python_type() are now created from a PyType_Spec on CPython 3.12+ instead of by filling in PyHeapTypeObject fields. PYBIND11_TYPE_CREATION_VIA_SPEC (0/1) controls this; define it as 0, or configure with -DPYBIND11_TYPE_CREATION_VIA_SPEC=OFF, to keep the legacy path. PyPy, GraalPy and Python < 3.12 keep the legacy path. py::custom_type_setup(), metaclasses with a custom tp_new, and metaclass combinations that PyType_FromMetaclass() rejects (such as a base whose metaclass is not related to pybind11_type) still use the legacy path. A user-defined PYBIND11_BACKWARD_COMPATIBILITY_TP_DICTOFFSET also selects the legacy path, so all bound classes share one __dict__ layout. The instance layout and the internals ID do not change. The macro is encoded in the precompiled config check. A new CI job tests the legacy path on CPython 3.12+. See pybind#6104. Assisted-by: ClaudeCode:claude-opus-5-5
|
Initial codex GPT-6.1-Sol ultra review below. Before the review, I locally merged latest master. I'll use the same codex session to generate a fix. I found one reproducible regression, treating the Python 3.12+ switch as intentional. [P2] Preserve supplied class names containing dots — class-inl.h:840–841. For example: py::class_<T>(m, "Wrapper[pkg.Value]");The new path changes This reproduces on Python 3.12, 3.14, and free-threaded 3.14. Master and the legacy opt-out preserve the supplied names. Explicitly restoring Your local merged revision passed:
No other introduced actionable issues emerged from the independent reviews. |
— codex GPT-6 on behalf of Ralf — Use the existing legacy type-creation fallback when a bound name contains a dot. PyType_FromMetaclass() treats the last dot as the module separator, truncating names such as Wrapper[pkg.Value]. Preserve both the public __name__/__qualname__ and the fully qualified C tp_name. Assigning __name__ after creation would also overwrite tp_name. Add top-level and nested regression cases; both fail without the fix.
|
In case anyone is looking at the moment: I'm having doubts myself about the direction taken with commit f9eda9d. I'm still working on making up my mind. |
— codex GPT-6 on behalf of Ralf — Revert f9eda9d so the naming behavior introduced by spec-based type creation can be characterized across CI. The naming policy will be discussed separately after collecting results.
— codex GPT-6 on behalf of Ralf — Record name, qualified name, literal lookup, construction, reference-return identity and generated signatures for dotted and bracketed class names. Include nested scopes, a child of a dotted class, and custom type setup. Keep expectations specific to the current creation path and Python runtime. These tests collect evidence for the naming-policy discussion without choosing whether to retain, reject or accommodate the changed behavior.
|
Update: I'm using the CI here to fully characterize the behavior changes introduced by this PR. I'm uncertain if we should care about them or not. I believe it's best to have complete ground truth, then we can decide. |
— codex GPT-6 on behalf of Ralf — Select true/false with the preprocessor instead of casting the numeric configuration macro to bool. This satisfies modernize-use-bool-literals in Clang-Tidy, including the Python3.11 macro-zero branch.
🤖 AI text below 🤖
Description
On CPython 3.12+, pybind11 now creates its type objects (
pybind11_static_property, thepybind11_typemetaclass,pybind11_object, and all bound classes) withPyType_FromMetaclass()and aPyType_Spec. It no longer fills inPyHeapTypeObjectfields by hand there.PYBIND11_TYPE_CREATION_VIA_SPECmacro (0/1) controls this. It defaults to 1 on CPython 3.12+ and to 0 on older CPython, PyPy, and GraalPy. Define it as 0, or configure with-DPYBIND11_TYPE_CREATION_VIA_SPEC=OFF, to keep the legacy path. A new CI job tests the legacy path on 3.12+.py::custom_type_setup(), metaclasses with a customtp_new, and metaclass combinations thatPyType_FromMetaclass()rejects still use the legacy path. One example of a rejected combination is a base whose metaclass is not a base or subtype ofpybind11_type. Without the fallback, binding a class derived from such a base fails with a metaclass conflict. A new test covers this case.PYBIND11_BACKWARD_COMPATIBILITY_TP_DICTOFFSET, the legacy path is the default. The spec path usesPy_TPFLAGS_MANAGED_DICT, and all bound classes must have the same__dict__layout.PYBIND11_TYPE_CREATION_VIA_SPEC=1together with that macro is a compile error.PYBIND11_INTERNALS_IDdo not change. The macro is added to the precompiled config check.This prepares for stable-ABI support (#6104), but it is also useful without it.
Suggested changelog entry:
PyType_FromMetaclass(). DefinePYBIND11_TYPE_CREATION_VIA_SPEC=0(CMake:-DPYBIND11_TYPE_CREATION_VIA_SPEC=OFF) to use the previousPyHeapTypeObjectpath.📚 Documentation preview 📚: https://pybind11--6231.org.readthedocs.build/