Request('POST',url,data,files).prepare() munging data when it contains a nested dict

Not sure what's happening but nested dicts seem to be broken when POSTing along side a file upload. One layered dicts arrive unaltered, two layers and bits go missing.

https://gist.github.com/rsalmond/5726554


Hi @rsalmond, thanks for opening this issue! I just wanted to let you know that I've seen this and will circle back to it at some point this weekend when I have actual time to address it. =)


Hey awesome, I tried to unwind that code myself but got a bit lost. This lib is mighty handy, your work is much appreciated!


Can I just clarify, @rsalmond: are you trying to POST json-encoded data, or are you expecting to POST a normal HTML form?


The reason I ask is that by default our `data` parameter assumes you're posting an HTML form. If you are, then nested dictionaries doesn't make any sense, because you can't nest HTML forms.

If you aren't, then you want to be posting JSON. Doing that along with a file is awkward, and I'd have to see what your API expects you to do.


I _think_ I need to post JSON encoded data along with a file to the freshdesk API. Their docs are not great but I was given [some example ruby code](https://gist.github.com/rsalmond/5736708) that I'm trying to emulate. When I point that at httpbin.org/post I get this back for the JSON encoded data.

```
"form": {
"helpdesk_ticket[email]": "test@abc.com",
"helpdesk_ticket[custom_field][department_category_16699]": "Information Technology",
"helpdesk_ticket[description]": "Test ticket creation with attachments",
"helpdesk_ticket[subject]": "new ticket sample"
},
```

And this for the file upload:

```
 "files": {
   "helpdesk_ticket[attachments][][resource]": "data:image/jpeg;base64,(lots of base64)"
}
```

But the dict structure in the first gist creates a ticket successfully when I do not attach a file which is what makes me think the nested dict is the way to go.


I think they're relying on something that rest_client does for you. I think it will traverse the hash looking for File objects and read them into memory.

To do something similar with requests (please excuse my generalities, I'm on my phone) you create a dictionary similar to their hash. Wherever you see `:word` replace it with `'word'`. And with your files opened ahead of time - named fd1 and fd2 -, replace their File.open calls with fd1.read() and fd2.read().

Then import the json module and call `json.dumps(data)` before giving your data to requests. You can also set the content type via the headers parameter.

I don't have the luxury to look the gists or fork them and help you. I hope the above is helpful enough. 


Sorry @rsalmond, I lost track of this briefly.

I think @sigmavirus24 has basically got the right idea here. JSON has to be the way to go, and your two options there are either to send multipart data with JSON in one part and the file in another, or to JSONify the whole thing. I'd go with his idea for now.

Btw, on the topic of nested dictionaries working without files, I don't see that behaviour:

``` python
>>> import requests
>>> data = {'outer': {'key1': 'val1', 'key2': 'val2'}}
>>> r = requests.post('http://httpbin.org/post', data=data)
>>> print r.text
#...snip...
  "form": {
    "form": [
      "key2",
      "key1"
    ]
  }
#...snip...
```


Hey there, sigmavirus24 I think I can pull that off. I was assuming requests did some sort of similar magic as rest_client but I'll give that a go.

Lukasa my mistake, you are correct. I in my tests I was passing the dict through json.dumps() before handing it to requests. Removing that I see the same behaviour you pasted above. 

Thanks for the suggestions!


Awesome. =)

For the moment I'm going to close this. If you're still having trouble, reopen it again and Ian and I will come running. =)