SUDS - programmatic access to methods and types
Asked Answered
V

8

23

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?

Vernonvernor answered 28/10, 2008 at 0:52 Comment(0)
O
30

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!

Office answered 7/12, 2009 at 6:12 Comment(1)
For some reason, these are all "None" with the wsdl I'm working with, so I don't get the parameters or the type, however, they do show up in str(client) and have both the parameter and type there.Stylolite
J
20

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.

Jamestown answered 3/12, 2009 at 20:46 Comment(0)
P
10

Here's a quick script I wrote based on the above information to list the input methods suds reports as available on a WSDL. Pass in the WSDL URL. Works for the project I'm currently on, I can't guarantee it for yours.

import suds

def list_all(url):
    client = suds.client.Client(url)
    for service in client.wsdl.services:
        for port in service.ports:
            methods = port.methods.values()
            for method in methods:
                print(method.name)
                for part in method.soap.input.body.parts:
                    part_type = part.type
                    if(not part_type):
                        part_type = part.element[0]
                    print('  ' + str(part.name) + ': ' + str(part_type))
                    o = client.factory.create(part_type)
                    print('    ' + str(o))
Purposeful answered 17/5, 2013 at 19:25 Comment(0)
S
4

You can access suds's ServiceDefinition object. Here's a quick sample:

from suds.client import Client
c = Client('http://some/wsdl/link')

types = c.sd[0].types

Now, if you want to know the prefixed name of a type, it's also quite easy:

c.sd[0].xlate(c.sd[0].types[0][0])

This double bracket notation is because the types are a list (hence a first [0]) and then in each item on this list there may be two items. However, suds's internal implementation of __unicode__ does exactly that (i.e. takes only the first item on the list):

s.append('Types (%d):' % len(self.types))
    for t in self.types:
        s.append(indent(4))
        s.append(self.xlate(t[0]))

Happy coding ;)

Showiness answered 24/7, 2013 at 9:43 Comment(0)
P
1

Once you created WSDL method object you can get information about it from it's __metadata__, including list of it's arguments' names.

Given the argument's name, you can access it's actual instance in the method created. That instance also contains it's information in __metadata__, there you can get it's type name

# creating method object
method = client.factory.create('YourMethod')
# getting list of arguments' names
arg_names = method.__metadata__.ordering
# getting types of those arguments
types = [method.__getitem__(arg).__metadata__.sxtype.name for arg in arg_names]

Disclaimer: this only works with complex WSDL types. Simple types, like strings and numbers, are defaulted to None

Phylloxera answered 23/12, 2015 at 20:1 Comment(0)
S
1
from suds.client import Client
url = 'http://localhost:1234/sami/2009/08/reporting?wsdl'
client = Client(url)
functions = [m for m in client.wsdl.services[0].ports[0].methods]
count = 0
for function_name in functions:
    print (function_name)
    count+=1
print ("\nNumber of services exposed : " ,count)
Skintight answered 23/11, 2016 at 10:42 Comment(0)
D
0

i needed an example of using suds with objects. beside the answers found here, i found a very good article that answered my question even further.

here is a short summary:

first, print the client to see an overview of it's content.

from suds.client import Client client =
Client("https://wsvc.cdiscount.com/MarketplaceAPIService.svc?wsdl")
print client

second, create an instance of a type (using it's name including it's prefix ns*.), and print it, to see it's member data.

HeaderMessage = client.factory.create('ns0:HeaderMessage')
print HeaderMessage

to fill your object's data members, either assign them a scalar value for scalar members, or a dict, to object members.

HeaderMessage.Context =  {
     "CatalogID": "XXXXX"
     "CustomerID": 'XXXXX'
     "SiteID": 123
 }

members whose type name start with ArrayOf expect a list of objects of the type mentioned in the rest of the type name.

ArrayOfDomainRights = client.factory.create('ns0:ArrayOfDomainRights')
ArrayOfDomainRights.DomainRights = [XXXXXXXXXXXXX, XXXXXXXXXXXX]
Delija answered 13/5, 2020 at 6:7 Comment(0)
D
0

i needed an example of using suds with objects. beside the answers found here, i found a very good article that answered my question even further.

here is a short summary:

first, print the client to see an overview of it's content.

from suds.client import Client client =
Client("https://wsvc.cdiscount.com/MarketplaceAPIService.svc?wsdl")
print client

second, create an instance of a type (using it's name including it's prefix ns*.), and print it, to see it's member data.

HeaderMessage = client.factory.create('ns0:HeaderMessage')
print HeaderMessage

to fill your object's data members, either assign them a scalar value for scalar members, or a dict, to object members.

HeaderMessage.Context =  {
     "CatalogID": "XXXXX"
     "CustomerID": 'XXXXX'
     "SiteID": 123
 }

members whose type name start with ArrayOf expect a list of objects of the type mentioned in the rest of the type name.

ArrayOfDomainRights = client.factory.create('ns0:ArrayOfDomainRights')
ArrayOfDomainRights.DomainRights = [XXXXXXXXXXXXX, XXXXXXXXXXXX]
Delija answered 16/5, 2020 at 20:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.