Using the UDDI Public Registry with Python

Julio Ruano
Software Engineer, IBM
June 2002

The Universal Description, Discovery and Integration (UDDI) Registry serves as a central location for publishing/acquiring information about various businesses, the services that they provide, and any technical interfaces they may use. Users can access the registry via an Internet graphical interface or programmatically through SOAP messaging. In this article Julio Ruano introduces UDDI4Py, a Python package that facilitates the transport and processing of the various SOAP messages that the UDDI 2.0 API supports. It available for download at IBM alphaWorks, and its usage as well as some examples are provided below.

Software systems are moving away from tightly bundled integrated programs, to ones that are loosely related and rely on open communication standards.At the heart of this evolution is the Web Service, defined as a unit of sofware that performs specific task(s), and can be assembled as a distributed application or to function as certain business process(es) [1]. It's main advantage is that it conforms to accepted standards, and open messaging interfaces which help interoperability with other services. This allows developers to easily interchange services as needed without worrying about having to write tedious code for the sole purpose of making them work together. Central to the idea of swapping programs in and out of these open distributed systems is the ability to discover and/or make available needed services. The UDDI Public Registry serves as a central location on the Internet to allow developers to incorporate and/or expose available services (information) to integrate into Web applications.

The Python scripting language fits very easily into this new Web services development environment. The standard Python system comes with a variety of modules well suited towards Internet development. Programmers can easily create robust Internet software using tools for http, ftp, smtp transport, XML processing, socket and URL connections, and much more. The interpreter is also available for a wide variety of platforms from the PalmOS to Linux on the mainframe, and programs are highly portable. Python is object-oriented, which gives it a significant advantage when compared to other scripting languages (PERL, Rexx, etc...). It is very helpful to model XML data as objects, and this is easily implemented using Python's object-oriented constructs. The Python web site is a good starting place to get all of the information needed to get started using this powerful language. There are also many other articles pertaining to Python development hosted on the IBM developerWork's Web Services Zone.

In this article I will provide an introduction to UDDI4Py, explaining set-up and usage of the package. I am assuming that the reader is familiar with using Python, and also has some experience with the UDDI API. The Resources section contains links to all of the information needed to fulfill these prerequisites.

UDDI4Py Installation

The following are required:

This is a recommended package: Win32
          python -V

          You should see the following reply:
 
          Python 2.2.1 

          If this is not the case, you should download and install the 2.2.1 (or most recent) version from the Python website.

     python find_business.py
         <businessList generic="2.0" operator="www.ibm.com/services/uddi" truncated="false" xmlns="urn:uddi-org:api_v2">
            <businessInfos>
               <businessInfo businessKey="FDFDBBA0-A7D3-11D5-A30A-002035229C64">
                  <name xml:lang="en">
                     IBM WSTK Tutorial
                  </name>
                  <description xml:lang="en">
                     IBM WSTK Tutorial
                  </description>
                  <serviceInfos>
                     <serviceInfo businessKey="FDFDBBA0-A7D3-11D5-A30A-002035229C64" serviceKey="12F63B90-A7D4-11D5-A30A-002035229C64">
                        <name xml:lang="en">
                           NasdaqQuotes
                        </name>
                     </serviceInfo>
                  </serviceInfos>
              </businessInfo>
            </businessInfos>
         </businessList>

Linux

As of this time, the UDDI4Py has not been tested under Linux.

Using UDDI4Py

The UDDI4Py package is organized into several modules, each of which help with the construction and processing of UDDI SOAP messages to and from the Registry. In order to facilitate these XML transactions, the toolkit consists of Python classes which represent corresponding XML defined structures of the API. Each Python class contains an appropriate toDOM() method, which converts the underlying Python object into a DOM structure. This helps the transition of the Python object --> to a DOM structure --> to an XML string format (and also from XML string --> to DOM --> to Python object). The Python classes are grouped together as follows, according to certain shared characteristics:

