Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stepwise debugging of selected Python code

The essence:

Using Spyder, it's possible to run parts of code by highlighting it and clicking F9. This works with For Loops as well, but the problem (for me at least) is that it seems impossible to run the selected part step by step. I find this a bit strange since it's possible to run For Loops step by step under other cirmustances (and inspect the state of the variables at each step).

Allow me to explain:


The snippet below is an operation on two variables names = ['A', 'B', 'C'] and values = [11,12,13] using a For Loop. In order to give a proper description of what I'm unable to do with this setup, I feel it's necessary to explain what I am able to do and also why I think the whole thing is a bit strange if it turns out that what I would like to do is in fact impossible.

I often find myself messing around with a lot of variables using different routines. The problem I'm facing is that in order to debug these routines, I often have to re-run parts of the code that redefine all my variables before I'm actually able to look for bugs in other parts of the code. And THAT'S why it would be great to be able run a stepwise debugging of a For Loop on pre-existing variables that I can inspect in Spyders Variable explorer. I'm mostly messing around with Python in Spyder, but please suggest other IDEs where this may be possible.


Here's an example:

def foo():
    names = ['A', 'B', 'C']
    values = [11,12,13]
    i = 0
    for n in names:
        variable = str(n)  + ' = ' + str(values[i])
        print(variable)
        i += 1      
foo()

Below are my options (if the issue seems clear enough, you can easily jump to the last part Option 5):

Option 1 - Run code using Run file (F5):

This unsurprisingly prints the following in the IPython console:

A = 11
B = 12
C = 13

The rest of the environment looks like below. Notice that it doesn't leave any variables in memory and/or to be inspected in the Variable explorer. That's good for memory management, but bad for a small scale wanna-be programmer that doesn't care about these things.

enter image description here

Option 2 - Forget the function and just Run file

Commenting out def foo() and foo() and clicking Run file (F5) (also fixing the indentation) prints the same thing to the IPython console AND leaves the variables behind in the Variable explorer for further inspection.

The edited code:

#def foo():
names = ['A', 'B', 'C']
values = [11,12,13]
    
i = 0
for n in names:
    variable = str(n)  + ' = ' + str(values[i])
    print(variable)
    i += 1      
#foo()

The environment:

enter image description here

Notice that the Variable explorer shows the state of each variable after the execution of the code.

Option 3 - Same code as option 2 now using Debug File (Cltr+F5) and Run Current Line (Ctrl+F10)

Clicking Debug File (Cltr+F5) will let me start at the beginning of the routine, and step through it line by line using Run Current Line (Ctrl+f10). Including the lines in the For Loop. At each step, I can easily inspect the state of the variables as they change in the Variable explorer.

The environment after stepping through the For Loop one time:

enter image description here

To a non-professional programmer like myself, this would look like the easiest and most basic way of both writing and debugging code. However, It's hard to avoid the benefits of wrapping code into functions for greater re-useability. So, back to foo() again:

Option 4 - Debug function with Debug File (Cltr+F5), Continue Execution Until Next Breakpoint (Ctrl+F12) and Step Into Function or Method of current line (Ctrl+F11) and Run Current Line (Ctrl+F10).

Using Debug File (Cltr+F5) initiates the debugging and highlights line 2. To progress, I can use Continue Execution Until Next Breakpoint (Ctrl+F12) which halts the execution at line 11. Here I can choose to Run Current Line (Ctrl+f10) which calls the function without any more fuzz, or I can Step Into Function or Method of current line (Ctrl+F11) which brings me to my happy place. Now I can Run Current Line (Ctrl+F10) to define the variables, and even inspect the variables in the For Loop step by step in the Variable explorer. Here's the environment after defining the variables within the function and stepping through the For Loop one time:

enter image description here

So what was the question again??

Option 5 - Debug a for Loop using existing varibles

In Spyder, you can run parts of code simply by highlighting it and using Run Selection or Current Line (F9) without even defining the function. So starting from scratch, I can define my variables simply by selecting them and clicking F9. Now they're available in the Variable explorer for further inspection:

enter image description here

You can do the same thing with the rest of the code. The For Loop is run in its entirety and the variables become available in the Variable explorer.

