5

I'd like to have my debugger run post_mortem() any time an exception is encountered, without having to modify the source that I'm working on. I see lots of examples that involve wrapping code in a try/except block, but I'd like to have it always run, regardless of what I'm working on.

I worked on a python wrapper script but that got to be ugly and pretty much unusable.

I use pudb, which is API-equivalent to pdb, so a pdb-specific answer is fine. I run code from within my editor (vim) and would like to have the pm come up any time an exception is encountered.

icecrime
  • 74,451
  • 13
  • 99
  • 111
Captain Midday
  • 659
  • 8
  • 18

3 Answers3

7

It took a few months of not doing anything about it, but I happened to stumble upon a solution. I'm sure this is nothing new for the more experienced.

I have the following in my environment:

export PYTHONUSERBASE=~/.python
export PYTHONPATH=$PYTHONPATH:$PYTHONUSERBASE

And I have the following file:

~/.python/lib/python2.7/site-packages/usercustomize.py

With the following contents:

import traceback
import sys

try:
    import pudb as debugger
except ImportError:
    import pdb as debugger

def drop_debugger(type, value, tb):
  traceback.print_exception(type, value, tb)
  debugger.pm()

sys.excepthook = drop_debugger

__builtins__['debugger'] = debugger
__builtins__['st'] = debugger.set_trace

Now, whether interactively or otherwise, the debugger always jumps in upon an exception. It might be nice to smarten this up some.

It's important to make sure that you have no no-global-site-packages.txt in your site-packages. This will disable the usercustomize module with the default site.py (my virtualenv had a no-global-site-packages.txt)

Just in case it would help others, I left in the bit about modifying __builtins__. I find it quite handy to always be able to rely on some certain tools being available.

Flavor to taste.

Captain Midday
  • 659
  • 8
  • 18
1

A possible solution is to invoke pdb (I don't know about pudb, but I'll just assume it works the same) as a script:

python -m pdb script.py

Quoting the the documentation:

When invoked as a script, pdb will automatically enter post-mortem debugging if the program being debugged exits abnormally. After post-mortem debugging (or after normal exit of the program), pdb will restart the program.

icecrime
  • 74,451
  • 13
  • 99
  • 111
  • Yes. That's what the docs say, but if I run that, even on a tivial script, I always enter the debugger: $ echo '' > /tmp/x.py && python -m pdb /tmp/x.py > /tmp/x.py(1)() -> (Pdb) – Captain Midday May 06 '13 at 10:50
  • You're right, the program doesn't start immediately. You could add a `.pdbrc` file containing `continue` in you home or project directory, but unfortunately this is [only supported since 3.2](http://docs.python.org/dev/library/pdb.html#module-pdb) – icecrime May 07 '13 at 09:01
  • It looks like that's one significant difference from pudb. There's no ".pudbrc". – Captain Midday May 07 '13 at 09:47
  • Under `pdb`, [since 3.2](http://docs.python.org/dev/library/pdb.html#module-pdb) the script **does start immediately** when I run `python3 -m pdb -c c script.py`, no need for a `.pdbrc` file or any changes to the script itself. – V-R May 12 '20 at 12:55
0

A solution for pdb since Python 3.2 is to start the program under the debugger via -m pdb and tell pdb to continue via -c c:

python3 -m pdb -c c program.py

Quoting the pdb documentation:

When invoked as a script, pdb will automatically enter post-mortem debugging if the program being debugged exits abnormally. After post-mortem debugging (or after normal exit of the program), pdb will restart the program.

As-of pudb 2019.2: according to the pudb documentation, the official way involves changing your code a bit (and even then, I don't end up in post-mortem mode if I just run python3 program.py!):

To start the debugger without actually pausing use:

from pudb import set_trace; set_trace(paused=False)

at the top of your code. This will start the debugger without breaking, and run it until a predefined breakpoint is hit. You can also press b on a set_trace call inside the debugger, and it will prevent it from stopping there.

Although it is possible to start the program properly under the debugger via python3 -m pudb.run program.py, pudb's command-line args do not support anything like pdb's -c c. The pudb's --pre-run=COMMAND is for external commands, not pudb commands.

What I currently do is run python3 -m pudb.run program.py without mentioning pudb or set_tracein program.py at all and press c on the keyboard. This way pudb enters its post-mortem mode upon any unhandled exception. This however only works well when I know that the exception will be reproduced. For hunting down sporadically occuring exceptions I go back to the pdb solution.

V-R
  • 1,309
  • 16
  • 32
  • Theres a lot of references to pudb; did you mean pdb? – D. Ben Knoble May 14 '20 at 13:58
  • 1
    [pudb](https://documen.tician.de/pudb/index.html) is a console-based visual debugger for python, which has some similarities to the well-known `pdb` but is really a separate thing. The question was about both `pdb` and `pudb` and so were the answers. – V-R May 15 '20 at 06:30