The UDDI API classifies its messages into two categories:
 
Inquiry API messages:
Publish API mesages:
find_binding  add_publisherAssertions
find_business delete_binding
find_relatedBusinesses delete_business
find_service delete_publisherAssertions
find_tModel delete_service
get_bindingDetail delete_tModel
get_businessDetail discard_authToken
qget_businessDetailExt get_assertionStatusReport
get_serviceDetail get_authToken
get_tModelDetail get_publisherAssertions
get_registeredInfo
save_binding
save_business
save_service
save_tModel
set_publisherAssertions

All Publish API messages require authenticated access information, whereas the Inquiry API messages do not. It is also necessary to connect to the Publish API via an SSL connection.

I will now walk you through a simple find_business request, using a UDDI4Py simple client as an example. You should consult the UDDI Version 2.0 API Specification as a reference for the message arguments sent to and response XML received from the respective API's.

Listing 1: A UDDI SOAP request to find business.
<?xml version="1.0" encoding="UTF-8" ?>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
    <find_business generic="2.0" xmlns="urn:uddi-org:api_v2">
        <name>some business name</name>
        <categoryBag>
            <keyedReference keyName="some keyName" keyValue="some keyValue" tModelKey="some tModelKey" />
        </categoryBag>
    </find_business>
</Body>
</Envelope>

The first line describes this as being an XML defined document with its character encoding as Unicode. The next line lets the XML processor know that this is a SOAP envelope that wraps a UDDI specific request inside the <Body/> tag. The UDDI specific elements begin at line 4, where the <find_business/> tag denotes the API request. This tag also has two important attributes namely "generic" and "xmlns". The "generic" attribute tells the UDDI API that this is a version 2.0 request, where the "xmlns" attribute states that all of the contents of the find_business element are contained within the "urn:uddi-org:api_v2" namespace. The <name/> tag contains the name of the business you wish to search for. The content of the <categoryBag/> tag, denotes established keyedReferences which are used as categorizations for this business.

Listing 2: Expected XML response from the find_business request made above.
<?xml version="1.0" encoding="UTF-8" ?>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
   <Body> 
      <businessList generic="2.0" xmlns="urn:uddi-org:api_v2" operator="www.ibm.com/services/uddi" truncated="false"> 
         <businessInfo businessKey="some business key">
               <name xml:lang="en">
                 some business name
               </name>
               <description xml:lang="en">
               some business description
               </description>
               <serviceInfos>
                  <serviceInfo businessKey="some business key" serviceKey="some service key">
                     <name>
                      some service name
                     </name>
                  </serviceInfo>
               </serviceInfos>
            </businessInfo>
         </businessInfos>
      </businessList>
   </Body>
</Envelope>

The UDDI return elements again begin at line 4 with the <businessList/> tag. This denotes the start of the list of businesses found from the name in the request. There can be multiple matches because the search on the value of name is done from left to right. For example, the name "IBM" can match IBM, IBM Software, IBM Global Services, etc... The <businessInfo/> tag at line 5 denotes the information (description, name, etc...) for a single business.  The <serviceInfos/> tag at line 12 contains one or more <serviceInfo/> elements that define a specific service for the business (A business does not have to define a service and this can be blank).

It is becoming quite clear from this simple example that it is tedious to deal with the creation and processing of the XML used for communicating with the UDDI API. The UDDI4Py library abstracts the internal handling of XML and provides a set of classes with methods to deal with this messaging.

Example 1: A complete program to send and process a find_business UDDI SOAP request.
# ****************
# Import the modules.
# ****************
from UDDI4Py.client import *
from UDDI4Py.requestDOM import *
from UDDI4Py.responseDOM import *

# ********************************
# The URL's where the UDDI API's reside.
# ********************************
iURL = "http://www-3.ibm.com/services/uddi/v2beta/inquiryapi"
pURL = "https://www-3.ibm.com/services/uddi/v2beta/protect/publishapi"

