TAGS :Viewed: 15 - Published at: a few seconds ago

[ Uploading files using Python requests module ]

I need to load a file using a soap endpoint url...When I use the below code to load it the files are getting loaded but they are not in a readable format...When I load using SOAPUI tool it loads properly...

import requests

xml = '''<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                xmlns:v1="http://s.sa.com/services/Attachment/v1.0">
   <soapenv:Header/>
   <soapenv:Body>
      <v1:attachment>
         <filename>FUZZY.csv</filename>
         <data>cid:138641430598</data>
      </v1:attachment>
   </soapenv:Body>
</soapenv:Envelope>'''
target_url =  'https://s.sa.com:443/soatest/FileAttachmentService'
headers = {'Content-Type': 'text/xml','charset':'utf-8'}
r = requests.post(target_url,data=xml,headers=headers,auth=('3user1',''))
print 'r.text = ', r.text
print 'r.content = ', r.content
print 'r.status_code = ', r.status_code

New changes:-

files = {'file':open('./FUZZY.csv','rb')}
print files
r = requests.post(target_url,files=files,data=xml,headers=headers,auth=('p3user1',''))

Error:

Traceback (most recent call last):
  File "soapcall_python.py", line 18, in <module>
    r = requests.post(target_url,files=files,data=xml,headers=headers,auth=('p3user1',''))
  File "/opt/python2.7/lib/python2.7/site-packages/requests-2.3.0-py2.7.egg/requests/api.py", line 88, in post
    return request('post', url, data=data, **kwargs)
  File "/opt/python2.7/lib/python2.7/site-packages/requests-2.3.0-py2.7.egg/requests/api.py", line 44, in request
    return session.request(method=method, url=url, **kwargs)
  File "/opt/python2.7/lib/python2.7/site-packages/requests-2.3.0-py2.7.egg/requests/sessions.py", line 418, in request
    prep = self.prepare_request(req)
  File "/opt/python2.7/lib/python2.7/site-packages/requests-2.3.0-py2.7.egg/requests/sessions.py", line 356, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
  File "/opt/python2.7/lib/python2.7/site-packages/requests-2.3.0-py2.7.egg/requests/models.py", line 297, in prepare
    self.prepare_body(data, files)
  File "/opt/python2.7/lib/python2.7/site-packages/requests-2.3.0-py2.7.egg/requests/models.py", line 432, in prepare_body
    (body, content_type) = self._encode_files(files, data)
  File "/opt/python2.7/lib/python2.7/site-packages/requests-2.3.0-py2.7.egg/requests/models.py", line 109, in _encode_files
    raise ValueError("Data must not be a string.")
ValueError: Data must not be a string.

Answer 1


You aren't sending the contents of the file anywhere. You're just sending a reference to a file that doesn't exist anywhere that the server can see.

As the docs for SOAP references to attachments explains, the way you do this is to send a MIME-multipart message. If you're using the CID reference mechanism, that cid isn't some arbitrary string, it has to match the Content-ID header of a message in the MIME envelope.

The requests docs for POST a Multipart-Encoded File explain how to send the contents of a file as a message within a MIME request; briefly:

with open('FUZZY.csv', 'rb') as f:
    files = {'file': f}
    r = requests.post(target_url,
                      data=xml, headers=headers, auth=('3user1',''), 
                      files=files)

However, this simple method doesn't give you access to the Content-ID that will be generated under the covers for your message. So, if you want to use the CID reference mechanism, you will need to generate the MIME envelope manually (e.g., by using email.mail.MIMEMultipart) and sending the entire thing as a data string.