Source code for src.adapter

import json
import urllib.request
import time
from .response import Response


[docs] class BaseAdapter: """Abstract base class for HTTP adapters Defines the interface that all HTTP adapter implementations must follow Adapters are responsible for executing the actual HTTP request and returning a Response object """
[docs] def request(self, method, url, **kwargs): """Execute an HTTP request Args: method (str): HTTP method (GET, POST, and so on) url (str): URL to request **kwargs: Additional arguments for the adapter Returns: Response: Response object containing status, headers, and body Raises: NotImplementedError: Must be implemented by subclass """ raise NotImplementedError("Subclass must implement abstract method")
[docs] class UrllibAdapter(BaseAdapter): """HTTP adapter using Python's built-in urllib library. Provides a lightweight HTTP adapter without external dependencies. **Note**: Does not support connection pooling """
[docs] def request( self, method: str, url: str, headers: dict = None, data: dict = None, timeout: int = 10, ) -> Response: """Execute an HTTP request using urllib. Args: method (str): HTTP method (GET, POST, PUT, DELETE, etc.) url (str): URL to request headers (dict, optional): HTTP headers. Defaults to None data (dict, optional): Request body data. Defaults to None timeout (int, optional): Request timeout in seconds. Defaults to 10 Returns: Response: Response object with status code, headers, body, and elapsed time """ # urllib does not support proper pooling and it will be leave it as is # if we tend to support pooling, it's not worth to use urllib headers = headers or {} start_time = time.perf_counter() if isinstance(data, dict): data = json.dumps(data).encode("utf-8") headers["Content-Type"] = "application/json" request = urllib.request.Request(url=url, data=data, headers=headers, method=method) try: with urllib.request.urlopen(request, timeout=timeout) as response: elapsed_time = time.perf_counter() - start_time return Response( status_code=response.status, headers=dict(response.headers), body=response.read(), elapsed=elapsed_time, ) except urllib.error.HTTPError as e: return Response(status_code=e.code, headers=dict(e.headers), body=e.read())
[docs] class RequestsAdapter(BaseAdapter): """HTTP adapter using the requests library Provides connection pooling and advanced HTTP features through the requests library """ def __init__(self, pool_connections: int = 10, pool_maxsize: int = 50) -> None: """Initialize RequestsAdapter with connection pooling configuration. Args: pool_connections (int, optional): Number of connection pools. Defaults to 10. pool_maxsize (int, optional): Maximum size of connection pool. Defaults to 50. Raises: ImportError: If requests library is not installed """ try: import requests from requests.adapters import HTTPAdapter except ImportError: raise ImportError( "It seems you haven't installed requests library. Please install it using `pip install requests`" ) self.requests = requests self.session = requests.Session() # mount default requests adapter adapter = HTTPAdapter(pool_connections=pool_connections, pool_maxsize=pool_maxsize) self.session.mount("http://", adapter) self.session.mount("https://", adapter)
[docs] def request( self, method: str, url: str, headers: dict = None, data: dict = None, timeout: int = None, ) -> Response: """Execute an HTTP request using requests library. Args: method (str): HTTP method (GET, POST, PUT, DELETE, etc.) url (str): URL to request headers (dict, optional): HTTP headers. Defaults to None. data (dict, optional): Request body data. Defaults to None. timeout (int, optional): Request timeout in seconds. Defaults to None. Returns: Response: Response object with status code, headers, body, and elapsed time """ start_time = time.perf_counter() try: response = self.requests.request( method=method, url=url, headers=headers, json=data if isinstance(data, dict) else None, data=data if not isinstance(data, dict) else None, timeout=timeout, ) elapsed_time = time.perf_counter() - start_time return Response( status_code=response.status_code, headers=response.headers, body=response.content, elapsed=elapsed_time, ) except Exception as e: return Response(status_code=0, headers={}, body=str(e).encode("utf-8"))
[docs] def close(self) -> None: """Close the session and clean up connection pools. Closes the underlying requests session, releasing all pooled connections and resources. """ # clean up session such as close connection pool or adapters self.session.close()