Spot any errors? let me know, but Unleash your pedant politely please.

Monday, 18 May 2009

Example of an exception class in Python

If I'm going to suggest that you define your own exceptions, I really ought to give an example:

class PlayerError(Exception):
    pass

class PlayerIsNotPlayingInExpectedDirectionError(PlayerError):
    def __init__(self, direction):
        """direction parameter should be 'forwards' or 'in reverse'"""
        if 'rev' in direction : direction = 'in reverse'
        self.direction = direction

    def __str__(self):
        return "Player was not playing %s as expected." % self.direction

Define and raise exceptions liberally.

It does the job, but this doesn't really feel like it's enough:

  if not playerIsPlayingForwards():
      raise "Player is not playing forwards'

I'm using this structure instead, liberally raising my own verbose exceptions :

  try:
      assert playerIsPlayingForwards():
  except AssertionError:
      raise PlayerIsNotPlayingInExpectedDirectionError('Forwards')

It takes a bit more time, but it's worth it. You get it back in debug time saved. You also get a nice warm fuzzy feeling when one of your explicit exceptions gets raised, highlighting a very specific problem.

Finding the name of the current function in Python. nameOfThisFunction()

As part of my testing, I need to create logs that give me some traceability for when things go wrong, evidence of testing whatever the result. Kind of like permanent debug text. I'll look at differences between log files of the same tests run on previous and new versions. It's ad-hoc testing when it's first written and it's regression testing thereafter.

One of the ways to show trace is simply to show which methods/functions are being called. Being lazy, I simply want to cut and paste something, I don't want to also have to change it. I would prefer to use the actual function name rather than hard coding into a string for printing / logging. The name might change in the future. I might forget to alter the name after pasting it.

This is what I don't want:

def testStepA(param):
    writeToLogFile('Reached function 'testStepA')
    ...

def testStepB(param):
    writeToLogFile('Reached function 'testStepB')
    ...

I want something like this instead:

def testStepA(param):
    writeToLogFile('Reached function '%s', nameOfThisFunction())
    ...

def testStepB(param):
    writeToLogFile('Reached function '%s', nameOfThisFunction())
    ...

Fortunately, inspect gives me the information I'm after:

import inspect

def nameOfThisFunction (offset=0):
    return inspect.stack()[1 + offset][3]

Handling exceptions and printing a useful trace in Python

In writing a test harness for functional automated testing, I'm expecting things to fail. In writing some of the tests, I'm trying to get things to fail, poking around the boundaries etc. WhenI have a test suite that takes 50 hours to run, that I kick off on a Friday night, what I don't want is for it to stop running five minutes after I leave the office.

I want it to carry on with the rest of the tests, but I also want some information about these failures. What exceptions were raised and where they were raised. This is how I'm doing it:

import sys
import traceback

try:
    myTestCase.executeTestSteps()
except:
    # handle and log exceptions
    exctype, value, trace = sys.exc_info()[:3]
    extracted_tb = traceback.extract_tb(trace)
    printAndLog("**********************');
    printAndLog(str(exctype) + ':' + str(value))
    for tb_line in extracted_tb:
        printAndLog(str(tb_line[0]) + 'line ' + str(tb_line[1]) + ' in ' + str(tb_line[2]) + ' (' + str(tb_line[3]) + ')')
    printAndLog("**********************');

    del trace

( Where myTestCase is the thing I want to run and printAndLog (you'll have to roll your own) sends to the console and to a log file)

Profit per head. Tech stock

The $210K profit per head at Google figures are interesting (as John Gruber points out).

Apple's not known for talking small profits and Microsoft pride take pride associating themselves with cheap so what's going on here ?

I have a few initial thoughts…

1 - Microsoft doesn't have stores. Although the Apple stores must bring in lot of revenue, they're also a massive overhead.

2 - Apple isn't in enterprise, and this is where Microsoft gets its profit. Money for old rope with Office and Exchange and Windows volume licenses.

3 - The data is based on 'employees', but that's not the same as staff. It probably excludes contract staff. Those companies using lots of contractors might be showing artificially high numbers using this measurement. I've no idea whether Microsoft, Google or Apple uses a lot of contact staff (I suspect not), but I bet a few of the companies listed do.

Sunday, 17 May 2009

Python: count of parameters in a function

I recently had a problem with a that class had several ways to populate one of its instance variables. An instance method was called in each case, either with a parameter, (using the method provided by the class), or without a parameter, (in the case of the same method overridden in a subclass). I've since realised that there was a simpler/better way to achieve this, but no matter, Python allowed me to figure out which one to call by being able to count the parameters in the method, and then call

import inspect

def parametersInMethod(method):
    return len(inspect.getargspec(method)[0])

Allowed me to do this...

if parametersInMethod(self.populateInstanceVariable) == 0:
    self.populateInstanceVariable()
else:
    self.populateInstanceVariable(withValue)

This give a little insight into 'inspect' and also shows how methods being objects allow them to be passed as parameters into functions.

Saturday, 9 May 2009

More on Python and a bit on Objective C

I can't quite put my finger on it, possibly because I've not used ObjC in anger yet, but it seems to have a similar ethos to Python. I'm probably going to ignore ObjC for a while longer, but I may dabble with PyObjC instead. Learn some Cocoa through the increasingly familiar Python, then apply that knowledge to an ObjC project.

What I love about Python so far is that just trying things seems to usually just work. It's a language that does what you want it to. It's a little dangerous, because so much is checked and can be manipulated at runtime. It's the least nanny-ish language I've come across, trusting the programmer to do the right thing and allowing the programmer to break convention when it is appropriate. It's counter-intuitive, perhaps, but the responsibility given to the programmer seems to lead to responsible programming. Treat me like an adult and I will behave like an adult kind of thing.