A comprehensive HTTP client library that supports many features left out of other HTTP libraries.
—
Response objects provide access to HTTP status codes, headers, and response metadata. Response objects behave like dictionaries for header access while providing additional status information and response details.
HTTP response object that extends Python's dict class to provide dictionary-like access to headers while maintaining response status and metadata.
class Response(dict):
"""
HTTP response containing status code, headers, and metadata.
Inherits from dict to provide header access via dictionary interface.
"""
def __init__(self, info):
"""
Initialize response from HTTP response info.
Args:
info: Either email.message or httplib.HTTPResponse object
"""
# Dictionary methods inherited from dict
# Additional attributes available:
# - status: HTTP status code (int)
# - reason: HTTP reason phrase (str)
# - version: HTTP version (int)Response objects provide several key attributes:
# Status information
response.status # HTTP status code (200, 404, 500, etc.)
response.reason # Reason phrase ("OK", "Not Found", etc.)
response.version # HTTP version (11 for HTTP/1.1)
# Dictionary interface for headers
response['content-type'] # Access headers by name
response['content-length'] # All header names are lowercase
response['cache-control'] # Headers stored as strings
response.get('etag', None) # Use dict methods for safe accessimport httplib2
h = httplib2.Http()
(resp, content) = h.request("http://example.org/")
# Check status code
if resp.status == 200:
print("Request successful")
elif resp.status == 404:
print("Resource not found")
else:
print(f"Request failed with status {resp.status}: {resp.reason}")import httplib2
h = httplib2.Http()
(resp, content) = h.request("http://example.org/")
# Access headers (case-insensitive, stored as lowercase)
content_type = resp['content-type']
content_length = resp.get('content-length', 'unknown')
server = resp.get('server', 'unknown')
# Check if header exists
if 'etag' in resp:
etag = resp['etag']
print(f"ETag: {etag}")
# Iterate over all headers
for header_name, header_value in resp.items():
print(f"{header_name}: {header_value}")import httplib2
h = httplib2.Http(".cache")
(resp, content) = h.request("http://example.org/")
# Check caching headers
cache_control = resp.get('cache-control', '')
expires = resp.get('expires', '')
etag = resp.get('etag', '')
last_modified = resp.get('last-modified', '')
print(f"Cache-Control: {cache_control}")
print(f"ETag: {etag}")
print(f"Last-Modified: {last_modified}")
# Check if response was served from cache
# (httplib2 adds custom headers to indicate cache status)
if 'fromcache' in resp:
print("Response served from cache")import httplib2
h = httplib2.Http()
(resp, content) = h.request("http://example.org/")
# Parse content type
content_type = resp.get('content-type', '')
if 'application/json' in content_type:
import json
data = json.loads(content.decode('utf-8'))
elif 'text/html' in content_type:
html = content.decode('utf-8')
elif 'image/' in content_type:
# Binary image data
with open('image.jpg', 'wb') as f:
f.write(content)
# Check encoding from content-type header
if 'charset=' in content_type:
charset = content_type.split('charset=')[1].split(';')[0]
text = content.decode(charset)
else:
# Default to UTF-8
text = content.decode('utf-8')import httplib2
h = httplib2.Http()
(resp, content) = h.request("http://example.org/protected")
# Check authentication requirements
if resp.status == 401:
www_auth = resp.get('www-authenticate', '')
if 'Basic' in www_auth:
print("Server requires Basic authentication")
elif 'Digest' in www_auth:
print("Server requires Digest authentication")
# Add credentials and retry
h.add_credentials('username', 'password')
(resp, content) = h.request("http://example.org/protected")import httplib2
h = httplib2.Http()
(resp, content) = h.request("http://example.org/redirect")
# Check for redirects
if resp.status in (301, 302, 303, 307, 308):
location = resp.get('location', '')
print(f"Redirected to: {location}")
# httplib2 follows redirects automatically by default
# The final response will have the status of the final destinationimport httplib2
h = httplib2.Http()
try:
(resp, content) = h.request("http://example.org/api/data")
if resp.status == 200:
# Success
data = content.decode('utf-8')
elif resp.status == 404:
print("Resource not found")
elif resp.status >= 400:
print(f"Client error: {resp.status} {resp.reason}")
elif resp.status >= 500:
print(f"Server error: {resp.status} {resp.reason}")
except httplib2.HttpLib2Error as e:
print(f"HTTP error: {e}")import httplib2
h = httplib2.Http()
headers = {'Accept': 'application/json, text/xml, */*'}
(resp, content) = h.request("http://api.example.com/data", headers=headers)
content_type = resp.get('content-type', '')
if 'application/json' in content_type:
import json
data = json.loads(content.decode('utf-8'))
elif 'text/xml' in content_type or 'application/xml' in content_type:
import xml.etree.ElementTree as ET
root = ET.fromstring(content.decode('utf-8'))
else:
# Handle other content types
text = content.decode('utf-8')All header names in Response objects are normalized to lowercase for consistent access:
Content-Type becomes content-typeContent-Length becomes content-lengthCache-Control becomes cache-controlWWW-Authenticate becomes www-authenticateThis normalization ensures reliable header access regardless of how the server sends the headers.
Install with Tessl CLI
npx tessl i tessl/pypi-httplib2