8000 gh-76785: Raise InterpreterError, Not RuntimeError (gh-117489) · python/cpython@976bcb2 · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 976bcb2

Browse files
gh-76785: Raise InterpreterError, Not RuntimeError (gh-117489)
I had meant to switch everything to InterpreterError when I added it a while back. At the time I missed a few key spots. As part of this, I've added print-the-exception to _PyXI_InitTypes() and fixed an error case in `_PyStaticType_InitBuiltin().
1 parent 7ecd55d commit 976bcb2

File tree

8 files changed

+40
-23
lines changed

8 files changed

+40
-23
lines changed

Lib/test/support/interpreters/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def __getattr__(name):
4343
{formatted}
4444
""".strip()
4545

46-
class ExecutionFailed(RuntimeError):
46+
class ExecutionFailed(InterpreterError):
4747
"""An unhandled exception happened during execution.
4848
4949
This is raised from Interpreter.exec() and Interpreter.call().
@@ -158,7 +158,7 @@ def close(self):
158158
"""Finalize and destroy the interpreter.
159159
160160
Attempting to destroy the current interpreter results
161-
in a RuntimeError.
161+
in an InterpreterError.
162162
"""
163163
return _interpreters.destroy(self._id)
164164

Lib/test/test__xxsubinterpreters.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def clean_up_interpreters():
8080
continue
8181
try:
8282
interpreters.destroy(id)
83-
except RuntimeError:
83+
except interpreters.InterpreterError:
8484
pass # already destroyed
8585

8686

@@ -464,11 +464,11 @@ def test_all(self):
464464

465465
def test_main(self):
466466
main, = interpreters.list_all()
467-
with self.assertRaises(RuntimeError):
467+
with self.assertRaises(interpreters.InterpreterError):
468468
interpreters.destroy(main)
469469

470470
def f():
471-
with self.assertRaises(RuntimeError):
471+
with self.assertRaises(interpreters.InterpreterError):
472472
interpreters.destroy(main)
473473

474474
t = threading.Thread(target=f)
@@ -496,7 +496,7 @@ def test_from_current(self):
496496
import _xxsubinterpreters as _interpreters
497497
try:
498498
_interpreters.destroy({id})
499-
except RuntimeError:
499+
except interpreters.InterpreterError:
500500
pass
501501
""")
502502

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

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

677677
def test_already_running(self):
678678
with _running(self.id):
679-
with self.assertRaises(RuntimeError):
679+
with self.assertRaises(interpreters.InterpreterError):
680680
interpreters.run_string(self.id, 'print("spam")')
681681

682682
def test_does_not_exist(self):

Lib/test/test_interpreters/test_api.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -364,11 +364,11 @@ def test_all(self):
364364

365365
def test_main(self):
366366
main, = interpreters.list_all()
367-
with self.assertRaises(RuntimeError):
367+
with self.assertRaises(interpreters.InterpreterError):
368368
main.close()
369369

370370
def f():
371-
with self.assertRaises(RuntimeError):
371+
with self.assertRaises(interpreters.InterpreterError):
372372
main.close()
373373

374374
t = threading.Thread(target=f)
@@ -389,7 +389,7 @@ def test_from_current(self):
389389
interp = interpreters.Interpreter({interp.id})
390390
try:
391391
interp.close()
392-
except RuntimeError:
392+
except interpreters.InterpreterError:
393393
print('failed')
394394
"""))
395395
self.assertEqual(out.strip(), 'failed')
@@ -424,7 +424,7 @@ def test_still_running(self):
424424
main, = interpreters.list_all()
425425
interp = interpreters.create()
426426
with _running(interp):
427-
with self.assertRaises(RuntimeError):
427+
with self.assertRaises(interpreters.InterpreterError):
428428
interp.close()
429429
self.assertTrue(interp.is_running())
430430

@@ -1103,7 +1103,7 @@ def test_create(self):
11031103
self.assert_ns_equal(config, default)
11041104

11051105
with self.subTest('arg: \'empty\''):
1106-
with self.assertRaises(RuntimeError):
1106+
with self.assertRaises(interpreters.InterpreterError):
11071107
# The "empty" config isn't viable on its own.
11081108
_interpreters.create('empty')
11091109

Modules/_xxsubinterpretersmodule.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds)
612612
// XXX Move the chained exception to interpreters.create()?
613613
PyObject *exc = PyErr_GetRaisedException();
614614
assert(exc != NULL);
615-
PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed");
615+
PyErr_SetString(PyExc_InterpreterError, "interpreter creation failed");
616616
_PyErr_ChainExceptions1(exc);
617617
return NULL;
618618
}
@@ -664,7 +664,7 @@ interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
664664
return NULL;
665665
}
666666
if (interp == current) {
667-
PyErr_SetString(PyExc_RuntimeError,
667+
PyErr_SetString(PyExc_InterpreterError,
668668
"cannot destroy the current interpreter");
669669
return NULL;
670670
}
@@ -673,7 +673,7 @@ interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
673673
/* XXX We *could* support destroying a running interpreter but
674674
aren't going to worry about it for now. */
675675
if (is_running_main(interp)) {
676-
PyErr_Format(PyExc_RuntimeError, "interpreter running");
676+
PyErr_Format(PyExc_InterpreterError, "interpreter running");
677677
return NULL;
678678
}
679679

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

699699

Objects/typeobject.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7963,6 +7963,7 @@ _PyStaticType_InitBuiltin(PyInterpreterState *interp, PyTypeObject *self)
79637963
res = type_ready(self, !ismain);
79647964
END_TYPE_LOCK()
79657965
if (res < 0) {
7966+
_PyStaticType_ClearWeakRefs(interp, self);
79667967
static_builtin_state_clear(interp, self);
79677968
}
79687969
return res;

Python/crossinterp.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -845,7 +845,7 @@ _PyXI_ApplyErrorCode(_PyXI_errcode code, PyInterpreterState *interp)
845845
return 0;
846846
case _PyXI_ERR_OTHER:
847847
// XXX msg?
848-
PyErr_SetNone(PyExc_RuntimeError);
848+
PyErr_SetNone(PyExc_InterpreterError);
849849
break;
850850
case _PyXI_ERR_NO_MEMORY:
851851
PyErr_NoMemory();
@@ -856,11 +856,11 @@ _PyXI_ApplyErrorCode(_PyXI_errcode code, PyInterpreterState *interp)
856856
_PyInterpreterState_FailIfRunningMain(interp);
857857
break;
858858
case _PyXI_ERR_MAIN_NS_FAILURE:
859-
PyErr_SetString(PyExc_RuntimeError,
859+
PyErr_SetString(PyExc_InterpreterError,
860860
"failed to get __main__ namespace");
861861
break;
862862
case _PyXI_ERR_APPLY_NS_FAILURE:
863-
PyErr_SetString(PyExc_RuntimeError,
863+
PyErr_SetString(PyExc_InterpreterError,
864864
"failed to apply namespace to __main__");
865865
break;
866866
case _PyXI_ERR_NOT_SHAREABLE:
@@ -935,7 +935,7 @@ _PyXI_ApplyError(_PyXI_error *error)
935935
if (error->uncaught.type.name != NULL || error->uncaught.msg != NULL) {
936936
// __context__ will be set to a proxy of the propagated exception.
937937
PyObject *exc = PyErr_GetRaisedException();
938-
_PyXI_excinfo_Apply(&error->uncaught, PyExc_RuntimeError);
938+
_PyXI_excinfo_Apply(&error->uncaught, PyExc_InterpreterError);
939939
PyObject *exc2 = PyErr_GetRaisedException();
940940
PyException_SetContext(exc, exc2);
941941
PyErr_SetRaisedException(exc);
@@ -1671,6 +1671,7 @@ PyStatus
16711671
_PyXI_InitTypes(PyInterpreterState *interp)
16721672
{
16731673
if (init_exceptions(interp) < 0) {
1674+
PyErr_PrintEx(0);
16741675
return _PyStatus_ERR("failed to initialize an exception type");
16751676
}
16761677
return _PyStatus_OK();

Python/crossinterp_exceptions.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ static PyTypeObject _PyExc_InterpreterError = {
55
PyVarObject_HEAD_INIT(NULL, 0)
66
.tp_name = "interpreters.InterpreterError",
77
.tp_doc = PyDoc_STR("A cross-interpreter operation failed"),
8+
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
9+
//.tp_traverse = ((PyTypeObject *)PyExc_BaseException)->tp_traverse,
10+
//.tp_clear = ((PyTypeObject *)PyExc_BaseException)->tp_clear,
811
//.tp_base = (PyTypeObject *)PyExc_BaseException,
912
};
1013
PyObject *PyExc_InterpreterError = (PyObject *)&_PyExc_InterpreterError;
@@ -15,6 +18,9 @@ static PyTypeObject _PyExc_InterpreterNotFoundError = {
1518
PyVarObject_HEAD_INIT(NULL, 0)
1619
.tp_name = "interpreters.InterpreterNotFoundError",
1720
.tp_doc = PyDoc_STR("An interpreter was not found"),
21+
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
22+
//.tp_traverse = ((PyTypeObject *)PyExc_BaseException)->tp_traverse,
23+
//.tp_clear = ((PyTypeObject *)PyExc_BaseException)->tp_clear,
1824
.tp_base = &_PyExc_InterpreterError,
1925
};
2026
PyObject *PyExc_InterpreterNotFoundError = (PyObject *)&_PyExc_InterpreterNotFoundError;
@@ -55,16 +61,25 @@ _get_not_shareable_error_type(PyInterpreterState *interp)
5561
static int
5662
init_exceptions(PyInterpreterState *interp)
5763
{
64+
PyTypeObject *base = (PyTypeObject *)PyExc_BaseException;
65+
5866
// builtin static types
59-
_PyExc_InterpreterError.tp_base = (PyTypeObject *)PyExc_BaseException;
67+
68+
_PyExc_InterpreterError.tp_base = base;
69+
_PyExc_InterpreterError.tp_traverse = base->tp_traverse;
70+
_PyExc_InterpreterError.tp_clear = base->tp_clear;
6071
if (_PyStaticType_InitBuiltin(interp, &_PyExc_InterpreterError) < 0) {
6172
return -1;
6273
}
74+
75+
_PyExc_InterpreterNotFoundError.tp_traverse = base->tp_traverse;
76+
_PyExc_InterpreterNotFoundError.tp_clear = base->tp_clear;
6377
if (_PyStaticType_InitBuiltin(interp, &_PyExc_InterpreterNotFoundError) < 0) {
6478
return -1;
6579
}
6680

6781
// heap types
82+
6883
// We would call _init_not_shareable_error_type() here too,
6984
// but that leads to ref leaks
7085

Python/pystate.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1073,7 +1073,7 @@ int
10731073
_PyInterpreterState_FailIfRunningMain(PyInterpreterState *interp)
10741074
{
10751075
if (interp->threads.main != NULL) {
1076-
PyErr_SetString(PyExc_RuntimeError,
1076+
PyErr_SetString(PyExc_InterpreterError,
10771077
"interpreter already running");
10781078
return -1;
10791079
}

0 commit comments

Comments
 (0)
0