"""Shared `requests` session helper. Many providers still use `requests` directly. Reusing a Session provides: - Connection pooling (fewer TCP/TLS handshakes) - Lower CPU overhead per request This module intentionally avoids importing the heavy httpx-based stack. """ from __future__ import annotations import threading from typing import Any, Dict, Optional import requests from requests.adapters import HTTPAdapter from API.ssl_certs import resolve_verify_value _DEFAULT_USER_AGENT = ( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0 Safari/537.36" ) _local = threading.local() def get_requests_session( *, user_agent: str = _DEFAULT_USER_AGENT, verify_ssl: bool = True, pool_connections: int = 16, pool_maxsize: int = 16, ) -> requests.Session: """Return a thread-local shared Session configured for pooling.""" session: Optional[requests.Session] = getattr(_local, "session", None) if session is not None: return session session = requests.Session() session.headers.update({"User-Agent": str(user_agent or _DEFAULT_USER_AGENT)}) # Expand connection pool; keep max_retries=0 to avoid semantic changes. adapter = HTTPAdapter(pool_connections=pool_connections, pool_maxsize=pool_maxsize, max_retries=0) session.mount("http://", adapter) session.mount("https://", adapter) # Configure verify once. session.verify = resolve_verify_value(verify_ssl) _local.session = session return session def request( method: str, url: str, *, params: Optional[Dict[str, Any]] = None, headers: Optional[Dict[str, str]] = None, timeout: Optional[float] = None, **kwargs: Any, ) -> requests.Response: """Convenience wrapper around the shared Session.""" sess = get_requests_session() return sess.request(method, url, params=params, headers=headers, timeout=timeout, **kwargs)