|
|
||||||||||||||||||
|
|
||||||||||||||||||
![]() |
![]() |
Issue 5 - Revision 7 / April 20, 2004
|
|||
|
XML-RPC for Python - - - - - - - - - - - - By Mike Olson and Uche Ogbuji | April 1, 2004 XML-RPC for Python XML-RPC is the grandfather of XML web services. It is a simple specification for remote procedure calls (RPC) that uses HTTP as the transport protocol and an XML vocabulary as the message payload. It has become very popular because of its simplicity (the full specification is less than ten printed pages), and most languages now have standard or readily available XML-RPC implementations. This includes Python, which started bundling xmlrpclib, an XML-RPC implementation by Fredrik Lundh, in version 2.2. In this article, we shall focus on using the Python implementation. You must have Python 2.2. to run the examples in this article. Also, in the last article, we looked at the relative performance of XML-RPC, SOAP, and other distributed programming technologies. You may want to read that before making major decisions to deploy XML-RPC. Writing a Python XML-RPC client is very easy. The module xmlrpclib has all the needed machinery. In order to invoke a remote XML-RPC object, you create a proxy object which forwards requests to the server using XML-RPC. The proxy object looks and feels just like a regular Python object, and your requests are simple function calls. Listing 1 (currtime.py) uses XML-RPC to get the current time from the UserLand server.
import xmlrpclib
#Port 80 is the default
server = xmlrpclib.ServerProxy("http://time.xmlrpc.com")
currentTimeObj = server.currentTime
currtime = currentTimeObj.getCurrentTime()
print currtime
print currtime.value
What is actually being proxied is the server, which is set up by
initializing an instance of the One important clarification: the idea of distinct proxy objects within the server is really an illusion. XML-RPC allows method names to have periods in them, and it is a common convention to use method names such as "pseudo_object.foo", which allows clients to treat it as a call to a method "foo" on a remote object named "pseudo_object". However, as far as XML-RPC protocol is concerned, this is just a method named "pseudo_object.foo" defined on the remote server. You'll see later on why this distinction is important. The result of running the script: $ python currtime.pySpecial types DataType, as we've seen, is one special type used in Python's XML-RPC implementation based on the specification. It must be used for input and output to XML-RPC systems if they require such types. In other words, if a remote function takes a DateTime argument, you cannot send it a string such as "20020808T10:43:06". You would first construct an instance of the DateTime class. For instance:
datetime_arg = xmlrpclib.DateTime("20020808T10:43:06")
remote_obj.method(datetime_arg)
There are a few other such special types. import xmlrpclib
server = xmlrpclib.ServerProxy("http://xmlrpc.usefulinc.com/demo/server.php")
eg_obj = server.examples
result = eg_obj.stringecho(u"Freude, schönergötterfunken")
print unicode(result)
However, if you run it, you will find that the string has been corrupted by the remote server: $ python stringecho.py Freude, schnergtterfunken This is because although Python supports Unicode strings, the remote system does not. XML-RPC oficially only specifies ASCII as a string encoding, a well-known and unfortunate limitation. The first attractive solution to encode to UTF-8, unfortunately, will not work since UTF-8 does not "fit" into the 7-bit ASCII range. One could use is to use UTF-7, which does fit into ASCII range, but this is a less common and more verbose encoding. To use UTF-7, replace the relevant line with:
result = eg_obj.stringecho(u"Freude, schöne götterfunken".encode("utf-7"))
resulting in: $ python stringecho.py Freude, sch+APY-ne g+APY-tterfunken This is unfortunate because it distorts the value being sent remotely, and requires an "out of band" understanding between the parties that strings being passed are in UTF-7 encoding. If this sort of communication can be established between the parties, the server could also accept binary objects rather than strings, which means that UTF-8 could be used. But this is just hacking around a glaring fault in the protocol itself, and perhaps a good reason to consider SOAP, which is properly internationalized. Handling faultsWhen the server needs to signal an error, it does so using an XML-RPC fault. This is interpreted in Python using a special exception object which gives a fault code and descriptive string. Listing 3 (getstate.py) uses an XML-RPC service for returning a state name according to a number passed in which represents the index of the state in alphabetic order. We purposefully use a bogus value of -1 which causes the server to raise a fault: import xmlrpclib
server = xmlrpclib.ServerProxy("http://xmlrpc.usefulinc.com/demo/server.php")
eg_obj = server.examples
try:
result = eg_obj.getStateName(-1)
except xmlrpclib.Fault, fault:
print fault.faultCode
print fault.faultString
Which results in: $ python getstate.py 800 I don't have a state for the index '-1' If it is the XML-RPC machinery rather than the service itself that
encounters a problem (for instance, you give it a URL that cannot be
reached), a Python also comes with import calendar, SimpleXMLRPCServer
#The server object
class Calendar:
def getMonth(self, year, month):
return calendar.month(year, month)
def getYear(self, year):
return calendar.calendar(year)
calendar_object = Calendar()
server = SimpleXMLRPCServer.SimpleXMLRPCServer(("localhost", 8888))
server.register_instance(calendar_object)
#Go into the main listener loop
print "Listening on port 8888"
server.serve_forever()
The class To test the server, we write a simple client in listing 5 (calclient.py): import xmlrpclib
server = xmlrpclib.ServerProxy("http://localhost:8888")
month = server.getMonth(2002, 8)
print month
And here you can see the effect of our not having a period in the method names. Rather than first of all obtaining a pseudo-object from the server (which really just represents an abstraction of the part of the method name before the period), we simply call the method on the server proxy itself. The resulting output is:
$ python calclient.py
August 2002
Mo Tu We Th Fr Sa Su
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Conclusion
XML-RPC is simpler than SOAP, and is very popular in open-source projects. It is an essential toolkit for any language or framework to offer these days, and so Python's XML-RPC modules are a welcome addition. However, it does have its weaknesses, chief of which is its support for character encodings, which shows an apalling bias towards English which seems out of place in these days when the importance of internationalization is well understood.
|
|||||||||||||||||||||||||||||||||||||||||
|
Py is committed to bringing you great Python Articles. | ||||||||||||||||||||||||||||||||||||||||||
![]() |
Reproduction of material from any of PyZine's pages without prior written permission is strictly prohibited. Copyright 2003 - 2005 PyZine |
|