Armed with a text editor

mu's views on program and recipe! design

pyxyz.require('sense') Posted 2006.01.18 20:36 PST (#)

I'm a big fan of high level programming libraries, and of particular relevance is pygtk. Some time ago in the dark ages of GTK+ 1.x, you would merely import gtk and all was well. Then GTK+ 2.0 was released and pygtk moved to support it. In order to support side-by-side installability (like the C libraries beneath) they decided to do the following.

They created a helper package called pygtk. The purpose of this package was to manipulate the python library paths such that a subsequent import gtk pulled in the desired package. On the surface this seems like an okay idea. It lets the python continue to use the name gtk. It lets a user have applications that need pygtk 1.x and ones that need 2.x installed and running side by side.

What is lost in this trade for side-by-side support? Elegance. What is gained? Subtle bugs. First the subtle bug: skipping the pygtk helper often works. In particular if you're on a machine with only the 2.x version of the library, you get exactly what you expect when you import gtk. However, the moment you install the 1.x library, or share your code with a friend who has it, you may unexpectedly get the 1.x library and things start to fail mysteriously. This is by design - it was intended to allow a site to have a default version. I don't understand the benefit, as the percentage even of python programs that can be used with either library is minimal.

(I find it hard enough to use different versions of pygtk-2.x with the same code, but that's another story.)

What about the elegance? Here I present two options. The first is what you must currently do to successfully import gtk in all scenarios. Of special note is the string 2.0 which describes some abstract API level which is distinct from 1.2, but is shared between 2.0, 2.2, 2.6, and 2.8 so far. The second is what I would have considered a better choice.

import pygtk
pygtk.require('2.0')
import gtk

import gtk2 as gtk

This is of course the minimal case. A more realistic sample would also need to import gobject and pango; these days pangocairo, cairo and some other packages join the fray. If you apply the same trick, this changes the line ratio from 3:1 to 5:3 or 7:5, which isn't as horrid. However at this point none of those packages have 1.x versions. They could just as clearly be imported on one line.

How about supporting the mythical runs-on-both scenario? Easy:

try: import gtk2 as gtk
except ImportError: import gtk

What about system defaults? I don't see that as a realistic use case, and since it fails in the pygtk.require() case as well, I'm not worried about duplicating it.

There's one thing that the pygtk method handles: it's much harder to import both the 1.x and the 2.x library in a single program. But is this such a danger that it's worth all these other problems? The python philosophy is to trust the programmer not to do something catastrophic without reason. Can you imagine someone coding import gtk; import gtk2 without a reason?

Where are we today? Heading the wrong way. The python-gstreamer package now has a pygst module, almost a verbatim copy of pygtk.py. Let's squash this now. It's way too late to back this out of pygtk 2.x, but let's not repeat it for 3.x. I don't know if it's too late for pygst, but if it's not, let's back it out immediately and switch to a saner approach.

[Disclaimer: I don't work on either the pygtk or pygst projects, I just use them.]

Categories: pygtk python