@@ -282,52 +282,60 @@ typedef struct {
282282
283283/**
284284 * @brief Compatibility layer for Python exception handling API changes.
285- * PyErr_Fetch was deprecated in Python 3.12 in favor of PyErr_GetRaisedException.
285+ * PyErr_Fetch/PyErr_Restore were deprecated in Python 3.12 in favor of
286+ * PyErr_GetRaisedException/PyErr_SetRaisedException.
286287 */
287- #if PY_VERSION_HEX >= 0x030c0000
288- /* Python 3.12+ - use new API */
288+
289+ /* General-purpose compatibility wrappers */
289290static inline void
290- CallState_fetch_exception (CallState * cs ) {
291+ cfl_exception_fetch (PyObject * * exc_type , PyObject * * exc_value , PyObject * * exc_traceback ) {
292+ #if PY_VERSION_HEX >= 0x030c0000
293+ /* Python 3.12+ - use new API */
291294 PyObject * exc = PyErr_GetRaisedException ();
292295 if (exc ) {
293- cs -> exception_type = (PyObject * )Py_TYPE (exc );
294- Py_INCREF (cs -> exception_type );
295- cs -> exception_value = exc ;
296- cs -> exception_traceback = PyException_GetTraceback (exc );
296+ * exc_type = (PyObject * )Py_TYPE (exc );
297+ Py_INCREF (* exc_type );
298+ * exc_value = exc ;
299+ * exc_traceback = PyException_GetTraceback (exc );
297300 } else {
298- cs -> exception_type = NULL ;
299- cs -> exception_value = NULL ;
300- cs -> exception_traceback = NULL ;
301+ * exc_type = * exc_value = * exc_traceback = NULL ;
301302 }
303+ #else
304+ /* Python < 3.12 - use legacy API */
305+ PyErr_Fetch (exc_type , exc_value , exc_traceback );
306+ #endif
302307}
303308
304309static inline void
305- CallState_restore_exception (CallState * cs ) {
306- if (cs -> exception_value ) {
307- PyErr_SetRaisedException (cs -> exception_value );
308- /* PyErr_SetRaisedException steals the reference, so clear our pointer */
309- cs -> exception_value = NULL ;
310- Py_XDECREF (cs -> exception_type );
311- cs -> exception_type = NULL ;
312- Py_XDECREF (cs -> exception_traceback );
313- cs -> exception_traceback = NULL ;
310+ cfl_exception_restore (PyObject * exc_type , PyObject * exc_value , PyObject * exc_traceback ) {
311+ #if PY_VERSION_HEX >= 0x030c0000
312+ /* Python 3.12+ - use new API */
313+ if (exc_value ) {
314+ PyErr_SetRaisedException (exc_value );
315+ Py_XDECREF (exc_type );
316+ Py_XDECREF (exc_traceback );
314317 }
315- }
316318#else
317- /* Python < 3.12 - use legacy API */
319+ /* Python < 3.12 - use legacy API */
320+ PyErr_Restore (exc_type , exc_value , exc_traceback );
321+ #endif
322+ }
323+
324+ /* CallState-specific convenience wrappers */
318325static inline void
319326CallState_fetch_exception (CallState * cs ) {
320- PyErr_Fetch (& cs -> exception_type , & cs -> exception_value , & cs -> exception_traceback );
327+ cfl_exception_fetch (& cs -> exception_type , & cs -> exception_value , & cs -> exception_traceback );
321328}
322329
323330static inline void
324331CallState_restore_exception (CallState * cs ) {
325- PyErr_Restore (cs -> exception_type , cs -> exception_value , cs -> exception_traceback );
326- cs -> exception_type = NULL ;
327- cs -> exception_value = NULL ;
328- cs -> exception_traceback = NULL ;
332+ if (cs -> exception_type ) {
333+ cfl_exception_restore (cs -> exception_type , cs -> exception_value , cs -> exception_traceback );
334+ cs -> exception_type = NULL ;
335+ cs -> exception_value = NULL ;
336+ cs -> exception_traceback = NULL ;
337+ }
329338}
330- #endif
331339
332340/**
333341 * @brief Initialiase a CallState and unlock the GIL prior to a
0 commit comments