Skip to content

Commit 362412d

Browse files
Return a excinfo object from _PyXI_ApplyError().
1 parent d93f584 commit 362412d

File tree

3 files changed

+143
-19
lines changed

3 files changed

+143
-19
lines changed

Include/internal/pycore_crossinterp.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,7 @@ typedef struct _sharedexception {
203203
_PyXI_excinfo uncaught;
204204
} _PyXI_error;
205205

206-
PyAPI_FUNC(void) _PyXI_ApplyError(
207-
_PyXI_error *err,
208-
PyObject *exctype);
206+
PyAPI_FUNC(PyObject *) _PyXI_ApplyError(_PyXI_error *err);
209207

210208

211209
typedef struct xi_session _PyXI_session;
@@ -273,9 +271,7 @@ PyAPI_FUNC(int) _PyXI_Enter(
273271
PyObject *nsupdates);
274272
PyAPI_FUNC(void) _PyXI_Exit(_PyXI_session *session);
275273

276-
PyAPI_FUNC(void) _PyXI_ApplyCapturedException(
277-
_PyXI_session *session,
278-
PyObject *excwrapper);
274+
PyAPI_FUNC(PyObject *) _PyXI_ApplyCapturedException(_PyXI_session *session);
279275
PyAPI_FUNC(int) _PyXI_HasCapturedException(_PyXI_session *session);
280276

281277

Modules/_xxsubinterpretersmodule.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,18 @@ _run_script(PyObject *ns, const char *codestr, Py_ssize_t codestrlen, int flags)
225225
return 0;
226226
}
227227

228+
static void
229+
_raise_formatted(PyObject *exctype, PyObject *excinfo)
230+
{
231+
PyObject *formatted = PyObject_GetAttrString(excinfo, "formatted");
232+
if (formatted == NULL) {
233+
assert(PyErr_Occurred());
234+
return;
235+
}
236+
PyErr_SetObject(exctype, formatted);
237+
Py_DECREF(formatted);
238+
}
239+
228240
static int
229241
_run_in_interpreter(PyInterpreterState *interp,
230242
const char *codestr, Py_ssize_t codestrlen,
@@ -237,7 +249,10 @@ _run_in_interpreter(PyInterpreterState *interp,
237249
// Prep and switch interpreters.
238250
if (_PyXI_Enter(&session, interp, shareables) < 0) {
239251
assert(!PyErr_Occurred());
240-
_PyXI_ApplyError(session.error, excwrapper);
252+
PyObject *excinfo = _PyXI_ApplyError(session.error);
253+
if (excinfo != NULL) {
254+
_raise_formatted(excwrapper, excinfo);
255+
}
241256
assert(PyErr_Occurred());
242257
return -1;
243258
}
@@ -251,7 +266,10 @@ _run_in_interpreter(PyInterpreterState *interp,
251266
// Propagate any exception out to the caller.
252267
assert(!PyErr_Occurred());
253268
if (res < 0) {
254-
_PyXI_ApplyCapturedException(&session, excwrapper);
269+
PyObject *excinfo = _PyXI_ApplyCapturedException(&session);
270+
if (excinfo != NULL) {
271+
_raise_formatted(excwrapper, excinfo);
272+
}
255273
}
256274
else {
257275
assert(!_PyXI_HasCapturedException(&session));

Python/crossinterp.c

Lines changed: 121 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "pycore_ceval.h" // _Py_simple_func
66
#include "pycore_crossinterp.h" // struct _xid
77
#include "pycore_initconfig.h" // _PyStatus_OK()
8+
#include "pycore_namespace.h" //_PyNamespace_New()
89
#include "pycore_pyerrors.h" // _PyErr_Clear()
910
#include "pycore_pystate.h" // _PyInterpreterState_GET()
1011
#include "pycore_typeobject.h" // _PyType_GetModuleName()
@@ -1145,6 +1146,116 @@ _PyXI_excinfo_Apply(_PyXI_excinfo *info, PyObject *exctype)
11451146
Py_DECREF(formatted);
11461147
}
11471148

1149+
static PyObject *
1150+
_PyXI_excinfo_TypeAsObject(_PyXI_excinfo *info)
1151+
{
1152+
PyObject *ns = _PyNamespace_New(NULL);
1153+
if (ns == NULL) {
1154+
return NULL;
1155+
}
1156+
int empty = 1;
1157+
1158+
if (info->type.name != NULL) {
1159+
PyObject *name = PyUnicode_FromString(info->type.name);
1160+
if (name == NULL) {
1161+
goto error;
1162+
}
1163+
int res = PyObject_SetAttrString(ns, "__name__", name);
1164+
Py_DECREF(name);
1165+
if (res < 0) {
1166+
goto error;
1167+
}
1168+
empty = 0;
1169+
}
1170+
1171+
if (info->type.qualname != NULL) {
1172+
PyObject *qualname = PyUnicode_FromString(info->type.qualname);
1173+
if (qualname == NULL) {
1174+
goto error;
1175+
}
1176+
int res = PyObject_SetAttrString(ns, "__qualname__", qualname);
1177+
Py_DECREF(qualname);
1178+
if (res < 0) {
1179+
goto error;
1180+
}
1181+
empty = 0;
1182+
}
1183+
1184+
if (info->type.module != NULL) {
1185+
PyObject *module = PyUnicode_FromString(info->type.module);
1186+
if (module == NULL) {
1187+
goto error;
1188+
}
1189+
int res = PyObject_SetAttrString(ns, "__module__", module);
1190+
Py_DECREF(module);
1191+
if (res < 0) {
1192+
goto error;
1193+
}
1194+
empty = 0;
1195+
}
1196+
1197+
if (empty) {
1198+
Py_CLEAR(ns);
1199+
}
1200+
1201+
return ns;
1202+
1203+
error:
1204+
Py_DECREF(ns);
1205+
return NULL;
1206+
}
1207+
1208+
static PyObject *
1209+
_PyXI_excinfo_AsObject(_PyXI_excinfo *info)
1210+
{
1211+
PyObject *ns = _PyNamespace_New(NULL);
1212+
if (ns == NULL) {
1213+
return NULL;
1214+
}
1215+
int res;
1216+
1217+
PyObject *type = _PyXI_excinfo_TypeAsObject(info);
1218+
if (type == NULL) {
1219+
if (PyErr_Occurred()) {
1220+
goto error;
1221+
}
1222+
type = Py_NewRef(Py_None);
1223+
}
1224+
res = PyObject_SetAttrString(ns, "type", type);
1225+
Py_DECREF(type);
1226+
if (res < 0) {
1227+
goto error;
1228+
}
1229+
1230+
PyObject *msg = info->msg != NULL
1231+
? PyUnicode_FromString(info->msg)
1232+
: Py_NewRef(Py_None);
1233+
if (msg == NULL) {
1234+
goto error;
1235+
}
1236+
res = PyObject_SetAttrString(ns, "msg", msg);
1237+
Py_DECREF(msg);
1238+
if (res < 0) {
1239+
goto error;
1240+
}
1241+
1242+
PyObject *formatted = _PyXI_excinfo_format(info);
1243+
if (formatted == NULL) {
1244+
goto error;
1245+
}
1246+
res = PyObject_SetAttrString(ns, "formatted", formatted);
1247+
Py_DECREF(formatted);
1248+
if (res < 0) {
1249+
goto error;
1250+
}
1251+
1252+
return ns;
1253+
1254+
error:
1255+
Py_DECREF(ns);
1256+
return NULL;
1257+
}
1258+
11481259

11491260
/***************************/
11501261
/* short-term data sharing */
@@ -1238,15 +1349,12 @@ _PyXI_InitError(_PyXI_error *error, PyObject *excobj, _PyXI_errcode code)
12381349
return failure;
12391350
}
12401351

1241-
void
1242-
_PyXI_ApplyError(_PyXI_error *error, PyObject *exctype)
1352+
PyObject *
1353+
_PyXI_ApplyError(_PyXI_error *error)
12431354
{
1244-
if (exctype == NULL) {
1245-
exctype = PyExc_RuntimeError;
1246-
}
12471355
if (error->code == _PyXI_ERR_UNCAUGHT_EXCEPTION) {
12481356
// Raise an exception that proxies the propagated exception.
1249-
_PyXI_excinfo_Apply(&error->uncaught, exctype);
1357+
return _PyXI_excinfo_AsObject(&error->uncaught);
12501358
}
12511359
else if (error->code == _PyXI_ERR_NOT_SHAREABLE) {
12521360
// Propagate the exception directly.
@@ -1259,13 +1367,14 @@ _PyXI_ApplyError(_PyXI_error *error, PyObject *exctype)
12591367
if (error->uncaught.type.name != NULL || error->uncaught.msg != NULL) {
12601368
// __context__ will be set to a proxy of the propagated exception.
12611369
PyObject *exc = PyErr_GetRaisedException();
1262-
_PyXI_excinfo_Apply(&error->uncaught, exctype);
1370+
_PyXI_excinfo_Apply(&error->uncaught, PyExc_RuntimeError);
12631371
PyObject *exc2 = PyErr_GetRaisedException();
12641372
PyException_SetContext(exc, exc2);
12651373
PyErr_SetRaisedException(exc);
12661374
}
12671375
}
12681376
assert(PyErr_Occurred());
1377+
return NULL;
12691378
}
12701379

12711380
/* shared namespaces */
@@ -1877,14 +1986,15 @@ _capture_current_exception(_PyXI_session *session)
18771986
session->error = err;
18781987
}
18791988

1880-
void
1881-
_PyXI_ApplyCapturedException(_PyXI_session *session, PyObject *excwrapper)
1989+
PyObject *
1990+
_PyXI_ApplyCapturedException(_PyXI_session *session)
18821991
{
18831992
assert(!PyErr_Occurred());
18841993
assert(session->error != NULL);
1885-
_PyXI_ApplyError(session->error, excwrapper);
1886-
assert(PyErr_Occurred());
1994+
PyObject *res = _PyXI_ApplyError(session->error);
1995+
assert((res == NULL) != (PyErr_Occurred() == NULL));
18871996
session->error = NULL;
1997+
return res;
18881998
}
18891999

18902000
int

0 commit comments

Comments
 (0)