This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Title: format_exception() doesn't work with PyErr_Fetch
Type: Stage: resolved
Components: Versions: Python 3.5
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: jason.haslam, pablogsal, tomasheran
Priority: normal Keywords:

Created on 2018-10-29 08:59 by tomasheran, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (4)
msg328796 - (view) Author: Tomáš Heran (tomasheran) Date: 2018-10-29 08:59
When embedding Python into a C/C++ based programs, one of the ways to access the formatted traceback is/was to get the type, value and tb by calling the C API PyErr_Fetch() and then call native Python traceback.format_exception() function to get a list of strings representing the tracback.

This worked fine in 2.7.

Doing the same in 3.5 doesn't work because:

1. PyErr_Fetch()'s middle output argument 'value' is not an instance of Exception (or a subclass), but rather (what seems to me) a __str__ or __repr__ (i.e. the type is str) of said raised exception. 

An aside - this seems to be the case both in 2.7 and 3.5, but differs (in both 2.7 and 3.5, I believe) from what sys.exc_info() returns, as there the middle output 'value' is of an Exception (or a subclass) type.

2. In the overhauled traceback module in 3.x, functions like format_exception() now use an internal class TracebackException which expects the exc_value (which it gets from format_exception()'s value argument) to be an instance of Exception (or a subclass), thus feeding traceback.format_exception() whatever I got from PyErr_Fetch() ends up throwing another exception.

As a temporary workaround, I can use traceback.format_tb() which luckily doesn't use the TracebackException class and works fine in 3.5.
msg377677 - (view) Author: Jason Haslam (jason.haslam) * Date: 2020-09-29 17:52
FWIW, I believe that you have to call `PyErr_NormalizeException` on the values returned from `PyErr_Fetch`. It looks like this is working as expected.
msg377684 - (view) Author: Pablo Galindo Salgado (pablogsal) * (Python committer) Date: 2020-09-29 21:54
> FWIW, I believe that you have to call `PyErr_NormalizeException` on the values returned from `PyErr_Fetch`. It looks like this is working as expected.

Indeed that is the case, from the docs:

Under certain circumstances, the values returned by PyErr_Fetch() below can be “unnormalized”, meaning that *exc is a class object but *val is not an instance of the same class. This function can be used to instantiate the class in that case. If the values are already normalized, nothing happens. The delayed normalization is implemented to improve performance.
msg377685 - (view) Author: Pablo Galindo Salgado (pablogsal) * (Python committer) Date: 2020-09-29 21:55
Closing as not a bug, feel free to reopen if we are missing something here :)
Date User Action Args
2022-04-11 14:59:07adminsetgithub: 79284
2020-09-29 21:55:06pablogsalsetstatus: open -> closed
resolution: not a bug
messages: + msg377685

stage: resolved
2020-09-29 21:54:35pablogsalsetnosy: + pablogsal
messages: + msg377684
2020-09-29 17:52:41jason.haslamsetnosy: + jason.haslam
messages: + msg377677
2018-10-29 08:59:54tomasherancreate