# *********************************************
# find_business
#
# Find a business by name and using a specfic categorization.
# Note that default behavior for find requests is to "and" all
# the request parameters together to produce the search
# criteria. For this example the result will consist of a business
# matching on "name" and "categoryBag".
# *********************************************
try:

      # Construct a proxy object used to send a response object to the 
      # appropriate URL.
      uddiCon = UDDIProxy(iURL,pURL)

      # Construct a findBusiness request object. This object maps to the 
      # find_business UDDI API. The classes that define request objects 
      # are found in the UDDI4Py.requestDOM module.
      request = findBusiness()

      # Set the name for the name of the business to search for.
      request.setNameStrings("Python Test Business")

      # These next statements use constructs that are defined by the UDDI 
      # Specification. The keyedReference is used to categorize information to 
      # allow for easier retrieval of data.
      # Construct a keyedReference object.
      keyRef = keyedReference()

      # Set the tModelKey for the keyedReference.
      keyRef.setTModelKey("UUID:4E49A8D6-D5A2-4FC2-93A0-0411D8D19E88")

      # Set the keyName for the keyedReference.
      keyRef.setKeyName("United States")

      # Set the keyValue for the keyedReference
      keyRef.setKeyValue("US")

      # Construct a categoryBag object.
      cBag = categoryBag()

      # Set the keyedReferences to the keyRef object created above.
      cBag.setKeyedReferences([keyRef])

      # Set the categoryBag for the request object.
      request.setCategoryBag(cBag)

      # Send the request object to the API and store the response DOM object in a 
      # local variable.
      responseDOM = uddiCon.send(request)

      # Construct a businessList object from the businessList DOM in 
      # the local variable above.
      response = businessList(responseDOM)

      # Display the response as XML format. All the objects defined by the
      # toolkit provide a method to convert the underlying object to an XML
      # string format.
      print response

# Catch any errors or in particular a UDDIError object.
except(socket.error,UDDIError), e:
     print e
 

The above syntax should seem fairly familiar, if not please check the Resources section for some links to Python documentation. It is hopeful that the inline comments guide the flow of the logic for the program listed above. The basic steps for using the toolkit are:

    1.) Instantiate a UDDIProxy obejct for communication to the API's with the appropriate URL's.
    2.) Instantiate an appropriate request object to interface with the respective API.
    3.) Set the message parameters for the request object that is being used.
    4.) Use the UDDIProxy object to send the request object to the appropriate API and store the response in a local variable.
    5.) Construct the appropriate response object using the responseDOM stored in step 4. Make sure that the correct response object
         is instantiated, as it should correspond to the return message explicitly stated in the UDDI Specification for the request
         message that was sent.
    6.) Process data using access methods provided in the response object.
    7.) The steps listed above should also be wrapped in a try/except block in order to catch any unexpected UDDIError's.

** It is important to note that Python is a loosely-typed language, meaning that there is no strict type enforcement. In other words, a method that is expecting a string, can be passed an integer, list of objects, or anything. If this happens, a nasty exception will be raised when the string that was expected is actually referenced within the method at runtime (this same principle can be extended to improper referencing of return types). For the example above, the setNameStrings method is expecting a list of string values only. Anything else that is passed in will cause an exception to be raised at runtime (which may lead to countless hours of wasted time bug tracking). I have taken great care to explicitly state the parameter types (and return types) for each and every method where it is not very clear from the code. It is very convenient to pass values blindly around without worrying about their types, if special care is taken to ensure that the correct types are used. Please take the time to look over the methods you wish to use (examing argument and return types), so that you do not cause invalid types to be referenced. **

