Dot Net Mafia

Group site for developer blogs dealing with (usually) .NET, SharePoint, Office 365, Mobile Development, and other Microsoft products, as well as some discussion of general programming related concepts.

Broken has_key on GAE, using Cheetah Templates

The GAE developers have done something that seems incredibly stupid to me, but it probably won't seem to matter that much to anyone who hasn't been using Python for a while.

They've defined a has_key() method on their ORM's Model class. What it really does is check to see if the Model instance has been saved and (thus) has a completed primary key.

No big deal, right? Except the Law of Unintended Consequences shows up to bite end-users in the ass.

has_key() has an extremely long history in the Python community. It's used to see if a dictionary instance has a specific key. You pass in the key name, it returns a bool. That functionality has been in place pretty much since the Beginning of Time. The problem is, it's been deprecated. The test should now be "key_name in dictionary".

The problem really is existing library code that uses the old functionality.

The Cheetah templating engine is where I got bit.

They (very helpfully, to the graphics-type people who will actually be creating the templates) have put a lot of effort into letting people use objects seamlessly. If the engine comes across a.foo, it first checks to see if a is a dictionary-style object, and then it tries to pull a value from the "foo" key. If that fails, it tries to access the foo property of the a object.

The problem with that approach is python's duck-typing (which is usually one of the best aspects of the language). The only real way (until Python 3.0) to see if an object implements dictionary-style semantics is to check whether it implements a has_key() method. If it does, call it, passing in the specified key as a parameter.

Since GAE's models implement has_key() to take only one parameter (self), this winds up causing the following TypeError exception:

has_key() takes exactly 1 argument (2 given)

The second argument is the name of the key you're checking out. For those of you who don't know, it's one of python's warts that you have to specify "self" as the first parameter to any instance method (like specifying this as the first paramater to every C# function). That was a kludge that got added way-back-when when Guido decided this whole OOP thing might have some merit. Considering all the existing code that would have to be re-written to make it go away, this wart is probably with the language forever. After a while, as with the warts in any other language, you get used to it and just get back to writing code productively.

There are tons of work-arounds, but they're all ugly hacks (at least, I haven't run across one yet that didn't seem that way). Bug #898 is dedicated to this issue. If you've been bitten by this, (or even if you just feel my pain), please go star that (hey, all it costs you is about 30 seconds and an email when someone adds a comment). The problem is, which side is responsible for fixing the problem?

If it weren't deprecated, I'd place the burden of change squarely in google's court (it's a quick 3-line renaming refactor, except that it breaks any existing user code that calls this method...probably not much (the method should probably have been at least protected in the first place), the service is in Beta testing, and, honestly, this is just stupid on their part).

Since the method has been deprecated, it seems like the onus lies upon library writers who are using the old functionality. Except there's really no other way to tell (until python 3.0, which GAE probably won't support anytime soon) whether an object implements dictionary-style semantics or not. If you try to call "foo in bar" (the new preferred way) against something that isn't iterable, you get another TypeError exception. You can check to see if an object's iterable *and* has a has_key() method, which would fix this special case, until Google makes the Model class iterable.

To make matters worse, if the object's an iterable like something derived from list, and it implements has_key() there's a good chance the "foo in bar" test might succeed, but then trying to access the value by the given key will blow up...another one of python's warts. And has_key() doesn't seem to have been deprecated in python 2.5, which is the version GAE uses.

This just feels like the tail wagging the dog, and they're both arguing which is which.

This is also a perfect example of why it's good to work on Open Source projects. If this were Microsoft and Telerik, my reluctant molehill hack would be an insurmountable mountain that I couldn't even see. Come to think of it, this is why Stallman started the FOSS movement in the first place: he couldn't get access to a printer driver's source code so he could fix a bug.