Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to inspect variables after Traceback?

My Python script is crashing. To debug it, I ran it in interactive mode python -i example.py

Traceback (most recent call last):
  File "example.py", line 5, in <module>
    main()
  File "example.py", line 3, in main
    message[20]
IndexError: string index out of range

At this point, I would like to inspect the variable message. I tried

>>> message
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'message' is not defined

Alas message is not in scope (though main is). That's frustrating. How can I inspect the variable? Is there a more useful version of python -i that keeps what's in scope at the crash (rather than the top level)?


Code used for example.py above. Needless to say, this is a simplification.

def main():
    message = "hello world"
    message[20]

main()
like image 521
Colonel Panic Avatar asked Mar 16 '14 18:03

Colonel Panic


2 Answers

To drop to a debugger only if there is an exception you could define a custom excepthook:

import sys
def excepthook(type_, value, tb):
    import traceback
    import pdb
    traceback.print_exception(type_, value, tb)
    pdb.post_mortem(tb)
sys.excepthook = excepthook

def main():
    message = "hello world"
    message[20]

main()

Running the script drops you into pdb and in the frame which raised the exception:

% script.py
Traceback (most recent call last):
  File "/home/unutbu/pybin/script.py", line 16, in <module>
    main()
  File "/home/unutbu/pybin/script.py", line 14, in main
    message[20]
IndexError: string index out of range
> /home/unutbu/pybin/script.py(14)main()
-> message[20]
(Pdb) p message
'hello world'
(Pdb) p message[20]
*** IndexError: IndexError('string index out of range',)
(Pdb) p len(message)
11

If defining the excepthook seems like too much code, you could tuck it away in a utility module, such as utils_debug.py:

import sys
def enable_pdb():
    def excepthook(type_, value, tb):
        import traceback
        import pdb
        traceback.print_exception(type_, value, tb)
        pdb.post_mortem(tb)
    sys.excepthook = excepthook

and then you would only need to add

import utils_debug as UDBG
UDBG.enable_pdb()

to your script.py.


Or, if you are using IPython, you could use the %pdb magic function (which drops you into ipdb when there is an exception).


It is unclear why inspecting size at the pdb prompt is giving you a NameError. (A runnable example would be very useful.) You might try using bt (backtrace) to inspect the frame stack. If size is defined in a different frame than the one pdb is currently in, you might be able use u (up) to go up to the frame where size is defined.

like image 63
unutbu Avatar answered Nov 17 '22 11:11

unutbu


According to the Python docs https://docs.python.org/3.4/library/pdb.html

pdb.py can also be invoked as a script to debug other scripts. For example: python -m pdb myscript.py. When invoked as a script, pdb will automatically enter post-mortem debugging if the program being debugged exits abnormally.

This isn't entirely accurate. It actually enters debugging at the first line.

$ python -m pdb example.py
> example.py(1)<module>()
-> def main():

However if you type c it will then continue to the crash

(Pdb) c
Traceback (most recent call last):
  File "C:\Python34\lib\pdb.py", line 1661, in main
    pdb._runscript(mainpyfile)
  File "C:\Python34\lib\pdb.py", line 1542, in _runscript
    self.run(statement)
  File "C:\Python34\lib\bdb.py", line 431, in run
    exec(cmd, globals, locals)
  File "<string>", line 1, in <module>
  File "example.py", line 1, in <module>
    def main():
  File "example.py", line 3, in main
    message[20]
IndexError: string index out of range
Uncaught exception. Entering post mortem debugging
Running 'cont' or 'step' will restart the program
> example.py(3)main()

At this point you can type message to inspect the variable.

-> message[20]
(Pdb) message
'hello world'

Wahey!

like image 7
Colonel Panic Avatar answered Nov 17 '22 09:11

Colonel Panic