enter image description here

And now, finally, we arrive at the main question. Is it in any way possible to run through the highlighted For Loop step by step instead of the whole thing at the same time like in Option 1? (And without having to run through the function, stop at a breakpoint and continue using F10 like described in Option 4?)

Ideally, it would be as simple as highlighting the code and do something like Stepwise debug selected code (Ctrl'??) and that's it.

I hope this makes sense to some of you. And please let me know if this approach is just completely wrong from start to finish!

Thank you!

Edit: Adding a breakpoint before running the selected part with F9 has no effect:

enter image description here

Edit 2 - System info:

  • Windows 7
  • Python 3.6.0 Anaconda custom (64-bit)
  • Spyder 3.2.5
like image 390
vestland Avatar asked Jan 10 '18 07:01

vestland


2 Answers

(Spyder maintainer here) There is a trick not many people know to introduce breakpoints wherever you want in your Python code: import pdb; pdb.set_trace().

In your case, you need to replace your code with

def foo():
    names = ['A', 'B', 'C']
    values = [11,12,13]
    i = 0
    import pdb; pdb.set_trace()
    for n in names:
        variable = str(n)  + ' = ' + str(values[i])
        print(variable)
        i += 1

foo()

and then run your file with Run file/F5 or also as a cell with Ctrl + Enter. With this simple change you'll get a debugger session exactly at the line pdb.set_trace() is placed and enter the for cycle below it to iterate line by line through it.

Note: Since Python 3.7 this is even simpler because it adds a new builtin function called breakpoint to replace pdb.set_trace(), but with the exact same effect.

like image 149
Carlos Cordoba Avatar answered Nov 10 '22 01:11

Carlos Cordoba


Visual Studio Community Edition

(with some Add-Ins not relevat to python):

Disclaimer: I use it because im familiar with it (C#) and it is free to use - not because it's especially pythonic.


Coding (Layout configureable):

  • Left: Code

  • Left-low: Output (normally I collaps that down to tabs only at the bottom to get more coding screen estate. Maybe downsized and switched to tab Error List which lists errors in your code (doh). Your code was perfect, so you do not see any of the sqigglies pointing out errors in the code.

  • Right: Solution explorer - essentially what files are inside this special python solution.

  • Right-low: Properties of a selected file

All the windows can be removed, resized, un-pinned to become "free floating windows" or collapsed into vertical tabs at left/right side of the window to get more screen estate for whats important to you)

Code not running

See the red dots on the side of the lines? You place them before running the code. They mark break points, code execution automatically stops running when hitting one (basic use) or you can configure them to

  • not stop running but print out trace info of variables
  • stop only conditionally on f.e. variable value becomes 5 (loop index after that your program crashes all the time or other "conditions")
  • they can also only stop on 4th time hit and some other things:

break point config


Debugging Code:

F5 to start code running changes the layout (see above, you can change it and changes persist for next run):

debugging code

When stopped you can hover over variables that are already used and inspect them, you can pin those information to the side - if one changes the text of the pin will get red to visualize this.

You can also put stuff in the "watch window" or use "quick watch" to inspect it - window lower half of screenshot. From a break you can continue wiht F5 to run till next breakpoint, or use F10 or F11:

  • F10 "steps over" statements line by line
  • F11 "steps into" statements - i.e. if your statement is function call it would execute the function wiht F10 and step into the function with F11

If inside a function you can use SHIFT+F11 complete the function and step out again and go from there.

I used F5 and F10 twice and I am currently at the line indicated by the arrow-thingy. You can also dragg the arrow some lines up to reexecute code, but this can have sideeffects - I rarly use it, most times I just restart the program Ctrl+Shift+F5 or stop debugging Shift+F5

The print output of your program is shown in a normal Console window thats cropped from the screenshots.

AddOn1: You can also simply execute all code, no debugging with CTRL+F5 and the IDE has 'a few' other features for python.

AddOn2: VS naturally comes with a lot of other features useful in an IDE, like integration to git etc. - if you use those they are "usable" from within the IDE via plugins -although some things are better done on the git.bash.

like image 45
Patrick Artner Avatar answered Nov 10 '22 00:11

Patrick Artner