Skip to content

Commit c6fc791

Browse files
committed
Additional Python 3.13 changes
1 parent 742ea56 commit c6fc791

File tree

5 files changed

+111
-33
lines changed

5 files changed

+111
-33
lines changed

src/interrogatedb/dtool_super_base.cxx

+14
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,18 @@ static void Dtool_FreeInstance_DTOOL_SUPER_BASE(PyObject *self) {
6161
*/
6262
Dtool_PyTypedObject *Dtool_GetSuperBase() {
6363
Dtool_TypeMap *type_map = Dtool_GetGlobalTypeMap();
64+
65+
// If we don't have the GIL, we have to protect this with a lock to make
66+
// sure that there is only one DTOOL_SUPER_BASE instance in the world.
67+
#ifdef Py_GIL_DISABLED
68+
PyMutex_Lock(&type_map->_lock);
69+
#endif
70+
6471
auto it = type_map->find("DTOOL_SUPER_BASE");
6572
if (it != type_map->end()) {
73+
#ifdef Py_GIL_DISABLED
74+
PyMutex_Unlock(&type_map->_lock);
75+
#endif
6676
return it->second;
6777
}
6878

@@ -148,13 +158,17 @@ Dtool_PyTypedObject *Dtool_GetSuperBase() {
148158

149159
if (PyType_Ready((PyTypeObject *)&super_base_type) < 0) {
150160
PyErr_SetString(PyExc_TypeError, "PyType_Ready(Dtool_DTOOL_SUPER_BASE)");
161+
PyMutex_Unlock(&type_map->_lock);
151162
return nullptr;
152163
}
153164
Py_INCREF(&super_base_type._PyType);
154165

155166
PyDict_SetItemString(super_base_type._PyType.tp_dict, "DtoolGetSuperBase", PyCFunction_New(&methods[0], (PyObject *)&super_base_type));
156167

157168
(*type_map)["DTOOL_SUPER_BASE"] = &super_base_type;
169+
#ifdef Py_GIL_DISABLED
170+
PyMutex_Unlock(&type_map->_lock);
171+
#endif
158172
return &super_base_type;
159173
}
160174

src/interrogatedb/py_compat.h

+14
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,20 @@ INLINE PyObject *_PyObject_FastCall(PyObject *func, PyObject **args, Py_ssize_t
189189
} while (0)
190190
#endif
191191

192+
#if PY_VERSION_HEX < 0x03070000
193+
INLINE PyObject *PyImport_GetModule(PyObject *name) {
194+
PyObject *modules = PyImport_GetModuleDict();
195+
if (modules != nullptr) {
196+
PyObject *module = PyDict_GetItem(modules, name);
197+
if (module != nullptr) {
198+
Py_INCREF(module);
199+
return module;
200+
}
201+
}
202+
return nullptr;
203+
}
204+
#endif
205+
192206
/* Python 3.8 */
193207
#if PY_VERSION_HEX < 0x03080000
194208
INLINE PyObject *_PyLong_Rshift(PyObject *a, size_t shiftby) {

src/interrogatedb/py_panda.cxx

+54-17
Original file line numberDiff line numberDiff line change
@@ -375,23 +375,26 @@ static PyObject *Dtool_EnumType_Repr(PyObject *self) {
375375
* should be a tuple of (name, value) pairs.
376376
*/
377377
PyTypeObject *Dtool_EnumType_Create(const char *name, PyObject *names, const char *module) {
378-
static PyObject *enum_class = nullptr;
379378
#if PY_VERSION_HEX >= 0x03040000
380-
static PyObject *enum_meta = nullptr;
381-
static PyObject *enum_create = nullptr;
382-
if (enum_meta == nullptr) {
383-
PyObject *enum_module = PyImport_ImportModule("enum");
384-
nassertr_always(enum_module != nullptr, nullptr);
379+
PyObject *enum_module = PyImport_ImportModule("enum");
380+
nassertr_always(enum_module != nullptr, nullptr);
385381

386-
enum_class = PyObject_GetAttrString(enum_module, "Enum");
387-
enum_meta = PyObject_GetAttrString(enum_module, "EnumMeta");
388-
enum_create = PyObject_GetAttrString(enum_meta, "_create_");
389-
nassertr(enum_meta != nullptr, nullptr);
390-
}
382+
PyObject *enum_meta = PyObject_GetAttrString(enum_module, "EnumMeta");
383+
nassertr(enum_meta != nullptr, nullptr);
384+
385+
PyObject *enum_class = PyObject_GetAttrString(enum_module, "Enum");
386+
Py_DECREF(enum_module);
387+
nassertr(enum_class != nullptr, nullptr);
388+
389+
PyObject *enum_create = PyObject_GetAttrString(enum_meta, "_create_");
390+
Py_DECREF(enum_meta);
391391

392392
PyObject *result = PyObject_CallFunction(enum_create, (char *)"OsN", enum_class, name, names);
393+
Py_DECREF(enum_create);
394+
Py_DECREF(enum_class);
393395
nassertr(result != nullptr, nullptr);
394396
#else
397+
static PyObject *enum_class = nullptr;
395398
static PyObject *name_str;
396399
static PyObject *name_sunder_str;
397400
static PyObject *value_str;
@@ -528,16 +531,39 @@ PyObject *DTool_CreatePyInstance(void *local_this, Dtool_PyTypedObject &in_class
528531
* Returns a borrowed reference to the global type dictionary.
529532
*/
530533
Dtool_TypeMap *Dtool_GetGlobalTypeMap() {
534+
#if PY_VERSION_HEX >= 0x030d0000 // 3.13
535+
PyObject *istate_dict = PyInterpreterState_GetDict(PyInterpreterState_Get());
536+
PyObject *key = PyUnicode_InternFromString("_interrogate_types");
537+
PyObject *capsule = PyDict_GetItem(istate_dict, key);
538+
if (capsule != nullptr) {
539+
Py_DECREF(key);
540+
return (Dtool_TypeMap *)PyCapsule_GetPointer(capsule, nullptr);
541+
}
542+
#else
531543
PyObject *capsule = PySys_GetObject((char *)"_interrogate_types");
532544
if (capsule != nullptr) {
533545
return (Dtool_TypeMap *)PyCapsule_GetPointer(capsule, nullptr);
534-
} else {
535-
Dtool_TypeMap *type_map = new Dtool_TypeMap;
536-
capsule = PyCapsule_New((void *)type_map, nullptr, nullptr);
537-
PySys_SetObject((char *)"_interrogate_types", capsule);
546+
}
547+
#endif
548+
549+
Dtool_TypeMap *type_map = new Dtool_TypeMap;
550+
capsule = PyCapsule_New((void *)type_map, nullptr, nullptr);
551+
552+
#if PY_VERSION_HEX >= 0x030d0000 // 3.13
553+
PyObject *result;
554+
if (PyDict_SetDefaultRef(istate_dict, key, capsule, &result) != 0) {
555+
// Another thread already beat us to it.
538556
Py_DECREF(capsule);
539-
return type_map;
557+
delete type_map;
558+
capsule = result;
559+
type_map = (Dtool_TypeMap *)PyCapsule_GetPointer(capsule, nullptr);
540560
}
561+
Py_DECREF(key);
562+
#endif
563+
564+
PySys_SetObject((char *)"_interrogate_types", capsule);
565+
Py_DECREF(capsule);
566+
return type_map;
541567
}
542568

543569
/**
@@ -594,6 +620,10 @@ PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], const char *modulen
594620

595621
Dtool_TypeMap *type_map = Dtool_GetGlobalTypeMap();
596622

623+
#ifdef Py_GIL_DISABLED
624+
PyMutex_Lock(&type_map->_lock);
625+
#endif
626+
597627
// the module level function inits....
598628
MethodDefmap functions;
599629
for (size_t i = 0; defs[i] != nullptr; i++) {
@@ -627,12 +657,19 @@ PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], const char *modulen
627657
if (it != type_map->end()) {
628658
types->type = it->second;
629659
} else {
630-
return PyErr_Format(PyExc_NameError, "name '%s' is not defined", types->name);
660+
PyErr_Format(PyExc_NameError, "name '%s' is not defined", types->name);
661+
#ifdef Py_GIL_DISABLED
662+
PyMutex_Unlock(&type_map->_lock);
663+
#endif
664+
return nullptr;
631665
}
632666
++types;
633667
}
634668
}
635669
}
670+
#ifdef Py_GIL_DISABLED
671+
PyMutex_Unlock(&type_map->_lock);
672+
#endif
636673

637674
PyMethodDef *newdef = new PyMethodDef[functions.size() + 1];
638675
MethodDefmap::iterator mi;

src/interrogatedb/py_panda.h

+7
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,14 @@ static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
174174
// forward declared of typed object. We rely on the fact that typed objects
175175
// are uniquly defined by an integer.
176176

177+
#if PY_VERSION_HEX >= 0x030d0000
178+
class Dtool_TypeMap : public std::map<std::string, Dtool_PyTypedObject *> {
179+
public:
180+
PyMutex _lock { 0 };
181+
};
182+
#else
177183
typedef std::map<std::string, Dtool_PyTypedObject *> Dtool_TypeMap;
184+
#endif
178185

179186
EXPCL_PYPANDA Dtool_TypeMap *Dtool_GetGlobalTypeMap();
180187

src/interrogatedb/py_wrappers.cxx

+22-16
Original file line numberDiff line numberDiff line change
@@ -17,27 +17,33 @@
1717
#endif
1818

1919
static void _register_collection(PyTypeObject *type, const char *abc) {
20-
PyObject *sys_modules = PyImport_GetModuleDict();
21-
if (sys_modules != nullptr) {
22-
PyObject *module = PyDict_GetItemString(sys_modules, _COLLECTIONS_ABC);
23-
if (module != nullptr) {
24-
PyObject *dict = PyModule_GetDict(module);
25-
if (module != nullptr) {
2620
#if PY_MAJOR_VERSION >= 3
27-
PyObject *register_str = PyUnicode_InternFromString("register");
21+
PyObject *module_name = PyUnicode_InternFromString(_COLLECTIONS_ABC);
2822
#else
29-
PyObject *register_str = PyString_InternFromString("register");
23+
PyObject *module_name = PyString_InternFromString(_COLLECTIONS_ABC);
3024
#endif
31-
PyObject *obj = nullptr;
32-
if (register_str == nullptr ||
33-
PyDict_GetItemStringRef(dict, abc, &obj) <= 0 ||
34-
PyObject_CallMethodOneArg(obj, register_str, (PyObject *)type) == nullptr) {
35-
PyErr_Print();
36-
}
37-
Py_XDECREF(obj);
38-
Py_XDECREF(register_str);
25+
PyObject *module = PyImport_GetModule(module_name);
26+
Py_DECREF(module_name);
27+
if (module != nullptr) {
28+
PyObject *dict = PyModule_GetDict(module);
29+
if (dict != nullptr) {
30+
#if PY_MAJOR_VERSION >= 3
31+
PyObject *register_str = PyUnicode_InternFromString("register");
32+
#else
33+
PyObject *register_str = PyString_InternFromString("register");
34+
#endif
35+
PyObject *obj = nullptr;
36+
if (register_str == nullptr ||
37+
PyDict_GetItemStringRef(dict, abc, &obj) <= 0 ||
38+
PyObject_CallMethodOneArg(obj, register_str, (PyObject *)type) == nullptr) {
39+
PyErr_Print();
3940
}
41+
Py_XDECREF(obj);
42+
Py_XDECREF(register_str);
43+
} else {
44+
PyErr_Clear();
4045
}
46+
Py_DECREF(module);
4147
}
4248
}
4349

0 commit comments

Comments
 (0)