self.assertIn('ExceptionGroup', output)
self.assertLessEqual(output.count('ExceptionGroup'), LIMIT)
+ @cpython_only
+ def test_print_exception_bad_type_capi(self):
+ from _testcapi import exception_print
+ with captured_output("stderr") as stderr:
+ exception_print(42)
+ self.assertEqual(
+ stderr.getvalue(),
+ ('TypeError: print_exception(): '
+ 'Exception expected for value, int found\n')
+ )
+
+ def test_print_exception_bad_type_python(self):
+ msg = "Exception expected for value, int found"
+ with self.assertRaisesRegex(TypeError, msg):
+ traceback.print_exception(42)
+
cause_message = (
"\nThe above exception was the direct cause "
raise ValueError("Both or neither of value and tb must be given")
if value is tb is _sentinel:
if exc is not None:
- return exc, exc.__traceback__
+ if isinstance(exc, BaseException):
+ return exc, exc.__traceback__
+
+ raise TypeError(f'Exception expected for value, '
+ f'{type(exc).__name__} found')
else:
return None, None
return value, tb
--- /dev/null
+Functions in the :mod:`traceback` module raise :exc:`TypeError` rather than :exc:`AttributeError` when an exception argument is not of type :exc:`BaseException`.
\ No newline at end of file
exception_print(PyObject *self, PyObject *args)
{
PyObject *value;
- PyObject *tb;
+ PyObject *tb = NULL;
if (!PyArg_ParseTuple(args, "O:exception_print",
- &value))
- return NULL;
- if (!PyExceptionInstance_Check(value)) {
- PyErr_Format(PyExc_TypeError, "an exception instance is required");
+ &value)) {
return NULL;
}
- tb = PyException_GetTraceback(value);
+ if (PyExceptionInstance_Check(value)) {
+ tb = PyException_GetTraceback(value);
+ }
+
PyErr_Display((PyObject *) Py_TYPE(value), value, tb);
Py_XDECREF(tb);