If a Python exception is set, fetch a string for it, clear, and return * a Lean IO error result. Caller transfers ownership. */
| 269 | /* If a Python exception is set, fetch a string for it, clear, and return |
| 270 | * a Lean IO error result. Caller transfers ownership. */ |
| 271 | static lean_object *raise_py_error(void) { |
| 272 | PyObject *etype = NULL, *evalue = NULL, *etb = NULL; |
| 273 | p_PyErr_Fetch(&etype, &evalue, &etb); |
| 274 | p_PyErr_NormalizeException(&etype, &evalue, &etb); |
| 275 | char buf[1024]; |
| 276 | const char *etname = "PythonError"; |
| 277 | const char *emsg = ""; |
| 278 | PyObject *s = NULL, *tn = NULL; |
| 279 | if (evalue) { |
| 280 | s = p_PyObject_Str(evalue); |
| 281 | if (s) { |
| 282 | const char *cs = p_PyUnicode_AsUTF8(s); |
| 283 | if (cs) emsg = cs; |
| 284 | } |
| 285 | if (etype) { |
| 286 | tn = p_PyObject_GetAttrString(etype, "__name__"); |
| 287 | if (tn) { |
| 288 | const char *cn = p_PyUnicode_AsUTF8(tn); |
| 289 | if (cn) etname = cn; |
| 290 | } |
| 291 | } |
| 292 | snprintf(buf, sizeof(buf), "%s: %s", etname, emsg); |
| 293 | /* DecRef after snprintf: etname/emsg point into s/tn internals. */ |
| 294 | if (tn) p_Py_DecRef(tn); |
| 295 | if (s) p_Py_DecRef(s); |
| 296 | } else { |
| 297 | snprintf(buf, sizeof(buf), "Python error (no value)"); |
| 298 | } |
| 299 | if (etype) p_Py_DecRef(etype); |
| 300 | if (evalue) p_Py_DecRef(evalue); |
| 301 | if (etb) p_Py_DecRef(etb); |
| 302 | return raise_io_error(buf); |
| 303 | } |
| 304 | |
| 305 | /* Wrap an owned PyObject as IO Py; if NULL, propagate any pending Py error. */ |
| 306 | static lean_object *ok_owned_or_err(PyObject *o) { |
no test coverage detected