Archive for January 2009

Module wsgiref doesn't work in Python 3.0 - How to fix it

A very large oddity regarding the newest version of Python is that the wsgiref module is completely broken. Go ahead and try to run the following:

from wsgiref.simple_server import make_server, demo_app
httpd = make_server('', 8000, demo_app)
httpd.handle_request()

You should notice that a nice little "ValueError: need more than 1 value to unpack" message when you try to open it in your web browser. The main ticket for this bug can be found here, and it comes with a patch! If you're running Linux, then the fix is easy. Once you download it simply run this in the command line in the same folder as the patch to issue it:

sudo patch < wsgiref.patch

It will come up with prompts for each of the files to in wsgiref to patch. Simply specify their locations and you're done!

Update: Sources have told me that this has been fixed in Python 3.0.1, so here's hoping.

Cross-platform file locking support in Python

On occasion, one requires the need to lock a file. Now, this is relatively easy if you're targeting a specific platform because there is often a function in the library to do it for you. But what if you want to target a larger set of platforms? The following is a solution I wrote up today. It's lockfile creation is an atomic operation and thus doesn't suffer from any race conditions. It should work in both Windows and Unix environments.

import os
import time
import errno
 
class FileLockException(Exception):
    pass
 
class FileLock(object):
    """ A file locking mechanism that has context-manager support so 
        you can use it in a with statement. This should be relatively cross
        compatible as it doesn't rely on msvcrt or fcntl for the locking.
    """
 
    def __init__(self, file_name, timeout=10, delay=.05):
        """ Prepare the file locker. Specify the file to lock and optionally
            the maximum timeout and the delay between each attempt to lock.
        """
        self.is_locked = False
        self.lockfile = os.path.join(os.getcwd(), "%s.lock" % file_name)
        self.file_name = file_name
        self.timeout = timeout
        self.delay = delay
 
 
    def acquire(self):
        """ Acquire the lock, if possible. If the lock is in use, it check again
            every `wait` seconds. It does this until it either gets the lock or
            exceeds `timeout` number of seconds, in which case it throws 
            an exception.
        """
        start_time = time.time()
        while True:
            try:
                self.fd = os.open(self.lockfile, os.O_CREAT|os.O_EXCL|os.O_RDWR)
                break;
            except OSError as e:
                if e.errno != errno.EEXIST:
                    raise 
                if (time.time() - start_time) >= self.timeout:
                    raise FileLockException("Timeout occured.")
                time.sleep(self.delay)
        self.is_locked = True
 
 
    def release(self):
        """ Get rid of the lock by deleting the lockfile. 
            When working in a `with` statement, this gets automatically 
            called at the end.
        """
        if self.is_locked:
            os.close(self.fd)
            os.unlink(self.lockfile)
            self.is_locked = False
 
 
    def __enter__(self):
        """ Activated when used in the with statement. 
            Should automatically acquire a lock to be used in the with block.
        """
        if not self.is_locked:
            self.acquire()
        return self
 
 
    def __exit__(self, type, value, traceback):
        """ Activated at the end of the with statement.
            It automatically releases the lock if it isn't locked.
        """
        if self.is_locked:
            self.release()
 
 
    def __del__(self):
        """ Make sure that the FileLock instance doesn't leave a lockfile
            lying around.
        """
        self.release()

The above class is best used in a context manager fashion through the with statement like in the example below:

with FileLock("test.txt", timeout=2) as lock:
    print("Lock acquired.")
    # Do something with the locked file

The largest downside of this is that the directory the file is located in must be writable. I hope this code helps you. Of course, if you have a better recipe, please share it in the comments. ;)

rot13 in Python 3.x

As of Python 3.0, rot13 is no longer built accessible from the str.encode("rot13") call. If needed, here is an implementation I pieced together:

from string import ascii_uppercase, ascii_lowercase
 
def rot13(data):
    """ A simple rot-13 encoder since `str.encode('rot13')` was removed from
        Python as of version 3.0.  It rotates both uppercase and lowercase letters individually.
    """
    total = []
    for char in data:
        if char in ascii_uppercase:
            index = (ascii_uppercase.find(char) + 13) % 26
            total.append(ascii_uppercase[index])
        elif char in ascii_lowercase:
            index = (ascii_lowercase.find(char) + 13) % 26
            total.append(ascii_lowercase[index])
        else:
            total.append(char)
    return "".join(total)

Pretty simple, right? Knowing how modulus (%) works helped greatly in finding the proper index. I hope this helps.

Update: There's a simpler solution on the comments below. You should probably use it instead.

CovertClick - finished!

I spent a lot of today and yesterday night working out the final details for this tool. What CovertClick does is allow you to create links which don't send the referer to the website being navigated to. It is another tool in the fight for Internet anonymity. You can learn more about it at the CovertClick website, http://CovertClick.com/.