1
1
"""Utility functions for API requests"""
2
2
3
3
import json
4
+ from asyncio import sleep as asleep
4
5
from io import BytesIO
6
+ from time import sleep
5
7
from typing import Optional
6
8
7
9
import requests
8
- from aiohttp import ClientResponse , ClientSession , FormData
10
+ from aiohttp import ClientError , ClientResponse , ClientSession , FormData
9
11
from aiohttp .payload import BytesIOPayload
10
12
11
13
from codeboxapi .config import settings
@@ -48,9 +50,13 @@ def handle_response(response: requests.Response):
48
50
response .headers ["Content-Type" ].split (";" )[0 ], lambda r : r .content .decode ()
49
51
)
50
52
if response .status_code != 200 :
53
+ try :
54
+ json_body = response .json ()
55
+ except Exception :
56
+ json_body = {"" : response .text }
51
57
raise CodeBoxError (
52
58
http_status = response .status_code ,
53
- json_body = response . json () ,
59
+ json_body = json_body ,
54
60
headers = dict (response .headers .items ()),
55
61
)
56
62
return handler (response )
@@ -100,13 +106,35 @@ def base_request(
100
106
endpoint : str ,
101
107
body : Optional [dict ] = None ,
102
108
files : Optional [dict ] = None ,
109
+ retries : int = 3 ,
110
+ backoff_factor : float = 0.3 ,
103
111
) -> dict :
104
112
"""
105
- Makes a request to the CodeBox API.
113
+ Makes a request to the CodeBox API with retry logic.
114
+
115
+ Args:
116
+ - method: HTTP method as a string.
117
+ - endpoint: API endpoint as a string.
118
+ - body: Optional dictionary containing the JSON body.
119
+ - files: Optional dictionary containing file data.
120
+ - retries: Maximum number of retries on failure.
121
+ - backoff_factor: Multiplier for delay between retries (exponential backoff).
122
+
123
+ Returns:
124
+ - A dictionary response from the API.
106
125
"""
107
126
request_data = build_request_data (method , endpoint , body , files )
108
- response = requests .request (** request_data , timeout = 270 )
109
- return handle_response (response )
127
+ for attempt in range (retries ):
128
+ try :
129
+ response = requests .request (** request_data , timeout = 270 )
130
+ return handle_response (response )
131
+ except requests .RequestException as e :
132
+ if attempt < retries - 1 :
133
+ sleep_time = backoff_factor * (2 ** attempt )
134
+ sleep (sleep_time )
135
+ else :
136
+ raise e
137
+ raise CodeBoxError (http_status = 500 , json_body = {"error" : "Max retries exceeded" })
110
138
111
139
112
140
async def abase_request (
@@ -115,9 +143,23 @@ async def abase_request(
115
143
endpoint : str ,
116
144
body : Optional [dict ] = None ,
117
145
files : Optional [dict ] = None ,
146
+ retries : int = 3 ,
147
+ backoff_factor : float = 0.3 ,
118
148
) -> dict :
119
149
"""
120
- Makes an asynchronous request to the CodeBox API.
150
+ Makes an asynchronous request to the CodeBox API with retry functionality.
151
+
152
+ Args:
153
+ - session: The aiohttp ClientSession.
154
+ - method: HTTP method as a string.
155
+ - endpoint: API endpoint as a string.
156
+ - body: Optional dictionary containing the JSON body.
157
+ - files: Optional dictionary containing file data.
158
+ - retries: Maximum number of retries on failure.
159
+ - backoff_factor: Multiplier for delay between retries (exponential backoff).
160
+
161
+ Returns:
162
+ - A dictionary response from the API.
121
163
"""
122
164
request_data = build_request_data (method , endpoint , body , files )
123
165
if files is not None :
@@ -133,11 +175,20 @@ async def abase_request(
133
175
request_data .pop ("files" )
134
176
request_data .pop ("json" )
135
177
request_data ["data" ] = data
136
- response = await session .request (** request_data )
137
178
else :
138
179
request_data .pop ("files" )
139
- response = await session .request (** request_data )
140
- return await handle_response_async (response )
180
+
181
+ for attempt in range (retries ):
182
+ try :
183
+ response = await session .request (** request_data )
184
+ return await handle_response_async (response )
185
+ except ClientError as e :
186
+ if attempt < retries - 1 :
187
+ sleep_time = backoff_factor * (2 ** attempt )
188
+ await asleep (sleep_time )
189
+ else :
190
+ raise e
191
+ raise CodeBoxError (http_status = 500 , json_body = {"error" : "Max retries exceeded" })
141
192
142
193
143
194
def set_api_key (api_key : str ) -> None :
0 commit comments