Skip to content

Commit 759e92e

Browse files
committed
Add test for PyErr_Restore
1 parent ef7eecd commit 759e92e

File tree

1 file changed

+75
-6
lines changed
  • graalpython/com.oracle.graal.python.test/src/tests/cpyext

1 file changed

+75
-6
lines changed

graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_err.py

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,38 @@ def _reference_setstring(args):
4747
raise args[0](args[1])
4848

4949

50-
def _reference_setobject(args):
51-
exc_type, value = args
50+
def _normalize_exception(exc_type, value):
5251
if issubclass(exc_type, BaseException):
5352
if isinstance(value, exc_type):
54-
raise value
53+
return value
5554
if value is None:
56-
raise exc_type
55+
return exc_type()
5756
if isinstance(value, tuple):
58-
raise exc_type(*value)
59-
raise exc_type(value)
57+
return exc_type(*value)
58+
return exc_type(value)
59+
60+
61+
def _reference_setobject(args):
62+
exc_type, value = args
63+
raise _normalize_exception(exc_type, value)
64+
65+
66+
def _reference_restore(args):
67+
exc_type, value, tb = args
68+
exc = _normalize_exception(exc_type, value)
69+
if tb:
70+
exc.__traceback__ = tb
71+
raise exc
72+
73+
74+
def compare_restore_result(x, y):
75+
return (
76+
isinstance(x, BaseException) and
77+
type(x) == type(y) and
78+
# Compare str because different exceptions are not equal
79+
str(x.args) == str(y.args) and
80+
(x.__traceback__ is example_traceback) == (y.__traceback__ is example_traceback)
81+
)
6082

6183

6284
def _new_ex_result_check(x, y):
@@ -158,6 +180,20 @@ class Dummy:
158180
pass
159181

160182

183+
def raise_erorr():
184+
raise NameError
185+
186+
187+
try:
188+
raise_erorr()
189+
except NameError as e:
190+
example_traceback = e.__traceback__
191+
else:
192+
assert False
193+
194+
assert example_traceback
195+
196+
161197
class TestPyErr(CPyExtTestCase):
162198

163199
def compile_module(self, name):
@@ -464,6 +500,39 @@ def compile_module(self, name):
464500
cmpfunc=unhandled_error_compare
465501
)
466502

503+
test_PyErr_Restore = CPyExtFunctionVoid(
504+
_reference_restore,
505+
lambda: (
506+
(RuntimeError, None, None),
507+
(RuntimeError, RuntimeError("error"), None),
508+
(ValueError, "hello", None),
509+
(TypeError, "world", None),
510+
(KeyError, "key", None),
511+
(RuntimeError, ValueError(), None),
512+
(OSError, (2, "error"), None),
513+
(NameError, None, example_traceback),
514+
),
515+
# Note on CPython all the exception creation happens not in PyErr_Restore, but when leaving the function and
516+
# normalizing the exception in the caller. So this really test both of these mechanisms together.
517+
code="""PyObject* wrap_PyErr_Restore(PyObject* typ, PyObject* val, PyObject* tb) {
518+
if (typ == Py_None) typ = NULL;
519+
if (val == Py_None) val = NULL;
520+
if (tb == Py_None) tb = NULL;
521+
Py_XINCREF(typ);
522+
Py_XINCREF(val);
523+
Py_XINCREF(tb);
524+
PyErr_Restore(typ, val, tb);
525+
return NULL;
526+
}
527+
""",
528+
resultspec="O",
529+
argspec='OOO',
530+
arguments=["PyObject* typ", "PyObject* val", "PyObject* tb"],
531+
resultval="NULL",
532+
callfunction="wrap_PyErr_Restore",
533+
cmpfunc=compare_restore_result
534+
)
535+
467536
test_PyErr_Fetch = CPyExtFunction(
468537
_reference_fetch,
469538
lambda: (

0 commit comments

Comments
 (0)