As already stated in the introduction to this chapter, knowing the debugger of the language you are developing in and how to put it to use is part of the bread-and-butter business of a programmer, just like writing the code in the first place. In case of Python, this means knowing how to use the pdb debugger, which will be introduced throughout the course of this recipe.
The pdb debugger operates as an interactive prompt, accepting simple text commands that trigger actions like advancing program execution, or setting break points that stop program execution at a given line. In the following tasks, you will be walked through an example debug session, teaching you all the commands needed for analyzing code and hunting down those nasty bugs!
However, note that pdb is not the only debugger available for Python. There are plenty of alternatives available like pydbgr, pudb, or Winpdb that might provide more features or a user interface that's easier to use. Though the big plus point for pdb, on the other hand, is that it comes included with the Python runtime, that's part of the Panda3D engine.
The program you are going to debug is the one developed in the recipe Managing recurring tasks, found in Chapter 7, Application Control. Please prepare the code and before proceeding, make the following changes to the source code:
removeSmileys()
method.taskMgr.doMethodLater(60, taskMgr.remove, "RemoveUpdate", extraArgs = ["UpdateSmileys"])
uponDeath
parameter from the call that adds the updateSmileys()
method to the task manager.Finally, check if Panda3D's bin
directory can be found in the system search path. You can do this by opening a command prompt and issuing the command ppython
. This should start an interactive Python session.
Let's take a look at the Python debugger:
src
subdirectory of your project directory.> ppython m pdb main.py
(Pdb) help
addSmiley()
method:(Pdb) tbreak Application.py:15
updateSmileys()
method and set a condition for triggering the breakpoint:(Pdb) break Application.py:27 (Pdb) condition 2 self.smileyCount > 50
(Pdb) break
(Pdb) continue
(Pdb) list
(Pdb) args
addSmiley()
method until the point from which it is going to return:(Pdb) return
smileyCount
variable:(Pdb) p self.smileyCount
(Pdb) c
(Pdb) where
(Pdb) next (Pdb) n
vel:
(Pdb) whatis vel
smileyCount
variable and continue execution:(Pdb) !self.smileyCount = 55 (Pdb) c
updateSmileys()
and let the program continue execution:(Pdb) clear 2 (Pdb) continue
The pdb debugger is actually implemented as a Python module, which we load from the library search path using the -m pdb
parameters we pass to the Python runtime. This starts up the debugger's command shell, loads our main.py
file, and pauses program execution.
We then go on to add breakpoints to our code. A breakpoint marks a line of code so the debugger halts the program when it is reached while the program is executed. While a standard breakpoint, created with the break
command, causes program execution to be stopped whenever it is hit, we add some special cases of breakpoints: A temporary and a conditional breakpoint.
Temporary breakpoints are deleted after being hit once. This is useful if you're only interested in the first iteration of a loop, for example. If you want to narrow down the cause of a bug in more detail, or want to skip loop iterations, conditional breakpoints allow the contents of variables to be examined and evaluated. Only if the expression provided evaluates to true, the program gets stopped.
Beneath breakpoints, another set of commands is dedicated to controlling how to run the program. Using next, return
, and continue
, we are able to execute step by step, to the point where the current function is about to return, or until the next breakpoint is hit.
Additionally to these commands, there's step
, which we didn't use in this recipe. This command steps the program line by line just like next
, with the exception that instead of stepping over function calls, it jumps into the body of the function being executed. This makes it possible to observe what's going on inside a function instead of just seeing the result or return value of the current call.
The last group of commonly used commands is used for gathering information about where in the code we currently are (list), how we got there (where), and the types as well as the values of variables and function parameters (whatis, p, args)
. These are the essentials for observing program state and finding problems with our code!
One additional great thing about this debugger is the possibility to execute Python code directly within the debug session. Lines beginning with an exclamation mark are directly passed to the Python runtime to be interpreted, which makes it possible to halt execution using a breakpoint, change the value of a variable or the state of an object before proceeding the execution. This can be quite useful for quickly trying fixes or finding program states that cause erroneous behavior.