Sunday, August 26, 2007

Simplifying gPodder website navigation

Today, I've updated the gPodder website (navigation) to be more usable and easier to navigate. I've added stock Gnome icons and moved some previously top-level items into the "documentation" menu item or elsewhere. This makes navigation easier and the design also looks a bit more modern, have a look:



You can find the new gPodder website at the usual location: http://gpodder.berlios.de/. Oh, and by the way: I've just released a new version (0.9.5) today, so if you're using gPodder, be sure to check out the new release.

Wednesday, August 22, 2007

Minimalistic Evolution phonebook extractor

If you're using Evolution as your E-Mail client and contact management application, and you like Python, here is a small snippet that allows you to dump out all phone numbers of your contacts to the console. Of course, with this code as a guide, you can produce even more useful applications ;)

What you need: Evolution, pygobject, evolution-python, Python (2.4 or higher) and some contacts in your contact list
#!/usr/bin/python

import evolution
import gobject

book = evolution.open_addressbook('default')

props = gobject.list_properties( evolution.EContact)
pp = [ p.name for p in props if 'phone' in p.name ]

for contact in book.get_all_contacts():
gp = contact.get_property
name = gp('file-as')
numbers = ', '.join( [ gp(p) for p in pp if gp(p) ])
if numbers:
print ': '.join( [ name, numbers ])

Thursday, August 9, 2007

Threading and Locks

This week, I've been bitten by a dead-lock bug in my website's code twice already, and I've decided to fix it, and to write about it, as it seems like a common problem when starting with threading. To use a thread lock in Python, the threading module provides a Lock class that has two methods: acquire() and release(). Usually, one would think that thread-unsafe code should be "protected" by the lock like this ("lo" is a Lock variable):
def do_something():
lo.acquire()
do_threadunsafe_operation()
lo.release()

The problem is, that if do_threadunsafe_operation() raises an exception, the lock will not be released, and therefore, all subsequent calls to do_something() will lock forever. You have to put the code in a try..finally block to make sure the lock gets released when the function ends:
def do_something():
lo.acquire()
try:
do_threadunsafe_operation()
finally:
lo.release()

In the Python Cookbook, there is also a decorator version of this, so when using Python 2.4 and above, and you like using decorators, try the sychronized decorator and "decorate" your function:
@synchronized(lo)
def do_threadunsafe_operation():
pass

Threads in Python are cool, and if you're careful using them, you can make your application run faster without affecting the stability or flow of your application. A lesson I learned last weekend when a bug with locking resulting in my WSGI app dead-locking and the website unreacheable.

Tuesday, August 7, 2007

Python Paste Easter Egg.

While looking for documentation on Paste's HTTP server module, I have found something funny:
from paste import pony
print pony.PONY.decode('base64').decode('zlib')
print pony.UNICORN.decode('base64').decode('zlib')
The module documentation for paste.pony can be found here, and the corresponding highlighted source file here.

Sunday, August 5, 2007

Python Import Hell

Coming from a Java background to Python about two years ago, I suppose I confused Python packages and modules a bit (compare Java's packages and classes - it's a different thing!). Anyway, gPodder's current module and package structure is a bit uncoordinated, partly because I started out with the module layout early in my Python carreer and partly because I sometimes added classes where they shouldn't be placed, resulting in circular imports. I somehow managed to fix all import errors and it runs for quite a while with that layout now.

After Pierre-Luc Beaudoin informed me that his Sofa Media Center now uses gPodder as its podcast client/backend, and after looking at Pierre-Luc's code, I thought it would be good to provide some kind of gPodder API for other developers to build upon the gPodder functionality. This way, gPodder would be a modular app with a GUI, but it could also function as simple podcast client library (if needed).

So, yesterday, I started to restructure the gPodder package/module layout a bit. While doing this, I had some problems with circular imports. The problem was that I had a "gpodder" module in the "gpodder" package, and Python 2.4's "import" statement first searches the current package and then the "global" package/module path. I read about Python's built-in Package support that is available since Python 1.5. Great! But it already mentions that there could be problems with relative imports. Another article entited Importing Python Modules then explained the partly confusing import hell of Python. The article says one should "always use import X" (except for some special cases).

Circular imports can often easily be avoided by placing depended-on code in seperate modules. It's also good to see that this problem is partly solved by PEP 328, which is (optionally) available starting with python 2.5, throws a warning and 2.6 and will be the default in Python 2.7: Absolute imports. This way, naming a package-local module like a top-level package will not result in confusion. One can either use "import X" to do an absolute import or do "from . import X" to do a relative import. Currently (Python 2.4), "import X" will prefer the local module over a global package/module with the same name. Confusing, isn't it?