2

I want to send a zip file through SOAP (from a SOAP client to a SOAP server) in python.

Following the reading of this SO question, I choose to use suds as my python client. But according to this, suds do not support sending attachment. A method is given to circumvent the problem but I've not been able to make it work. I'm puzzled over what I'm supposed to give as parameters.

Anyone know how to send a file through Soap in python ?

If needed I'll switch to another SOAP client library.

Community
  • 1
  • 1
Philippe Carriere
  • 3,712
  • 4
  • 25
  • 46
  • """suds do not support sending attachement.""" what should that mean? If an webservice accepts binary data - encoded using some encoding - then what should be the problem??? –  Jul 06 '11 at 18:28
  • I don't know if suds can or cannot send files. What I'm asking is how do you send a file from the hard drive through SOAP in python. – Philippe Carriere Jul 06 '11 at 18:50
  • 2
    @Sentinel SOAP messages are XML. As a consequence Suds deals with XML not binary. SOAP "attachements" is an enhancement to the SOAP protocol that allows HTTP request/responses with the MIME type multipart/related where the main element is text/xml and a secondary element includes the binary data. Suds hasn't been extended to support that enhancement. – Pace Jul 06 '11 at 20:57
  • You have all been really helpful, so I gave +1 to a few. I still don't know who to give the bounty to... I wish I could split it... I also wish I could give points to vezult who was a lot of help thanks to his script. – Philippe Carriere Jul 14 '11 at 19:32
  • Here is an additional link: http://stackoverflow.com/questions/1992239/python-soap-using-soaplib-server-and-suds-client – ThreaderSlash Jul 15 '11 at 15:26
  • Thanks ThreaderSlash but that's not what I'm looking for. – Philippe Carriere Jul 15 '11 at 20:03

3 Answers3

7

Download the provided wrapper, and then where you would normally say something like...

client.service.fooMethod(fooParam1,fooParam2,...)

...instead do...

soap_attachments.with_soap_attachment(client.service.fooMethod,binaryParam,fooParam1,fooParam2,...)

Where binaryParam is of the type expected by soap_attachements.py. For example, if you wanted to send a png image I think (never done this) you would do:

imageFile = open('imageFile.png','rb')
imageData = imageFile.read()
mimeType = 'image/png'
binaryParam = (imageData, uuid.uuid4(), mimeType)
vezult
  • 5,185
  • 25
  • 41
Pace
  • 41,875
  • 13
  • 113
  • 156
  • Thank you for your answer. Unfortunately the variable 'HUD_ARM_SERVICE_URL' is not defined and I don't know what should go in it. I can't comment or contact the author. So I can't use this method unless someone has an insight for the value. :( – Philippe Carriere Jul 07 '11 at 13:56
  • 1
    I wrote the wrapper. `HUD_ARM_SERVICE_URL`, in my case, is the URL passed as the `location` parameter when instanciating the client: `client = suds.client.Client( HUD_ARM_WSDL_URL, location=HUD_ARM_SERVICE_URL, transport=t, wsse=security, **extra_args )` – vezult Jul 13 '11 at 13:46
  • 1
    I've updated the wrapper so that it uses `Client.location()` rather than a global location variable. This is what `Client.invoke()` does anyway. I've also added in the requisite imports, in an attempt to make the script a simple copy, paste, and run sort of deal. – vezult Jul 14 '11 at 14:52
  • @vezult Thanks for cleaning things up and thanks for writing the wrapper in the first place! – Pace Apr 03 '12 at 14:35
3

Attachments are best way to send binary file through SOAP. If you can't use any other method but only SOAP, just encode your binaries with Base64 and paste it into SOAP method as a parameter. It isn't pure, but works great with small attachments. Large binaries? Use FTP, WebDAV and all others native ways for sending files between hosts.

  • Believe it or not, there are some broken soap services out there which claim to take b64binary, but break if you don't use attachments. – vezult Jul 14 '11 at 15:02
1

I made the following changes to soap_attachments.py under suds to get my own uploads to work. You may not need some of the changes that I've made to this, but hopefully it'll at least give you a start.

--- /home/craig/Downloads/soap_attachments.py   2011-07-08 20:38:55.708038918 -0400
+++ soap_attachments.py 2011-06-21 10:29:50.090243052 -0400
@@ -1,4 +1,8 @@
+import uuid
+import re
 def with_soap_attachment(suds_method, attachment_data, *args, **kwargs):
+    HUD_ARM_SERVICE_URL = suds_method.client.wsdl.url
+    HUD_ARM_SERVICE_URL = HUD_ARM_SERVICE_URL.replace('wsdl','xsd')
     """ Add an attachment to a suds soap request.

     attachment_data is assumed to contain a list:
@@ -16,7 +20,9 @@
     soap_method = suds_method.method

     if len(attachment_data) == 3:
+        print "here"
         data, attachment_id, attachment_mimetype = attachment_data
+        attachment_id = uuid.uuid4()
     elif len(attachment_data) == 2:
         data, attachment_id = attachment_data
         attachment_mimetype = MIME_DEFAULT
@@ -55,7 +61,7 @@
     ])

     # Build the full request
-    request_text = '\n'.join([
+    request_text = '\r\n'.join([
       '',
       '--%s' % boundary_id,
       soap_headers,

I then use:

f = open(dir_path + infile,'rb')
data_file = f.read()
data_file_type = mimetypes.guess_type(infile)[0]
(filename,ext) = infile.split('.')
...

clientargs = [...]
identifier = with_soap_attachment(client.service.fooThing, [data_file, '1', data_file_type], credentials['foo'],credentials['bar'], morefoo)

You might not need all of these changes, but it's what got me going.

Hope this helps!