Wednesday, 14 September 2011

Search pypi through an authenticating proxy

In an effort to do more rigorous python testing, I've been looking into alternative packaging tools that facilitate building isolated test environments. Previously I'd used easy_install and distribute. A popular alternative that plays nicely with virtulenv is pip.

It turns out that pip 0.72 has a few annoying little bugs, one of which is search does not support xmlrpc proxies, in particular authenticating proxies, correctly (207, 243). Changing pip, and the associated version of pip in virtualenv would be a slow process (I assume), and not something I'm capable of testing at the moment.

My quick fix solution is a command-line tool for searching pypi. This is done by replacing the transport used by xmlrpclib with one that uses urllib2. However, I've (informally) tested similar code in pip by patching download.py, and can confirm that it worked correctly on my system.

import os
import urllib2
import xmlrpclib

# install a proxy handler if required
_proxy = os.environ.get('http_proxy', None)
if _proxy:
    proxysupport = urllib2.ProxyHandler({"http": _proxy})
    opener =  urllib2.build_opener(proxysupport, urllib2.CacheFTPHandler)
    urllib2.install_opener(opener)

class ProxyTransport(xmlrpclib.Transport):
    def request(self, host, handler, request_body, verbose):
        self.verbose = verbose
        url = 'http://%s%s' % (host, handler)
        request = urllib2.Request(url)
        request.add_data(request_body)
        # Note: 'Host' and 'Content-Length' are added automatically
        request.add_header("User-Agent", self.user_agent)
        request.add_header("Content-Type", "text/xml") # Important
        f = urllib2.urlopen(request)
        return(self.parse_response(f))

if __name__ == "__main__":
    import sys
    pypiurl = 'http://pypi.python.org/pypi'
    transport = ProxyTransport()
    pypi = xmlrpclib.ServerProxy(pypiurl, transport = transport)
    packages = pypi.search({'name' : sys.argv[1]})
    for pkg in packages:
        print pkg['name']
        print '  ', pkg['summary'].splitlines()[0]

No comments:

Post a Comment