Wed 26 Jan 2011
PyChecker is a cool tool for checking Python scripts for bugs. It works with Python 2.0 – 2.7. In this article, we will write some crappy code to see what PyChecker can pick up on. Then we’ll improve the code according to what we find until the code checks out. According to PyChecker’s website, it can detect the following problems:
- No global found (e.g., using a module without importing it)
- Passing the wrong number of parameters to functions/methods/constructors
- Passing the wrong number of parameters to builtin functions & methods
- Using format strings that don’t match arguments
- Using class methods and attributes that don’t exist
- Changing signature when overriding a method
- Redefining a function/class/method in the same scope
- Using a variable before setting it
- self is not the first parameter defined for a method
- Unused globals and locals (module or variable)
- Unused function/method arguments (can ignore self)
- No doc strings in modules, classes, functions, and methods
We won’t test everything that it can detect, but we can make some pretty messy code for PyChecker to check. Let’s start coding!
import sys ######################################################################## class CarClass: """""" #---------------------------------------------------------------------- def __init__(self, color, make, model, year): """Constructor""" self.color = color self.make = make self.model = model self.year = year if "Windows" in platform.platform(): print "You're using Windows!" self.weight = self.getWeight(1, 2, 3) #---------------------------------------------------------------------- def getWeight(this): """""" return "2000 lbs"
This code doesn’t really do much of anything and is only for illustration purposes. According to PyChecker, there are four problems with this code. Can you see the issues? If not, then let’s find out how to use PyChecker to expose them! Once you have installed PyChecker and put it on your path (see PyChecker’s documentation), you should be able to do the following command:
C:\Users\Mike\Documents\My Dropbox\Scripts\code analysis>pychecker bad.py
Note: The above only works if you have pychecker on your system path on Windows. Technically, on Windows you will be using pychecker.bat
If you do this, you’ll end up with something like the following:
Hopefully you can tell what that all means, but we’ll break it down just in case you don’t. There are four problems that it has identified. The first issue it found is that we import the sys module, but we don’t use it. The second issue is the opposite of the first. We refer to the platform module, but it’s not actually imported! Thirdly, we call our getWeight method and it reports that we passed it too many parameters. I think PyChecker may have a bug here as our method should accept one method, not zero. The “this” parameter must confuse PyChecker. Fortunately, the last problem it finds is that getWeight doesn’t have self as the first parameter. This kind of rectifies the bug I mentioned. While the first method doesn’t require us to name it “self”, that is the normal naming convention for the first parameter in a class method.
PyChecker doesn’t just work on the command line. You can also use it directly in your code! All you have to do is import PyChecker at the top of your module, like this:
This will make PyChecker check all the following imported modules, although it won’t do the main module. What does that mean? It means that if you stick that line in the example we used, you won’t see any errors related to that code. The PyChecker documentation says that you can also set PyChecker’s option via os.environ. Here’s an example:
os.environ['PYCHECKER'] = 'command line options here'
Speaking of which, here are the common command line options:
|--only||only warn about files passed on the command line||no|
|-#, --limit||the maximum number of warnings to be displayed||10|
|--no-shadowbuiltin||check if a variable shadows a builtin||off|
|-q, --stdlib||ignore warnings from files under standard library||off|
|-T, --argsused||unused method/function arguments||on|
If you’d like a full list of commands, type the following: pychecker -h
NOTE: PyChecker’s docstring checking is off by default, so if you want it you need to pass the “-m -f” commands. This only found the class module’s empty docstring. There seems to be a minor bug with “-f” in which it thinks empty doc strings are ok. I have alerted the PyChecker team to that.
I think PyChecker is pretty cool and it looks like it could be a handy tool. Give it a try and see what you think!