Wednesday, September 26, 2007

Clean your code: Pylint

pylint is a tool that "analyzes Python source code looking for bugs and signs of poor quality". Now, that can mean optimizing and cleaning your code at a fairly advanced level at which, if you are a beginning programmer like me, you will not get much out of.

However, it can help with lots of small checking too, and improve the form of your Python code in a quick and convenient manner. It will show you problems you might not even know were problems! I have not gotten into too many of the features myself, but some quick examples should show you its utility. Getting it is pretty simple. On Ubuntu for example, installing is only a matter of sudo apt-get install pylint. To run it, just do pylint YOURAPP.py.

It can take a little while to run, and then it spits out several blocks of results. Some examples:
  • C: 68: Line too long (154/80)
    • One of the lines in the file has way too many characters. It is recommended to keep each line at 79 characters or less. To learn why, check out PEP 8, under "Code Lay-out", "Maximum Line Length".
  • C: 5: Operator not preceded by a space
    __version__="0.1"
  • W: 40:Frame.__init__: Unused variable 'statusbar'
    • No need for this variable anymore, just taking up space.
  • C: 93:App.OnInit: Invalid name "OnInit" (should match [a-z_][a-z0-9_]{2,30}$)
As can be seen from these examples, the alerts are pretty easy to read. pylint also shows you how many lines are duplicated, metrics such as how many lines of code versus docstrings, how many modules, and more. In the end, it gives your code an overall score. If you fix some errors and re-run it, it will show you your current and previous scores.

To start using the more advanced features, peruse the man page. Now, go clean your code.

Monday, September 24, 2007

Tips: Toolbar icons in wxPython

I have started playing around with wxPython, a great toolkit for making clean, cross-platform, flexible GUIs in Python. While there are a lot of great tutorials out there on how to get started making apps with wxPython, having The Book has been a definite boon.

While going through the basic exercises and starting to make my own GUIs, I kept running into an issue that got more and more annoying: toolbar icons. I wanted to have a toolbar, with some basic icons, for actions like New, Open, etc. In the book, Rappin and Dunn give an example of using toolbar icons (p49). The pertinent part:
import wx
import images
[SNIP]
toolbar = self.CreateToolbar()
toolbar.AddSimpleTool(wx.NewId(), images.getNewBitMap(), "New", "Long help for 'new'")
toolbar.Realize()
This in no way works. When I ran it on Ubuntu (7.04), I got:

ImportError: No module named images

After some Googling, I found this is a common problem for beginners. Lots of related example code will be similar to the above, but specify something like "stock_new.png" for the image. To get all these to work, you actually need to download some images, and specify those. Seems obvious after the fact, but it seemed quite possible to me starting out there there would be a built-in facility to grab OS-specific icons for basic tasks such as New and Load.

A great source of good-looking free icons for desktop applications is the Tango Desktop Project. Sometimes that page is down or takes a very long time to load. If so, you can download the .zip on this page. Every icon you will likely want for a toolbar may be found in "actions", once you extract the Tango folder and select an icon size to use. I found it helpful to place the icons I wanted in a "resources" folder in the folder holding my application, and use them with code such as:
    toolbar = self.CreateToolBar()
toolbar.AddSimpleTool(wx.NewId(), wx.Image('resources/document-new.png',
wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'New', 'Long help for New')
toolbar.AddSimpleTool(wx.NewId(), wx.Image('resources/document-open.png',
wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Open', 'Long help for Open')
toolbar.AddSimpleTool(wx.NewId(), wx.Image('resources/document-save.png',
wx.BITMAP_TYPE_PNG).ConvertToBitmap(), 'Save', 'Long help for Save')
toolbar.Realize()
That will result in something like the following (Menubar added for positional context):