I’ve added this snippets into my python notes. Here they are for convenience.
Dynamic Xml-Rpc server
This server code will use python “reflection” to publish all methods whose name are prefixed with PREFIX. In this case, the prefix is xmlrpc_, so all methods within this server such as xmlrpc_hello, will get published. The code already uses options, so it can be easily started like so:
python server.py –host=$HOSTNAME –port=portNum
Server skeleton code
import sys from optparse import OptionParser from SimpleXMLRPCServer import SimpleXMLRPCServer class DynamicXMLRPCServer(SimpleXMLRPCServer): """ An XMLRPC server that will register all function whose name are prefixed with PREFIX via xml-rpc Zen Sugiarto - 2011 """ # this is the prefix used by this sever to decide whether a given method should be published over xml-rpc or not. PREFIX="xmlrpc_" # constructor def __init__(self, params): self.params=params self.host=params['host'] self.port=params['port'] SimpleXMLRPCServer.__init__(self,(self.host, self.port)) # register all xmlrpc_ functions over xml-rpc for name in dir(self): if name[:len(DynamicXMLRPCServer.PREFIX)] == DynamicXMLRPCServer.PREFIX: function=getattr(self,name) print "registering function: %s as %s " % ( name, name[len(DynamicXMLRPCServer.PREFIX):] ) self.register_function(function, name[len(DynamicXMLRPCServer.PREFIX):]) # note: xmlrpc_ prefix is used by this server to mark that this function will be published def xmlrpc_hello(self,msg): """ A simple hello function used for simple ping check. @param msg - msg to pass to hello @return dictionary {"hello":msg} """ return {"hello":msg} def xmlrpc_describe(self): """ Retrieves the description/documentation of available functions within this service. by the grace of python's .__doc__ object. @return dictionary of the following format { 'function_name' : 'documentation/description of that function '} } """ metaDescription={} for name in dir(self): if name[:len(DynamicXMLRPCServer.PREFIX)] == DynamicXMLRPCServer.PREFIX: function=getattr(self,name) metaDescription[name[len(DynamicXMLRPCServer.PREFIX):]]=function.__doc__ return metaDescription; def xmlrpc_yourFunction(self): """ Put in more function here!~ """ print "IMPLEMENT ME" def main(): """ main method """ parser = OptionParser(""" Template service object - please put your comment in here """) parser.add_option("--host", dest="host", help="hostname to publish the service against") parser.add_option("--port", dest="port", help="port number to use") (options, args) = parser.parse_args() if( options.host == None or options.port == None ): print "insufficient options provided. try --help" sys.exit(1); server = DynamicXMLRPCServer({'host':options.host,'port':int(options.port)}) server.serve_forever() if __name__ == "__main__": main()
Dynamic XML-RPC Client
This will invoke Hello world function via xml-rpc, this is as simple as it gets
import xmlrpclib print xmlrpclib.ServerProxy("http://localhost:8000/").hello("zen")
But this is even better: this is a client that will allow you to connect to any xml-rpc service (yes, even java ones in xml-rpc) and call any function as long as you know its signature.
import xmlrpclib import readline import cmd import traceback import pprint import datetime from optparse import OptionParser import sys class XmlRpcClientConsole(cmd.Cmd): """ Generic xml rpc client console, works with any xml rpc service """ def __init__(self, url): cmd.Cmd.__init__(self) self.url = url; self.server = xmlrpclib.ServerProxy(url) self.pp = pprint.PrettyPrinter(indent=2) self.updatePrompt() def updatePrompt(self): self.prompt = "\n[%s] %s\nxmlrpc >> " % (datetime.datetime.now().strftime("%Y.%m.%d %H:%M:%S"),self.url) def default(self, line): try: result=None exec("result=self.server.%s" % (line)) self.pp.pprint(result) # default formatter: pretty print the resultant data except Exception, ex: traceback.print_exc(ex) print; self.updatePrompt() def do_help(self,line): print print "-------------------------------------" print "GENERIC XML RPC CLIENT CONSOLE - HELP" print "-------------------------------------" print print "Simply type in the function name on the xml-rpc service end, like you would" print "on any good ol' python program. For example, if the other side has a method" print "called helloWorld(strparam), you can invoke it like so:" print print "... xmlrpc >> helloWorld('hello zen')" print print "the client is therefore completely transparent and exposes the full capabilities" print "of the server end. have fun." # -zen print def main(): parser = OptionParser("""Generic XML RPC Client console""") parser.add_option("--url", dest="url", help="The XML RPC service URL to connect") parser.add_option("--cmd", dest="cmd", help="A one-off command to execute") (options, args) = parser.parse_args() if options.url == None : parser.print_help() sys.exit(1) console = XmlRpcClientConsole(options.url) if options.cmd != None : # run the cmd and bomb out console.default(options.cmd) sys.exit(0) else: print "for help using the console, type 'help'" # enter into cmd loop for interactive session console.cmdloop() if __name__ == "__main__": main()
Example
Starting the server:
python server.py --host=localhost --port=6666
Starting the client in console mode:
python client.py --url=http://localhost:6666
Within the console:
[2011.06.22 11:31:25] http://localhost:6666
xmlrpc >> hello("zen")
{ 'hello': 'zen'}