I have a vendor-supplied webservice; the WSDL for a certain operation looks like:
<complexType name="ArrayOf_soapenc_string">
<complexContent>
<restriction base="soapenc:Array">
<attribute ref="soapenc:arrayType" wsdl:arrayType="soapenc:string[]"/>
</restriction>
</complexContent>
</complexType>
...
<wsdl:message name="initExportDeviceRequest">
<wsdl:part name="filter" type="soapenc:string"/>
<wsdl:part name="options" type="impl:ArrayOf_soapenc_string"/>
</wsdl:message>
...
<wsdl:operation name="initExportDevice" parameterOrder="filter options">
<wsdl:input message="impl:initExportDeviceRequest" name="initExportDeviceRequest"/>
<wsdl:output message="impl:initExportDeviceResponse" name="initExportDeviceResponse"/>
</wsdl:operation>
Running python -mzeep ipam_export.wsdl
on the WSDL yields this:
Global types:
ns0:ArrayOf_soapenc_string(_value_1: string[], arrayType: xsd:string, offset: ns1:arrayCoordinate, id: xsd:ID, href: xsd:anyURI, _attr_1: {})
...
Service: ExportsService
Port: Exports (Soap11Binding: {http://diamondip.com/netcontrol/ws/}ExportsSoapBinding)
Operations:
...
initExportDevice(filter: ns1:string, options: {_value_1: string[], arrayType: xsd:string, offset: ns1:arrayCoordinate, id: xsd:ID, href: xsd:anyURI, _attr_1: {}}) -> initExportDeviceReturn: ns2:WSContext
I am having difficulty in executing the initExportDevice call, specifically, the options
parameter.
How to use a complex type from a WSDL with zeep in Python suggests to me that this should work:
filter_type=client.get_type('ns1:string')
filter=filter_type('addrType=4')
options_type=client.get_type('ns0:ArrayOf_soapenc_string')
options=options_type(['recurseContainerHierarchy'])
client.service.initExportDevice(filter, options)
but it raises an exception
Any element received object of type 'str', expected lxml.etree._Element or zeep.objects.string
See http://docs.python-zeep.org/en/master/datastructures.html#any-objects for more information
Any of
options_type=client.get_type('ns0:ArrayOf_soapenc_string')
options=options_type('recurseContainerHierarchy')
client.service.initExportDevice(filter, options)
or
factory = client.type_factory('ns0')
options=factory.ArrayOf_soapenc_string(['recurseContainerHierarchy'])
client.service.initExportDevice(filter=filter, options=options)
or
factory = client.type_factory('ns0')
options=factory.ArrayOf_soapenc_string('recurseContainerHierarchy')
client.service.initExportDevice(filter=filter, options=options)
or
factory = client.type_factory('ns0')
options=factory.ArrayOf_soapenc_string(_value_1=['recurseContainerHierarchy'])
client.service.initExportDevice(filter=filter, options=options)
all raise the same exception
options_type=client.get_type('ns0:ArrayOf_soapenc_string')
options=xsd.AnyObject(options_type, ['recurseContainerHierarchy'])
client.service.initExportDevice(filter, options)
yields
argument of type 'AnyObject' is not iterable
How do I construct this parameter?
Ok so I had trouble with this using Zeep as well (works with suds easily), the problem is Zeep returns arrays as a function (from my testing) so you need to assign the function to an array, and then modify it. From your current code, it looks as if you are passing data directly to the function (which won't store it).
Using your example above, the below should retrieve the Array type and allow you to modify it as a valid data type.
emptyArrayPlaceholder = client.get_type('ns0:ArrayOf_soapenc_string')
Zeep then returns this type as a function, so first off you need to assign this function to a variable, such as:
options = emptyArrayPlaceholder()
If you were then to inspect options you will see it is a dict, with your list inside of it.
print (options)
{'soapenc': []}
You can then add items to the array easily with:
options['soapenc'].append('Foo')
You should then be able to submit your client with
client.service.initExportDevice(filter, options)
As options is now a valid Zeep data type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With