11# SPDX-FileCopyrightText: 2025 Siemens AG
22# SPDX-License-Identifier: MIT
3-
43import logging
4+ import time
55from dataclasses import dataclass
66
77import requests
@@ -17,6 +17,10 @@ def __init__(self, error_code: int, message: str):
1717 self .message = message
1818
1919
20+ class RateLimitError (Exception ):
21+ """Raised for rate limiting."""
22+
23+
2024@dataclass
2125class JSONAPIError :
2226 title : str = ""
@@ -47,6 +51,17 @@ def from_response(code: int, response_json: JSON) -> "JSONAPIRequestError":
4751
4852
4953def _request (verb : str , url : str , json : JSON = None , params : dict [str , str ] | None = None ) -> JSON :
54+ for i in range (10 ):
55+ try :
56+ return _rate_limited_request (verb , url , json , params )
57+ except RateLimitError :
58+ logger .debug ("Pausing due to rate limit" )
59+ time .sleep (1 )
60+
61+ raise RequestError (requests .codes .too_many_requests , "Ratelimit exceeded and retry failed" )
62+
63+
64+ def _rate_limited_request (verb : str , url : str , json : JSON = None , params : dict [str , str ] | None = None ) -> JSON :
5065 logger .debug ("%s: url=%s, params=%s, json=%s" , verb .upper (), url , params , json )
5166 response = api_config .client .request (
5267 verb , url , timeout = api_config .request_timeout_seconds , json = json , params = params
@@ -63,6 +78,9 @@ def _request(verb: str, url: str, json: JSON = None, params: dict[str, str] | No
6378 if "Server-Timing" in response .headers :
6479 logger .debug ("server-timing: %s" , response .headers ["Server-Timing" ])
6580
81+ if response .status_code == requests .codes .too_many_requests :
82+ raise RateLimitError ()
83+
6684 if not response .ok :
6785 raise JSONAPIRequestError .from_response (response .status_code , response_json )
6886
0 commit comments