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?
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.
Most helpful comment
Why not just shim the
request
method?