Warning

This document hasn't been checked for compatibility with current versions of Plone. Use at your own risk.

Importing a SOAP client object to be used by python scripts

by fessiers — last modified May 17, 2009 09:50 AM
This How-to shows the use of ZSI's code generation tool and how import the result objects into a python script. Loading these generated classes into Zope didn't go as easily as I had hoped, hence the impetus for this document. I use Amazon's Web Services platform as an example, but using this as SOAP client allows you to interconnect heterogeneous web services platforms with Plone. In particular, I show how to execute a keyword search for products on Amazon and use the result objects.

Loading external data is a topic frequently seen in Plone, as with any CMS. One way to accomplish this is with SOAP, if your data sources support it. With these tools, you can also use Plone to view, and even manage content in a heterogeneous platform.

You should be careful of the performance issues relating to any request relying on external systems. It would not be realistic to expect a fast response from Amazon for every visitor to your site!

Getting ZSI

There are several Python SOAP implementations and two of the most well-know are SOAPpy and ZSI . You will need ZSI installed to follow this example but before you do so, see the section below titled Altering the Offending Code.

WSDL2PY

ZSI includes a handy tool, WSDL2PY which generates types and interface code from a WSDL. For more info on WSDL2PY see OpenSourceTutorials.com Python SOAP libraries, Part 4, page 2 .

Connecting to Amazon

Amazon offers web services implementations for developers and can be had from Amazon Web Services .

To subscribe to their service, you need to register as a deveoper and be granted a Subscription ID AKA Developer Token AKA Developer Tag.

As of this writing, WSDL2PY was not compatible with Amazon E-Commerce Service (ECS) version 4.0, so I reverted to version 3.0. Finally here's the WSDL for version 3.0

Generating Python Code

To Generate their code:

    wsdl2py -f <wsdl file>

Modifying the generated code for use with restricted python and ZPT

To use a generated class, you will need to have the objects inherit from, at minimum, Acquisition.Explicit or Acquisition.Implicit. I was lazy, and inherited from OFS.SimpleItem. The object that I wanted to use in ZPT was Amazon's Details_Def, found in the generated AmazonSearch_services_types.py. import SimpleItem and Change:

  class Details_Def(ZSI.TCcompound.Struct)

To:

  class Details_Def(ZSI.TCcompound.Struct, SimpleItem)

Next, in all generated files, Change every instance of:

  .__init__(...)

to:

  .__dict__['__init__'](...)

That's easy. Is that it?

Well it should be. Unfortunately, as of this writing there exists an inheritance problem with ZSI which will not allow you to also inherit from an Acquisition class. If you haven't installed ZSI yet, you might as well make the following adjustments before you install.

Altering the Offending Code

In ZSI-1.6.0, the offending code should have been installed by ZSI in python/site_packages/ZSI/TCcompound.py. You will need to alter the typechecking to also check for extension classes. This is beyond my python skills so I simply commented out the following lines:

  TCcompound.py:63 
        if TypeCode.typechecks:
            if self.pyclass is not None and type(self.pyclass) != types.ClassType:
                raise TypeError('pyclass must be None or a class, not ' +
                        str(type(self.pyclass)))
            _check_typecode_list(self.ofwhat, 'Struct')

  TCcompound.py:272
            if t != types.InstanceType:
                raise TypeError(
                    'Array ofwhat must be an instance, not ' + str(t))

Using Generated Code in a Tool

Using the generated code is relatively easy. Creating a tool lets you query the service and manipulate the reqults as needed. Add the :

  from Products.CMFCore.utils import getToolByName, UniqueObject
  from Globals import InitializeClass
  from OFS.SimpleItem import SimpleItem
  from AmazonSearch_services import *
  import AmazonSearch_services_types
  class AmazonClass
          def extractByKeyword(zope,KEYWORD,mode,offset):
                tracefile=open('path/to/logfile','w')
                tracefile.write('Starting log session\n')
                kw = { 'tracefile' : tracefile }

                loc = AmazonSearchServiceLocator()
                porttype = loc.getAmazonSearchPort(**kw)

                keyword = ns1.KeywordRequest_Def()
                keyword._type='heavy'
                keyword._keyword=KEYWORD
                keyword._mode=mode
                keyword._page=offset
                keyword._devtag=<your developer id>
                keyword._tag=<your developer id>
                request=KeywordSearchRequestWrapper()
                request._KeywordSearchRequest=keyword

                response = porttype.KeywordSearchRequest(request)
                details = response._return._Details
                dli = []
                for detail in details:
                        detail.manage_permission(CMFCorePermissions.View, ('Anonymous','Manager','Mod','Owner'), 0)
                        dli.append(detail.__of__(zope))
                return dli

Contribute

Something wrong or out of date? Anybody can edit or create a new article in the knowledge base. Simply create an account on this site, log in, and click the Edit button to contribute.