Reputation: 2859
Is there a way to print variables scope from context where exception happens?
For example:
def f():
a = 1
b = 2
1/0
try:
f()
except:
pass # here I want to print something like "{'a': 1, 'b': 2}"
Upvotes: 15
Views: 6650
Reputation: 1868
Zero dependency solution for Python 3:
import traceback
def format_traceback_with_locals(exc):
traceback_segments = traceback.format_exception(exc)
traceback_string = traceback_segments[0]
tb = exc.__traceback__
while tb is not None:
locals_dict = {k: v for k, v in tb.tb_frame.f_locals.items() if not k.startswith("__")}
traceback_segment = traceback.format_tb(tb)[0]
traceback_string += traceback_segment
traceback_string += " -> local variables: " + str(locals_dict) + "\n"
tb = tb.tb_next
traceback_string += traceback_segments[-1]
return traceback_string
Usage:
try:
...
except Exception as e:
print(format_traceback_with_locals(e))
This iterates over traceback segments (the header, then each frame, and finally the exception) and prints the corresponding local variables after each frame.
Upvotes: 0
Reputation: 1178
Depending on what you need, there are 2 general best practices.
Just print the variables with minimal code edits
Have a look at some related packages. For simple usage you might pick traceback-with-variables (pip install traceback-with-variables
), here is it's postcard
Or try tbvaccine, or better-exceptions, or any other package
Programmatically access variables to use them in your code
Use inspect
module
except ... as ...:
x = inspect.trace()[-1][0].f_locals['x']
Upvotes: 2
Reputation: 44493
You can use the function sys.exc_info()
to get the last exception that occurred in the current thread in you except clause. This will be a tuple of exception type, exception instance and traceback. The traceback is a linked list of frame. This is what is used to print the backtrace by the interpreter. It does contains the local dictionnary.
So you can do:
import sys
def f():
a = 1
b = 2
1/0
try:
f()
except:
exc_type, exc_value, tb = sys.exc_info()
if tb is not None:
prev = tb
curr = tb.tb_next
while curr is not None:
prev = curr
curr = curr.tb_next
print prev.tb_frame.f_locals
Upvotes: 23
Reputation: 9331
You have to first extract traceback, in your example something like this would print it:
except:
print sys.exc_traceback.tb_next.tb_frame.f_locals
I'm not sure about the tb_next, I would guess you have to go through the complete traceback, so something like this (untested):
except:
tb_last = sys.exc_traceback
while tb_last.tb_next:
tb_last = tb_last.tb_next
print tb_last.tb_frame.f_locals
Upvotes: 7