11"""Utility functions for API requests"""
22
33import json
4+ from asyncio import sleep as asleep
45from io import BytesIO
6+ from time import sleep
57from typing import Optional
68
79import requests
8- from aiohttp import ClientResponse , ClientSession , FormData
10+ from aiohttp import ClientError , ClientResponse , ClientSession , FormData
911from aiohttp .payload import BytesIOPayload
1012
1113from codeboxapi .config import settings
@@ -48,9 +50,13 @@ def handle_response(response: requests.Response):
4850 response .headers ["Content-Type" ].split (";" )[0 ], lambda r : r .content .decode ()
4951 )
5052 if response .status_code != 200 :
53+ try :
54+ json_body = response .json ()
55+ except Exception :
56+ json_body = {"" : response .text }
5157 raise CodeBoxError (
5258 http_status = response .status_code ,
53- json_body = response . json () ,
59+ json_body = json_body ,
5460 headers = dict (response .headers .items ()),
5561 )
5662 return handler (response )
@@ -100,13 +106,35 @@ def base_request(
100106 endpoint : str ,
101107 body : Optional [dict ] = None ,
102108 files : Optional [dict ] = None ,
109+ retries : int = 3 ,
110+ backoff_factor : float = 0.3 ,
103111) -> dict :
104112 """
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.
106125 """
107126 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" })
110138
111139
112140async def abase_request (
@@ -115,9 +143,23 @@ async def abase_request(
115143 endpoint : str ,
116144 body : Optional [dict ] = None ,
117145 files : Optional [dict ] = None ,
146+ retries : int = 3 ,
147+ backoff_factor : float = 0.3 ,
118148) -> dict :
119149 """
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.
121163 """
122164 request_data = build_request_data (method , endpoint , body , files )
123165 if files is not None :
@@ -133,11 +175,20 @@ async def abase_request(
133175 request_data .pop ("files" )
134176 request_data .pop ("json" )
135177 request_data ["data" ] = data
136- response = await session .request (** request_data )
137178 else :
138179 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" })
141192
142193
143194def set_api_key (api_key : str ) -> None :
0 commit comments