How to inspect variables after Traceback?

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!


A simple alternative is to use cgitb module.

import cgitb; cgitb.enable(format='text')


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

main()

Now the traceback itself prints the value of the message.

A problem occurred in a Python script.  Here is the sequence of
function calls leading up to the error, in the order they occurred.

 /home/anand/projects/python/ptb/tes.py in <module>()
    4 def main():
    5     message = "hello world"
    6     message[20]
    7 
    8 main()
main = <function main>

 /home/anand/projects/python/ptb/tes.py in main()
    4 def main():
    5     message = "hello world"
    6     message[20]
    7 
    8 main()
message = 'hello world'
IndexError: string index out of range

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.