Sending multipart data - we need better API

Currently sending multipart data is supported by using `files` argument which is ugly from the API point of view and not obvious (see issue #190, SO question [How to send a “multipart/form-data” with requests in python?](http://stackoverflow.com/questions/12385179/).
I'd like to fix it. The following APIs come to mind:
1. Introducing new `transfer_encoding` parameter and encoding `data` according to it's value with fallback to `application/x-www-form-urlencoded`.
2. Introducing new parameter `multipart_data`.
3. Respecting `Transfer-Encoding` header when sending `data` with fallback to `application/x-www-form-urlencoded` if this header is not set.

I like the first option the best. What do you think?


It will also work if you use `data` & `files` together, but you're right it is a bit of a pain. Honestly I like 1 and 3, and I prefer 1 to 3 as well, but I absolutely abhor 2.


I think `files` is a great API. I'm not a fan of all the external contributions that have been made around it though, mostly involving tuples.


@kennethreitz 
What's great about using `files` as the name of the parameter for sending multipart data? Multipart data has nothing to do with sending files. Using (abusing) `files` to send data when there already exists `data` param is illogical. The fact it's wrong comes from the fact that every file is kind of data but data is not always a file. If anything we could expect users to pass files to `data` param but not the other way around like it is now. Sending files may require giving more metadata than sending plain data so it's kind of ok to have additional `files` param for this purpose. But there's no justification for forcing users to pass their data to `files` param if all they want is to send _data_ not files. `Files` param is currently abused to send multipart data only because it happens that uploading files uses multipart transfer encoding in http which is just implementation detail and as such shouldn't be exposed in any way through the API.

Also, could you elaborate on what's wrong with tuples as `files` value?


With respect to the tuples I think he means having tuples akin to `('field name', ('different file name', open('file')))` that people tend to use.


Locally, i made an ugly modif to accept ('field name', (None, open('file'))) which is really minimal (3 lignes in models.py).
Just to say i'm also interested to be able to send multiparts messages without filename

```
        if fn:
            new_fields.append((k, (fn, fp.read())))
        else:
            # we want no filename at all
            new_fields.append((k, fp.read()))
```

this comment is something like a +1 to solve the subject ;)


To chime in here... I really think we should be able to:
- Use multipart/mixed optionally
- Content-Disposition on each part should be optional.

I just wrote this to suit my needs, definitely needs to be humanized:  https://gist.github.com/4220756

I like the files way of doing it as it is. I think we just need an options param to specify how the files will be rendered.


Closing for now. The upcoming generator api will be an excellent one to solve these problems. Ideally, we can include a class for multipart-form, and it's **iter** method will be uploaded automatically.


Is there any way to send each different 'Content-Type' in the multipart-form data for each single input param
e.g.
Content-Type: multipart/form-data;boundary=q235Ht2tTWJhuFmC8sJxbQ7YGU7FwQafcZd8B
Accept-Charset: utf-8
"Content-Disposition: form-data; name="creative_id"
"Content-Type: text/plain;charset=ISO-8859-1”
…
"Content-Disposition: form-data; name=“file_role""
"Content-Type: text/plain;charset=ISO-8859-1”
…
"Content-Disposition: form-data; name="Filename""
"Content-Type: text/plain;charset=ISO-8859-1
"Content-Disposition: form-data; name="file"; filename="advertise_A.png"
 "Content-Type: image/x-png"

For the whole request, the header will be 
Content-Type: multipart/form-data;
but for its params like creative_id and file_role, 
I would like to send Content-Type: text/plain;charset=ISO-8859-1 
and for the file itself Content-Type: image/x-png

I tried this in two ways, but it doesnt work:
headers = {'Content-Type':'text/plain;charset=ISO-8859-1'} 
        files = {'file': open(asset_file, 'rb')}
and then in POST (url, files=files, headers=headers, params=values)

OR

files = {'file1': (open(asset_file, 'rb'), 'image/x-png'), 'creative_id': (1727968, 'text/plain;charset=ISO-8859-1'), 'file_role': ('PRIMARY', 'text/plain;charset=ISO-8859-1')}
and then in POST (url, files=files)


@vidula-mediamath questions belong on [StackOverflow](https://stackoverflow.com/questions/tagged/python-requests)


sorry, I will use [StackOverflow](https://stackoverflow.com/questions/tagged/python-requests)


I would still love to see an implementation of https://github.com/kennethreitz/requests/issues/935#issuecomment-11932921


@kennethreitz It already exists [here](http://toolbelt.readthedocs.org/en/latest/uploading-data.html#streaming-multipart-data-encoder).


`\o/`


So actually there's a minor difference. The default Encoder doesn't have an `__iter__` API. But it probably should because httplib's read size is 8192 and that can be dreadfully slow. Chunking things allows us to return our own chunk-size (and we could allow the user to override that size if they know better).