Access Keys:
Skip to content (Access Key - 0)

Knowledgebase

Developing Python Clients

Contents

The best way to access web services from Python is to use the ZSI library. The ZSI distribution contains a code generation feature that reads WSDL and generates a Python API. After this initial step, ZSI is then used as a SOAP library. Unfortunately, the ZSI library does not currently work "out-of-the-box" with caGrid services. Some code modifications to ZSI are necessary and so they are described here in detail.

Prerequisites

This tutorial demonstrates how to access the caCORE 4.0 Grid Service from a Python client. This is a typical data service on the caGrid, making it a general example of Python access to the caGrid.

Software version prerequisites:

  • Python 2.5+
  • ZSI 2.1_a1

Download

Download the ZSI source distribution from SourceForge and install it. Do not use the .egg file, because you will need to make some modifications to the ZSI code base. Also note that this tutorial contains workarounds specific to ZSI version 2.1_a1. Future versions of ZSI may require updates to these instructions.

Extract the File:

> tar xvfz ZSI-2.1-a1.tar.gz 
> cd ZSI-2.1-a1 

As mentioned previously, ZSI requires some minor code changes to work with caGrid. You can choose to apply all the patches at once, or see the ZSI Code Changes section below for step-by-step directions. These patches are temporary stop-gap measures and should not be relied on for production code.

ZSI Code Changes

ComplexType with Annotation

Running wsdl2py may initially produce the following exception:

 IndexError: list index out of range
This seems to be a bug in ZSI in that it assumes a <complexType> always has another child after an <annotation>. You can fix this as follows:

ZSI/wstools/XMLSchema.py
2471,2472c2474,2479
<             component = SplitQName(contents[indx].getTagName())[1]
<
---
>             if indx < len(contents):
>                 component = SplitQName(contents[indx].getTagName())[1]
>             else:
>                 component = None

Unsupported Base Type

When you make the first change and run wsdl2py again, you encounter another error:

 Unsupported base('http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-BaseFaults-1.4-draft-01.xsd', 'BaseFaultType')
This seems to be a limitation of ZSI, which only supports a limited set of base types. Commenting out the error code seems to work.

ZSI/generate/containers.py
2392,2399c2392,2399
<             if base is None:
<                 raise ContainerError, 'Unsupported derivation: %s'\
<                         %derivation.getItemTrace()
<
<             if base \!= (SOAP.ENC,'Array') and base \!= (SCHEMA.XSD3,'anyType'):
<                 raise ContainerError, 'Unsupported base(%s): %s' %(
<                     base, derivation.getItemTrace()
<                     )
---
> #            if base is None:
> #                raise ContainerError, 'Unsupported derivation: %s'\
> #                        %derivation.getItemTrace()
> #
> #            if base \!= (SOAP.ENC,'Array') and base \!= (SCHEMA.XSD3,'anyType'):
> #                raise ContainerError, 'Unsupported base(%s): %s' %(
> #                    base, derivation.getItemTrace()
> #                    )

The wsdl2py program should now run without issue.

CQLQuery Serialization

