Behaviors are different when data is a list(dict) and text

When data is unicode, it gives traceback.
A simple test case:

``` python
request = requests.Request(method='GET', url='https://httpbin.org/get')
request.data =  u'x=føø'
prepared = request.prepare()
requests.Session().send(prepared)
```

```
Traceback (most recent call last):
...
    requests.Session().send(prepared)
  File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 566, in send
    r = adapter.send(request, **kwargs)
  File "/usr/lib/python2.7/dist-packages/requests/adapters.py", line 331, in send
    timeout=timeout
  File "/usr/lib/python2.7/dist-packages/urllib3/connectionpool.py", line 558, in urlopen
    body=body, headers=headers)
  File "/usr/lib/python2.7/dist-packages/urllib3/connectionpool.py", line 383, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "/usr/lib/python2.7/httplib.py", line 975, in request
    self._send_request(method, url, body, headers)
  File "/usr/lib/python2.7/httplib.py", line 1009, in _send_request
    self.endheaders(body)
  File "/usr/lib/python2.7/httplib.py", line 971, in endheaders
    self._send_output(message_body)
  File "/usr/lib/python2.7/httplib.py", line 835, in _send_output
    self.send(message_body)
  File "/usr/lib/python2.7/httplib.py", line 805, in send
    self.sock.sendall(data)
  File "/usr/lib/python2.7/ssl.py", line 329, in sendall
    v = self.send(data[count:])
  File "/usr/lib/python2.7/ssl.py", line 298, in send
    v = self._sslobj.write(data)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 3-4: ordinal not in range(128)
```

When data is a list, it works fine.

``` python
    request = requests.Request(method='GET', url='https://httpbin.org/get')
    request.data = [(u'x', u'føø')]
    prepared = request.prepare()
    requests.Session().send(prepared)
```

Requests seems to be supporting unicode data, shown in the code. However, it seems not work well, and the behavior differs when the data is a list-like type and a text-like type, one try to encode using 'uft-8' and the other just pass through(in _encode_params).

``` python
    def prepare_body(self, data, files, json=None):
            ...
            if files:
                (body, content_type) = self._encode_files(files, data)
            else:
                if data and json is None:
                    body = self._encode_params(data)     #===> check data
                    if isinstance(data, basestring) or hasattr(data, 'read'):
                        content_type = None
                    else:
                        content_type = 'application/x-www-form-urlencoded'
                    ...
    @staticmethod
    def _encode_params(data):
        if isinstance(data, (str, bytes)):   #===> allows unicode
            return data                              #===> simply return
        elif hasattr(data, 'read'):
            return data
        elif hasattr(data, '__iter__'):        #===> the behavior is different.
            result = []
            for k, vs in to_key_val_list(data):
                if isinstance(vs, basestring) or not hasattr(vs, '__iter__'):
                    vs = [vs]
                for v in vs:
                    if v is not None:
                        result.append(
                            (k.encode('utf-8') if isinstance(k, str) else k,
                             v.encode('utf-8') if isinstance(v, str) else v))   #===>you try to encode as 'utf8'
            return urlencode(result, doseq=True)
        else:
            return data
```


Yeah, agreed, this is a bug. We shouldn't just return, we should chuck the data through `to_native_str` first.

However, that change is backward incompatible, so we should add this into 3.0.0.


So, I don't think that belongs in the `_encode_params` method though. That's mostly there to create an `application/x-www-form-urlencoded` body. The fact that it sees the data doesn't make it the right place, unless we change it's purpose. But that's more for people who are looking to pick this up.


So as when `python requests.params=u'x=føø'`, containing non-ascii characters.  _encode_params seems buggy. I find requests easily crashes when meeting non-ascii characters overall. Perhaps, it would be better if testing coverage about this could be higher. I seem find another traceback about this. I will raise a new issue then. Thanks for the response.


The real problem is that mixing unicode and non-unicode data is a bad idea. Requests will work best if you encode your unicode data before you pass it to us, so we don't have to guess what you want.

With that said, if there are problems at our interface, we should know about them


However, requests gives us a phantom being able to support unicode and non-unicode data with non-ascii characters. But to what stage, we don't know and the specification is fuzzy. Indeed, requests is a great project and I am really appreciated. Hope it would be better :100:  Thanks, you guys.