Skip to content

Commit 742ea56

Browse files
committed
Improve compatibility with Python 3.13
1 parent 0eecd69 commit 742ea56

File tree

3 files changed

+93
-13
lines changed

3 files changed

+93
-13
lines changed

src/interrogatedb/py_compat.h

+71
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,77 @@ INLINE bool PyLong_IsNonNegative(PyObject *value) {
279279
}
280280
#endif
281281

282+
/* Python 3.13 */
283+
284+
#if PY_VERSION_HEX < 0x030D00A1
285+
# define PyLong_AsInt(x) (_PyLong_AsInt(x))
286+
#endif
287+
288+
#if PY_VERSION_HEX < 0x030D00A1
289+
ALWAYS_INLINE int
290+
PyModule_Add(PyObject *mod, const char *name, PyObject *value) {
291+
int res = PyModule_AddObjectRef(mod, name, value);
292+
Py_XDECREF(value);
293+
return res;
294+
}
295+
#endif
296+
297+
#if PY_VERSION_HEX < 0x030D00A1
298+
INLINE int
299+
PyDict_GetItemRef(PyObject *mp, PyObject *key, PyObject **result) {
300+
#if PY_MAJOR_VERSION >= 3
301+
PyObject *item = PyDict_GetItemWithError(mp, key);
302+
#else
303+
PyObject *item = _PyDict_GetItemWithError(mp, key);
304+
#endif
305+
if (item != nullptr) {
306+
*result = Py_NewRef(item);
307+
return 1;
308+
}
309+
*result = nullptr;
310+
return PyErr_Occurred() ? -1 : 0;
311+
}
312+
313+
INLINE int
314+
PyDict_GetItemStringRef(PyObject *mp, const char *key, PyObject **result) {
315+
PyObject *item = nullptr;
316+
#if PY_MAJOR_VERSION >= 3
317+
PyObject *key_obj = PyUnicode_FromString(key);
318+
item = key_obj ? PyDict_GetItemWithError(mp, key_obj) : nullptr;
319+
#else
320+
PyObject *key_obj = PyString_FromString(key);
321+
item = key_obj ? _PyDict_GetItemWithError(mp, key_obj) : nullptr;
322+
#endif
323+
Py_DECREF(key_obj);
324+
if (item != nullptr) {
325+
*result = Py_NewRef(item);
326+
return 1;
327+
}
328+
*result = nullptr;
329+
return PyErr_Occurred() ? -1 : 0;
330+
}
331+
#endif
332+
333+
#if PY_VERSION_HEX >= 0x03050200 && PY_VERSION_HEX < 0x030D00A1
334+
# define PyThreadState_GetUnchecked() (_PyThreadState_UncheckedGet())
335+
#endif
336+
337+
#if PY_VERSION_HEX < 0x030D00A2
338+
# define PyList_Extend(list, iterable) (PyList_SetSlice((list), PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, (iterable)))
339+
# define PyList_Clear(list) (PyList_SetSlice((list), 0, PY_SSIZE_T_MAX, nullptr))
340+
#endif
341+
342+
#if PY_VERSION_HEX < 0x030D00A4
343+
# define PyList_GetItemRef(op, index) (Py_XNewRef(PyList_GetItem((op), (index))))
344+
#endif
345+
346+
#if PY_VERSION_HEX < 0x030D00B3
347+
# define Py_BEGIN_CRITICAL_SECTION(op) {
348+
# define Py_END_CRITICAL_SECTION() }
349+
# define Py_BEGIN_CRITICAL_SECTION2(a, b) {
350+
# define Py_END_CRITICAL_SECTION2() }
351+
#endif
352+
282353
/* Other Python implementations */
283354

284355
#endif // HAVE_PYTHON

src/interrogatedb/py_panda.cxx

+6-4
Original file line numberDiff line numberDiff line change
@@ -328,9 +328,9 @@ static PyObject *Dtool_EnumType_New(PyTypeObject *subtype, PyObject *args, PyObj
328328
PyObject *value2member = PyDict_GetItemString(subtype->tp_dict, "_value2member_map_");
329329
nassertr_always(value2member != nullptr, nullptr);
330330

331-
PyObject *member = PyDict_GetItem(value2member, arg);
332-
if (member != nullptr) {
333-
return Py_NewRef(member);
331+
PyObject *member;
332+
if (PyDict_GetItemRef(value2member, arg, &member) > 0) {
333+
return member;
334334
}
335335

336336
PyObject *repr = PyObject_Repr(arg);
@@ -886,7 +886,9 @@ bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args, PyObject *kwds,
886886
}
887887

888888
// We got the item, we just need to make sure that it had the right key.
889-
#if PY_VERSION_HEX >= 0x03060000
889+
#if PY_VERSION_HEX >= 0x030d0000
890+
return PyUnicode_CheckExact(key) && PyUnicode_EqualToUTF8(key, keyword);
891+
#elif PY_VERSION_HEX >= 0x03060000
890892
return PyUnicode_CheckExact(key) && _PyUnicode_EqualToASCIIString(key, keyword);
891893
#elif PY_MAJOR_VERSION >= 3
892894
return PyUnicode_CheckExact(key) && PyUnicode_CompareWithASCIIString(key, keyword) == 0;

src/interrogatedb/py_wrappers.cxx

+16-9
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,18 @@ static void _register_collection(PyTypeObject *type, const char *abc) {
2424
PyObject *dict = PyModule_GetDict(module);
2525
if (module != nullptr) {
2626
#if PY_MAJOR_VERSION >= 3
27-
static PyObject *register_str = PyUnicode_InternFromString("register");
27+
PyObject *register_str = PyUnicode_InternFromString("register");
2828
#else
29-
static PyObject *register_str = PyString_InternFromString("register");
29+
PyObject *register_str = PyString_InternFromString("register");
3030
#endif
31-
PyObject *sequence = PyDict_GetItemString(dict, abc);
32-
if (sequence != nullptr) {
33-
if (PyObject_CallMethodOneArg(sequence, register_str, (PyObject *)type) == nullptr) {
34-
PyErr_Print();
35-
}
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();
3636
}
37+
Py_XDECREF(obj);
38+
Py_XDECREF(register_str);
3739
}
3840
}
3941
}
@@ -1075,14 +1077,19 @@ static PyObject *Dtool_MutableMappingWrapper_update(PyObject *self, PyObject *ar
10751077
return PyErr_Format(PyExc_TypeError, "%s.update() takes either a dict argument or keyword arguments", wrap->_base._name);
10761078
}
10771079

1080+
PyObject *result = Py_None;
10781081
PyObject *key, *value;
10791082
Py_ssize_t pos = 0;
1083+
Py_BEGIN_CRITICAL_SECTION(dict);
10801084
while (PyDict_Next(dict, &pos, &key, &value)) {
10811085
if (wrap->_setitem_func(wrap->_base._self, key, value) != 0) {
1082-
return nullptr;
1086+
result = nullptr;
1087+
break;
10831088
}
10841089
}
1085-
return Py_NewRef(Py_None);
1090+
Py_END_CRITICAL_SECTION();
1091+
1092+
return Py_XNewRef(result);
10861093
}
10871094

10881095
/**

0 commit comments

Comments
 (0)