Thursday, August 14th, 2014

A JSON version of the standard Python xmlrpclib

I have always loved how easy Python made it to create simple RPC services using XML-RPC. I like how dead simple the API for both an XML-RPC server and client are. Here's an example XML-RPC Server in Python:

from SimpleXMLRPCServer import SimpleXMLRPCServer

# Create server
server = SimpleXMLRPCServer(("localhost", 8000))

# Register a function
def hello(name='World'):
    return 'Hello %s!' % name

# Run the server's main loop

Accessing this service via Python couldn't be simpler:

import xmlrpclib

s = xmlrpclib.ServerProxy('http://localhost:8000')

print s.hello()  # Outputs "Hello World!"
print s.hello('XML-RPC') # Outputs "Hello XML-RPC!"

I have been using XML-RPC a lot as a result, as I build mostly everything in Python. However, the overhead of XML parsing can be daunting for larger applications that are expected to receive many requests per minute. One technology that Python seems to be lacking in it's standard library is a simple service called JSON-RPC. Luckily I recently wrote a client library that currently only works on pure socket connections, here is the source code:

# JSON-RPC CLIENT LIBRARY inspired by the standard library xmlrpclib
# an JSON-RPC client interface for Python.
import urllib, json, socket

class _Method(object):
    # some magic to bind an JSON-RPC method to an RPC server.
    # supports "nested" methods (e.g. examples.getStateName)
    def __init__(self, send, name):
        self.__send = send
        self.__name = name
    def __getattr__(self, name):
        return _Method(self.__send, "%s.%s" % (self.__name, name))
    def __call__(self, **kwargs):
        return self.__send(self.__name, kwargs)

class ServerProxy(object):
    def __init__(self, uri):
        protocol, uri = urllib.splittype(uri)
        if protocol not in ('socket',):
            raise IOError, 'unsupported JSON-RPC protocol'
        self.__host, self.__handler = urllib.splithost(uri)
        self.__id = 0
    def __request(self, method, params):
        s = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
        s.connect(urllib.splitnport(self.__host, 80))
        self.__id +=1
        data = {"jsonrpc": "2.0", "method": method, "id":self.__id}
        if params != {}:
        resp = json.loads(s.recv(512))
        return resp['result']
    def __repr__(self):
        return '<ServerProxy for %s%s>' % (self.__host, self.__handler)
    __str__ = __repr__
    def __getattr__(self, name):
        return _Method(self.__request, name)

This library works in the exact same manner as the xmlrpclib shown above, expect it connects to JSON-RPC servers, such as the XBMC Media Center software Here is how you would interface with XBMC:

# A super simple XBMC JSON-RPC Interface for Python
# Control your XBMC in a Pythonic way!
import jsonrpclib, time

class XBMC(jsonrpclib.ServerProxy):
    def __init__(self, host, port=9090):
        super(XBMC, self).__init__('socket://%s:%s/' % (host, int(port)))
    def notification(self, title, message):
        return self.GUI.ShowNotification(title=title, message=message)
    def global_search(self, query):
        time.sleep(2) # Wait for keyboard on slower boxes.
        return self.Input.SendText(text=query)
    def weather(self):
        return self.GUI.ActivateWindow(window='weather')
    def home(self):
        return self.GUI.ActivateWindow(window='home')
    def favourites(self):
        return self.GUI.ActivateWindow(window='favourites')
    favorites = favourites

All of this code, plus many more, are now available on my newest bitbucket repository aptly called Python Experiments.

Comment #1: Posted 4 months, 1 week ago by Thomas


Just for information, a jsonrcplib library already exists since a long time :)
It also supports the serialization of custom types.

I've forked it to support both Python 2.7 and 3+

Although, the idea of an XBMC pythonic controller is great :D


Python Powered | © 2012-2014 Kevin Veroneau