Tuesday, January 20, 2009

Hypy 0.8.2 released

A minor version release of Hypy.  No material bugs reported so far.  That's good for my users, but bad for me because I can't do more releases until bugs get reported for me to fix. :-)

Some people would not have been able to easy_install release 0.8.1, so this release fixes that.

Hypy is a fulltext search interface for Python applications.

Homepage, downloads, everything: http://goonmill.org/hypy/

Release Version 0.8.2 (2009-01-20)
  • I was unconditionally importing ez_setup in my setup.py and that makes it hard to easy_install.  Don't do that.
  • No library functionality change, but now more users can install it.

Tuesday, January 06, 2009

On demonstrating the value of unit tests to beginners

A little anecdote.  I'm slowly trying to get my team to wrap their heads around the idea that any new feature must be accompanied by unit tests as we near the point where they are absolutely required to write unit tests before they write code and the tests become part of the deliverable.  One thing I know is that if you haven't written a lot of unit tests yet, you don't really understand the value of them except very much in the abstract, so I am also trying to point out the value to him as we go.

One of my developers is writing a function that uses the compiler module to inspect some Python code, it's not really important why.  He had just learned how to write some unit tests in Javascript and I was teaching him how to use the stdlib unittest module for his unit tests written in Python.   His implementation isn't written yet, he is just starting to figure out what the interfaces look like, which is a great time to start writing failing tests.

I told him, start with this:

import unittest

class MyTestCase(unittest.TestCase):
  def test_myParseFunction(self):
    assert 0

.. and run that test, which he did, and it failed, and I said "good".  I started pointing out to him ways he could make very minor modifications to his code to make it easier to test (not nearly enough has been written on the subject of making code easier to test, BTW--bloggers, get on it!).

One of the improvements I asked him to make was to move some functions into another, more relevant module than the one he was working in.  He did that, then wrote version two of the unit test:

import unittest
import mynewmodule

class MyTestCase(unittest.TestCase):
  def test_myParseFunction(self):
    self.assertEqual(mynewmodule.myParseFunction("(python.code)"), [expected, output, structure])

Now, remember that he hasn't implemented myParseFunction yet.  So I asked him to run his failing test one more time.  And, a surprise to both of us, we got this:

[ERROR]: test_mymodule.MyTestCase.test_myParseFunction

Traceback (most recent call last):
  File "/usr/lib/python2.5/unittest.py", line 260, in run
  File ".../test_mymodule.py", line 7, in test_myParseFunction
    self.assertEqual(mynewmodule.myParseFunction("(python.code)"), [expected, output, structure])
  File ".../mynewmodule.py", line 19, in myParseFunction
    return compiler.parse(s)
exceptions.NameError: global name 'compiler' is not defined

What the.. oh right!  He imported compiler in the original module, but forgot to move it to the new module.  The unit test - so far, one line long and expected to fail in a relatively uninteresting way, had already found a bug.  My favorite part was that it happened this way to someone learning why we put so much value on unit tests.