Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/urllib3/util/timeout.py: 26%

63 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1from __future__ import absolute_import 

2 

3import time 

4 

5# The default socket timeout, used by httplib to indicate that no timeout was 

6# specified by the user 

7from socket import _GLOBAL_DEFAULT_TIMEOUT 

8 

9from ..exceptions import TimeoutStateError 

10 

11# A sentinel value to indicate that no timeout was specified by the user in 

12# urllib3 

13_Default = object() 

14 

15 

16# Use time.monotonic if available. 

17current_time = getattr(time, "monotonic", time.time) 

18 

19 

20class Timeout(object): 

21 """Timeout configuration. 

22 

23 Timeouts can be defined as a default for a pool: 

24 

25 .. code-block:: python 

26 

27 timeout = Timeout(connect=2.0, read=7.0) 

28 http = PoolManager(timeout=timeout) 

29 response = http.request('GET', 'http://example.com/') 

30 

31 Or per-request (which overrides the default for the pool): 

32 

33 .. code-block:: python 

34 

35 response = http.request('GET', 'http://example.com/', timeout=Timeout(10)) 

36 

37 Timeouts can be disabled by setting all the parameters to ``None``: 

38 

39 .. code-block:: python 

40 

41 no_timeout = Timeout(connect=None, read=None) 

42 response = http.request('GET', 'http://example.com/, timeout=no_timeout) 

43 

44 

45 :param total: 

46 This combines the connect and read timeouts into one; the read timeout 

47 will be set to the time leftover from the connect attempt. In the 

48 event that both a connect timeout and a total are specified, or a read 

49 timeout and a total are specified, the shorter timeout will be applied. 

50 

51 Defaults to None. 

52 

53 :type total: int, float, or None 

54 

55 :param connect: 

56 The maximum amount of time (in seconds) to wait for a connection 

57 attempt to a server to succeed. Omitting the parameter will default the 

58 connect timeout to the system default, probably `the global default 

59 timeout in socket.py 

60 <http://hg.python.org/cpython/file/603b4d593758/Lib/socket.py#l535>`_. 

61 None will set an infinite timeout for connection attempts. 

62 

63 :type connect: int, float, or None 

64 

65 :param read: 

66 The maximum amount of time (in seconds) to wait between consecutive 

67 read operations for a response from the server. Omitting the parameter 

68 will default the read timeout to the system default, probably `the 

69 global default timeout in socket.py 

70 <http://hg.python.org/cpython/file/603b4d593758/Lib/socket.py#l535>`_. 

71 None will set an infinite timeout. 

72 

73 :type read: int, float, or None 

74 

75 .. note:: 

76 

77 Many factors can affect the total amount of time for urllib3 to return 

78 an HTTP response. 

79 

80 For example, Python's DNS resolver does not obey the timeout specified 

81 on the socket. Other factors that can affect total request time include 

82 high CPU load, high swap, the program running at a low priority level, 

83 or other behaviors. 

84 

85 In addition, the read and total timeouts only measure the time between 

86 read operations on the socket connecting the client and the server, 

87 not the total amount of time for the request to return a complete 

88 response. For most requests, the timeout is raised because the server 

89 has not sent the first byte in the specified time. This is not always 

90 the case; if a server streams one byte every fifteen seconds, a timeout 

91 of 20 seconds will not trigger, even though the request will take 

92 several minutes to complete. 

93 

94 If your goal is to cut off any request after a set amount of wall clock 

95 time, consider having a second "watcher" thread to cut off a slow 

96 request. 

97 """ 

98 

99 #: A sentinel object representing the default timeout value 

100 DEFAULT_TIMEOUT = _GLOBAL_DEFAULT_TIMEOUT 

101 

102 def __init__(self, total=None, connect=_Default, read=_Default): 

103 self._connect = self._validate_timeout(connect, "connect") 

104 self._read = self._validate_timeout(read, "read") 

105 self.total = self._validate_timeout(total, "total") 

106 self._start_connect = None 

107 

108 def __repr__(self): 

109 return "%s(connect=%r, read=%r, total=%r)" % ( 

110 type(self).__name__, 

111 self._connect, 

112 self._read, 

113 self.total, 

114 ) 

115 

116 # __str__ provided for backwards compatibility 

117 __str__ = __repr__ 

118 

119 @classmethod 

120 def _validate_timeout(cls, value, name): 

121 """Check that a timeout attribute is valid. 

122 

123 :param value: The timeout value to validate 

124 :param name: The name of the timeout attribute to validate. This is 

125 used to specify in error messages. 

126 :return: The validated and casted version of the given value. 

127 :raises ValueError: If it is a numeric value less than or equal to 

128 zero, or the type is not an integer, float, or None. 

129 """ 

130 if value is _Default: 

131 return cls.DEFAULT_TIMEOUT 

