Feature Request: Add timeout to session

It seems that every optional parameter that goes into send is also settable on the Session (e.g. verify, stream, etc.).  Except timeout.

Would it be possible to change the behaviour so that timeout gets merged in from session just like all the other arguments?


@ctheiss Hey, thanks for raising this issue!

This is something that's come up before, most recently in #1987 but also in #1130 and #1563 (all this year). Kenneth has generally expressed a lack of interest in making this change, expecting that it'd be done using Transport Adapters. If you're interested in getting some guidance as to how you'd do that, I'm happy to help, but I don't think we'll be adding `timeout` to the `Session`.

Sorry we can't be more helpful!


Thanks for the ultra-quick response.  I need to get better at searching through the issues, as the ones you mentioned are exact duplicates!

Is the idea to implement `BaseAdapter` (or subclass `HTTPAdapter`), then associate the subclass with a session using `mount`?  That seems oddly laborious just to implement "default timeout" (given how amazingly easy everything else is in requests).


The idea would be to subclass `HTTPAdapter`. It's not very laborious, really, but the main reason we do it is because it maintains a conceptual distinction in the library. `Session` objects strictly should manage things about the session that about how HTTP itself works: cookies, headers etc. The transport adapters manage things that are about how network connections work: sockets, timeouts etc.


To clarify, your recommendation is that people do this?

``` python
class MyHTTPAdapter(requests.adapters.HTTPAdapter):
    def __init__(self, timeout=None, *args, **kwargs):
        self.timeout = timeout
        super(MyHTTPAdapter, self).__init__(*args, **kwargs)

    def send(self, *args, **kwargs):
        kwargs['timeout'] = self.timeout
        return super(MyHTTPAdapter, self).send(*args, **kwargs)

s = requests.Session()
s.mount("http://", MyHTTPAdapter(timeout=10))
```


@staticshock that's an option. Yes


But, more specifically, is it the _recommendation_?


There is no specific recommendation because users needs will vary and there will be a multitude of ways to address this for those users.


@staticshock @sigmavirus24 

That solution seems overly complicated.  The following seems to work for me.

```python
s = requests.Session()
s.get_orig, s.get = s.get, functools.partial(s.get, timeout=3)
# this should now timeout
s.get('https://httpbin.org/delay/6')
# and this should succeed
s.get_orig('https://httpbin.org/delay/6')
```

> 
> 
> @staticshock @sigmavirus24
> 
> That solution seems overly complicated. The following seems to work for me.
> 
> ```python
> s = requests.Session()
> s.get_orig, s.get = s.get, functools.partial(s.get, timeout=3)
> # this should now timeout
> s.get('https://httpbin.org/delay/6')
> # and this should succeed
> s.get_orig('https://httpbin.org/delay/6')
> ```

Note that you'll also need to apply this to the other verbs e.g. `post`, `put` etc. if you use those. For completeness here's what I am using:

```python
session = requests.Session()
for method in ('get', 'options', 'head', 'post', 'put', 'patch', 'delete'):
    setattr(session, method, functools.partial(getattr(session, method), timeout=5))
# All methods of session should now timeout after 5 seconds
```

Why not just shim the `request` method?
```py
s = requests.Session()
s.request = functools.partial(s.request, timeout=3)
# this should now timeout
s.get('https://httpbin.org/delay/6')
```

If you need it globally at the module level and aren't using sessions, you could potentially do:

`requests.api.request = functools.partial(requests.api.request, timeout=3)`

I'm not sure how this plays with using it across multiple modules, I'd imagine you'd need the shim in each file where you're using requests.