11import json
22import posixpath
33import re
4- from http import HTTPStatus
4+
55from typing import List , Optional , Sequence , Union
66
77import requests
8- from tenacity import (
9- RetryError ,
10- retry ,
11- retry_if_result ,
12- stop_after_attempt ,
13- wait_random_exponential ,
14- )
8+
9+ from corva .api_utils import get_retry_strategy , get_requests_session
10+ from corva .configuration import SETTINGS
1511
1612
1713class Api :
@@ -21,26 +17,31 @@ class Api:
2117 convenient URL usage and reasonable timeouts to API requests.
2218 """
2319
24- TIMEOUT_LIMITS = (3 , 30 ) # seconds
25- DEFAULT_MAX_RETRIES = int (0 )
26-
2720 def __init__ (
2821 self ,
2922 * ,
3023 api_url : str ,
3124 data_api_url : str ,
3225 api_key : str ,
3326 app_key : str ,
34- timeout : Optional [int ] = None ,
3527 app_connection_id : Optional [int ] = None ,
28+ max_retries : Optional [int ] = SETTINGS .MAX_RETRY_COUNT ,
29+ pool_connections_count : Optional [int ] = SETTINGS .POOL_CONNECTIONS_COUNT ,
30+ pool_max_size : Optional [int ] = SETTINGS .POOL_MAX_SIZE ,
31+ pool_block : Optional [bool ] = SETTINGS .POOL_BLOCK ,
3632 ):
3733 self .api_url = api_url
3834 self .data_api_url = data_api_url
3935 self .api_key = api_key
4036 self .app_key = app_key
4137 self .app_connection_id = app_connection_id
42- self .timeout = timeout or self .TIMEOUT_LIMITS [1 ]
43- self ._max_retries = self .DEFAULT_MAX_RETRIES
38+ self ._retry_strategy = get_retry_strategy (max_retries ) if max_retries not in (None , 0 ) else None
39+ self ._session = get_requests_session (
40+ retry_strategy = self ._retry_strategy ,
41+ pool_connections_count = pool_connections_count ,
42+ pool_max_size = pool_max_size ,
43+ pool_block = pool_block ,
44+ )
4445
4546 @property
4647 def default_headers (self ):
@@ -99,15 +100,14 @@ def _get_url(self, path: str):
99100
100101 return posixpath .join (self .api_url , path )
101102
102- @staticmethod
103103 def _execute_request (
104+ self ,
104105 method : str ,
105106 url : str ,
106107 params : Optional [dict ],
107108 data : Optional [dict ],
108109 headers : Optional [dict ] = None ,
109- timeout : Optional [int ] = None ,
110- ):
110+ ) -> requests .Response :
111111 """Executes the request.
112112
113113 Args:
@@ -116,18 +116,17 @@ def _execute_request(
116116 data: request body, that will be casted to json.
117117 params: url query string params.
118118 headers: additional headers to include in request.
119- timeout: custom request timeout in seconds.
120119
121120 Returns:
122121 requests.Response instance.
123122 """
124- return requests .request (
123+
124+ return self ._session .request (
125125 method = method ,
126126 url = url ,
127127 params = params ,
128128 json = data ,
129129 headers = headers ,
130- timeout = timeout ,
131130 )
132131
133132 def _request (
@@ -138,7 +137,6 @@ def _request(
138137 data : Optional [dict ] = None ,
139138 params : Optional [dict ] = None ,
140139 headers : Optional [dict ] = None ,
141- timeout : Optional [int ] = None ,
142140 ) -> requests .Response :
143141 """Prepares HTTP request.
144142
@@ -148,70 +146,24 @@ def _request(
148146 data: request body, that will be casted to json.
149147 params: url query string params.
150148 headers: additional headers to include in request.
151- timeout: custom request timeout in seconds.
152149
153150 Returns:
154151 requests.Response instance.
155152 """
156- retryable_status_codes = [
157- HTTPStatus .TOO_MANY_REQUESTS , # 428
158- HTTPStatus .INTERNAL_SERVER_ERROR , # 500
159- HTTPStatus .BAD_GATEWAY , # 502
160- HTTPStatus .SERVICE_UNAVAILABLE , # 503
161- HTTPStatus .GATEWAY_TIMEOUT , # 504
162- ]
163-
164- timeout = timeout or self .timeout
165- self ._validate_timeout (timeout )
166-
167153 url = self ._get_url (path )
168154
169155 headers = {
170156 ** self .default_headers ,
171157 ** (headers or {}),
172158 }
173159
174- if self .max_retries > 0 :
175- retry_decorator = retry (
176- stop = stop_after_attempt (self .max_retries ),
177- wait = wait_random_exponential (multiplier = 0.25 , max = 10 ),
178- retry = retry_if_result (
179- lambda r : r .status_code in retryable_status_codes
180- ),
181- )
182- retrying_request = retry_decorator (self ._execute_request )
183- try :
184- response = retrying_request (
185- method = method ,
186- url = url ,
187- params = params ,
188- data = data ,
189- headers = headers ,
190- timeout = timeout ,
191- )
192- except RetryError as e :
193- if not e .last_attempt .failed :
194- response = e .last_attempt .result ()
195- else :
196- raise
197- else :
198- response = self ._execute_request (
160+ return self ._execute_request (
199161 method = method ,
200162 url = url ,
201163 params = params ,
202164 data = data ,
203165 headers = headers ,
204- timeout = timeout ,
205- )
206-
207- return response
208-
209- def _validate_timeout (self , timeout : int ) -> None :
210- if self .TIMEOUT_LIMITS [0 ] > timeout or self .TIMEOUT_LIMITS [1 ] < timeout :
211- raise ValueError (
212- f"Timeout must be between { self .TIMEOUT_LIMITS [0 ]} and "
213- f"{ self .TIMEOUT_LIMITS [1 ]} seconds."
214- )
166+ )
215167
216168 def get_dataset (
217169 self ,
0 commit comments