pythonpdb

How to ignore a specific breakpoint interactively?


Consider this script:

print("before loop")
for i in range(100):
    breakpoint()
print("after loop")
breakpoint()
print("exit")

Short of pressing "c" one hundred times, how can you get past the breakpoint within the loop at L3 and proceed to L5?

I've tried the ignore command but couldn't work it out:

$ python3 example.py
before loop
> /tmp/example.py(2)<module>()
-> for i in range(100):
(Pdb) ignore 0
*** Breakpoint 0 already deleted
(Pdb) c
> /tmp/example.py(2)<module>()
-> for i in range(100):
(Pdb) ignore 0
*** Breakpoint 0 already deleted
(Pdb) c
> /tmp/example.py(2)<module>()
-> for i in range(100):

I want to execute the remainder of the loop, without tripping again the breakpoint on L3, then print "after loop" and break before printing "exit", remaining in the debugger. The answer must not require exiting the debugger and re-entering the runtime, or modifying the source code.


Solution

  • You can use the PYTHONBREAKPOINT environment variable to call a custom breakpoint handler that you define in a separate file.

    For example:

    $ export PYTHONBREAKPOINT=mybreak.mybreak
    
    # mybreak/__init__.py
    
    import pdb
    
    _counter = 0
    
    def mybreak(*args, **kwargs):
        global _counter
        if _counter >= 100:
            # default behavior
            pdb.set_trace(*args, **kwargs)
        else:
            # skip dropping into pdb while inside the range(100) loop
            pass
        _counter += 1
    

    You might have to get a little tricky if there are other invocations of breakpoint() in the file but it would just be a matter of tracking what the counter value would be when you want to skip over the breakpoint.

    An alternate implementation of the custom handler, as suggested in nneonneo's answer:

    # mybreak/__init__.py
    
    import inspect
    import pdb
    
    def mybreak():
        caller = inspect.stack()[1]
        if caller.filename.endswith("/foo.py") and caller.lineno == 2:
            # skip this breakpoint
            return
        pdb.set_trace(*args, **kwargs)