Dalke Scientific Software: More science. Less time. Products
[ previous | newer ]     /home/writings/diary/archive/2006/10/24/xmlrpc_in_turbogears

XML-RPC in TurboGears

On-and-off I've looked for some way to get XML-RPC working in TurboGears. There's a CherryPy filter but I couldn't get it working. From what I've seen of the examples it makes all functions available to XML-RPC, which isn't something I wanted.

I finally gave up and rolled my own with xmlrpclib and using SimpleXMLRPCServer.py as a guide. It was simpler than trying to figure out the CherryPy mechanism, and simple enough that I'll list it here more as a recipe than a reusable module.

import sys
import xmlrpclib
import cherrypy
import turbogears
from turbogears import controllers

class RPCRoot(controllers.Controller):
    def index(self):
        params, method = xmlrpclib.loads(cherrypy.request.body.read())
            if method == "index":
                # prevent recursion
                raise AssertionError("method cannot be 'index'")
            # Get the function and make sure it's exposed.
            method = getattr(self, method, None)
            # Use the same error message to hide private method names
            if method is None or not getattr(method, "exposed", False):
                raise AssertionError("method does not exist")

            # Call the method, convert it into a 1-element tuple
            # as expected by dumps                       
            response = method(*params)
            response = xmlrpclib.dumps((response,), methodresponse=1)
        except xmlrpclib.Fault, fault:
            # Can't marshal the result
            response = xmlrpclib.dumps(fault)
            # Some other error; send back some error info
            response = xmlrpclib.dumps(
                xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value))

        cherrypy.response.headers["Content-Type"] = "text/xml"
        return response

    # User-defined functions must use cherrypy.expose; turbogears.expose
    # does additional checking of the response type.
    def add(self, a, b):
        return a+b

class Root(controllers.RootController):
    RPC2 = RPCRoot()

Speaking of recipe, also tried to list it in the Python Cookbook but after several minutes waiting for the login to work I got the message "We are currently experiencing technical issues. Please try again shortly."

Andrew Dalke is an independent consultant focusing on software development for computational chemistry and biology. Need contract programming, help, or training? Contact me

Copyright © 2001-2013 Andrew Dalke Scientific AB