Python DevCenter
oreilly.comSafari Books Online.Conferences.

advertisement


Interactive Debugging in Python
Pages: 1, 2, 3, 4, 5, 6, 7

This greeted me with a friendly debugger prompt. What next? I always like to know where I am, so doing a list is a good start:

(Pdb) l
 30             except:
 31                 #if we hit an exception, we can rely on tmp_dict 
                    being a backup to the point of the exception
 32                 return self.tmp_dict
 33
 34     def main():
 35  ->     ctd = ConvertToDict()
 36         for line in file(sys.argv[1]):
 37             line = line.strip()
 38             print "*" * 40
 39             print "line>>", line
 40             print ctd.get_number_dict(line)

At this point, I could either step through the file a line at a time and examine everything, or formulate a hypothesis and try to prove or disprove it. Formulating a hypothesis also helps to rule out some obvious dead ends. I thought about things I could rule out:

  • get_number_dict() is not corrupting the input string because it is passing it straight to walk_string().
  • The input data looked fine. All four lines were white space-separated integers.

What could it be? The problem appears to be happening on either line 1 or 2 and causing problems as far as line 3 of the input file. I wondered about things I might not have watched for:

  • Maybe I wasn't resetting tmp_dict and/or return_dict properly.
  • Maybe I wasn't walking over the input data properly.
  • Maybe I wasn't handling all exceptions properly.

I decided to set break points at lines 14 (the first line of code in the walk_string() method) and 18 (the first line of code after the for loop in the walk_string() method), run through execution of the script once while inspecting variables, and watch for anomalies.

(Pdb) b 14
Breakpoint 1 at /home/jmjones/debugger/example_debugger.py:14
(Pdb) b 18
Breakpoint 2 at /home/jmjones/debugger/example_debugger.py:18
(Pdb) c
****************************************
line>> 1 2 3 4 5 6 7 8 9 10
> /home/jmjones/svn/home/debugger/example_debugger.py(14)walk_string()
-> l = string.split(some_string)

To get my bearings, I listed where I was:

(Pdb) l
  9             self.tmp_dict = {}
 10             self.return_dict = {}
 11         def walk_string(self, some_string):
 12             '''walk given text string and return a dictionary.
 13             Maintain state in instance attributes in case
                we hit an exception'''
 14 B->         l = string.split(some_string)
 15             for i in range(len(l)):
 16                 key = str(i)
 17                 self.tmp_dict[key] = int(l[i])
 18 B           return_dict = self.tmp_dict
 19             self.return_dict = self.tmp_dict

You can see I was at line 14, and you can also see the break points at lines 14 and 18. Just out of paranoia, I checked what was in some_string, even though that printed out after the continue command:

(Pdb) print some_string
1 2 3 4 5 6 7 8 9 10

The continue command dropped me down to the next break point, at line 18:

(Pdb) c
> /home/jmjones/svn/articles/debugger/example_debugger.py(18)walk_string()
-> return_dict = self.tmp_dict

At this point, self.tmp_dict has everything in it that it is going to have:

(Pdb) print self.tmp_dict
{'1': 2, '0': 1, '3': 4, '2': 3, '5': 6, '4': 5, '7': 8, '6': 7, '9': \
    10, '8': 9}

This looked good. I continued and printed out the next input line:

(Pdb) c
{'1': 2, '0': 1, '3': 4, '2': 3, '5': 6, '4': 5, '7': 8, '6': 7, '9': \
    10, '8': 9}
****************************************
****************************************
line>> 1 2 3 4 5 6 7 8 9 10
> /home/jmjones/svn/articles/debugger/example_debugger.py(14)walk_string()
-> l = string.split(some_string)
(Pdb) print some_string
1 2 3 4 5 6 7 8 9 10

The input line looked fine. I continued further, knowing that the debugger should stop at the break point set at line 18. Then I could run through a couple of diagnostics and see whether everything looked OK:

(Pdb) c
{'1': 2, '0': 1, '3': 4, '2': 3, '5': 6, '4': 5, '7': 8, '6': 7}
****************************************
****************************************
line>> 1 2 3 4
> /home/jmjones/svn/articles/debugger/example_debugger.py(14)walk_string()
-> l = string.split(some_string)

Huh? It dropped me back to line 14 rather than on 18, and I was on the next data input line. This means that the interpreter returned before it hit line 18, so it did not fully process the second line of data from the data file. I just found where the problem was, but not what was causing it. I had to run through it again, a little more carefully this time, in order to figure it out. Fortunately, I could extract a little information from this run to help out with the next run.

If walk_string() returned before it hit line 18, it could not have done a proper reset(). What did self.return_dict and self.tmp_dict contain just then?

(Pdb) print self.return_dict
{}
(Pdb) print self.tmp_dict
{'1': 2, '0': 1, '3': 4, '2': 3, '5': 6, '4': 5, '7': 8, '6': 7}

That's why the program had too much information in the return dictionary for data line 3; it carried the dictionary self.tmp_dict with it from the data line that went bad. I felt pretty confident that the problem occurred between lines 14 and 18 when processing line 2 of the data file. I just didn't know why--yet.

Pages: 1, 2, 3, 4, 5, 6, 7

Next Pagearrow





Sponsored by: