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, )
PoolManager
is a feature ofurllib3
that 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
urllib3
response is wrapped in aResponse
object.1
response = self.build_response(request, response)
Adapter lifecycle
- Each
Session
object has a dictionary mapping schemes (likehttp
andhttps
) toHTTPAdapter
instances:
1
self.adapters = {'http://': HTTPAdapter(), 'https://': HTTPAdapter()}
- When a
Session
sends 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
HTTPAdapter
significantly improves performance, especially for APIs or websites with multiple requests.