Suppose I have a function that raises unexpected exceptions, so I wrap it in ipdb:
def boom(x, y):
try:
x / y
except Exception as e:
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']
What about debugger?
Debugger is made for step-by-step execution and breakpoints. Using it to inspect exception reasons is really inconvenient and should be avoided. You can automate your debug session using two mentioned best practices.
You can also use the context manager
with ipdb.launch_ipdb_on_exception():
main()
It's an easy-to-use wrapper using ipdb.post_mortem
.
Turns out that it is possible to extract variables from a traceback object.
To manually extract values:
ipdb> !import sys
ipdb> !tb = sys.exc_info()[2]
ipdb> p tb.tb_next.tb_frame.f_locals
{'y': 0, 'x': 2}
Even better, you can use an exception to explicitly do post-mortem debugging on that stack:
import sys
def boom(x, y):
x / y
def main():
x = 2
y = 0
boom(x, y)
if __name__ == '__main__':
try:
main()
except Exception as e:
# Most debuggers allow you to just do .post_mortem()
# but see https://github.com/gotcha/ipdb/pull/94
tb = sys.exc_info()[2]
import ipdb; ipdb.post_mortem(tb)
Which gets us straight to the offending code:
> /tmp/crash.py(4)boom()
3 def boom(x, y):
----> 4 x / y
5
ipdb> p x
2