Example 1a: Result of running the program in example 1.
d:\Python21\UDDI4Py\examples\article\python listing2.py
<businessList generic="2.0" operator="www.ibm.com/services/uddi" truncated="false" xmlns="urn:uddi-org:api_v2">
   <businessInfos>
      <businessInfo businessKey="DCE11330-78DA-11D6-8723-000629DC0A2B">
         <name xml:lang="en">
            Python Test Business
         </name>
         <description xml:lang="en">
            This is a test business for UDDI4Py illustration.
         </description>
         <serviceInfos>
            <serviceInfo businessKey="DCE11330-78DA-11D6-8723-000629DC0A2B" serviceKey="013AB050-78DC-11D6-8723-000629DC0A2B">
               <name xml:lang="en">
                  Python Test Service
               </name>
            </serviceInfo>
         </serviceInfos>
      </businessInfo>
   </businessInfos>
</businessList>

The user can also use all of the get methods provided by the businessList class in order to access member data. For the listing2 example, we could have easily done something like the following:

Listing 3: Example of using other access methods to retrieve data (Reference to code in example 1).
     # Access the businessInfo data contained within the businessList response object.
     # The businessList contains a businessInfos structure, which contains an array of
     # businessInfo structures.
     businessInfo = response.getBusinessInfos().getBusinessInfoArray()[0]
     print businessInfo

The above statement will print the businessInfo XML string format. The user can continue to extract data from the businessInfo object using any of its access methods.

Example 1 illustrated the simple technique for finding information from the registry. Often the user wants to publish data to the registry, and typically this involves sending a sequence of inquiries in order to use the results to build a request for a publish service. The next example serves as a template to demonstrate the technique for publishing information to the Registry. All of the Publish API messages require authenticated access, and as such, in order to use any of these API's you must have a registered account with a UDDI Operator Node. IBM provides a V2 Business Registry Beta where you can register for a free account and use any of the UDDI Publish API's.

Example 2: A complete program to publish updated business information.
# ****************
# Import the modules.
# ****************
from UDDI4Py.client import *
from UDDI4Py.requestDOM import *
from UDDI4Py.responseDOM import *

# ********************************
# The URL's where the UDDI API's reside.
# ********************************
iURL = "http://www-3.ibm.com/services/uddi/v2beta/inquiryapi"
pURL = "https://www-3.ibm.com/services/uddi/v2beta/protect/publishapi"

# **********************************************
# save_business
#
# Update an existing business with a new business description. 
# The distinguishing feature between a save and an update, is
# that for an update the business key will already exist.
# **********************************************
try:
    # Construct a proxy object used to send a response object to the 
    # appropriate URL.
    uddiCon = UDDIProxy(iURL,pURL)

    # These next steps illustrate a request to get an authToken
    # that is necessary for use in all Publish requests. The user
    # should have a valid account with the operator that the 
    # request is being sent to. The user ID and password
    # are supplied to the user upon registration with the 
    # operator.
    # Construct a getAuthToken request object.
    request = getAuthToken()

    # Please insert the appropriate user ID provided by the operator
    # for the account you wish to use.
    request.setUserID("some user id")

    # Please insert the appropriate password for this account.
    request.setCred("some user password")

    # Send the request object to the API, and construct an authToken
    # with the responseDOM object that is returned. (This is a shortcut
    # from the two step process used in Example 1)
    aToken = authToken(uddiCon.send(request))

    # These next steps illustrate a request to get a complete businessDetails for
    # a particular business owned by the account used above.
    # Assign a local variable a "business key" that this user account owns.
    businessKey = "some business key"

    # Construct a getBusinessDetail request object.
    request = getBusinessDetail()

    # Set the businessKey request parameter.
    request.setBusinessKeyStrings([businessKey])

    # Send the request object to the API, and construct a businessDetail
    # with the responseDOM object that is returned. (This is a shortcut
    # from the two step process used in Example 1)
    response = businessDetail(uddiCon.send(request))

    # Get the businessEntity object using the access method provided
    # by the response object. Notice that this returns an array of
    # businessEntity objects, and I am only interested in the first
    # occurrance.
    # Store in a local variable the first businessEntity in the array.
    business = response.getBusinessEntityArray()[0]

    # Store in a local variable the first description in the array.
    desc = business.getDescriptions()[0]

    # Set the description to something new.
    desc.setText("New business description.")

    # Set the businessEntity to this new description.
    business.setDescriptions([desc])

    # These next steps illustrate a request to save the business which 
    # we have modified the description for.
    # Construct a saveBusiness object.
    request = saveBusiness()

    # Insert into the businessEntityArray request parameter, the updated
    # business from above.
    request.setBusinessEntityArray([business])

    # Set the authentication information from the authToken that we 
    # initially retrieved.
    request.setAuthInfo(aToken.getAuthInfo())

    # Send the request object to the API, and construct a businessDetail
    # with the responseDOM object that is returned. (This is a shortcut
    # from the two step process used in Example 1)
    response = businessDetail(uddiCon.send(request))

    # Display the response as XML format. All the objects defined by the
    # toolkit provide a method to convert the underlying object to an XML
    # string format.
    print response

