Nick T
Nick T

Reputation: 26717

How do I ignore a line when using the pdb?

For some quick Python debugging I'll occasionally throw in a import pdb;pdb.set_trace() line that will drop me into the debugger. Very handy. However, if I want to debug a loop, that may run many, many, many times, it loses its effectiveness somewhat. I could mash on continue many, many, many times, but is there a way to remove/ignore that hard-coded breakpoint so I can let it finish?

I could set a global flag and run it conditionally, but then I'd lose the 'standalone-ness' of the one-line breakpoint, also requiring another flag for each pdb.set_trace().

Upvotes: 6

Views: 3719

Answers (5)

czxttkl
czxttkl

Reputation: 496

Using 'return' in pdb can pass pdb.set_trace() in the loop and jump to the last line of the current function.

Upvotes: 0

jtmckenzie
jtmckenzie

Reputation: 1

Have you tried using the "until" command that's provided by pdb?

From http://docs.python.org/2/library/pdb.html#debugger-commands:

unt(il)

Continue execution until the line with the line number greater than the current one is reached or when returning from current frame.

Upvotes: 0

shx2
shx2

Reputation: 64318

The following hack will disable all other calls to set_trace in current run (i.e., from anywhere in your code).

Create this noop_pdb drop-in:

# noop_pdb.py
def set_trace(*args, **kwargs):
    pass

Then, once your code breaks in the real pdb.set_trace, and you want to disable the rest of the calls to set_trace, do:

sys.modules['pdb'] = __import__('noop_pdb')

Next time the interpreter encounters a line like:

import pdb;pdb.set_trace()

It avoids re-importing the built-in pdb, picking up the drop-in.

EDIT: another way to implement this hack, which does not require noop_pdb, is by replacing set_trace with noop, instead of the whole pdb module: pdb.set_trace = lambda: None

Upvotes: 1

shx2
shx2

Reputation: 64318

My other answer is sort of a quick hack, and is not perfect (will disable all calls to set_trace). Here's a better solution.

We define a module wrapping pdb. In it, set_trace is a callable object, maintaining a list of disabled callers (identified by filename/line-number).

# mypdb.py
import inspect
import sys
try:
    import ipdb as PDB
except ImportError:
    import pdb as PDB

class SetTraceWrapper(object):
    def __init__(self):
        self.callers_disabled = set()
        self.cur_caller = None
    def __call__(self):
        self.cur_caller = self.get_caller_id()
        if self.cur_caller in self.callers_disabled:
            # already disabled for caller
            #print 'set_trace SKIPPED for %s' % ( self.cur_caller, )
            return
        #print 'set_trace BREAKING for %s' % ( self.cur_caller, )
        try:
            PDB.set_trace(sys._getframe().f_back)
        except TypeError:
            PDB.set_trace()
    def disable_current(self):
        #print 'set_trace DISABLING %s' % ( self.cur_caller, )
        self.callers_disabled.add(self.cur_caller)
    def get_caller_id(self, levels_up = 1):
        f = inspect.stack()[levels_up + 1]
        return ( f[1], f[2] )  # filename and line number

set_trace = SetTraceWrapper()

In your code, make sure you use the wrapper:

import mypdb as pdb; pdb.set_trace()

When you want to disable the current set_trace-calling-line, do:

pdb.set_trace.disable_current()

Notes:

  1. I personally prefer ipdb over pdb

  2. When using pdb, since the function actually calling pdb.set_trace is in the wrapper, the current frame when breaking will be in it. the up command gets you the to frame you want. This will not happen if using ipdb (the implementation in the wrapper makes sure to break in the right place).

  3. When using ipdb, I find it to report caller-frame line-numbers inconsistently. This means the first time you do pdb.set_trace.disable_current(), it might not hold. Just do it again if it breaks the next time -- the second time holds.

  4. In general, having your own pdb wrapper is useful for other things as well. I have my own set_trace wrapper which avoids breaking if not sys.stdout.isatty (you never want to break if the process is not connected to a terminal, nor when you redirect the stdout to a file/pipe). That is to say, having your own pdb wrapper and calling its set_trace instead of pdb's is a good practice.

Upvotes: 2

Michael W
Michael W

Reputation: 688

Did you look at condition bpnumber ? You could disable the breakpoint and then make it conditional. Alternatively you could just use break or tbreak to make the breakpoint conditional in the first place. Details can be found here.

Upvotes: 0

Related Questions