from __future__ import annotations import time from typing import Any, Dict import requests from intel.config import DEFAULT_HEALTH_POLICY, DEFAULT_REQUEST_POLICY DEFAULT_TIMEOUT = 30 DEFAULT_USER_AGENT = str(DEFAULT_REQUEST_POLICY.get("user_agent") or "Mozilla/5.0") def _request_policy(source: Dict[str, Any] | None = None) -> Dict[str, Any]: return {**DEFAULT_REQUEST_POLICY, **((source or {}).get("request_policy") or {})} def _health_policy(source: Dict[str, Any] | None = None) -> Dict[str, Any]: return {**DEFAULT_HEALTH_POLICY, **((source or {}).get("health_policy") or {})} def build_session(source: Dict[str, Any] | None = None) -> requests.Session: session = requests.Session() session.trust_env = True request_policy = _request_policy(source) headers = {"User-Agent": request_policy.get("user_agent") or DEFAULT_USER_AGENT} if request_policy.get("accept"): headers["Accept"] = request_policy["accept"] session.headers.update(headers) return session def request( method: str, url: str, *, source: Dict[str, Any] | None = None, session: requests.Session | None = None, timeout: int = DEFAULT_TIMEOUT, **kwargs: Any, ) -> requests.Response: request_policy = _request_policy(source) health_policy = _health_policy(source) client = session or build_session(source) headers = dict(kwargs.pop("headers", {}) or {}) if "User-Agent" not in headers: headers["User-Agent"] = request_policy.get("user_agent") or DEFAULT_USER_AGENT if request_policy.get("accept") and "Accept" not in headers: headers["Accept"] = request_policy["accept"] timeout_value = timeout if timeout != DEFAULT_TIMEOUT else int(request_policy.get("timeout_seconds") or DEFAULT_TIMEOUT) allow_redirects = kwargs.pop("allow_redirects", bool(request_policy.get("follow_redirects", True))) verify = kwargs.pop("verify", bool(request_policy.get("verify_tls", True))) status_retries = max(1, int(health_policy.get("retries") or 1)) backoff_seconds = float(health_policy.get("backoff_seconds") or 0.5) last_error: Exception | None = None for attempt in range(1, status_retries + 1): try: return client.request( method, url, headers=headers, timeout=timeout_value, allow_redirects=allow_redirects, verify=verify, **kwargs, ) except requests.exceptions.SSLError as exc: last_error = exc if verify: try: return client.request( method, url, headers=headers, timeout=timeout_value, allow_redirects=allow_redirects, verify=False, **kwargs, ) except requests.exceptions.RequestException as fallback_error: last_error = fallback_error if attempt < status_retries: time.sleep(backoff_seconds * attempt) except requests.exceptions.RequestException as exc: last_error = exc if attempt < status_retries: time.sleep(backoff_seconds * attempt) if last_error is not None: raise last_error raise RuntimeError(f"request failed without an exception for {method} {url}")