# Catch any errors or in particular a DispositionReport UDDIError object.
except(socket.error,UDDIError), e:
    print e

If you notice, the listing above follows the same distinct technique outlined in example 1. Each request object that is created is meant to retrieve data that is needed to build the final saveBusiness request message object. It is a typical pattern for all publish requests since there needs to be an initial code section to retrieve the authentication information.

It is important to note that although the previous example was updating existing data in the registry, the same procedure can be followed in order to save new data to the registry. The only difference between saving new versus updating data, is that the initial keys are not set. This indicates to the registry that the data does not exist and to generate a unique key to identify this data.

Example 3: A complete program to publish new business information.
# *******************
# Import the modules.
# *******************
from UDDI4Py.client import *
from UDDI4Py.requestDOM import *
from UDDI4Py.responseDOM import *

# **************************************
# The URL's where the UDDI API's reside.
# **************************************
iURL = "http://www-3.ibm.com/services/uddi/v2beta/inquiryapi"
pURL = "https://www-3.ibm.com/services/uddi/v2beta/protect/publishapi"

# ************************************************************
# save_business
#
# Save a new business with a new service to the registry. 
# The distinguishing feature between a save and an update, is
# that for a save the business key does not exist, and is not
# set for the corresponding objects.
# ************************************************************
try:
    # Construct a proxy object used to send a response object to the 
    # appropriate URL.
    uddiCon = UDDIProxy(iURL,pURL)

    # These next steps illustrate a request to get an authToken
    # that is necessary for use in all Publish requests. The user
    # should have a valid account with the operator that the 
    # request is being sent to. The user ID and password
    # are supplied to the user upon registration with the 
    # operator.
    # Construct a getAuthToken request object.
    request = getAuthToken()

    # Please insert the appropriate user ID provided by the operator
    # for the account you wish to use.
    request.setUserID("some user id")

    # Please insert the appropriate password for this account.
    request.setCred("some user password")

    # Send the request object to the API, and construct an authToken
    # with the responseDOM object that is returned. (This is a shortcut
    # from the two step process used in Example 1)
    aToken = authToken(uddiCon.send(request))

    # Construct a saveBusiness request object.
    request = saveBusiness()

    # Construct a businessEntity object.
    business = businessEntity()

    # Construct a description object, and set it's text description.
    desc = description()
    desc.setText("New business description")

    # Set the description array for the business object to the description.
    business.setDescriptions([desc])

    # Construct a name object, and set it's text name.
    name = name()
    name.setText("New business name")

    # Set the names array for the business object to the name.
    business.setNames([name])

    # Construct a businessService object.
    service = businessService()

    # Set the description object's text to reflect the service
    # description.
    desc.setText("New service description")

    # Set the description array for the service object to the description.
    service.setDescriptions([desc])

    # Set the name object's text to reflect the service name.
    name.setText("New service name")

    # Set the names array for the service object to the name.
    service.setNames([name])

    # Construct a businessServices object.
    bServices = businessServices()

    # Set the businessServices array for the businessServices object to the
    # businessService.
    bServices.setBusinessServices([service])

    # Set the businessServices object for the business object to the 
    # businessServices.
    business.setBusinessServices(bServices)

    # Set the businessEntityArray for the request object to the business.
    request.setBusinessEntityArray([business])

    # Set the authentication information from the authToken that we 
    # initially retrieved.
    request.setAuthInfo(aToken.getAuthInfo())

    # Send the request object to the API, and construct a businessDetail
    # with the responseDOM object that is returned. (This is a shortcut
    # from the two step process used in Example 1)
    response = businessDetail(uddiCon.send(request))

    # Display the response as XML format. All the objects defined by the
    # toolkit provide a method to convert the underlying object to an XML
    # string format.
    print response

