Bug hunting with PDB

So, let's simply run the program. We have three tests that we expect to run, and since this is a relatively simple program we expect it run very quickly:

$ python palindrome.py

Instead of running quickly, we see that this program seems to run forever! And if you look at its memory usage, you'll also see that it grows in size the longer it runs. Clearly something is wrong, so let's use Ctrl+C to kill the program.

Let's use PDB to try to understand what's going on here. Since we don't know where our problem might lie, we don't know where to put a set_trace() call. So we're going to instead start the program under the control of PDB using a command-line invocation:

$ python -m pdb palindrome.py
> /Users/sixty_north/examples/palindrome.py(1)<module>()
-> import unittest
(Pdb)

Here we're using the -m argument which tells Python to execute the specific module – in this case PDB – as a script. The remaining arguments are passed to that script. So here we're telling Python to execute the PDB module as a script, and we're passing the name of our broken file to it.

What we're seeing is that we're immediately taken to a PDB prompt. The arrow pointing to import unittest is telling us that this is the next statement that will be executed when we continue. But where is that statement?

Let's use the where command to find out:

(Pdb) where
/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/bdb.py(387)run()
-> exec cmd in globals, locals
<string>(1)<module>()
> /Users/sixty_north/examples/palindrome.py(1)<module>()
-> import unittest

The where command reports our current call stack, with the most recent frames at the bottom, and we can see that PDB has paused execution at the very first line of palindrome.py. This reinforces an important aspect of Python execution which we've discussed before: everything is evaluated at runtime. In this case, we've paused execution right before an import statement.

We can execute this import by running to the next statement using the next command:

(Pdb) next
> /Users/sixty_north/examples/palindrome.py(3)<module>()
-> def digits(x):
(Pdb)

We see that this takes us to the def call for the digits() function. When we execute another next, we move to the definition of the is_palindrome() function:

(Pdb) next
> /Users/sixty_north/examples/palindrome.py(12)<module>()
-> def is_palindrome(x):
(Pdb)

 

You may be wondering why the debugger didn't step into the body of digits. After all, isn't it evaluated at runtime like everything else? The answer is that the body of the function can only be evaluated when there are arguments supplied to it, so it will be run only when the function is called. The bodies of functions are checked for proper syntax when they're imported, but PDB doesn't let us debug that part of the process.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset