-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Stash pybind11 data structures in interpreter state dictionary #4293
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
Changes from all commits
3b14721
7a94406
3a89f67
daf768a
8df2e81
f4e6c78
cc03a56
780c6ff
39c21a3
78e074b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -401,9 +401,30 @@ inline void translate_local_exception(std::exception_ptr p) { | |
} | ||
#endif | ||
|
||
inline object get_internals_state_dict() { | ||
object state_dict; | ||
#if PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION) | ||
state_dict = reinterpret_borrow<object>(PyEval_GetBuiltins()); | ||
#else | ||
# if PY_VERSION_HEX < 0x03090000 | ||
PyInterpreterState *istate = _PyInterpreterState_Get(); | ||
# else | ||
PyInterpreterState *istate = PyInterpreterState_Get(); | ||
# endif | ||
if (istate) { | ||
state_dict = reinterpret_borrow<object>(PyInterpreterState_GetDict(istate)); | ||
} | ||
#endif | ||
if (!state_dict) { | ||
raise_from(PyExc_SystemError, "get_internals(): could not acquire state dictionary!"); | ||
} | ||
|
||
return state_dict; | ||
} | ||
|
||
/// Return a reference to the current `internals` data | ||
PYBIND11_NOINLINE internals &get_internals() { | ||
auto **&internals_pp = get_internals_pp(); | ||
internals **&internals_pp = get_internals_pp(); | ||
if (internals_pp && *internals_pp) { | ||
return **internals_pp; | ||
} | ||
|
@@ -419,11 +440,22 @@ PYBIND11_NOINLINE internals &get_internals() { | |
} gil; | ||
error_scope err_scope; | ||
|
||
PYBIND11_STR_TYPE id(PYBIND11_INTERNALS_ID); | ||
auto builtins = handle(PyEval_GetBuiltins()); | ||
if (builtins.contains(id) && isinstance<capsule>(builtins[id])) { | ||
internals_pp = static_cast<internals **>(capsule(builtins[id])); | ||
constexpr const char *id_cstr = PYBIND11_INTERNALS_ID; | ||
str id(id_cstr); | ||
|
||
dict state_dict = get_internals_state_dict(); | ||
|
||
if (state_dict.contains(id_cstr)) { | ||
object o = state_dict[id]; | ||
// May fail if 'capsule_obj' is not a capsule, or if it has a different | ||
// name. We clear the error status below in that case | ||
internals_pp = static_cast<internals **>(PyCapsule_GetPointer(o.ptr(), id_cstr)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why the raw CAPI here? Any particular reason we are changing it from pytype.h API it was before? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is my current version:
The nice thing is that I don't have a good idea for using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While looking around more (work under PR #4329) I noticed this code in embed.h (
Two things learned:
|
||
if (!internals_pp) { | ||
PyErr_Clear(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This PR (with the #4307 tweak) is now baked into PR #4329: Copying the commit message here (I think the link will stop working in case I have to rebase):
My commit changes the code here, to report the error rather than suppressing it. What is the rationale for suppressing it? |
||
} | ||
} | ||
|
||
if (internals_pp && *internals_pp) { | ||
// We loaded builtins through python's builtins, which means that our `error_already_set` | ||
// and `builtin_exception` may be different local classes than the ones set up in the | ||
// initial exception translator, below, so add another for our local exception classes. | ||
|
@@ -459,7 +491,7 @@ PYBIND11_NOINLINE internals &get_internals() { | |
# endif | ||
internals_ptr->istate = tstate->interp; | ||
#endif | ||
builtins[id] = capsule(internals_pp); | ||
state_dict[id] = capsule(internals_pp, id_cstr); | ||
internals_ptr->registered_exception_translators.push_front(&translate_exception); | ||
internals_ptr->static_property_type = make_static_property_type(); | ||
internals_ptr->default_metaclass = make_default_metaclass(); | ||
|
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.
It turns out it is extremely easy to invite the Python 3.12 core developers to test with pybind11, with a 1 or 2 line change here, depending on how you count. Diff below.
I tested that diff with a local installation of Python 3.12.0a1. Log also below.
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 also triggered CI testing under #4307, after git rebase master.