70

When debugging Python code at the interactive prompt (REPL), often I'll write some code which raises an exception, but I haven't wrapped it in a try/except, so once the error is raised, I've forever lost the exception object.

Often the traceback and error message Python prints out isn't enough. For example, when fetching a URL, the server might return a 40x error, and you need the content of the response via error.read() ... but you haven't got the error object anymore. For example:

>>> import urllib2
>>> f = urllib2.urlopen('http://example.com/api/?foo=bad-query-string')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  ...
urllib2.HTTPError: HTTP Error 400: Bad Request

Drat, what did the body of the response say? It probably had valuable error information in it...

I realize it's usually easy to re-run your code wrapped in a try/except, but that's not ideal. I also realize that in this specific case if I were using the requests library (which doesn't raise for HTTP errors), I wouldn't have this problem ... but I'm really wondering if there's a more general way to get the last exception object at a Python prompt in these cases.

Ben Hoyt
  • 10,694
  • 5
  • 60
  • 84

3 Answers3

84

The sys module provides some functions for post-hoc examining of exceptions: sys.last_type, sys.last_value, and sys.last_traceback.

sys.last_value is the one you're looking for.

Cairnarvon
  • 25,981
  • 9
  • 51
  • 65
  • 2
    @BenHoyt FYI, according to the documentation of `sys`, "These three are only available in an interactive session after a traceback has been printed. ". – satoru Feb 07 '14 at 02:21
  • 3
    @satoru Well, obviously. In a normal program, an unhandled exception will terminate the program. – Cairnarvon Feb 07 '14 at 10:50
  • 3
    I had to search a bit to find the right code to print all these correctly using traceback module. Here it is if any one needed: ```traceback.print_exception(etype=sys.last_type,value=sys.last_value,tb=sys.last_traceback)``` – Hassan Feb 25 '19 at 07:10
33

As @Cairnarvon mentioned, I didn't find any last_valuemember is sys module.

sys.exc_info() did the trick for me. sys.exc_info() returns a tuple with three values (type, value, traceback).

So sys.exc_info()[1] will give the readable error. Here is the example,

import sys
list = [1,2,3,4]
try:
    del list[8]
except Exception:
    print(sys.exc_info()[1])

will output list assignment index out of range

Also, traceback.format_exc() from traceback module can be used to print out the similar information.

Below is the output if format_exec() is used,

Traceback (most recent call last):
  File "python", line 6, in <module>
IndexError: list assignment index out of range
jnns
  • 5,148
  • 4
  • 47
  • 74
Kumar Sambhav Pandey
  • 1,713
  • 4
  • 22
  • 33
  • 1
    This is the answer to a different question. `sys.exc_info` only returns useful information while you're inside an except clause; the question was asking about getting information about the last exception *after* it's already fired. – Cairnarvon Sep 18 '19 at 02:22
0

The sys.last_type, sys.last_value, and sys.last_traceback variables are not always defined. Actually, they are intended to be used in an interactive session. I was able to get the last raised exception using sys.exc_info(). Usage:

import sys
ex_type, ex_value, traceback = sys.exc_info()

The last raised exception object will be stored in ex_value

fraverta
  • 75
  • 1
  • 13