132 

133 if value is None or value is cls.DEFAULT_TIMEOUT: 

134 return value 

135 

136 if isinstance(value, bool): 

137 raise ValueError( 

138 "Timeout cannot be a boolean value. It must " 

139 "be an int, float or None." 

140 ) 

141 try: 

142 float(value) 

143 except (TypeError, ValueError): 

144 raise ValueError( 

145 "Timeout value %s was %s, but it must be an " 

146 "int, float or None." % (name, value) 

147 ) 

148 

149 try: 

150 if value <= 0: 

151 raise ValueError( 

152 "Attempted to set %s timeout to %s, but the " 

153 "timeout cannot be set to a value less " 

154 "than or equal to 0." % (name, value) 

155 ) 

156 except TypeError: 

157 # Python 3 

158 raise ValueError( 

159 "Timeout value %s was %s, but it must be an " 

160 "int, float or None." % (name, value) 

161 ) 

162 

163 return value 

164 

165 @classmethod 

166 def from_float(cls, timeout): 

167 """Create a new Timeout from a legacy timeout value. 

168 

169 The timeout value used by httplib.py sets the same timeout on the 

170 connect(), and recv() socket requests. This creates a :class:`Timeout` 

171 object that sets the individual timeouts to the ``timeout`` value 

172 passed to this function. 

173 

174 :param timeout: The legacy timeout value. 

175 :type timeout: integer, float, sentinel default object, or None 

176 :return: Timeout object 

177 :rtype: :class:`Timeout` 

178 """ 

179 return Timeout(read=timeout, connect=timeout) 

180 

181 def clone(self): 

182 """Create a copy of the timeout object 

183 

184 Timeout properties are stored per-pool but each request needs a fresh 

185 Timeout object to ensure each one has its own start/stop configured. 

186 

187 :return: a copy of the timeout object 

188 :rtype: :class:`Timeout` 

189 """ 

190 # We can't use copy.deepcopy because that will also create a new object 

191 # for _GLOBAL_DEFAULT_TIMEOUT, which socket.py uses as a sentinel to 

192 # detect the user default. 

193 return Timeout(connect=self._connect, read=self._read, total=self.total) 

194 

195 def start_connect(self): 

196 """Start the timeout clock, used during a connect() attempt 

197 

198 :raises urllib3.exceptions.TimeoutStateError: if you attempt 

199 to start a timer that has been started already. 

200 """ 

201 if self._start_connect is not None: 

202 raise TimeoutStateError("Timeout timer has already been started.") 

203 self._start_connect = current_time() 

204 return self._start_connect 

205 

206 def get_connect_duration(self): 

207 """Gets the time elapsed since the call to :meth:`start_connect`. 

208 

209 :return: Elapsed time in seconds. 

210 :rtype: float 

211 :raises urllib3.exceptions.TimeoutStateError: if you attempt 

212 to get duration for a timer that hasn't been started. 

213 """ 

214 if self._start_connect is None: 

215 raise TimeoutStateError( 

216 "Can't get connect duration for timer that has not started." 

217 ) 

218 return current_time() - self._start_connect 

219 

220 @property 

221 def connect_timeout(self): 

222 """Get the value to use when setting a connection timeout. 

223 

224 This will be a positive float or integer, the value None 

225 (never timeout), or the default system timeout. 

226 

227 :return: Connect timeout. 

228 :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None 

229 """ 

230 if self.total is None: 

231 return self._connect 

232 

233 if self._connect is None or self._connect is self.DEFAULT_TIMEOUT: 

234 return self.total 

235 

236 return min(self._connect, self.total) 

237 

238 @property 

239 def read_timeout(self): 

240 """Get the value for the read timeout. 

241 

242 This assumes some time has elapsed in the connection timeout and 

243 computes the read timeout appropriately. 

244 

245 If self.total is set, the read timeout is dependent on the amount of 

246 time taken by the connect timeout. If the connection time has not been 

247 established, a :exc:`~urllib3.exceptions.TimeoutStateError` will be 

248 raised. 

249 

250 :return: Value to use for the read timeout. 

251 :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None 

252 :raises urllib3.exceptions.TimeoutStateError: If :meth:`start_connect` 

253 has not yet been called on this object. 

254 """ 

255 if ( 

256 self.total is not None 

257 and self.total is not self.DEFAULT_TIMEOUT 

258 and self._read is not None 

259 and self._read is not self.DEFAULT_TIMEOUT 

260 ): 

261 # In case the connect timeout has not yet been established. 

262 if self._start_connect is None: 

263 return self._read 

264 return max(0, min(self.total - self.get_connect_duration(), self._read)) 

265 elif self.total is not None and self.total is not self.DEFAULT_TIMEOUT: 

266 return max(0, self.total - self.get_connect_duration()) 

267 else: 

268 return self._read