PyAPI_FUNC(void) PyErr_Print(void);
PyAPI_FUNC(void) PyErr_PrintEx(int);
PyAPI_FUNC(void) PyErr_Display(PyObject *, PyObject *, PyObject *);
+
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030C0000
PyAPI_FUNC(void) PyErr_DisplayException(PyObject *);
+#endif
/* Stuff with no proper home (yet) */
class CAPIExceptionFormattingMixin:
+ LEGACY = 0
+
def get_exception(self, callable, slice_start=0, slice_end=-1):
from _testcapi import exception_print
try:
self.fail("No exception thrown.")
except Exception as e:
with captured_output("stderr") as tbstderr:
- exception_print(e)
+ exception_print(e, self.LEGACY)
return tbstderr.getvalue().splitlines()[slice_start:slice_end]
callable_line = get_exception.__code__.co_firstlineno + 3
+class CAPIExceptionFormattingLegacyMixin(CAPIExceptionFormattingMixin):
+ LEGACY = 1
@requires_debug_ranges()
class TracebackErrorLocationCaretTestBase:
Same set of tests as above but with Python's internal traceback printing.
"""
+@cpython_only
+@requires_debug_ranges()
+class CPythonTracebackErrorCaretTests(
+ CAPIExceptionFormattingLegacyMixin,
+ TracebackErrorLocationCaretTestBase,
+ unittest.TestCase,
+):
+ """
+ Same set of tests as above but with Python's legacy internal traceback printing.
+ """
class TracebackFormatTests(unittest.TestCase):
exception_print(PyObject *self, PyObject *args)
{
PyObject *exc;
+ int legacy = 0;
- if (!PyArg_ParseTuple(args, "O:exception_print", &exc)) {
+ if (!PyArg_ParseTuple(args, "O|i:exception_print", &exc, &legacy)) {
return NULL;
}
-
- PyErr_DisplayException(exc);
+ if (legacy) {
+ PyObject *tb = NULL;
+ if (PyExceptionInstance_Check(exc)) {
+ tb = PyException_GetTraceback(exc);
+ }
+ PyErr_Display((PyObject *) Py_TYPE(exc), exc, tb);
+ Py_XDECREF(tb);
+ }
+ else {
+ PyErr_DisplayException(exc);
+ }
Py_RETURN_NONE;
}