Can querystring params be non-strings?

Many functions in requests take a parameter named `params`. There we are supposed to pass a mapping which will be used to construct the querystring. Here is the documentation I found about it:
http://docs.python-requests.org/en/master/user/quickstart/#passing-parameters-in-urls
http://docs.python-requests.org/en/master/api/#requests.request

In none of these places there is any mention of whether it's allowed to pass non-string objects. This example shows that even `int`s and `bool`s are accepted.
```
>>> Request(url='http://localhost', params={1: True}).prepare().url
'http://localhost/?1=True'
```

After some experimentation, it seems that requests can accept anything which can be converted to a string. I looked at the source code of [`requests.models._encode_params`](https://github.com/kennethreitz/requests/blob/master/requests/models.py#L82) so I know why it's behaving like this. But is this the intended behavior?

Also, comments in the source code of `requests.models._encode_params` say that a list of 2-tuples is also accepted. Even this isn't mentioned in the documentation links above.

So my point is that I want to know what is the intended way of using the `params` parameter in requests. What can and cannot be passed in as `params`? Is there some existing documentation about this which I haven't been able to find? If no, this information needs to be documented somewhere.

(I'm actually trying to improve [typeshed](https://github.com/python/typeshed) stubs for requests. Whether non-string objects are allowed in `params` or not will determine how to write stubs.)

Oh boy, you are going to get @Lukasa screaming after you soon :) From this email https://lwn.net/Articles/643399/ it is intentional that requests take all sort of types for the "param" value. If something needs a fix, that probably would be Requests documentation.

Also, if you have not already, read #3855 

So the fact that Requests can accept anything that can be converted to a string is accidental, and not something we commit to supporting. If you read `encode_params` more closely you'll note that in fact it deals with the *entire* `params` argument (it also deals with `data`, incidentally). It can thus be broken down as follows:

1. If `params` is a literal string object, pass it through unchanged. This allows sending already urlencoded query strings, or literal data, or JSON.
2. Otherwise, if it has a `read` method, pass it through unchanged. This makes no sense for query string parameters, and in fact will fail later on, but this method is also used for the `data` argument where it *does* make sense, so the code allows it for now.
3. Otherwise, it's iterable. We assume here that the iterable is of the form of an iterable of two-tuples or something that can be converted to that (e.g. a dict). This drops into a further decision tree for each entry in the iterable, which is split as a two-tuple into key and value:
    1. If the value is not an iterable (or it's a string), we put it into a one-element list. This is to allow lists of elements for query string parameters.
    2. Then, for each element in the value, if it's not `None`, we add a two-tuple of (key, value), optionally encoding the key and value in UTF-8 if they're unicode strings.
    3. We then urlencode this iterable of two-tuples and return it.

So, let's be clear about the kinds of non-string entries that are allowed. `params` can be:

- A string
- A bytestring
- An object with the read method (though this later fails)
- Anything that conforms to `collections.Mapping`.
- Anything that is an Iterable of two-tuples, including generators.

For the last two cases, those two-tuples need to be of things that urlencode will accept, so the type signature there is whatever urlencode's type signature is.

All of this is to say: the reason Requests' documentation doesn't go into this level of detail is because it's so absurdly far beyond the pale of what is reasonable to document. The *reality* here is that we *promise* to work only with strings, mappings of string to string, and iterables of two-tuples of strings. Non-string objects are *allowed* in the sense that they have worked for a long time and will likely continue to work for the remainder of the 2.0 release cycle due to the ossification of that API, but they are not formally condoned by the Requests documentation or team and we won't be advertising them as a feature because they rely on an implementation detail of the Python standard library that could change at any time.

I'm of the opinion that the fact that the Requests documentation only ever uses strings for those arguments is a sufficient indicator that we don't support anything else. However, to resolve this for future discussion, I've opened #3857.

In the longer term, I'd like to suggest that you don't ask the Requests team to write the stub files for you. :wink: There's a reason we haven't done it, and this kind of ambiguity is one part of it. There are large chunks of the API where what we can accept is limited by the tools we use, and by the Python standard library, and where we will often be able to work with things that we don't technically want to support. Pursuing entirely accurate stub files for Requests is likely to be a frustrating endeavour.