11
votes

I am trying to do the following with requests:

data = {'hello', 'goodbye'}
json_data = json.dumps(data)
headers = {
        'Access-Key': self.api_key,
        'Access-Signature': signature,
        'Access-Nonce': nonce,
        'Content-Type': 'application/json',
        'Accept': 'text/plain'
    }
r = requests.post(url, headers=headers, data=json_data, 
                 files={'file': open('/Users/david/Desktop/a.png', 'rb')})

However, I get the following error:

ValueError: Data must not be a string.

Note that if I remove the files parameter, it works as needed. Why won't requests allow me to send a json-encoded string for data if files is included?

Note that if I change data to be just the normal python dictionary (and not a json-encoded string), the above works. So it seems that the issue is that if files is not json-encoded, then data cannot be json-encoded. However, I need to have my data encoded to match a hash signature that's being created by the API.

3
Have you tried data=data? (no json encoding) - keyser
Yes, but then it screws up the API signature (which every other method depends on). - David542
You need to specify the header so that the module knows it's a JSON string. See this question for details. - tyteen4a03
@tyteen4a03 -- no, that's not it. I already have those headers. It has to do with the data being passed is a string but the files being passed is not. - David542
@David542 What is your header right now? - tyteen4a03

3 Answers

8
votes

When you specify your body to a JSON string, you can no longer attach a file since file uploading requires the MIME type multipart/form-data.

You have two options:

  1. Encapsulate your JSON string as part as the form data (something like json => json.dumps(data))
  2. Encode your file in Base64 and transmit it in the JSON request body. This looks like a lot of work though.
0
votes

Alternative solution to this problem is to post data as file.

  1. You can post strings as files. Read more here: http://docs.python-requests.org/en/latest/user/quickstart/#post-a-multipart-encoded-file

  2. Here is explained how to post multiple files: http://docs.python-requests.org/en/latest/user/advanced/#post-multiple-multipart-encoded-files

0
votes

removing the following helped me in my case:

'Content-Type': 'application/json'

then the data should be passed as dictionary