At some point in their career, most programmers realize that their job title should be "senior debugger" instead of senior developer. Debugging is the art of getting your code to run as you intended, instead of running as you wrote it. That is the nub, really—in most cases it's your code that is wrong. Python itself is pretty flawless — there are hardly any noticeable bugs left. The same goes for Qt. PyQt might still have a few bugs in it, but you would have to be using decidedly advanced features to stumble onto them. In most cases, your own ‘undocumented features' will be your undoing.
In this chapter we'll use the debugger included in BlackAdder to find bugs in some simple scripts. If you don't understand the actual code yet, don't worry — you can always come back later. The main goal is to familiarize yourself with the BlackAdder environment and the concept of debugging.
There are two basic methods of debugging. The first is sprinkling your code with print statements that dump the contents of the variables of your application. The second method is to follow your application as it executes using a good debugger, examining the application data using the tools the debugger provides.
Python has always been possessed of a basic command-line based debugger, pdb, similar to the infamous Unix debuggers, dbx and gdb. If you've ever tried to actually trace an application using one of these, you'll know the exact meaning of the word ‘inconvenient'. Using them is on a par with using ed or edlin — both line editors — for editing code.
To show a session with pdb:
Python 2.1.1 (#1, Aug 11 2001, 20:14:53) [GCC 2.95.2 19991024 (release)] on linux2 Type "copyright", "credits" or "license" for more information. >>> import pdb >>> import button >>> pdb.run("button.main()") > /home/boudewijn/doc/pyqt/ch23/<string>(0)?() (Pdb) continue > /home/boudewijn/doc/pyqt/ch23/<string>(1)?() (Pdb) continue Traceback (most recent call last): File "button.py", line 26, in slotSlot i = 1/0 ZeroDivisionError: integer division or modulo by zero --Return-- > /home/boudewijn/doc/pyqt/ch23/<string>(1)?()->None (Pdb) w > /home/boudewijn/doc/pyqt/ch23/<string>(1)?()->None (Pdb) l [EOF] (Pdb) q >>>
You can see why there have been many attempts to create a useful GUI fronted to pdb. Most have suffered from the fact that they don't know where to stop debugging. If you are debugging a piece of code that contains the statement string.join(), you probably don't want to single-step into the string.py module, which is part of the Python system library—and yet this is exactly what happens very often.
BlackAdder includes a very nice debugger, one that knows where to stop debugging. It includes all the usual facilities, like single-stepping, breakpoints and a watch panel for variable values.
Currently missing features include conditional breakpoints (a breakpoint that only breaks execution on certain values for certain variables) and runtime code changes. You can change variable values runtime using the Python interpreter window, though.
The BlackAdder debugger.
The PyQt library includes another, simpler debugger, called eric. This application is no longer maintained, so I won't spend much time here describing the way it works. It does, however, provide a very nice example of using regular expressions and PyQt's QCanvas widget. You can start eric by typing eric on the command-line.
Eric, the debugger included in PyQt.
The BlackAdder toolbar has two buttons for debugging your code. You can either debug a single script, or the whole project.
The script execution toolbar. From left to right: run script, run project, debug script, debug project, restart debugger, continue, single step, set breakpoint, clear breakpoint and cancel debugging.
One thing to be aware of when running scripts or projects from BlackAdder is that everything you print or write to standard error or standard output gets lost, unless you have the Python interpreter window active. Eric also prints the output to the Python shell window.