Attach a PEP 678 note formatted via PyUnicode_FromFormatV to the in- * flight exception. Mirrors the pure-Python encoder's * `except BaseException as exc: exc.add_note(...); raise` wrappers * around each recursive encode step. * * Crucially, PyErr_Fetch runs BEFORE the note is built: the `%R` * formatter walks into PyObject_Repr, which on debug builds * (cpython-3.14-debug and cpython-3.14t
| 3203 | * |
| 3204 | * Only compiled on Python 3.11+, where PEP 678 exists. */ |
| 3205 | static void |
| 3206 | encoder_annotate_exception(_speedups_state *state, const char *format, ...) |
| 3207 | { |
| 3208 | PyObject *exc_type; |
| 3209 | PyObject *exc_value; |
| 3210 | PyObject *exc_tb; |
| 3211 | PyObject *note; |
| 3212 | PyObject *result; |
| 3213 | va_list args; |
| 3214 | |
| 3215 | PyErr_Fetch(&exc_type, &exc_value, &exc_tb); |
| 3216 | if (exc_value == NULL) { |
| 3217 | /* No live exception to annotate — callsites always have one, |
| 3218 | * so this is a defensive no-op. */ |
| 3219 | PyErr_Restore(exc_type, exc_value, exc_tb); |
| 3220 | return; |
| 3221 | } |
| 3222 | PyErr_NormalizeException(&exc_type, &exc_value, &exc_tb); |
| 3223 | |
| 3224 | va_start(args, format); |
| 3225 | note = PyUnicode_FromFormatV(format, args); |
| 3226 | va_end(args); |
| 3227 | |
| 3228 | if (note != NULL) { |
| 3229 | result = PyObject_CallMethodObjArgs(exc_value, state->JSON_attr_add_note, |
| 3230 | note, NULL); |
| 3231 | Py_DECREF(note); |
| 3232 | if (result == NULL) |
| 3233 | PyErr_Clear(); |
| 3234 | else |
| 3235 | Py_DECREF(result); |
| 3236 | } |
| 3237 | else { |
| 3238 | PyErr_Clear(); |
| 3239 | } |
| 3240 | |
| 3241 | PyErr_Restore(exc_type, exc_value, exc_tb); |
| 3242 | } |
| 3243 | #endif |
| 3244 | |
| 3245 | static int |
no outgoing calls
no test coverage detected
searching dependent graphs…