String comparison function in Python (alpha)

December 22, 2007
7 comments Python

I was working on a unittest which when it failed would say "this string != that string" and because some of these strings were very long (output of a HTML lib I wrote which spits out snippets of HTML code) it became hard to spot how they were different. So I decided to override the usual self.assertEqual(str1, str2) in Python's unittest class instance with this little baby:


def assertEqualLongString(a, b):
   NOT, POINT = '-', '*'
   if a != b:
       print a
       o = ''
       for i, e in enumerate(a):
           try:
               if e != b[i]:
                   o += POINT
               else:
                   o += NOT
           except IndexError:
               o += '*'

       o += NOT * (len(a)-len(o))
       if len(b) > len(a):
           o += POINT* (len(b)-len(a))

       print o
       print b

       raise AssertionError, '(see string comparison above)'

It's far from perfect and doesn't really work when you've got Unicode characters that the terminal you use can't print properly. It might not look great on strings that are really really long but I'm sure that's something that can be solved too. After all, this is just a quick hack that helped me spot that the difference between one snippet and another was that one produced <br/> and the other produced <br />. Below are some examples of this utility function in action.

Truncated! Read the rest by clicking the link below.

isArithmeticExpression() in Javascript

December 19, 2007
0 comments JavaScript

Following from some work that I blogged about two days ago (Calculator in Python for dummies) I've now extended the functionality thinking into the AJAX scripts that sit on top of this Python server-side functionality. How this was implemented is boring but the following function helped me a lot. Here's the code with a very basic unit test after:


function isArithmeticExpression(s) {
  return /[\d]\s*\+\s*[\d]|[\d]\s*\-\s*[\d]|[\d]\s*\/\s*[\d]|[\d]\s*\*\s*[\d]|[\d]\s*\^\s*[\d]/.test(s) &amp;&amp;
        s.split(/\)/).length == s.split(/\(/).length &amp;&amp;
        !/[A-Za-z_]/.test(s);
}

function assert(fact) {
  if (!fact) alert("Assert failure!");
}
assert(isArithmeticExpression('') == false);
assert(isArithmeticExpression('++123') == false);
assert(isArithmeticExpression('+123') == false);
assert(isArithmeticExpression('2+123') == true);
assert(isArithmeticExpression('2 + 123') == true);
assert(isArithmeticExpression('2 + - 123') == false);
assert(isArithmeticExpression('2 + 123') == true);
assert(isArithmeticExpression('(2 + 123)') == true);
assert(isArithmeticExpression('2^6') == true);
assert(isArithmeticExpression('(2+1))^6') == false);
assert(isArithmeticExpression('a+123') == false);
assert(isArithmeticExpression('1a1+2x3') == false);

Basically, it returns true if the string appears to contain only numbers and one of the expected operators +, -, *, / or ^ in between two numbers.

It's far from perfect. I can think of cases where it will actually fail. But those cases are very rare and are too unlikely to happy and cause a major problem in this application and I'd rather get on with it than to spend any more time on this. After all, this is just a Javascript that tries to help if it can. The server-side code needs to "perfect" and if someone enters a weird expression, the server-side error handling will at least pick it up.

Calculator in Python for dummies

December 17, 2007
17 comments Python

I need a mini calculator in my web app so that people can enter basic mathematical expressions instead of having to work it out themselfs and then enter the result in the input box. I want them to be able to enter "3*2" or "110/3" without having to do the math first. I want this to work like a pocket calculator such that 110/3 returns a 36.6666666667 and not 36 like pure Python arithmetic would. Here's the solution which works but works like Python:


def safe_eval(expr, symbols={}):
   return eval(expr, dict(__builtins__=None), symbols)

def calc(expr):
   return safe_eval(expr, vars(math))

assert calc('3*2')==6
assert calc('12.12 + 3.75 - 10*0.5')==10.87
assert calc('110/3')==36

Truncated! Read the rest by clicking the link below.

T-Mobile MMS collection

December 14, 2007
1 comment Web development

F**ing great! I received an MMS from my dad in Sweden and I can't open it on either my T-Mobile branded Nokia or on my Firefox. First of all, why is it still not possible to receive MMSes from different countries? Secondly, if you receive an SMS from T-Mobile with a web link (and a password) wouldn't you expect that web page to work on mobile phones?

When you open it you get this Javascript popup warning: Nice!

T-Mobile MMS collection

When I later tried it instead with my Firefox web browser (under Linux) the interface for reading your received MMS messages is awful and done in frames and then it turns out that the bloody video format is Quicktime which is a crap proprietary format which doesn't work on Linux (unless you hack around).

