Requests: Feature Request: Add timeout to session

Created on 21 Apr 2014  ·  11Comments  ·  Source: psf/requests

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?

Most helpful comment

Why not just shim the request method?

s = requests.Session()
s.request = functools.partial(s.request, timeout=3)
# this should now timeout
s.get('https://httpbin.org/delay/6')

All 11 comments

@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?

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.

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.

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:

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?

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.

Was this page helpful?
0 / 5 - 0 ratings