I want to call a web service method that has a spyne binary type as argument. But I'm not able to find any python soap client supporting it.
To debug my problem, I made a simple web service method that should print a file:
# @srpc(Attachment, _returns=Unicode)
@srpc(ByteArray, _returns=Unicode)
# @srpc(File, _returns=Unicode)
# @srpc(Unicode, _returns=Unicode)
def print_file(file_content):
logger.info(u"print file:\n{}\ntype:{}".format(file_content, file_content.__class__))
return u''
As you can see, I tried with 3 spyne binary types. For debug, I also tried with Unicode, and passing the file content in base64, and in this case there is no problem. Thus the web service is operational.
The server side is a Django application and a spyne application. My problem is on client side. With suds, the obtained error is very obscur, and no solution exists according forums.
I tried all SOAP clients described on https://wiki.python.org/moin/WebServices#SOAP, with python 2.7 and 3.3. They all fail when building the request, when serializing the spyne binary object.
My last try is with zeep. I instantiate the zeep client with wsdl local url. Sorry, wsdl is not public.
I call this method with an empty ByteArray:
param = ByteArray()
client.service.print_file(param)
The catched exception is:
File "/usr/lib/python2.7/site-packages/zeep/client.py", line 41, in __call__
self._op_name, args, kwargs)
File "/usr/lib/python2.7/site-packages/zeep/wsdl/bindings/soap.py", line 107, in send
options=options)
File "/usr/lib/python2.7/site-packages/zeep/wsdl/bindings/soap.py", line 65, in _create
serialized = operation_obj.create(*args, **kwargs)
File "/usr/lib/python2.7/site-packages/zeep/wsdl/definitions.py", line 165, in create
return self.input.serialize(*args, **kwargs)
File "/usr/lib/python2.7/site-packages/zeep/wsdl/messages/soap.py", line 48, in serialize
self.body.render(body, body_value)
File "/usr/lib/python2.7/site-packages/zeep/xsd/elements.py", line 333, in render
self._render_value_item(parent, value)
File "/usr/lib/python2.7/site-packages/zeep/xsd/elements.py", line 354, in _render_value_item
return self.type.render(node, value)
File "/usr/lib/python2.7/site-packages/zeep/xsd/types.py", line 356, in render
element.render(parent, element_value)
File "/usr/lib/python2.7/site-packages/zeep/xsd/indicators.py", line 189, in render
element.render(parent, element_value)
File "/usr/lib/python2.7/site-packages/zeep/xsd/elements.py", line 333, in render
self._render_value_item(parent, value)
File "/usr/lib/python2.7/site-packages/zeep/xsd/elements.py", line 354, in _render_value_item
return self.type.render(node, value)
File "/usr/lib/python2.7/site-packages/zeep/xsd/types.py", line 180, in render
parent.text = self.xmlvalue(value)
File "/usr/lib/python2.7/site-packages/zeep/xsd/builtins.py", line 83, in _wrapper
return func(self, value)
File "/usr/lib/python2.7/site-packages/zeep/xsd/builtins.py", line 357, in xmlvalue
return base64.b64encode(value)
File "/usr/lib64/python2.7/base64.py", line 53, in b64encode
encoded = binascii.b2a_base64(s)[:-1]
TypeError: must be convertible to a buffer, not ModelBaseMeta
Does anyone know if there is a solution with zeep ?
Perhaps with a dedicated zeep plugin ?
Or is there another solution ?
Perhaps in C/C++, compiled as a python package ?
Eric
============================================================
== Solution
As I lost a lot of time on this problem, here is the solution for me.
Finally I needed also the filename, not only file data. The type spyne.model.binary.File would have been perfect, but it is not serialisable into SOAP format.
Thank to discussion with Burak, the final solution is to create a custom ComplexType like:
class File(ComplexModel):
filename = Unicode
data = ByteArray
On client side with suds, replace the ByteArray field directly with the data encoded in base64:
f = File()
data = open({FILENAME}, "rb").read()
f.data = base64.b64encode(data)
On server side, f.data will directly contain the data decoded.