2023-02-26 01:27:00 +01:00
|
|
|
import logging
|
2022-07-20 16:33:03 +02:00
|
|
|
from typing import Optional
|
|
|
|
|
2022-07-27 17:50:18 +02:00
|
|
|
from requests import Response, Session as BaseSession
|
2022-07-20 16:33:03 +02:00
|
|
|
from requests.adapters import HTTPAdapter
|
|
|
|
from requests.exceptions import RequestException
|
|
|
|
from urllib3.util import Retry
|
|
|
|
|
2023-02-26 01:27:00 +01:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2022-07-20 16:33:03 +02:00
|
|
|
DEFAULT_TIMEOUT = 5
|
|
|
|
|
|
|
|
|
|
|
|
class TimeoutHTTPAdapter(HTTPAdapter):
|
|
|
|
timeout: int = DEFAULT_TIMEOUT
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
if "timeout" in kwargs:
|
|
|
|
self.timeout = kwargs["timeout"]
|
|
|
|
del kwargs["timeout"]
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
|
|
|
|
def send(self, request, *args, **kwargs):
|
|
|
|
if "timeout" not in kwargs:
|
|
|
|
kwargs["timeout"] = self.timeout
|
|
|
|
return super().send(request, *args, **kwargs)
|
|
|
|
|
|
|
|
|
2023-02-26 13:17:36 +01:00
|
|
|
def default_retry(max_retries: int = 5):
|
|
|
|
return Retry(
|
|
|
|
total=max_retries,
|
|
|
|
backoff_factor=2,
|
|
|
|
status_forcelist=[413, 429, 500, 502, 503, 504],
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2022-07-20 16:33:03 +02:00
|
|
|
class Session(BaseSession):
|
|
|
|
base_url: Optional[str]
|
|
|
|
|
2023-02-26 13:17:36 +01:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
base_url: Optional[str] = None,
|
|
|
|
retry: Optional[Retry] = None,
|
|
|
|
):
|
2022-07-20 16:33:03 +02:00
|
|
|
super().__init__()
|
|
|
|
self.base_url = base_url
|
|
|
|
|
2023-02-26 13:17:36 +01:00
|
|
|
adapter = TimeoutHTTPAdapter(max_retries=retry)
|
2022-07-20 16:33:03 +02:00
|
|
|
|
|
|
|
self.mount("http://", adapter)
|
|
|
|
self.mount("https://", adapter)
|
|
|
|
|
|
|
|
def request(self, method, url, *args, **kwargs):
|
|
|
|
"""Send the request after generating the complete URL."""
|
|
|
|
url = self.create_url(url)
|
|
|
|
return super().request(method, url, *args, **kwargs)
|
|
|
|
|
|
|
|
def create_url(self, url):
|
|
|
|
"""Create the URL based off this partial path."""
|
2022-07-26 17:57:14 +02:00
|
|
|
if self.base_url is None:
|
|
|
|
return url
|
|
|
|
return f"{self.base_url.rstrip('/')}/{url.lstrip('/')}"
|
2022-07-20 16:33:03 +02:00
|
|
|
|
|
|
|
|
|
|
|
# pylint: disable=too-few-public-methods
|
|
|
|
class AbstractApiClient:
|
|
|
|
session: Session
|
|
|
|
base_url: str
|
|
|
|
|
2023-02-26 13:17:36 +01:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
base_url: str,
|
|
|
|
retry: Optional[Retry] = None,
|
|
|
|
):
|
2022-07-20 16:33:03 +02:00
|
|
|
self.base_url = base_url
|
2023-02-26 13:17:36 +01:00
|
|
|
self.session = Session(
|
|
|
|
base_url=base_url,
|
|
|
|
retry=retry,
|
|
|
|
)
|
2022-07-20 16:33:03 +02:00
|
|
|
|
|
|
|
def _request(
|
|
|
|
self,
|
|
|
|
method,
|
|
|
|
url,
|
|
|
|
**kwargs,
|
|
|
|
) -> Response:
|
|
|
|
try:
|
|
|
|
response = self.session.request(method, url, **kwargs)
|
|
|
|
response.raise_for_status()
|
|
|
|
return response
|
|
|
|
|
|
|
|
except RequestException as exception:
|
|
|
|
logger.error(exception)
|
|
|
|
raise exception
|