SUDS – acceso programático a métodos y tipos

Estoy investigando SUDS como cliente de SOAP para python. Quiero inspeccionar los métodos disponibles de un servicio específico y los tipos requeridos por un método específico.

El objective es generar una interfaz de usuario que permita a los usuarios seleccionar un método y luego completar los valores en un formulario generado dinámicamente.

Puedo obtener información sobre un método en particular, pero no estoy seguro de cómo analizarlo:

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

No puedo determinar de manera programática qué tipo de objeto debo crear para poder llamar al servicio

 obj = client.factory.create('?') res = client.service.MyMethod(obj, soapheaders=authen) 

¿Alguien tiene algún código de ejemplo?

Bien, entonces SUDS hace un poco de magia.

Un suds.client.Client , se construye a partir de un archivo WSDL:

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

Descarga el WSDL y crea una definición en client.wsdl . Cuando llama a un método utilizando SUDS a través de client.service. en realidad está haciendo un montón de magia de resolución recursiva tras bambalinas contra el WSDL interpretado. Para descubrir los parámetros y tipos de métodos, deberá realizar una introspección de este objeto.

Por ejemplo:

 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)) 

Esto debería imprimir algo como:

 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) 

Por lo tanto, el primer elemento del tipo de tupla de la pieza es probablemente lo que está buscando:

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

Actualizar:

Para el servicio meteorológico, parece que los “parámetros” son una parte con un element no es un 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 } 

Pero esto está incluido en los parámetros de la llamada al método (a la client.service.GetWeatherByZipCode("12345") . IIRC es un estilo de enlace SOAP RPC. Creo que hay suficiente información aquí para comenzar. Sugerencia: el Python interfaz de línea de comandos es tu amigo!

De acuerdo con la documentación de la suds , puede inspeccionar el objeto de service con __str()__ . Así que lo siguiente obtiene una lista de métodos y tipos complejos:

 from suds.client import Client; url = 'http://www.webservicex.net/WeatherForecast.asmx?WSDL' client = Client(url) temp = str(client); 

El código anterior produce el siguiente resultado (contenido de 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 

Esto sería mucho más fácil de analizar. Además, cada método se enumera con sus parámetros junto con sus tipos. Probablemente, incluso podría usar expresiones regulares para extraer la información que necesita.

Aquí hay una secuencia de comandos rápida que escribí en base a la información anterior para enumerar los informes de los métodos de entrada de suds que están disponibles en un WSDL. Pase en la URL WSDL. Trabaja para el proyecto en el que estoy actualmente, no puedo garantizarlo para el tuyo.

 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)) 

Puede acceder al objeto ServiceDefinition de suds. Aquí hay una muestra rápida:

 from suds.client import Client c = Client('http://some/wsdl/link') types = c.sd[0].types 

Ahora, si quieres saber el nombre prefijado de un tipo, también es bastante fácil:

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

Esta notación de doble corchete se debe a que los tipos son una lista (de ahí un primer [0]) y luego en cada elemento de esta lista puede haber dos elementos. Sin embargo, la implementación interna de __unicode__ de suds hace exactamente eso (es decir, toma solo el primer elemento de la lista):

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

Feliz encoding;)

Una vez que haya creado el objeto del método WSDL, puede obtener información sobre él desde __metadata__ , incluida la lista de los nombres de sus argumentos.

Dado el nombre del argumento, puede acceder a su instancia real en el método creado. Esa instancia también contiene su información en __metadata__ , allí puede obtener su nombre de tipo

 # 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] 

Descargo de responsabilidad: esto solo funciona con tipos WSDL complejos. Los tipos simples, como cadenas y números, están predeterminados en Ninguno

 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)