Difference between revisions of "Python:Debugging"

From PrattWiki
Jump to navigation Jump to search
(Simple Example of Step)
(External Links)
 
(5 intermediate revisions by the same user not shown)
Line 2: Line 2:
  
 
== Introduction ==
 
== Introduction ==
The debugging tools show up in two places in Spyder.  The '''Debug''' menu at the top contains a list of all the options for debugging and also shows the icons associated with those tasks.  The navigation bar has a subset of the commands in graphical form.  The commands are:
+
The debugging tools show up in two places in Spyder.  The '''Debug''' menu at the top contains a list of all the options for debugging and also shows the icons associated with those tasks.  The navigation bar also has the first six of the commands in graphical form.  The commands are:
* Debug
+
* Debug ("Debug file" button, blue play-pause)
* Step
+
* Step ("Run current line" button, blue arrow connecting dots)
* Step Into
+
* Step Into ("Step into function or method of current line" button, blue arrow entering a paragraph)
* Step Return
+
* Step Return ("Run until current method or function returns" button, blue arrow leaving paragraph)
* Continue
+
* Continue ("Continue execution until next breakpoint" button, blue double play)
* Stop
+
* Stop ("Stop debugging" button, blue box
 
* Set/Clear breakpoint
 
* Set/Clear breakpoint
 
* Set/Edit conditional breakpoint
 
* Set/Edit conditional breakpoint
 
* Clear breakpoints in all files
 
* Clear breakpoints in all files
 
* List breakpoints
 
* List breakpoints
We will now cover each of the options above.
+
We will now cover some use cases.  The processes themselves will be given by a bold version of the command; that is, if an example below says to '''Step Into,''' you can do that either by going to the <code>Debug</code> menu and selecting <code>Step Into</code> or by clicking the "Step into function or method of current line" button, the third of six blue icons.
 +
 
 
=== Debug ===
 
=== Debug ===
The '''Debug''' command will start the '''ipdb''' process on your script.  The IPython console prompt will change to read <code>ipdb></code> and the console will also show you where the debugger is in the code.  As a first step, the '''Debug''' command will skip to the end of any initial comments in your script. Generally you will only use the '''Debug''' command once while debugging - it starts the process for you.
+
The '''Debug''' command will start the '''ipdb''' process on your script.  The IPython console prompt will change to read <code>ipdb</code> and the console will also show you where the debugger is in the code.  As a first step, the '''Debug''' command will skip to the end of any initial comments in your script. Generally you will only use the '''Debug''' command once while debugging - it starts the process for you.
  
 
=== Step ===
 
=== Step ===
The '''Step''' command will tell the debugger to run the current line of code.  You can go step by step through your code and monitor how variables change either in the Variable explorer or by asking questions at the '''ipdb''' prompt.  Note that when '''ipdb''' hits a line of code that starts to define a function or calls a function, it will consider defining or calling the entire function as one step.  The '''Step''' command is probably the most useful button as it goes through your code, but if you are trying to troubleshoot something going on ''inside'' a function, you will need to look at the next command.
+
The '''Step''' command will tell the debugger to run the current line of code.  You can go step by step through your code and monitor how variables change either in the Variable explorer or by asking questions at the <code>ipdb</code> prompt.  Note that when <code>ipdb</code> hits a line of code that starts to define a function or calls a function, it will consider defining or calling the entire function as one step.  The '''Step''' command is probably the most useful button as it goes through your code, but if you are trying to troubleshoot something going on ''inside'' a function, you will need to look at the next command.
  
 
=== Step Into ===
 
=== Step Into ===
The '''Step Into''' command is used when you want to actually look at how a function runs line by line.  You need to be careful with this because sometimes it will lead you to "debugging" built-in Python code!  If you have a line of code that calls the functions you want to investigate, use '''Step''' to get the debugger to the point where it is pointing at that line of code, then use '''Step Into'''.  The debugger should now be pointing at the function definition of the first function called in that line.  You can now use '''Step''' to step through that function and any others called in that line.  '''Note''': if your line has both functions that you created and built-in functions, '''ipdb''' will also try to step through the built in functions in the order that they will run.
+
The '''Step Into''' command is used when you want to actually look at how a function runs line by line.  You need to be careful with this because sometimes it will lead you to "debugging" built-in Python code!  If you have a line of code that calls the functions you want to investigate, use '''Step''' to get the debugger to the point where it is pointing at that line of code, then use '''Step Into''' on the line of code with the call you want to investigate.  The debugger will then point at the function definition of the first function called in that line.  You can now use '''Step''' to step through that function and any others called in that line.  '''Note''': if your line has both functions that you created and built-in functions, '''ipdb''' will also try to step through the built in functions in the order that they will run.
  
 
== Examples ==
 
== Examples ==
Line 51: Line 52:
 
</syntaxhighlight>
 
</syntaxhighlight>
 
and you want to debug it step by step.  Here's what you would do and what you would see in the IPython console and the variable explorer assuming you cleared variables before starting:
 
and you want to debug it step by step.  Here's what you would do and what you would see in the IPython console and the variable explorer assuming you cleared variables before starting:
* Start the debugging process by either going to the Debug menu and selecting <code>Debug</code>, or by clicking the '''Start Debugging button''', or using the keyboard shortcut for Debug.
+
* Start the debugging process by either going to the Debug menu and selecting <code>Debug</code>, or by clicking the '''Debug file''' button (blue pause-play button), or using the keyboard shortcut for '''Debug file'''.
** The console will show that it is pointing at line 4, the last of the commented lines at the top
+
** The console will show that it is pointing at line 2, the first of the commented lines at the top
 
** The variable explorer is empty
 
** The variable explorer is empty
* Step through by either going to the Debug menu and selecting <code>Step</code>, or by clicking the '''Step''' button, or by using the keyboard shortcut for '''Step'''
+
* Step through by either going to the Debug menu and selecting <code>Step</code>, or by clicking the '''Run current line''' button (blue dot with arrow arching over it), or by using the keyboard shortcut for '''Run current line'''.
 
** The console will show that it is pointing at line 7 - it hasn't run this line, it is showing that line 7 will be the next line to run.
 
** The console will show that it is pointing at line 7 - it hasn't run this line, it is showing that line 7 will be the next line to run.
 
** The variable explorer is still empty
 
** The variable explorer is still empty
 
* Take another step
 
* Take another step
 
** The console will show that it is pointing at line 14
 
** The console will show that it is pointing at line 14
** The variable explorer will show that there is now a function called <code>fun</code>, indicating that lines 7-11 have run
 
 
* Take another step
 
* Take another step
** The console will show that it is pointing at line 14
+
** The console will show that it is pointing at line 20
** The variable explorer will show that there is now a function called <code>main</code>, indicating that lines 14-17 have run
 
 
* Take another step
 
* Take another step
** Since __name__ is __main__, the console will show that it went into the <code>if</code> branch and is pointing at like 21
+
** Since __name__ is __main__, the console will show that it went into the <code>if</code> branch and is pointing at line 21
 
** The console has not changed
 
** The console has not changed
 
* Take another step
 
* Take another step
 
** Since <code>main()</code> ran, the console will indicate that a 37 was printed and returned.
 
** Since <code>main()</code> ran, the console will indicate that a 37 was printed and returned.
 
** The console has not changed
 
** The console has not changed
* Take another step.  The program is over and the debugger exits
+
* Take another step.  The program is over and the debugger exits. The prompt changes from the IPdb prompt to a regular In prompt.
 +
 
 +
=== Simple Example of '''Step''' and '''Step Into''' ===
 +
Assume you have the same code as above but now you want to see what specifically is going on with the <code>main</code> function.  Here's what you would do and what you would see in the IPython console and the variable explorer assuming you cleared variables before starting:
 +
* Start the debugging process by either going to the Debug menu and selecting <code>Debug</code>, or by clicking the '''Debug file''' button (blue pause-play button), or using the keyboard shortcut for '''Debug file'''.
 +
** The console will show that it is pointing at line 2, the first of the commented lines at the top
 +
** The variable explorer is empty
 +
* Step through by either going to the Debug menu and selecting <code>Step</code>, or by clicking the '''Run current line''' button (blue dot with arrow arching over it), or by using the keyboard shortcut for '''Run current line'''.
 +
** The console will show that it is pointing at line 7 - it hasn't run this line, it is showing that line 7 will be the next line to run.
 +
** The variable explorer is still empty
 +
* Take another step
 +
** The console will show that it is pointing at line 14
 +
* Take another step
 +
** The console will show that it is pointing at line 20
 +
* Take another step
 +
** Since __name__ is __main__, the console will show that it went into the <code>if</code> branch and is pointing at line 21
 +
** The variable explorer has not changed
 +
* '''Step Into''' the <code>main</code> function by either going to the Debug menu and selecting <code>Step into</code>, or by clicking the '''Step into''' button (blue arrow pointing down to a dot), or using the keyboard shortcut for '''Step into'''.  This will now tell the debugger that you actually want to look at the inner workings of <code>main</code> rather than just stepping past it
 +
** The console will show that is pointing at line 14, the function definition line for <code>main</code>
 +
** The variable explorer has not changed
 +
* Take a step - at this point, taking a '''Step''' or '''Step Into''' will do the same thing
 +
** The console will show that it is pointing at line 15
 +
** The variable explorer has not changed
 +
* Take another step -  once again, taking a '''Step''' or '''Step Into''' here will do the same thing
 +
** The console will show that it is pointing at line 16
 +
** The variable explorer now shows that there is an int called <code>k</code> equal to 2
 +
* Now you have a decision to make -- if you simply want line 16 to do its job, you can take a '''Step'''; if you want to go step by step through the <code>fun(k)</code> call, you can '''Step Into''' it.
 +
** If you took a '''Step'''
 +
*** Line 16 does its thing and runs <code>fun(k)</code>
 +
**** The console will show that it is pointing at line 17
 +
**** The variable explorer has not changed
 +
** If you took a '''Step Into'''
 +
*** You now have the opportunity to go through the <code>fun(k)</code>
 +
**** The console will show that it is pointing at line 7
 +
**** The variable explorer now shows that there is an int called <code>a</code> equal to 2
 +
*** You can now '''Step''' through each line.  If you want to skip to the end of this run, you can also '''Step Return''' to get to the return line of <code>fun</code>; regardless, whenever you get to the end of this function you will go back to line 17.
 +
** Now that are on line 17 we are in dangerous territory.  For the <code>print(fun(k))</code> line, there are two function calls, one to <code>fun()</code> and one to <code>print()</code>.  If you decide to '''Step Into''' this line it will take you through the <code>fun(k)</code> run but then, after the return from the function happens, it will take you through the <code>print()</code> command. 
 +
*** The way you can tell is Spyder will open the iostream.py file, an internal script that tells Spyder how to print things
 +
**** You definitely do not want to change things here...
 +
***** Best bet is to either '''Stop''' debugging (the blue box), '''Continue''' execution (two blue right arrows), or '''Step Return''' a few times while in the <code>iostream</code> file since it usually calls a few functions to do its work. In the first two cases, debugging will end; in the third, the debugger will take you back to line 17 of the code since that line produced a return; Using '''Step''' two more times will get out of the <code>main</code> and then out of the script itself.
 +
 
 +
== External Links ==
 +
* Dr. Philip Yip has an excellent WordPress site on [https://dellwindowsreinstallationguide.com/python/ Python Programming and Data Science], on which there is a segment on [https://dellwindowsreinstallationguide.com/python/#code-blocks-and-debugging Code Blocks and Debugging] - you are highly encouraged to follow the entire video.  The code blocks for this video are listed as 3-18 (excluding 12 and 13).  The video also covers if trees, loops, dictionaries, and functions.  The content from 48 to 51 minutes is a little beyond things we've done yet with functions(we have looked at *args but not **kwargs).  At the 1 hour mark, the video talks about assertions for error handling, which he have not covered but is interesting.  The video ends with lambda functions and list comprehensions.

Latest revision as of 04:42, 16 February 2022

There are several different ways to debug code. The Spyder user interface provides access to a system called ipdb. There is documentation for it at the Spyder Docs page on Debugging though that page might be a little too complicated to understand at first. This page will seek to go through the basics of how to debug using the Debug features of the Spyder IDE.

Introduction

The debugging tools show up in two places in Spyder. The Debug menu at the top contains a list of all the options for debugging and also shows the icons associated with those tasks. The navigation bar also has the first six of the commands in graphical form. The commands are:

  • Debug ("Debug file" button, blue play-pause)
  • Step ("Run current line" button, blue arrow connecting dots)
  • Step Into ("Step into function or method of current line" button, blue arrow entering a paragraph)
  • Step Return ("Run until current method or function returns" button, blue arrow leaving paragraph)
  • Continue ("Continue execution until next breakpoint" button, blue double play)
  • Stop ("Stop debugging" button, blue box
  • Set/Clear breakpoint
  • Set/Edit conditional breakpoint
  • Clear breakpoints in all files
  • List breakpoints

We will now cover some use cases. The processes themselves will be given by a bold version of the command; that is, if an example below says to Step Into, you can do that either by going to the Debug menu and selecting Step Into or by clicking the "Step into function or method of current line" button, the third of six blue icons.

Debug

The Debug command will start the ipdb process on your script. The IPython console prompt will change to read ipdb and the console will also show you where the debugger is in the code. As a first step, the Debug command will skip to the end of any initial comments in your script. Generally you will only use the Debug command once while debugging - it starts the process for you.

Step

The Step command will tell the debugger to run the current line of code. You can go step by step through your code and monitor how variables change either in the Variable explorer or by asking questions at the ipdb prompt. Note that when ipdb hits a line of code that starts to define a function or calls a function, it will consider defining or calling the entire function as one step. The Step command is probably the most useful button as it goes through your code, but if you are trying to troubleshoot something going on inside a function, you will need to look at the next command.

Step Into

The Step Into command is used when you want to actually look at how a function runs line by line. You need to be careful with this because sometimes it will lead you to "debugging" built-in Python code! If you have a line of code that calls the functions you want to investigate, use Step to get the debugger to the point where it is pointing at that line of code, then use Step Into on the line of code with the call you want to investigate. The debugger will then point at the function definition of the first function called in that line. You can now use Step to step through that function and any others called in that line. Note: if your line has both functions that you created and built-in functions, ipdb will also try to step through the built in functions in the order that they will run.

Examples

Simple Example of Step

Assume you have the following code:

 1 # -*- coding: utf-8 -*-
 2 """
 3 Comments
 4 """
 5 
 6 
 7 def fun(a):
 8     b = a**2
 9     c = 2*b
10     d = 25
11     return b+c+d
12 
13 
14 def main():
15     k = 2
16     fun(k)
17     print(fun(k))
18 
19 
20 if __name__ == "__main__":
21     main()

and you want to debug it step by step. Here's what you would do and what you would see in the IPython console and the variable explorer assuming you cleared variables before starting:

  • Start the debugging process by either going to the Debug menu and selecting Debug, or by clicking the Debug file button (blue pause-play button), or using the keyboard shortcut for Debug file.
    • The console will show that it is pointing at line 2, the first of the commented lines at the top
    • The variable explorer is empty
  • Step through by either going to the Debug menu and selecting Step, or by clicking the Run current line button (blue dot with arrow arching over it), or by using the keyboard shortcut for Run current line.
    • The console will show that it is pointing at line 7 - it hasn't run this line, it is showing that line 7 will be the next line to run.
    • The variable explorer is still empty
  • Take another step
    • The console will show that it is pointing at line 14
  • Take another step
    • The console will show that it is pointing at line 20
  • Take another step
    • Since __name__ is __main__, the console will show that it went into the if branch and is pointing at line 21
    • The console has not changed
  • Take another step
    • Since main() ran, the console will indicate that a 37 was printed and returned.
    • The console has not changed
  • Take another step. The program is over and the debugger exits. The prompt changes from the IPdb prompt to a regular In prompt.

Simple Example of Step and Step Into

Assume you have the same code as above but now you want to see what specifically is going on with the main function. Here's what you would do and what you would see in the IPython console and the variable explorer assuming you cleared variables before starting:

  • Start the debugging process by either going to the Debug menu and selecting Debug, or by clicking the Debug file button (blue pause-play button), or using the keyboard shortcut for Debug file.
    • The console will show that it is pointing at line 2, the first of the commented lines at the top
    • The variable explorer is empty
  • Step through by either going to the Debug menu and selecting Step, or by clicking the Run current line button (blue dot with arrow arching over it), or by using the keyboard shortcut for Run current line.
    • The console will show that it is pointing at line 7 - it hasn't run this line, it is showing that line 7 will be the next line to run.
    • The variable explorer is still empty
  • Take another step
    • The console will show that it is pointing at line 14
  • Take another step
    • The console will show that it is pointing at line 20
  • Take another step
    • Since __name__ is __main__, the console will show that it went into the if branch and is pointing at line 21
    • The variable explorer has not changed
  • Step Into the main function by either going to the Debug menu and selecting Step into, or by clicking the Step into button (blue arrow pointing down to a dot), or using the keyboard shortcut for Step into. This will now tell the debugger that you actually want to look at the inner workings of main rather than just stepping past it
    • The console will show that is pointing at line 14, the function definition line for main
    • The variable explorer has not changed
  • Take a step - at this point, taking a Step or Step Into will do the same thing
    • The console will show that it is pointing at line 15
    • The variable explorer has not changed
  • Take another step - once again, taking a Step or Step Into here will do the same thing
    • The console will show that it is pointing at line 16
    • The variable explorer now shows that there is an int called k equal to 2
  • Now you have a decision to make -- if you simply want line 16 to do its job, you can take a Step; if you want to go step by step through the fun(k) call, you can Step Into it.
    • If you took a Step
      • Line 16 does its thing and runs fun(k)
        • The console will show that it is pointing at line 17
        • The variable explorer has not changed
    • If you took a Step Into
      • You now have the opportunity to go through the fun(k)
        • The console will show that it is pointing at line 7
        • The variable explorer now shows that there is an int called a equal to 2
      • You can now Step through each line. If you want to skip to the end of this run, you can also Step Return to get to the return line of fun; regardless, whenever you get to the end of this function you will go back to line 17.
    • Now that are on line 17 we are in dangerous territory. For the print(fun(k)) line, there are two function calls, one to fun() and one to print(). If you decide to Step Into this line it will take you through the fun(k) run but then, after the return from the function happens, it will take you through the print() command.
      • The way you can tell is Spyder will open the iostream.py file, an internal script that tells Spyder how to print things
        • You definitely do not want to change things here...
          • Best bet is to either Stop debugging (the blue box), Continue execution (two blue right arrows), or Step Return a few times while in the iostream file since it usually calls a few functions to do its work. In the first two cases, debugging will end; in the third, the debugger will take you back to line 17 of the code since that line produced a return; Using Step two more times will get out of the main and then out of the script itself.

External Links

  • Dr. Philip Yip has an excellent WordPress site on Python Programming and Data Science, on which there is a segment on Code Blocks and Debugging - you are highly encouraged to follow the entire video. The code blocks for this video are listed as 3-18 (excluding 12 and 13). The video also covers if trees, loops, dictionaries, and functions. The content from 48 to 51 minutes is a little beyond things we've done yet with functions(we have looked at *args but not **kwargs). At the 1 hour mark, the video talks about assertions for error handling, which he have not covered but is interesting. The video ends with lambda functions and list comprehensions.