easy_install Fails under Windows

I’ve seen a few questions on various Python mailing lists ranging from TurboGears to SQLite that appear to be centered around failures of easy_install under Windows. The problem generally manifests itself during the installation phase of a package with the cryptic message “not a valid archive type.” (Python supports zip, tar, gzip/bzipped tars, and so forth.) Oddly, I’ve never come across a reasonable answer!

Thankfully, this particular issue isn’t difficult to solve!

The issue related to easy_install appears to be tied to the implementation of $python_path/lib/site-packages/tarfile.py prior to Python 2.5.2 (or thereabouts). The TarFile class dies during the parse phase of the tarball headers, specifically during read of the checksum. Under Windows, the checksum string does not get processed as intended and spits out an exception when an attempt is made to convert it to an integer. Under *nix systems, the checksum header entry would appear, for example, as 1234\x00; in win32, this string is read as “1234\x00 ” (note the trailing space). As a consequence, the one-liner to convert this to an int fails.

Fortunately, upgrading Python to 2.5.2 or later (preferably 2.6) appears to fix the problem. Here’s a look at the different nti implementations from Python for Windows (2.5.1) and Python under Gentoo (2.5.2):

Python 2.5.1, Windows
Pay special attention to line 7:

1
2
3
4
5
6
7
8
9
10
11
12
13
def nti(s):
    """Convert a number field to a python number.
    """
    # There are two possible encodings for a number field, see
    # itn() below.
    if s[0] != chr(0200):
        n = int(s.rstrip(NUL) or "0", 8)
    else:
        n = 0L
        for i in xrange(len(s) - 1):
            n <<= 8
            n += ord(s[i + 1])
    return n

Python 2.5.2, Gentoo Linux

1
2
3
4
5
6
7
8
9
10
11
12
13
def nti(s):
    """Convert a number field to a python number.
    """
    # There are two possible encodings for a number field, see
    # itn() below.
    if s[0] != chr(0200):
        n = int(nts(s) or "0", 8)
    else:
        n = 0L
        for i in xrange(len(s) - 1):
            n <<= 8
            n += ord(s[i + 1])
    return n

In Python 2.5.2 a new function, nts(), is now used to process and strip trailing nulls–and anything that follows:

1
2
3
4
5
6
7
8
def nts(s):
    """Convert a null-terminated string field to a python string.
    """
    # Use the string up to the first null char.
    p = s.find("\0")
    if p == -1:
        return s
    return s[:p]

In Short, if You’re Lazy

If you’re lazy and don’t wish to upgrade, copy tarfile.py from a newer Python distribution into your lib/site-packages directory or replace the nti() function (around line 141) with the two definitions from Python 2.5.2 (above). Do this, and you’ll be able to use easy_install under Windows!

***

Leave a comment

Valid tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>