tags:

views:

705

answers:

2

I'm investigating SUDS as a SOAP client for python. I want to inspect the methods available from a specified service, and the types required by a specified method.

The aim is to generate a user interface, allowing users to select a method, then fill in values in a dynamically generated form.

I can get some information on a particular method, but am unsure how to parse it:

client = Client(url)
method = client.sd.service.methods['MyMethod']

I am unable to programmaticaly figure out what object type I need to create to be able to call the service

obj = client.factory.create('?')

res = client.service.MyMethod(obj, soapheaders=authen)

Does anyone have some sample code?

+2  A: 

According to suds documentation, you can inspect service object with __str()__. So the following gets a list of methods and complex types:

from suds.client import Client;

url = 'http://www.webservicex.net/WeatherForecast.asmx?WSDL'
client = Client(url)

temp = str(client);

The code above produces following result (contents of temp):

Suds ( https://fedorahosted.org/suds/ )  version: 0.3.4 (beta)  build: R418-20081208

Service ( WeatherForecast ) tns="http://www.webservicex.net"
   Prefixes (1)
      ns0 = "http://www.webservicex.net"
   Ports (2):
      (WeatherForecastSoap)
         Methods (2):
            GetWeatherByPlaceName(xs:string PlaceName, )
            GetWeatherByZipCode(xs:string ZipCode, )
         Types (3):
            ArrayOfWeatherData
            WeatherData
            WeatherForecasts
      (WeatherForecastSoap12)
         Methods (2):
            GetWeatherByPlaceName(xs:string PlaceName, )
            GetWeatherByZipCode(xs:string ZipCode, )
         Types (3):
            ArrayOfWeatherData
            WeatherData
            WeatherForecasts

This would be much easier to parse. Also every method is listed with their parameters along with their types. You could, probably, even use just regular expression to extract information you need.

artdanil
+1  A: 

Okay, so SUDS does quite a bit of magic.

A suds.client.Client, is built from a WSDL file:

client = suds.client.Client("http://mssoapinterop.org/asmx/simple.asmx?WSDL")

It downloads the WSDL and creates a definition in client.wsdl. When you call a method using SUDS via client.service.<method> it's actually doing a whole lot of recursive resolve magic behind the scenes against that interpreted WSDL. To discover the parameters and types for methods you'll need to introspect this object.

For example:

for method in client.wsdl.services[0].ports[0].methods.values():
    print '%s(%s)' % (method.name, ', '.join('%s: %s' % (part.type, part.name) for part in method.soap.input.body.parts))

This should print something like:

echoInteger((u'int', http://www.w3.org/2001/XMLSchema): inputInteger)
echoFloatArray((u'ArrayOfFloat', http://soapinterop.org/): inputFloatArray)
echoVoid()
echoDecimal((u'decimal', http://www.w3.org/2001/XMLSchema): inputDecimal)
echoStructArray((u'ArrayOfSOAPStruct', http://soapinterop.org/xsd): inputStructArray)
echoIntegerArray((u'ArrayOfInt', http://soapinterop.org/): inputIntegerArray)
echoBase64((u'base64Binary', http://www.w3.org/2001/XMLSchema): inputBase64)
echoHexBinary((u'hexBinary', http://www.w3.org/2001/XMLSchema): inputHexBinary)
echoBoolean((u'boolean', http://www.w3.org/2001/XMLSchema): inputBoolean)
echoStringArray((u'ArrayOfString', http://soapinterop.org/): inputStringArray)
echoStruct((u'SOAPStruct', http://soapinterop.org/xsd): inputStruct)
echoDate((u'dateTime', http://www.w3.org/2001/XMLSchema): inputDate)
echoFloat((u'float', http://www.w3.org/2001/XMLSchema): inputFloat)
echoString((u'string', http://www.w3.org/2001/XMLSchema): inputString)

So the first element of the part's type tuple is probably what you're after:

>>> client.factory.create(u'ArrayOfInt')
(ArrayOfInt){
   _arrayType = ""
   _offset = ""
   _id = ""
   _href = ""
   _arrayType = ""
 }

Update:

For the Weather service it appears that the "parameters" are a part with an element not a type:

>>> client = suds.client.Client('http://www.webservicex.net/WeatherForecast.asmx?WSDL')
>>> client.wsdl.services[0].ports[0].methods.values()[0].soap.input.body.parts[0].element
(u'GetWeatherByZipCode', http://www.webservicex.net)
>>> client.factory.create(u'GetWeatherByZipCode')
(GetWeatherByZipCode){
   ZipCode = None
 }

But this is magic'd into the parameters of the method call (a la client.service.GetWeatherByZipCode("12345"). IIRC this is SOAP RPC binding style? I think there's enough information here to get you started. Hint: the Python command line interface is your friend!

sj26