Skip to content

gh-76785: Raise InterpreterError, Not RuntimeError #117489

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Lib/test/support/interpreters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def __getattr__(name):
{formatted}
""".strip()

class ExecutionFailed(RuntimeError):
class ExecutionFailed(InterpreterError):
"""An unhandled exception happened during execution.

This is raised from Interpreter.exec() and Interpreter.call().
Expand Down Expand Up @@ -158,7 +158,7 @@ def close(self):
"""Finalize and destroy the interpreter.

Attempting to destroy the current interpreter results
in a RuntimeError.
in an InterpreterError.
"""
return _interpreters.destroy(self._id)

Expand Down
12 changes: 6 additions & 6 deletions Lib/test/test__xxsubinterpreters.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def clean_up_interpreters():
continue
try:
interpreters.destroy(id)
except RuntimeError:
except interpreters.InterpreterError:
pass # already destroyed


Expand Down Expand Up @@ -464,11 +464,11 @@ def test_all(self):

def test_main(self):
main, = interpreters.list_all()
with self.assertRaises(RuntimeError):
with self.assertRaises(interpreters.InterpreterError):
interpreters.destroy(main)

def f():
with self.assertRaises(RuntimeError):
with self.assertRaises(interpreters.InterpreterError):
interpreters.destroy(main)

t = threading.Thread(target=f)
Expand Down Expand Up @@ -496,7 +496,7 @@ def test_from_current(self):
import _xxsubinterpreters as _interpreters
try:
_interpreters.destroy({id})
except RuntimeError:
except interpreters.InterpreterError:
pass
""")

Expand Down Expand Up @@ -531,7 +531,7 @@ def test_still_running(self):
self.assertTrue(interpreters.is_running(interp),
msg=f"Interp {interp} should be running before destruction.")

with self.assertRaises(RuntimeError,
with self.assertRaises(interpreters.InterpreterError,
msg=f"Should not be able to destroy interp {interp} while it's still running."):
interpreters.destroy(interp)
self.assertTrue(interpreters.is_running(interp))
Expand Down Expand Up @@ -676,7 +676,7 @@ def test_fork(self):

def test_already_running(self):
with _running(self.id):
with self.assertRaises(RuntimeError):
with self.assertRaises(interpreters.InterpreterError):
interpreters.run_string(self.id, 'print("spam")')

def test_does_not_exist(self):
Expand Down
10 changes: 5 additions & 5 deletions Lib/test/test_interpreters/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,11 +364,11 @@ def test_all(self):

def test_main(self):
main, = interpreters.list_all()
with self.assertRaises(RuntimeError):
with self.assertRaises(interpreters.InterpreterError):
main.close()

def f():
with self.assertRaises(RuntimeError):
with self.assertRaises(interpreters.InterpreterError):
main.close()

t = threading.Thread(target=f)
Expand All @@ -389,7 +389,7 @@ def test_from_current(self):
interp = interpreters.Interpreter({interp.id})
try:
interp.close()
except RuntimeError:
except interpreters.InterpreterError:
print('failed')
"""))
self.assertEqual(out.strip(), 'failed')
Expand Down Expand Up @@ -424,7 +424,7 @@ def test_still_running(self):
main, = interpreters.list_all()
interp = interpreters.create()
with _running(interp):
with self.assertRaises(RuntimeError):
with self.assertRaises(interpreters.InterpreterError):
interp.close()
self.assertTrue(interp.is_running())

Expand Down Expand Up @@ -1103,7 +1103,7 @@ def test_create(self):
self.assert_ns_equal(config, default)

with self.subTest('arg: \'empty\''):
with self.assertRaises(RuntimeError):
with self.assertRaises(interpreters.InterpreterError):
# The "empty" config isn't viable on its own.
_interpreters.create('empty')