Thanks a lot T-Mobile! :(

WSSE Authentication and Apache

December 13, 2007
1 comment Python

I recently wrote a Grok application that implements a REST API for Atom Publishing so that I can connect a website I have via my new Nokia phone has LifeBlog which uses the Atom API to talk to the server.

Anyway, the authentication on Atom is WSSE (good introduction article) which basically works like this:


PasswordDigest = Base64 \ (SHA1 (Nonce + CreationTimestamp + Password))

This is one of the pieces in a request header called Authorization which can look something like this:


Authorization: WSSE profile="UsernameToken"
X-WSSE: UsernameToken Username="bob", PasswordDigest="quR/EWLAV4xLf9Zqyw4pDmfV9OY=", 
Nonce="d36e316282959a9ed4c89851497a717f", Created="2003-12-15T14:43:07Z"

What I did was I wrote a simple Python script to mimic what the Nokia does but from a script. The script creates a password digest using these python modules: sha, binascii and base64 and then fires off a POST request. Here's thing, if you generate this header with base64.encodestring(ascii_string) you get something like this:


quR/EWLAV4xLf9Zqyw4pDmfV9OY=\n

Notice the extra newline character at the end of the base64 encoded string. This is perfectly valid and is decoded easily with base64.decodestring(base64_string) by the Grok app. Everything was working fine when I tried posting to http://localhost:8080/++rest++atompub/snapatom and my application successfully authenticated the dummy user. I was happy.

Then I set this up properly on atom.someotherdomain.com which was managed by Apache who internally rewrote the URL to a Grok on localhost:8080. The problem now was that the Authentication header value was broken into two lines because of the newline character and then the whole request was rejected by Apache because some header values came without a : semi-colon.

The solution was to not use base64.encodestring() and base64.decodestring() but to instead use base64.urlsafe_b64encode() and base64.urlsafe_b64decode(). Let me show you:


>>> import base64
>>> x = 'Peter'
>>> base64.encodestring(x)
'UGV0ZXI=\n'
>>> base64.urlsafe_b64encode(x)
'UGV0ZXI='
>>> base64.decodestring(base64.urlsafe_b64encode(x))
'Peter'

If you're still reading, then hopefully you won't make the same mistake as I did and wasting time on trying to debug Apache. The lesson learned from this is to use the URL safe base64 header values and not the usual ones.

geopy distance calculation pitfall

December 10, 2007
1 comment Python

Geopy is a great little Python library for working with geocoding and distances using various online services such as Google's geocoder API.

Today I spent nearly half an hour trying to debug what was going on with my web application since I was getting this strange error:


AttributeError: 'VincentyDistance' object has no attribute '_kilometers'

Truncated! Read the rest by clicking the link below.

Kill Ugly Radio - A Frank Zappa blog

December 6, 2007
0 comments Misc. links

Kill Ugly Radio - A Frank Zappa blog I haven't fully explored this site yet but it looks great. Some sort of blog about themed around Frank Zappa.

This site has got a great discography and lots of other misc stuff that looks worthy of some decent reading time. I also very much like the name which I guess you have to be a Zappa fan to appreciate.

Photos from Fuzhou 2007

November 28, 2007
0 comments Photos

Photos from Fuzhou 2007 I've now uploaded the photos from my latest holiday i Fuzhou, China.

Most of the photos are of kung fu training and that's because I didn't want to distance myself from the holiday too much by constantly being the the photographer. When we went training I lent the camera to our translator who at times got bored whilst we were just training and she loved to snap.

Basically, Chris and I had the great opportunity to learn the first form of Calling Crane by Master Ruan Dong and the first form of Dog Style by Master Hu Chen Wu both resident in Fuzhou in the Fujian province in the south-east of China.

Futurama is back!

November 27, 2007
0 comments Misc. links

Futurama is back! I wouldn't call myself a diehard fan of Futurama but I sure as h**l love that show.

"Futurama was killed, but like some B-movie cyborg it refused to stay dead. The fans watched the 72 episodes religiously in syndication and shelled out $170 to get the entire run on DVD. So, in 2005, Fox green-lighted 16 new episodes. Cohen and Groening have reassembled many of the hundreds of writers, animators, and voice artists who'd gone on to other projects to create four DVDs of new material, including sexy robot stage shows. The first DVD hits stores on November 27, and the features will then be divided into half-hour episodes when the entire run of the series begins airing on Comedy Central next year."

I'm actually re-watching all of the previous 5 series at the moment at home and hopefully by the time I've watched it all, the new series will start to become available on DVD here in the UK (unlikely but one can hope).

Note to self about Jeditable

November 22, 2007
0 comments JavaScript

I've been struggling hard this morning to get Jeditable to work in IE (6 and 7). Whilst everything was working perfectly fine in Firefox, in IE the clickable editable text would just disappear and never return. The solution was to use the latest jQuery 1.2.1. I was using version 1.1.4 which was why it didn't work.

Jeditable is a brilliant plugin with really good configuration options (hint read the source code's documentation comment) and I'll now send an email to Mika about this pitfall and suggest that he includes it in his documentation.