Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pdb bypass error/Jump failed: can only jump from a 'line' trace event

I'm trying to debug a Python program using pdb. The program could be like this:

def main():
    a = 1
    print(b)
    c = 2
    d = 3

Apparently, print(b) is a typo which should be print(a) but it is not important and I can fix it with the text editor but I want to bypass this error and continue debugging.

I tried jump, like jump 4(assuming "c=2" is line 4) but I was given error "Jump failed: f_lineno can only be set by a line trace function", which means I need to give a line trace function when I'm programming.

So, is there a way to deal with this problem, or is there some other way to bypass the error line when using pdb?

like image 265
sky zhang Avatar asked Nov 17 '18 02:11

sky zhang


People also ask

How do I run Python code in debug mode?

Starting Python Debugger To start debugging within the program just insert import pdb, pdb. set_trace() commands. Run your script normally, and execution will stop where we have introduced a breakpoint. So basically we are hard coding a breakpoint on a line below where we call set_trace().

How do I exit pdb?

Whenever you want to leave the pdb console, type the command quit or exit . If you would like to explicitly restart a program at any place within the program, you can do so with the command run .

How do I debug Python in Terminal Linux?

Directly use command python pdg-debug.py without -m pdb to run the code. The program will automatically break at the position of pdb. set_trace() and enter the pdb debugging environment. You can use the command p variable to view the variables or use the command c to continue to run.

What is pdb in Python?

Pdb is a powerful tool for finding syntax errors, spelling mistakes, missing code, and other issues in your Python code.


1 Answers

TLDR: this is pdb's post-mortem mode in which jumping is not supposed to work. But it's still very useful.

enter image description here

Painting by Rembrandt (public domain)

I reproduce it with python 3.8.2 as *** Jump failed: can only jump from a 'line' trace event by running the script "under pdb" like so: python3 -m pdb -c c script.py and trying to jump to another line in pdb prompt which then appears.

What's happened: an unhandled exception, in this case NameError: name 'b' is not defined caused python to stop interpreting the script; pdb intercepted this situation and entered its post-mortem mode.

As Almar Klein nicely put it in his blog post,

Post-mortem debugging refers to the concept of entering debug mode after something has broken. There is no setting of breakpoints involved, so it's very quick and you can inspect the full stack trace, making it an effective way of tracing errors.

Although jump, next, return won't work in post-mortem, bt, up, down, ll and pp, along with the possibility to import modules and run arbitrary python code directly in the pdb's interactive shell can be very effective ways to get the root cause. In our simple example the root cause of the NameError is shown immediately upon a quick ll: pdb prefixes the offending line of code with >>.

Had we not passed -c c (meaning continue), pdb would have shown its prompt and paused before the first line of your program is interpreted, so you'd have a chance to step through the whole program or set a breakpoint before or at the offending line, and jump over it, never entering the post-mortem.

Even in post-mortem, you can prepare a breakpoint anywhere in the program, e.g. break 2 for line 2, and say c or continue so pdb will finish post-mortem, reload the file, and restart the program with the updated set of breakpoints.


Another way to deal with it is to import pdb and pdb.set_trace() in suspicious code - or since python 3.7, simply breakpoint() - and run the python program normally (not "under" pdb anymore) which allows then to jump, next, return etc, as well as everything else - when the breakpoint is hit.


If your Python program is started through behave:

  • prefer to run behave with --no-capture whenever using pdb or similar debuggers (whether post-mortem mode or not), to avoid problems with behave's stdin/stdout capturing making pdb unresponsive and/or its prompt invisible.
  • best of all, if you want to end up in the pdb post-mortem mode automatically while potentially still supporting capturing, set the post_mortem environment variable (can also name it differently) to any value (but only on dev machine, not for automated CI or production!) and commit the following permanently into environment.py:
def after_step(context, step):
    import os
    if 'post_mortem' in os.environ and step.status == 'failed':
        import pdb
        # Similar to "behave --no-capture" calling stop_capture() ensures visibility of pdb's prompts,
        # while still supporting capture until an uncaught error occurs.
        # Warning: this does rely on behave's internals which might change
        context._runner.stop_capture()  # pylint: disable=protected-access
        pdb.post_mortem(step.exc_traceback)
like image 171
V-R Avatar answered Nov 15 '22 21:11

V-R