# Catch any errors or in particular a UDDIError object.
except(socket.error,UDDIError), e:
    print e

You should also take notice from the previous example that not only is a new business being saved, but also a new service for this business is saved. This is accomplished by not specifying a key for the service object that is created for the business. The publishing of this new service could have be done in a separate call to the save_service API, but for this example it is intended to show how sometimes multiple requests can be combined into a single request to the registry.

The examples provided thus far have demonstrated the publishing of business and service information to the registry. Users of the UDDI Registry also have the capability of publishing technical references to Web interfaces (specifications) that they define. These technical references are called tModels by the UDDI Specification, and the interfaces that they reference are typically Web Services. The publishing of tModels to the registry follows the same outline as described in the previous publish examples. In using the UDDI Registry for publishing tModels, users make the discovery and integration of their Web Services easily accessible.

Example 4: A complete program to publish new a new tModel.
# *******************
# Import the modules.
# *******************
from UDDI4Py.client import *
from UDDI4Py.requestDOM import *
from UDDI4Py.responseDOM import *

# **************************************
# The URL's where the UDDI API's reside.
# **************************************
iURL = "http://www-3.ibm.com/services/uddi/v2beta/inquiryapi"
pURL = "https://www-3.ibm.com/services/uddi/v2beta/protect/publishapi"

# ************************************************************
# save_tModel
#
# Save a new tModel to the registry. The distinguishing 
# feature between a save and an update, is that for a save 
# the tModel key does not exist, and is not set for the 
# corresponding objects.
# ************************************************************
try:
    # Construct a proxy object used to send a response object to the 
    # appropriate URL.
    uddiCon = UDDIProxy(iURL,pURL)

    # These next steps illustrate a request to get an authToken
    # that is necessary for use in all Publish requests. The user
    # should have a valid account with the operator that the 
    # request is being sent to. The user ID and password
    # are supplied to the user upon registration with the 
    # operator.
    # Construct a getAuthToken request object.
    request = getAuthToken()

    # Please insert the appropriate user ID provided by the operator
    # for the account you wish to use.
    request.setUserID("some user id")

    # Please insert the appropriate password for this account.
    request.setCred("some user password")

    # Send the request object to the API, and construct an authToken
    # with the responseDOM object that is returned. (This is a shortcut
    # from the two step process used in Example 1)
    aToken = authToken(uddiCon.send(request))

    # Construct a saveTModel request object.
    request = saveTModel()

    # Construct a tModel object.
    aTModel = tModel()

    # Construct a description object, and set it's text description.
    desc = description()
    desc.setText("New tModel description")

    # Set the description array for the business object to the description.
    aTModel.setDescriptions([desc])

    # Construct a name object, and set it's text name.
    name = name()
    name.setText("New tModel name")

    # Set the names array for the business object to the name.
    aTModel.setName(name)

    # Set the tModelArray for the request object to the tModel.
    request.setTModelArray([aTModel])

    # Set the authentication information from the authToken that we 
    # initially retrieved.
    request.setAuthInfo(aToken.getAuthInfo())

    # Send the request object to the API, and construct a tModelDetail
    # with the responseDOM object that is returned. (This is a shortcut
    # from the two step process used in Example 1)
    response = tModelDetail(uddiCon.send(request))

    # Display the response as XML format. All the objects defined by the
    # toolkit provide a method to convert the underlying object to an XML
    # string format.
    print response

