Requests Library Deep Dive - 6
Continuing the study of the requests module. Today, I am diving into requests/adapters.py, which implements the low-level connection management and is crucial for handling HTTP requests efficiently.
Key Concepts in requests/adapters.py
The HTTPAdapter Class
The HTTPAdapter class is responsible for:
- Handling connections (e.g., opening, reusing and closing).
- Managing retries and timeouts.
- Sending the actual http requests using
urllib3, which is a dependency ofrequests.
Key Attributes of Session:
poolmanager: Manages connection pools for reusing the connections to the same host.max_retries: Defines how many times to retry a failed request.timeout: Sets a default timeout for requests if not provided explicitly.1 2 3 4 5 6 7
def __init__(self, pool_connections=10, pool_maxsize=10, max_retries=3, pool_block=False): self.max_retries = max_retries self.poolmanager = PoolManager( num_pools=pool_connections, maxsize=pool_maxsize, block=pool_block, )
PoolManageris a feature ofurllib3that handles connection pooling.
Sending a request
The send method is the core of the HTTPAdapter class. It sends a PreparedRequest and returns a Response object.
Key Steps Inside send:
- Get connection:
A connection from a pool is fetched using
PoolManager.1
conn = self.poolmanager.connection_from_url(request.url)
- Make the request:
The actual HTTP request is made via
conn.urlopen, which comes fromurllib3.1 2 3 4 5 6 7 8
response = conn.urlopen( method=request.method, url=request.url, body=request.body, headers=request.headers, retries=self.max_retries, timeout=timeout, )
- Wrap the response:
The raw
urllib3response is wrapped in aResponseobject.1
response = self.build_response(request, response)
Adapter lifecycle
- Each
Sessionobject has a dictionary mapping schemes (likehttpandhttps) toHTTPAdapterinstances:
1
self.adapters = {'http://': HTTPAdapter(), 'https://': HTTPAdapter()}
- When a
Sessionsends a request, it looks up the adapter for the request’s URL scheme.1 2 3 4
def get_adapter(self, url): for prefix, adapter in self.adapters.items(): if url.lower().startswith(prefix): return adapter
Why Connection Pooling matters
- Without connection pooling, every HTTP request would require a new TCP connection, which is expensive.
- By reusing TCP connections for requests to the same host, the
HTTPAdaptersignificantly improves performance, especially for APIs or websites with multiple requests.