cowlinator
cowlinator

Reputation: 8833

Python: How to print the stacktrace of an exception object without a "currently being handled" exception?

How can I print the stacktrace of an exception object such as the return value of concurrent.futures.Future.exception() ? Most of the traceback and sys exception functions depend upon an implicit exception that is "currently being handled" (this includes sys.exc_info, traceback.print_exc, traceback.format_exc). The exception has already been handled, and is returned as an object, so these are worthless to me. There are a couple of traceback functions which take an exception argument, but they either give no stack trace output, or they require a traceback object as input, which I do not have. I could of course create a traceback object, but that object would not contain the information I need.

Yes, I am aware that there are lots of Q/A here about printing the stacktrace of an exception. I've searched through them. This question is completely distinct from those.

This is an example of what I'm trying to do.

with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
    for idx in range(0, 10):
        future = executor.submit(third_party_script.main)
        threads.append(future)

for future in threads:
    if(future.exception()):
        print(magic_traceback_function(future.exception()))

How can I print the stacktrace of an exception object such as the return value of concurrent.futures.Future.exception() ?

Upvotes: 2

Views: 2469

Answers (3)

M.M
M.M

Reputation: 2304

I was struggling with this until I discovered that with loguru you can actually use the @logger.catch annotation to see the exception logs/stacktrace (and actually in a colorful way!), like so:

@logger.catch
def other_script():
    ...

with concurrent.futures.ThreadPoolExecutor() as executor:
    for idx in range(0, 10):
        executor.submit(other_script)

However, it might not help if you can't annotate the third party script. In any case, it helped me.

Upvotes: 1

don_vanchos
don_vanchos

Reputation: 1540

There is the exception method which returns the exception raised by the call. So, you can get the traceback from it as from any other exception (Python 3.5+). Use traceback.TracebackException for it (just replace ex with your exception):

print("".join(traceback.TracebackException.from_exception(ex).format())

An extended example and other features to do this:

import traceback

try:
    1/0
except Exception as ex:
    print("".join(traceback.TracebackException.from_exception(ex).format()) == traceback.format_exc() == "".join(traceback.format_exception(type(ex), ex, ex.__traceback__)))
    print("".join(traceback.TracebackException.from_exception(ex).format()))

The output will be something like:

True
Traceback (most recent call last):
  File "untidsfsdfsdftled.py", line 29, in <module>
    1/0
ZeroDivisionError: division by zero

Upvotes: 5

sytech
sytech

Reputation: 41169

You can get the exception to raise by calling future.result(). As far as I know, it should contain the original traceback, too. So, you could catch the exception by putting future.result() in a try block and print the traceback. There's also the __traceback__ attribute which may be helpful for you.

Upvotes: 2

Related Questions