Greg Aker

Debugging Python with pdb or ipdb

Filed in: Python, VideoBlobbing

April 5, 2012

Python has a wonderful debugger called pdb you should use if you aren't already. If you're like me and prefer to not use an IDE, you could have a mess of print statements as you try to debug things. If you don't know about it, you should be using pdb. It makes debugging a far nicer experience.

Here's a little script I came up with to remove odd numbers from a list.

import unittest

def remove_odd_numbers():
    my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    for item in my_list:
        if item % 2 == 1:
           my_list.remove(item)
    return my_list

class RunTests(unittest.TestCase):
    def test_remove_odd_numbers(self):
        a = remove_odd_numbers()
        for item in a:
            number = item % 2
            self.assertEqual(number, 0)

if __name__ == "__main__":
    unittest.main()

Yay, unit tests pass. What happens if I change that list to:

my_list = [0, 1, 3, 2, 4, 6, 5, 8, 7, 6, 10]

I run my unit tests and get

F
======================================================================
FAIL: test_remove_odd_numbers (__main__.RunTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test.py", line 18, in test_remove_odd_numbers
    self.assertEqual(number, 0)
AssertionError: 1 != 0

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures=1)

Well shoot. We can use pdb to trace through the code. I prefer ipdb because of the iPython shell. You can install it with pip install ipdb. Drop import ipdb; ipdb.set_trace() into that remove_odd_numbers function and step through the code.

So after seeing we took a few too many stupid pills today, the code is refactored and works.

import unittest
from copy import copy

def remove_odd_numbers():
    my_list = [0, 1, 3, 2, 4, 6, 5, 8, 7, 6, 10]

    _my_list = copy(my_list)

    for item in _my_list:
        if item % 2 == 1:
           my_list.remove(item)
    return my_list

class RunTests(unittest.TestCase):
    def test_remove_odd_numbers(self):
        a = remove_odd_numbers()
        for item in a:
            number = item % 2
            self.assertEqual(number, 0)

if __name__ == "__main__":
    unittest.main()

Here's a video showing how I stepped through to figure out what was going on.

This is just scratching the surface of what you can do with pdb and ipdb. As you get into it, check the manual (link below). It will make your programming life happier.

Further Reading

Shameless plug

Want to learn some more Python? Check out my screencasts at Mijingo.