Expand Down
8 changes: 4 additions & 4 deletions Modules/_xxsubinterpretersmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds)
// XXX Move the chained exception to interpreters.create()?
PyObject *exc = PyErr_GetRaisedException();
assert(exc != NULL);
PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed");
PyErr_SetString(PyExc_InterpreterError, "interpreter creation failed");
_PyErr_ChainExceptions1(exc);
return NULL;
}
Expand Down Expand Up @@ -664,7 +664,7 @@ interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
return NULL;
}
if (interp == current) {
PyErr_SetString(PyExc_RuntimeError,
PyErr_SetString(PyExc_InterpreterError,
"cannot destroy the current interpreter");
return NULL;
}
Expand All @@ -673,7 +673,7 @@ interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
/* XXX We *could* support destroying a running interpreter but
aren't going to worry about it for now. */
if (is_running_main(interp)) {
PyErr_Format(PyExc_RuntimeError, "interpreter running");
PyErr_Format(PyExc_InterpreterError, "interpreter running");
return NULL;
}

Expand All @@ -693,7 +693,7 @@ PyDoc_STRVAR(destroy_doc,
\n\
Destroy the identified interpreter.\n\
\n\
Attempting to destroy the current interpreter results in a RuntimeError.\n\
Attempting to destroy the current interpreter raises InterpreterError.\n\
So does an unrecognized ID.");


Expand Down
1 change: 1 addition & 0 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -7963,6 +7963,7 @@ _PyStaticType_InitBuiltin(PyInterpreterState *interp, PyTypeObject *self)
res = type_ready(self, !ismain);
END_TYPE_LOCK()
if (res < 0) {
_PyStaticType_ClearWeakRefs(interp, self);
static_builtin_state_clear(interp, self);
}
return res;
Expand Down
9 changes: 5 additions & 4 deletions Python/crossinterp.c
Original file line number Diff line number Diff line change
Expand Up @@ -845,7 +845,7 @@ _PyXI_ApplyErrorCode(_PyXI_errcode code, PyInterpreterState *interp)
return 0;
case _PyXI_ERR_OTHER:
// XXX msg?
PyErr_SetNone(PyExc_RuntimeError);
PyErr_SetNone(PyExc_InterpreterError);
break;
case _PyXI_ERR_NO_MEMORY:
PyErr_NoMemory();
Expand All @@ -856,11 +856,11 @@ _PyXI_ApplyErrorCode(_PyXI_errcode code, PyInterpreterState *interp)
_PyInterpreterState_FailIfRunningMain(interp);
break;
case _PyXI_ERR_MAIN_NS_FAILURE:
PyErr_SetString(PyExc_RuntimeError,
PyErr_SetString(PyExc_InterpreterError,
"failed to get __main__ namespace");
break;
case _PyXI_ERR_APPLY_NS_FAILURE:
PyErr_SetString(PyExc_RuntimeError,
PyErr_SetString(PyExc_InterpreterError,
"failed to apply namespace to __main__");
break;
case _PyXI_ERR_NOT_SHAREABLE:
Expand Down Expand Up @@ -935,7 +935,7 @@ _PyXI_ApplyError(_PyXI_error *error)
if (error->uncaught.type.name != NULL || error->uncaught.msg != NULL) {
// __context__ will be set to a proxy of the propagated exception.
PyObject *exc = PyErr_GetRaisedException();
_PyXI_excinfo_Apply(&error->uncaught, PyExc_RuntimeError);
_PyXI_excinfo_Apply(&error->uncaught, PyExc_InterpreterError);
PyObject *exc2 = PyErr_GetRaisedException();
PyException_SetContext(exc, exc2);
PyErr_SetRaisedException(exc);
Expand Down Expand Up @@ -1671,6 +1671,7 @@ PyStatus
_PyXI_InitTypes(PyInterpreterState *interp)
{
if (init_exceptions(interp) < 0) {
PyErr_PrintEx(0);
return _PyStatus_ERR("failed to initialize an exception type");
}
return _PyStatus_OK();
Expand Down
17 changes: 16 additions & 1 deletion Python/crossinterp_exceptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ static PyTypeObject _PyExc_InterpreterError = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "interpreters.InterpreterError",
.tp_doc = PyDoc_STR("A cross-interpreter operation failed"),
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
//.tp_traverse = ((PyTypeObject *)PyExc_BaseException)->tp_traverse,
//.tp_clear = ((PyTypeObject *)PyExc_BaseException)->tp_clear,
//.tp_base = (PyTypeObject *)PyExc_BaseException,
};
PyObject *PyExc_InterpreterError = (PyObject *)&_PyExc_InterpreterError;
Expand All @@ -15,6 +18,9 @@ static PyTypeObject _PyExc_InterpreterNotFoundError = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "interpreters.InterpreterNotFoundError",
.tp_doc = PyDoc_STR("An interpreter was not found"),
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
//.tp_traverse = ((PyTypeObject *)PyExc_BaseException)->tp_traverse,
//.tp_clear = ((PyTypeObject *)PyExc_BaseException)->tp_clear,
.tp_base = &_PyExc_InterpreterError,
};
PyObject *PyExc_InterpreterNotFoundError = (PyObject *)&_PyExc_InterpreterNotFoundError;
Expand Down Expand Up @@ -55,16 +61,25 @@ _get_not_shareable_error_type(PyInterpreterState *interp)
static int
init_exceptions(PyInterpreterState *interp)
{
PyTypeObject *base = (PyTypeObject *)PyExc_BaseException;

// builtin static types
_PyExc_InterpreterError.tp_base = (PyTypeObject *)PyExc_BaseException;

_PyExc_InterpreterError.tp_base = base;
_PyExc_InterpreterError.tp_traverse = base->tp_traverse;
_PyExc_InterpreterError.tp_clear = base->tp_clear;
if (_PyStaticType_InitBuiltin(interp, &_PyExc_InterpreterError) < 0) {
return -1;
}

_PyExc_InterpreterNotFoundError.tp_traverse = base->tp_traverse;
_PyExc_InterpreterNotFoundError.tp_clear = base->tp_clear;
if (_PyStaticType_InitBuiltin(interp, &_PyExc_InterpreterNotFoundError) < 0) {
return -1;
}

// heap types

// We would call _init_not_shareable_error_type() here too,
// but that leads to ref leaks

Expand Down
2 changes: 1 addition & 1 deletion Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -1073,7 +1073,7 @@ int
_PyInterpreterState_FailIfRunningMain(PyInterpreterState *interp)
{
if (interp->threads.main != NULL) {
PyErr_SetString(PyExc_RuntimeError,
PyErr_SetString(PyExc_InterpreterError,
"interpreter already running");
return -1;
}
Expand Down