22

Is there any way to make a python program start an interactive debugger, like what import pdb; pdb.set_trace() instead of actually throwing an exception?

I know the difficulty of making this work, but it would be much more valuable than a huge stack trace after which I have to use to figure out where to insert breakpoints and then restart the program to debug it. I know that simply making the debugger start instead of throwing an exception would not make sense because any exception can be caught at a level or another, so if I could just select a list of exceptions for which an interactive debug session would start instead of them being thrown (because I know the exceptions in this list would really be "errors" and no meaningful program behavior could follow afterwards)...

I've heard that Common Lisp has something like this, but I don't know how it works exactly, just that "true lispers" praise it a lot...

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
NeuronQ
  • 7,527
  • 9
  • 42
  • 60
  • 1
    This question looks very similar to: [Starting python debugger automatically on error](https://stackoverflow.com/questions/242485/starting-python-debugger-automatically-on-error) which has better answers. – Calimo Jun 09 '20 at 08:07

4 Answers4

18

The simplest way is to wrap your entire code inside a try block like this:

if __name__ == '__main__':

    try:
        raise Exception()
    except:
        import pdb
        pdb.set_trace()

There is a more complicated solution which uses sys.excepthook to override the handling of uncaught exceptions, as described in this recipe:

## {{{ http://code.activestate.com/recipes/65287/ (r5)
# code snippet, to be included in 'sitecustomize.py'
import sys

def info(type, value, tb):
   if hasattr(sys, 'ps1') or not sys.stderr.isatty():
      # we are in interactive mode or we don't have a tty-like
      # device, so we call the default hook
      sys.__excepthook__(type, value, tb)
   else:
      import traceback, pdb
      # we are NOT in interactive mode, print the exception...
      traceback.print_exception(type, value, tb)
      print
      # ...then start the debugger in post-mortem mode.
      pdb.pm()

sys.excepthook = info
## end of http://code.activestate.com/recipes/65287/ }}}

The above code should be included in a file called sitecustomize.py inside site-packages directory, which is automatically imported by python. The debugger is only started when python is run in non-interactive mode.

mmoya
  • 1,901
  • 1
  • 21
  • 30
Boris Gorelik
  • 29,945
  • 39
  • 128
  • 170
  • 1
    referring to you second example, as this is what I mean, I don't want to have to modify existing program code: yeah, but what I'd like is to have the debugger dynamically insert a breakpoint and start the 'live' debugger *instead* of throwing the exception (prevent it from being thrown or smth) not 'post mortem' – NeuronQ Nov 01 '12 at 10:12
  • 1
    @NeuronQ did you try to substitute `pdb.pm()` by `pdb.set_trace()`? This should work – Boris Gorelik Nov 01 '12 at 10:58
  • @NeuroQ see my answer for how to do this without any system modification – Bryce Guinta Apr 17 '18 at 19:55
10

This question is quite old, so this is mainly for future me

try:
    ...
except:
    import traceback, pdb, sys
    traceback.print_exc()
    print ''
    pdb.post_mortem()
    sys.exit(1)
dan_waterworth
  • 6,261
  • 1
  • 30
  • 41
2

I wrote a package to start pdb on exception. It takes @boreis-gorelik's answer, and modifies the interpreter state at runtime so no code changes are necessary:

Installation

 pip install mort

Usage

mort <file.py or module to execute>

When the exception occurs, the pdb repl should start in the given terminal

Bryce Guinta
  • 3,456
  • 1
  • 35
  • 36
1

If you are inside the REPL, you can do

import sys
import pdb
pdb.post_mortem(sys.last_traceback)

See https://docs.python.org/2/library/pdb.html and https://docs.python.org/3/library/traceback.html

serv-inc
  • 35,772
  • 9
  • 166
  • 188