Simpler way to put PDB breakpoints in Python code?

Viewed 118001

Just a convenience question. I've been a bit spoiled with debuggers in IDEs like Visual Studio and XCode. I find it a bit clumsy to have to type import pdb; pdb.set_trace() to set a breakpoint (I'd rather not import pdb at the top of the file as I might forget and leave it in).

Is there a simpler way of setting a breakpoint in Python code, as straightforward and unobtrusive as what you see in an IDE?

15 Answers

Easiest way to keep breakpoints, aliases and other settings saved across run is by using .pdbrc in the same folder as your script and then just run your script as python -m pdb <scriptname>.py

Enter commands just as you would do in pdb one per line. E.g.:

.\.pdbrc
--------
b 12
display var
c

You could use Vim with the Python-Mode plugin or Emacs with the Elpy plugin.

These plugins give you breakpoints with easy keystrokes (\ b in Vim and C-c C-u b in Emacs) plus many other features from heavy-weight IDEs (code folding, refactoring, linting, etc.) - all within a light-weight terminal-based text editor.

With this snippet breakpoints can be set automatically:

import pdb
import sys
try:
    from io import StringIO           # Python3
except:
    from StringIO import StringIO     # Python2

bp = 14    # or e.g. "submodule.py:123"

sys.stdin = StringIO('break %s\ncont\n' % bp)
pdb.set_trace()
sys.stdin = sys.__stdin__   # reset to usually stdin

print(1)     # lineno 14
print(2)

This approach works with Python 2 and 3.

Breakpoints could be also set via a .pdbrc file (locally or in home) and manipulated on the fly. Still, the cont command must not executed manually. So since pdb.set_trace requires stdin, the above code just "redirects" the command to stdin in a programmatic way.

Putting the code inside the main program and combined with argparse, the breakpoints can be passed from the command line with further stop until the breakpoint.

(I'd rather not import pdb at the top of the file as I might forget and leave it in).

Unlike

import pdb; pdb.set_trace()

which could leave the import part behind, this is "atomic":

__import__('pdb').set_trace()
Related