Skip to main content

If you don't have an IBM ID and password, register here.

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

The Python web services developer: XML-RPC for Python

Mike Olson, Principal Consultant, Fourthought, Inc.
Photo of Mike Olson
Mike Olson is a consultant and co-founder of Fourthought Inc., a software vendor and consultancy specializing in XML solutions for enterprise knowledge management applications. Fourthought develops 4Suite, an open source platform for XML middleware. You can contact Mr. Olson at mike.olson@fourthought.com.
Uche Ogbuji (uche@ogbuji.net), Principal Consultant, Fourthought, Inc.
Photo of Uche Ogbuji
Uche Ogbuji is a consultant and co-founder of Fourthought Inc., a software vendor and consultancy specializing in XML solutions for enterprise knowledge management applications. Fourthought develops 4Suite, open source platforms for XML middleware. Mr. Ogbuji is a Computer Engineer and writer born in Nigeria, living and working in Boulder, Colorado, USA. You can contact Mr. Ogbuji at uche@ogbuji.net.

Summary:  XML-RPC is a simple, lightweight web services technology that predates SOAP. In this installment of the Python web services developer, Mike Olson and Uche Ogbuji examine the XML-RPC facilities in Python.

Date:  19 Sep 2002
Level:  Introductory

Comments:  

XML-RPC is the granddaddy 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. Joe Johnston's IBM developerWorks article "Using XML-RPC for web services" (see Resources) covers the basics of XML-RPC in the first three sections. Start there if you need to review the basic technology. In this article, we will 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.

Clients

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 (see Resources for more information about this service).

  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 ServerProxy class. We pass in the full URL of the remote server (you must include the URL scheme "http://"). Port 80 is the default, as usual. If the remote server were instead listening on port 8080, we would use "http://time.xmlrpc.com:8080". The server proxy has all the actual remote objects they host as regular attributes, and in this way we get a handle to the remote object named currentTime. Now we can simply call the method on this proxy object, which returns the current time. The response is of a special XML-RPC type called a DateTime. To get a plain string representation of this object, we use its value attribute.

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, that 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.py
<DateTime 20020808T10:43:06 at 81dd0ec>
20020808T10:43:06


Special 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. Boolean and Binary are basic data types, and the special Fault object is used for exception handling. Boolean might be going away since Python 2.3 introduces a native boolean type bool. Binary is distinct from strings in that it does not restrict what bytes can be transmitted. The other XML-RPC types are represented by native Python objects, with lists and tuples standing in for arrays and dictionaries for structures. One important warning is about character encodings. A much-criticized limitation of XML-RPC is that it only supports the transmission of ASCII strings (or binary buffers). It offers no character encoding support at all. Listing 2 tries to use Useful Inc's sample string echo service (which simply takes a string and returns the same string).

  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önergö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 faults

When 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 ProtocolError exception object is raised rather than a Fault object.


XML-RPC servers

Python also comes with SimpleXMLRPCServer, a module for implementing XML-RPC servers. You can register functions or instances with an instance of the SimpleXMLRPCServer class in the module of the same name, in order to expose XML-RPC services. The most straightforward way is to just write an instance with methods that do what you need, and then register this instance. However, in this case, method names cannot have periods, and so the trickery we discussed above to make things appear as if there are multiple objects represented by the server is unavailable. The effect of this will become clear soon, but first of all, let us create a calendar server such as the one we've been using to demonstrate SOAP servers. Listing 4 (calserver.py) is the XML-RPC calendar server implementation:

  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 Calendar implements the methods we wish to expose. They take numbers and return strings. We create an instance of this object and then an instance of the XML-RPC server class, with which we register the calendar instance. This now makes the methods getMonth and getYear available on the server. Remember that Python is dynamically typed, and that you will want to add type-checking code to the methods in most cases. Of course Python's rich expressiveness makes this a breeze, and also means that you can easily do more sophisticated type checking than most languages allow. In the main code, we create a server object, giving it a tuple representing the listening address and port. The address can be a host name or IP address. Finally, we put this server into its main loop, which is only broken when an operating system signal interrupts it, such as when the user presses CTRL-C. Open up a separate console and run the server script.

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 new 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 appalling bias towards English which seems out of place in these days when the importance of internationalization is well understood.

In the next installment we shall examine Python tools for another web services interface that has gained widespread popularity: RDF site summary (RSS).


Resources

About the authors

Photo of Mike Olson

Mike Olson is a consultant and co-founder of Fourthought Inc., a software vendor and consultancy specializing in XML solutions for enterprise knowledge management applications. Fourthought develops 4Suite, an open source platform for XML middleware. You can contact Mr. Olson at mike.olson@fourthought.com.

Photo of Uche Ogbuji

Uche Ogbuji is a consultant and co-founder of Fourthought Inc., a software vendor and consultancy specializing in XML solutions for enterprise knowledge management applications. Fourthought develops 4Suite, open source platforms for XML middleware. Mr. Ogbuji is a Computer Engineer and writer born in Nigeria, living and working in Boulder, Colorado, USA. You can contact Mr. Ogbuji at uche@ogbuji.net.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in

If you don't have an IBM ID and password, register here.


Forgot your IBM ID?


Forgot your password?
Change your password


By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)


By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and web services
ArticleID=11709
ArticleTitle=The Python web services developer: XML-RPC for Python
publish-date=09192002
author1-email=mike.olson@fourthought.com
author1-email-cc=
author2-email=uche@ogbuji.net
author2-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).