Attempting to use query() with a CQLQuery may result in the following exception:

 TypeError: bad usage, failed to serialize element reference ([http://CQL.caBIG/1/gov.nih.nci.cagrid.CQLQuery], CQLQuery), in: /SOAP-ENV:Body/ns1:QueryRequest
The error message here is too vague to diagnose the problem. However, it will work if you comment out this error checking:

TCcompound.py
58,61c58,61
<         if (typecode.nspname,typecode.pname) == (sub.nspname,sub.pname):
<             raise TypeError(\
<                 'bad usage, failed to serialize element reference (%s, %s), in: %s' %
<                  (typecode.nspname, typecode.pname, sw.Backtrace(elt),))
---
> #        if (typecode.nspname,typecode.pname) == (sub.nspname,sub.pname):
> #            raise TypeError(\
> #                'bad usage, failed to serialize element reference (%s, %s), in: %s' %
> #                 (typecode.nspname, typecode.pname, sw.Backtrace(elt),))
67,70c67,70
<         raise TypeError(\
<             'failed to serialize (%s, %s) illegal sub GED (%s,%s): %s' %
<              (typecode.nspname, typecode.pname, sub.nspname, sub.pname,
<               sw.Backtrace(elt),))
---
> #        raise TypeError(\
> #            'failed to serialize (%s, %s) illegal sub GED (%s,%s): %s' %
> #             (typecode.nspname, typecode.pname, sub.nspname, sub.pname,
> #              sw.Backtrace(elt),))

Target Namespace

Finally, there is an error from the Axis side:

 ZSI.FaultException: org.xml.sax.SAXException: Invalid element in gov.nih.nci.cagrid.cqlquery.CQLQuery - Target
This is caused by the fact that the SOAP generated by ZSI is using the wrong namespace for Target and Attribute. For example:

<ns2:CQLQuery>
<Target name="gov.nih.nci.cabio.domain.Gene" xsi:type="ns2:Object">
<Attribute name="symbol" predicate="LIKE" value="Brca1" xsi:type="ns2:Attribute"></Attribute>
</Target>
</ns2:CQLQuery>

Target and Attribute should be in the same namespace as CQLQuery. ZSI discards the namespace on these elements and uses xsi:type instead. To ensure the namespace appears correctly:

schema.py
352c352,355
<             self.__cache = self.klass(pname=self.pname,
---
>             reconstruct_pname = self.pname
>             if self.nspname:
>                 reconstruct_pname = (self.nspname,self.pname)
>             self.__cache = self.klass(pname=reconstruct_pname,

All of these changes are available as a patch.

Installation

In the ZSI-2.1-a1 folder, do the following command:

> sudo python setup.py install

API Generation

You can use wsdl2py to generate the Python code for the domain and service object. In general, caGrid services will need two special options enabled: lazy typecode evaluation (-l) and complex types (-b).

> wsdl2py -lb http://cabiogrid40.nci.nih.gov/wsrf/services/cagrid/CaBIO40GridSvc?wsdl

This should generate three modules:

  • CaBIO40GridSvc_client.py
  • CaBIO40GridSvc_server.py
  • CaBIO40GridSvc_types.py

API Usage

As a simple example, make a file querying.py that searches for caBIO Genes that have a symbol starting with "Brca".

from CaBIO40GridSvc_client import *
c = CaBIO40GridSvcServiceLocator().getCaBIO40GridSvcPortTypePort()

# Create Attribute restriction
attr = ns17.Attribute_Def(None).pyclass()
attr._attrs = { 'name': 'symbol',
                'value': 'Brca%',
                'predicate': 'LIKE', }

# Create Target (Gene)
target = ns17.Object_Def(None).pyclass()
target._attrs = {'name':'gov.nih.nci.cabio.domain.Gene'}
target.Attribute = attr

# Create CQLQuery
cq = ns17.CQLQuery_Dec().pyclass()
cq.Target = target

# Create QueryRequest
qacq = ns4.QueryRequest_Dec.cqlQuery_Dec().pyclass()
qacq.CQLQuery = cq
qr = QueryRequest()
qr.CqlQuery = qacq

# Execute query
ret = c.query(qr)

# Print results
for o in ret.CQLQueryResultCollection.ObjectResult:print o.Any.get_attribute_fullName()

Run the program

> python querying.py

This program should output:

Breast cancer 1, early onset
Breast cancer 1
BRCA1 pseudogene 1
Breast cancer 2
Breast cancer 2, early onset
breast cancer 3
Breast cancer, 11;22 translocation associated

To print out SOAP messages for debugging purposes:

import sys
c = CaBIO40GridSvcServiceLocator().getCaBIO40GridSvcPortTypePort(tracefile=sys.stdout)
Last edited by
Saba Bokhari (565 days ago) , ...
Adaptavist Theme Builder Powered by Atlassian Confluence