# Catch any errors or in particular a UDDIError object.
except(socket.error,UDDIError), e:
    print e

There are a few other UDDI constructs that in conjunction with tModels, enable users of the registry to bind to Web Services through their applications. The bindingTemplate, tModelInstanceInfo, InstanceParms, and other constructs are described in more detail in the UDDI Programmer's guide. The process of discovering and publishing these structures using the UDDI Registry follow the same procedures outlined in the examples above.

These examples should provide you with the basis for formulating and processing the messages sent to and recieved from the UDDI API. So go visit the UDDI website to get a copy of the latest API Specification, get registered for an account with the IBM Operator Node, and get started publishing and integrating Web services with your Python applications.

Implementation Notes
The UDDI API is an XML based specification, and as such, the most natural way to represent these messages is to model them using DOM structures. A DOM structure kept in memory allows for an easy traversal to add data as needed. It also provides for a manageable way to retrieve needed data contained within the structure. The Python objects created using the UDDI4Py toolkit, all use an underlying DOM to abstract the XML handling from the user.

It is also important to note that XML adheres to the Unicode standard for text representation. The UDDI Specification supports this standard (since the defined messages are XML markup), and requires all requests to be UTF-8 encoded. Python provides support for Unicode data via the Unicode object. A Unicode string can be constructed in Python as follows:

Listing 4:  Constructing Unicode data using Python.
description = u"Unicode test description \u00DC"

The small u in front of the string indicates that this is a Unicode string. The \u00DC indicates a Unicode-Escape character to be inserted with an ordinal value of 0x00DC (the Ü character). This Unicode string can now be set as a description for any one of the appropriate UDDI constructs. This allows users to publish data to the registry using any international character set. Please keep in mind that while working with character data outside the 7-bit ASCII range, if you try to display or write this data out to file, you may get the following result (depending on the default encoding used by your system):

Listing 5: Using character data not supported by default encoding.
# The response object contains Unicode character data.
print response

Output (Exception thrown):
UnicodeError: ASCII encoding error: ordinal not in range(128)

I have assumed in Example 1 and 2, that I was not working with Unicode data. The exception above would have been thrown upon execution of the print statement, had this not been the case. To protect your applications from this, you may want to do the following when using methods that depend on the default system encoding (such as print):

Listing 6: Protect against invalid encoding errors for character data.
# Convert the response to a Unicode string object, and display it using utf-8 encoding.
print unicode(response).encode("utf-8")

For a complete instruction on using Unicode strings in Python, please visit the website.

The Python Web services revolution
Python is evolving as a natural way to develop Web services. A number of modules are bundled with the standard interpreter, as are hosted as open source on developerWorks. There is also a zone on the developerWorks website that is completely dedicated to providing information and resources on using and creating Web services. It is hopeful that the UDDI4Py toolkit becomes a necessary indegredient to the Python Web services recipe.

References
[1] Web services architect, Part I: An introduction to dynamic e-business. IBM DeveloperWorks 09-April-2001. Dan Gisolfi (IBM).

Resources

About the author
Julio Ruano is a Software Engineer working for the IBM UDDI Public Node team. He has a BS in Computer Science from Florida International University in Miami, Florida. As a member of the UDDI team, he is responsible for the development and implementation of the API, and its conformance to the specification. He is working hard trying to make developers aware of the power and significance that the Python language brings to the Web services arena. You can reach him at ruano@us.ibm.com.