@@ -914,15 +914,14 @@ Py_ssize_t CPyCppyy::Utility::GetBuffer(PyObject* pyobject, char tc, int size, v
914914 buf = 0 ; // not compatible
915915
916916 // clarify error message
917- PyObject* pytype = 0 , *pyvalue = 0 , *pytrace = 0 ;
918- PyErr_Fetch (&pytype, &pyvalue, &pytrace);
917+ auto error = FetchPyError ();
919918 PyObject* pyvalue2 = CPyCppyy_PyText_FromFormat (
920919 (char *)" %s and given element size (%ld) do not match needed (%d)" ,
921- CPyCppyy_PyText_AsString (pyvalue ),
920+ CPyCppyy_PyText_AsString (error. fValue . get () ),
922921 seqmeths->sq_length ? (long )(buflen/(*(seqmeths->sq_length ))(pyobject)) : (long )buflen,
923922 size);
924- Py_DECREF (pyvalue );
925- PyErr_Restore (pytype, pyvalue2, pytrace );
923+ error. fValue . reset (pyvalue2 );
924+ RestorePyError (error );
926925 }
927926 }
928927
@@ -1079,20 +1078,50 @@ PyObject* CPyCppyy::Utility::PyErr_Occurred_WithGIL()
10791078}
10801079
10811080
1081+ // ----------------------------------------------------------------------------
1082+ CPyCppyy::Utility::PyError_t CPyCppyy::Utility::FetchPyError ()
1083+ {
1084+ // create a PyError_t RAII object that will capture and store the exception data
1085+ CPyCppyy::Utility::PyError_t error{};
1086+ #if PY_VERSION_HEX >= 0x030c0000
1087+ error.fValue .reset (PyErr_GetRaisedException ());
1088+ #else
1089+ PyObject *pytype = nullptr ;
1090+ PyObject *pyvalue = nullptr ;
1091+ PyObject *pytrace = nullptr ;
1092+ PyErr_Fetch (&pytype, &pyvalue, &pytrace);
1093+ error.fType .reset (pytype);
1094+ error.fValue .reset (pyvalue);
1095+ error.fTrace .reset (pytrace);
1096+ #endif
1097+ return error;
1098+ }
1099+
1100+
1101+ // ----------------------------------------------------------------------------
1102+ void CPyCppyy::Utility::RestorePyError (CPyCppyy::Utility::PyError_t &error)
1103+ {
1104+ #if PY_VERSION_HEX >= 0x030c0000
1105+ PyErr_SetRaisedException (error.fValue .release ());
1106+ #else
1107+ PyErr_Restore (error.fType .release (), error.fValue .release (), error.fTrace .release ());
1108+ #endif
1109+ }
1110+
1111+
10821112// ----------------------------------------------------------------------------
10831113size_t CPyCppyy::Utility::FetchError (std::vector<PyError_t>& errors, bool is_cpp)
10841114{
10851115// Fetch the current python error, if any, and store it for future use.
10861116 if (PyErr_Occurred ()) {
1087- PyError_t e{is_cpp};
1088- PyErr_Fetch (&e.fType , &e.fValue , &e.fTrace );
1089- errors.push_back (e);
1117+ errors.emplace_back (FetchPyError ());
1118+ errors.back ().fIsCpp = is_cpp;
10901119 }
10911120 return errors.size ();
10921121}
10931122
10941123// ----------------------------------------------------------------------------
1095- void CPyCppyy::Utility::SetDetailedException (std::vector<PyError_t>& errors, PyObject* topmsg, PyObject* defexc)
1124+ void CPyCppyy::Utility::SetDetailedException (std::vector<PyError_t>&& errors, PyObject* topmsg, PyObject* defexc)
10961125{
10971126// Use the collected exceptions to build up a detailed error log.
10981127 if (errors.empty ()) {
@@ -1123,14 +1152,18 @@ void CPyCppyy::Utility::SetDetailedException(std::vector<PyError_t>& errors, PyO
11231152
11241153 // bind the original C++ object, rather than constructing from topmsg, as it
11251154 // is expected to have informative state
1126- Py_INCREF (unique_from_cpp->fType ); Py_INCREF (unique_from_cpp->fValue ); Py_XINCREF (unique_from_cpp->fTrace );
1127- PyErr_Restore (unique_from_cpp->fType , unique_from_cpp->fValue , unique_from_cpp->fTrace );
1155+ RestorePyError (*unique_from_cpp);
11281156 } else {
11291157 // try to consolidate Python exceptions, otherwise select default
11301158 PyObject* exc_type = nullptr ;
11311159 for (auto & e : errors) {
1132- if (!exc_type) exc_type = e.fType ;
1133- else if (exc_type != e.fType ) {
1160+ #if PY_VERSION_HEX >= 0x030c0000
1161+ PyObject* pytype = (PyObject*)Py_TYPE (e.fValue .get ());
1162+ #else
1163+ PyObject* pytype = e.fType .get ();
1164+ #endif
1165+ if (!exc_type) exc_type = pytype;
1166+ else if (exc_type != pytype) {
11341167 exc_type = defexc;
11351168 break ;
11361169 }
@@ -1139,14 +1172,15 @@ void CPyCppyy::Utility::SetDetailedException(std::vector<PyError_t>& errors, PyO
11391172 // add the details to the topmsg
11401173 PyObject* separator = CPyCppyy_PyText_FromString (" \n " );
11411174 for (auto & e : errors) {
1175+ PyObject *pyvalue = e.fValue .get ();
11421176 CPyCppyy_PyText_Append (&topmsg, separator);
1143- if (CPyCppyy_PyText_Check (e. fValue )) {
1144- CPyCppyy_PyText_Append (&topmsg, e. fValue );
1145- } else if (e. fValue ) {
1146- PyObject* excstr = PyObject_Str (e. fValue );
1177+ if (CPyCppyy_PyText_Check (pyvalue )) {
1178+ CPyCppyy_PyText_Append (&topmsg, pyvalue );
1179+ } else if (pyvalue ) {
1180+ PyObject* excstr = PyObject_Str (pyvalue );
11471181 if (!excstr) {
11481182 PyErr_Clear ();
1149- excstr = PyObject_Str ((PyObject*)Py_TYPE (e. fValue ));
1183+ excstr = PyObject_Str ((PyObject*)Py_TYPE (pyvalue ));
11501184 }
11511185 CPyCppyy_PyText_AppendAndDel (&topmsg, excstr);
11521186 } else {
@@ -1161,8 +1195,6 @@ void CPyCppyy::Utility::SetDetailedException(std::vector<PyError_t>& errors, PyO
11611195 PyErr_SetString (exc_type, CPyCppyy_PyText_AsString (topmsg));
11621196 }
11631197
1164- // cleanup stored errors and done with topmsg (whether used or not)
1165- std::for_each (errors.begin (), errors.end (), PyError_t::Clear);
11661198 Py_DECREF (topmsg);
11671199}
11681200
0 commit comments