1010
1111import impit
1212
13- from apify_client ._consts import DEFAULT_MAX_RETRIES , DEFAULT_MIN_DELAY_BETWEEN_RETRIES , DEFAULT_TIMEOUT
13+ from apify_client ._consts import (
14+ DEFAULT_MAX_RETRIES ,
15+ DEFAULT_MIN_DELAY_BETWEEN_RETRIES ,
16+ DEFAULT_REQUEST_TIMEOUT ,
17+ Timeout ,
18+ )
1419from apify_client ._docs import docs_group
1520from apify_client ._http_clients import HttpClient , HttpClientAsync
1621from apify_client ._logging import log_context , logger_name
2025if TYPE_CHECKING :
2126 from collections .abc import Awaitable , Callable
2227
23- from apify_client ._consts import JsonSerializable
28+ from apify_client ._consts import JsonSerializable , Timeout
2429 from apify_client ._http_clients import HttpResponse
2530 from apify_client ._statistics import ClientStatistics
2631
@@ -45,6 +50,24 @@ def _is_retryable_error(exc: Exception) -> bool:
4550 )
4651
4752
53+ def _compute_timeout (
54+ client_timeout : timedelta ,
55+ attempt : int ,
56+ timeout : Timeout ,
57+ ) -> float :
58+ """Compute timeout for a request attempt with exponential increase, bounded by client timeout.
59+
60+ For `'no_timeout'`, returns 0 (impit interprets this as no timeout). For `None`, uses the client-level timeout.
61+ For `timedelta` values, doubles the timeout with each attempt but caps at the client-level timeout.
62+ """
63+ if timeout == 'no_timeout' :
64+ return 0
65+
66+ timeout_secs = to_seconds (timeout or client_timeout )
67+ client_timeout_secs = to_seconds (client_timeout )
68+ return min (client_timeout_secs , timeout_secs * 2 ** (attempt - 1 ))
69+
70+
4871@docs_group ('HTTP clients' )
4972class ImpitHttpClient (HttpClient ):
5073 """Synchronous HTTP client for the Apify API built on top of [Impit](https://github.com/apify/impit).
@@ -58,7 +81,7 @@ def __init__(
5881 self ,
5982 * ,
6083 token : str | None = None ,
61- timeout : timedelta = DEFAULT_TIMEOUT ,
84+ timeout : timedelta = DEFAULT_REQUEST_TIMEOUT ,
6285 max_retries : int = DEFAULT_MAX_RETRIES ,
6386 min_delay_between_retries : timedelta = DEFAULT_MIN_DELAY_BETWEEN_RETRIES ,
6487 statistics : ClientStatistics | None = None ,
@@ -99,7 +122,7 @@ def call(
99122 data : str | bytes | bytearray | None = None ,
100123 json : JsonSerializable | None = None ,
101124 stream : bool | None = None ,
102- timeout : timedelta | None = None ,
125+ timeout : Timeout = None ,
103126 ) -> HttpResponse :
104127 """Make an HTTP request with automatic retry and exponential backoff.
105128
@@ -111,7 +134,8 @@ def call(
111134 data: Raw request body data. Cannot be used together with json.
112135 json: JSON-serializable data for the request body. Cannot be used together with data.
113136 stream: Whether to stream the response body.
114- timeout: Timeout override for this request.
137+ timeout: Timeout for the API HTTP request. `None` uses the timeout configured on the client,
138+ a `timedelta` overrides it for this call, and `'no_timeout'` disables the timeout entirely.
115139
116140 Returns:
117141 The HTTP response object.
@@ -154,7 +178,7 @@ def _make_request(
154178 params : dict [str , Any ] | None ,
155179 content : bytes | None ,
156180 stream : bool | None ,
157- timeout : timedelta | None ,
181+ timeout : Timeout ,
158182 ) -> impit .Response :
159183 """Execute a single HTTP request attempt.
160184
@@ -167,7 +191,7 @@ def _make_request(
167191 params: Query parameters.
168192 content: Request body content.
169193 stream: Whether to stream the response.
170- timeout: Timeout override for this request.
194+ timeout: Timeout for this request.
171195
172196 Returns:
173197 The HTTP response object.
@@ -188,7 +212,7 @@ def _make_request(
188212 url = url_with_params ,
189213 headers = headers ,
190214 content = content ,
191- timeout = self ._calculate_timeout ( attempt , timeout ),
215+ timeout = _compute_timeout ( self ._timeout , attempt , timeout ),
192216 stream = stream or False ,
193217 )
194218
@@ -284,7 +308,7 @@ def __init__(
284308 self ,
285309 * ,
286310 token : str | None = None ,
287- timeout : timedelta = DEFAULT_TIMEOUT ,
311+ timeout : timedelta = DEFAULT_REQUEST_TIMEOUT ,
288312 max_retries : int = DEFAULT_MAX_RETRIES ,
289313 min_delay_between_retries : timedelta = DEFAULT_MIN_DELAY_BETWEEN_RETRIES ,
290314 statistics : ClientStatistics | None = None ,
@@ -325,7 +349,7 @@ async def call(
325349 data : str | bytes | bytearray | None = None ,
326350 json : JsonSerializable | None = None ,
327351 stream : bool | None = None ,
328- timeout : timedelta | None = None ,
352+ timeout : Timeout = None ,
329353 ) -> HttpResponse :
330354 """Make an HTTP request with automatic retry and exponential backoff.
331355
@@ -337,7 +361,8 @@ async def call(
337361 data: Raw request body data. Cannot be used together with json.
338362 json: JSON-serializable data for the request body. Cannot be used together with data.
339363 stream: Whether to stream the response body.
340- timeout: Timeout override for this request.
364+ timeout: Timeout for the API HTTP request. `None` uses the timeout configured on the client,
365+ a `timedelta` overrides it for this call, and `'no_timeout'` disables the timeout entirely.
341366
342367 Returns:
343368 The HTTP response object.
@@ -380,7 +405,7 @@ async def _make_request(
380405 params : dict [str , Any ] | None ,
381406 content : bytes | None ,
382407 stream : bool | None ,
383- timeout : timedelta | None ,
408+ timeout : Timeout ,
384409 ) -> impit .Response :
385410 """Execute a single HTTP request attempt.
386411
@@ -393,7 +418,7 @@ async def _make_request(
393418 params: Query parameters.
394419 content: Request body content.
395420 stream: Whether to stream the response.
396- timeout: Timeout override for this request.
421+ timeout: Timeout for this request.
397422
398423 Returns:
399424 The HTTP response object.
@@ -414,7 +439,7 @@ async def _make_request(
414439 url = url_with_params ,
415440 headers = headers ,
416441 content = content ,
417- timeout = self ._calculate_timeout ( attempt , timeout ),
442+ timeout = _compute_timeout ( self ._timeout , attempt , timeout ),
418443 stream = stream or False ,
419444 )
420445
0 commit comments