diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 97bd9bae1d58e4..a0e4656d3d9eaa 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -1060,6 +1060,22 @@ def test_exception_group_deep_recursion_traceback(self): 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 " diff --git a/Lib/traceback.py b/Lib/traceback.py index b244750fd016ea..05f1fffef0d3b0 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -98,7 +98,11 @@ def _parse_value_tb(exc, value, tb): 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 diff --git a/Misc/NEWS.d/next/Library/2021-12-13-15-51-16.bpo-45615.hVx83Q.rst b/Misc/NEWS.d/next/Library/2021-12-13-15-51-16.bpo-45615.hVx83Q.rst new file mode 100644 index 00000000000000..f8cd911ea63651 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-12-13-15-51-16.bpo-45615.hVx83Q.rst @@ -0,0 +1 @@ +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 diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 6116365b2c0f71..be40d68b40b17c 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3513,17 +3513,17 @@ static PyObject * 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);