Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I ignore a specific breakpoint interactively?

Tags:

python

pdb

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 I 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 the breakpoint on L3 again, and then print "after loop" and break before printing "exit", remaining in the debugger. The answer must not require exiting the debugger and reentering the runtime, or modifying the source code.

like image 982
wim Avatar asked Oct 30 '25 15:10

wim


2 Answers

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)
like image 90
Woodford Avatar answered Nov 01 '25 07:11

Woodford


breakpoint is just a regular Python function, so for an ugly but functional solution, you can overwrite breakpoint temporarily with a new function that selectively skips breakpoints.

Suppose foo.py contains the following:

for i in range(100):
    breakpoint()

breakpoint()
print("hi")

Run foo.py, and it'll immediately break at the first breakpoint, where continuing repeatedly keeps going around the loop:

> /code/foo.py(1)<module>()
-> for i in range(100):
(Pdb) c
> /code/foo.py(1)<module>()
-> for i in range(100):
(Pdb) c
> /code/foo.py(1)<module>()
-> for i in range(100):

Put the following in a temporary module (e.g. tmp_break_3zfh.py):

import inspect
import builtins

def breakpoint():
    caller = inspect.stack()[1]
    if caller.filename.endswith("/foo.py") and caller.lineno == 2:
        return
    builtins.breakpoint()

Then import it from the pdb console to overwrite the real breakpoint function for that module alone. When we continue, then step (to get out of the wrapper breakpoint and into the caller), we can see that we're stopped after the loop:

(Pdb) from tmp_break_3zfh import breakpoint
(Pdb) c
--Return--
> /code/tmp_break_3zfh.py(8)breakpoint()->None
-> builtins.breakpoint()
(Pdb) s
--Return--
> /code/foo.py(5)<module>()
-> print("hi")
like image 41
nneonneo Avatar answered Nov 01 '25 07:11

nneonneo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!