Using Pypi XML-RPC API with Ruby
I had to play with the Pypi API today. Unfortunately, their JSON API is too limited for what I wanted to do.
If you need to browse, search or even get a list of the released versions of a package, you need to use their XML-RPC API.
Quite simple? Not so fast!
In Ruby, a XML-RPC request would be something like:
require 'xmlrpc/client'
client = XMLRPC::Client.new_from_uri('https://testpypi.python.org/pypi')
result = client.call(:list_packages)
puts result.inspect
But the code above raises RuntimeError: Wrong content-type (received 'text/html' but expected 'text/xml')
with the HTML content of the page https://testpypi.python.org/pypi.
Spoiler: It's all about HTTP headers.
As the Pypi documentation says:
XML-RPC requests are detected by
CONTENT_TYPE=text/xml
variable in CGI environment and processed byrpc.RequestHandler().__call__()
.
And if we look at Pypi source code, a XML-RPC requests requires that CONTENT_TYPE
should be exactly text/xml
.
Unfortunately for us, XMLRPC::Client
sets the Content-Type
header to text/xml; charset=utf-8
which doesn't match Pypi's condition.
Let's update our code:
require 'xmlrpc/client'
client = XMLRPC::Client.new_from_uri('https://testpypi.python.org/pypi')
client.http_header_extra = { 'Content-Type' => 'text/xml' }
result = client.call(:list_packages)
puts result.inspect
And here we are, a nice array of Python package names!
Note: In this example we use testpypi.python.org which is the alternate server for test purpose. In production, you'll want to use pypi.python.org.
Written by Xavier Dumesnil
Related protips
1 Response
Thanks. I would have given up on this.