Thursday, 23 July 2009

PyDev, PyLint and Refactoring

I've been using PyDev the Eclipse plugin for Python for some time now and it's certainly improving with each new release (I'm currently on 1.4.2). There are a couple of features I've been getting some benefit from recently.

With PyLint, I actually broke my Eclipse set-up for this a while ago but when I got it reinstated it's reminded me of how useful it is. One thing I hate about about interpreted languages is the huge scope for runtime errors. The PyLint plugin gives immediate feedback in the margin of the editor window with error information and hints. This is saving me a lot of time down the line. What's the metric for time spent fixing a bug immediately vs. at the other end of the scale trying to pick through code on a production deployment? :) Picking up references to undeclared variables is particularly useful. Especially in error blocks or places where test coverage might miss out. There's no doubt some messages can be annoying and getting a mark out of 10 for your code might not appeal to all. Fortunately, you can edit the settings for the Pylint command line that's executed and explicitly filter out warnings you don't like. The second feature I've revisited is the PyDev refactoring options. I have had a low expectation of these perhaps unfairly but there a couple of potential time savers. Take this simple class:


class MyTest(object):
def doSomething(self):
self.__a = None
self.__b = None
self.__c = []
Left like this PyLint will warn me that I haven't set up these attributes in an __init__ method. ;) PyDev refactoring to the rescue :) ... If I now right click in the editor and pick "Refactoring" -> "Generate Constructor using Fields ...". I'm taken through a series of steps in a dialog. I can get,

class MyTest(object):
def __init__(self, a, b, c):
self.__a = a
self.__b = b
self.__c = c

def doSomething(self):
self.__a = None
self.__b = None
self.__c = []


Not that exciting but could save some typing. More useful for me is the "Generate Properties..." to generate properties for new style classes together with their getters and setters:


class MyTest(object):
def __init__(self, a, b, c):
self.__a = a
self.__b = b
self.__c = c

def getA(self):
return self.__a

def getB(self):
return self.__b

def getC(self):
return self.__c

def setA(self, value):
self.__a = value

def setB(self, value):
self.__b = value

def setC(self, value):
self.__c = value

def delA(self):
del self.__a

def delB(self):
del self.__b

def delC(self):
del self.__c

def doSomething(self):
self.__a = None
self.__b = None
self.__c = []

a = property(getA, setA, delA, "A's Docstring")

b = property(getB, setB, delB, "B's Docstring")

c = property(getC, setC, delC, "C's Docstring")

It could be improved on - there's no explicit keywords inputs for property() - but it could save some time with the boiler plate. :)