34
34
// / further ABI-incompatible changes may be made before the ABI is officially
35
35
// / changed to the new version.
36
36
#ifndef PYBIND11_INTERNALS_VERSION
37
- # define PYBIND11_INTERNALS_VERSION 4
37
+ # if PY_VERSION_HEX >= 0x030C0000
38
+ // Version bump for Python 3.12+, before first 3.12 beta release.
39
+ # define PYBIND11_INTERNALS_VERSION 5
40
+ # else
41
+ # define PYBIND11_INTERNALS_VERSION 4
42
+ # endif
38
43
#endif
39
44
45
+ // This requirement is mainly to reduce the support burden (see PR #4570).
46
+ static_assert (PY_VERSION_HEX < 0x030C0000 || PYBIND11_INTERNALS_VERSION >= 5 ,
47
+ " pybind11 ABI version 5 is the minimum for Python 3.12+" );
48
+
40
49
PYBIND11_NAMESPACE_BEGIN (PYBIND11_NAMESPACE)
41
50
42
51
using ExceptionTranslator = void (*)(std::exception_ptr);
@@ -421,6 +430,38 @@ inline void translate_local_exception(std::exception_ptr p) {
421
430
}
422
431
#endif
423
432
433
+ inline object get_python_state_dict () {
434
+ object state_dict;
435
+ #if PYBIND11_INTERNALS_VERSION <= 4 || PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION)
436
+ state_dict = reinterpret_borrow<object>(PyEval_GetBuiltins ());
437
+ #else
438
+ # if PY_VERSION_HEX < 0x03090000
439
+ PyInterpreterState *istate = _PyInterpreterState_Get ();
440
+ # else
441
+ PyInterpreterState *istate = PyInterpreterState_Get ();
442
+ # endif
443
+ if (istate) {
444
+ state_dict = reinterpret_borrow<object>(PyInterpreterState_GetDict (istate));
445
+ }
446
+ #endif
447
+ if (!state_dict) {
448
+ raise_from (PyExc_SystemError, " pybind11::detail::get_python_state_dict() FAILED" );
449
+ }
450
+ return state_dict;
451
+ }
452
+
453
+ inline object get_internals_obj_from_state_dict (handle state_dict) {
454
+ return reinterpret_borrow<object>(dict_getitemstring (state_dict.ptr (), PYBIND11_INTERNALS_ID));
455
+ }
456
+
457
+ inline internals **get_internals_pp_from_capsule (handle obj) {
458
+ void *raw_ptr = PyCapsule_GetPointer (obj.ptr (), /* name=*/ nullptr );
459
+ if (raw_ptr == nullptr ) {
460
+ raise_from (PyExc_SystemError, " pybind11::detail::get_internals_pp_from_capsule() FAILED" );
461
+ }
462
+ return static_cast <internals **>(raw_ptr);
463
+ }
464
+
424
465
// / Return a reference to the current `internals` data
425
466
PYBIND11_NOINLINE internals &get_internals () {
426
467
auto **&internals_pp = get_internals_pp ();
@@ -445,12 +486,12 @@ PYBIND11_NOINLINE internals &get_internals() {
445
486
#endif
446
487
error_scope err_scope;
447
488
448
- PYBIND11_STR_TYPE id (PYBIND11_INTERNALS_ID );
449
- auto builtins = handle ( PyEval_GetBuiltins ());
450
- if (builtins. contains (id) && isinstance<capsule>(builtins[id])) {
451
- internals_pp = static_cast <internals **>( capsule (builtins[id]));
452
-
453
- // We loaded builtins through python's builtins , which means that our `error_already_set`
489
+ dict state_dict = get_python_state_dict ( );
490
+ if (object internals_obj = get_internals_obj_from_state_dict (state_dict)) {
491
+ internals_pp = get_internals_pp_from_capsule (internals_obj);
492
+ }
493
+ if (internals_pp && *internals_pp) {
494
+ // We loaded the internals through `state_dict` , which means that our `error_already_set`
454
495
// and `builtin_exception` may be different local classes than the ones set up in the
455
496
// initial exception translator, below, so add another for our local exception classes.
456
497
//
@@ -484,7 +525,7 @@ PYBIND11_NOINLINE internals &get_internals() {
484
525
# endif
485
526
internals_ptr->istate = tstate->interp ;
486
527
#endif
487
- builtins[id ] = capsule (internals_pp);
528
+ state_dict[PYBIND11_INTERNALS_ID ] = capsule (internals_pp);
488
529
internals_ptr->registered_exception_translators .push_front (&translate_exception);
489
530
internals_ptr->static_property_type = make_static_property_type ();
490
531
internals_ptr->default_metaclass = make_default_metaclass ();
0 commit comments