A mocking library for requests that enables testing Python applications without making actual HTTP calls
npx @tessl/cli install tessl/pypi-httmock@1.4.0A mocking library for Python's requests library that enables testing applications without making actual HTTP calls. HTTPMock provides decorators and context managers to intercept and mock HTTP requests with flexible response control.
pip install httmockfrom httmock import HTTMock, urlmatch, all_requests, with_httmock, responseImport specific decorators and utilities:
from httmock import remember_called, text_type, binary_typefrom httmock import urlmatch, HTTMock
import requests
# Create a URL-matching mock handler
@urlmatch(netloc=r'(.*\.)?google\.com$')
def google_mock(url, request):
return 'Feeling lucky, punk?'
# Use context manager to mock requests
with HTTMock(google_mock):
r = requests.get('http://google.com/')
print(r.content) # b'Feeling lucky, punk?'Alternative decorator usage:
from httmock import with_httmock, all_requests
import requests
@all_requests
def response_content(url, request):
return {'status_code': 200, 'content': 'Oh hai'}
@with_httmock(response_content)
def test_function():
r = requests.get('https://example.com/')
print(r.status_code) # 200
print(r.content) # b'Oh hai'
test_function()HTTPMock works by monkey-patching the requests.Session.send and requests.Session.prepare_request methods during the context manager's lifetime. This interceptor architecture allows:
requests library are intercepted before they reach the networkrequests.Response objects, with automatic conversionresponse.cookiesThe context manager pattern ensures that mocking is scoped and original functionality is restored when exiting the mock context.
Primary context manager for mocking HTTP requests within a specific scope.
class HTTMock:
def __init__(self, *handlers):
"""
Initialize with mock handler functions.
Parameters:
- handlers: Variable number of mock handler functions
"""
def __enter__(self):
"""Enter context, patch requests.Session methods."""
def __exit__(self, exc_type, exc_val, exc_tb):
"""Exit context, restore original requests.Session methods."""
def intercept(self, request, **kwargs):
"""
Intercept and handle mock responses.
Parameters:
- request: The HTTP request object
- kwargs: Additional request arguments
Returns:
- Mock response or None for fallthrough
"""Decorator for conditional URL-based request matching with regex support.
def urlmatch(scheme=None, netloc=None, path=None, method=None, query=None):
"""
Decorator for URL-based request matching.
Parameters:
- scheme: str, URL scheme to match (http, https, etc.)
- netloc: str, regex pattern for network location (domain)
- path: str, regex pattern for URL path
- method: str, HTTP method to match (GET, POST, etc.)
- query: str, regex pattern for query string
Returns:
- Decorator that wraps handler functions
Handler Function Signature:
- handler(url, request) -> str | dict | requests.Response | None
"""Decorator that matches all HTTP requests without conditions.
def all_requests(func):
"""
Decorator that matches all HTTP requests.
Parameters:
- func: Handler function to decorate
Returns:
- Decorated handler function
Handler Function Signature:
- handler(url, request) -> str | dict | requests.Response | None
"""Decorator that wraps functions with HTTP mocking context.
def with_httmock(*handlers):
"""
Function decorator for HTTP mocking.
Parameters:
- handlers: Variable number of mock handler functions
Returns:
- Decorator that wraps functions with mocking context
"""Factory function for creating mock Response objects with full control.
def response(status_code=200, content='', headers=None, reason=None,
elapsed=0, request=None, stream=False, http_vsn=11):
"""
Create a mock requests.Response object.
Parameters:
- status_code: int, HTTP status code (default: 200)
- content: str | dict | list | bytes, response content
- headers: dict, HTTP headers (default: None)
- reason: str, HTTP reason phrase (default: None)
- elapsed: int, elapsed time in seconds (default: 0)
- request: Request object to associate with response
- stream: bool, enable streaming response (default: False)
- http_vsn: int, HTTP version (10 or 11, default: 11)
Returns:
- requests.Response object
Notes:
- Dict/list content is automatically JSON-encoded
- String content is UTF-8 encoded
- Set-Cookie headers automatically populate response.cookies
"""Decorator that tracks call statistics for mock handlers.
def remember_called(func):
"""
Decorator that tracks handler call statistics.
Parameters:
- func: Handler function to track
Returns:
- Decorated function with call tracking attributes
Added Attributes:
- func.call['count']: int, number of times called
- func.call['called']: bool, whether function was called
- func.call['requests']: list, request objects from all calls
"""Helper functions for handler management and response processing.
def first_of(handlers, *args, **kwargs):
"""
Return first non-None result from handler list.
Parameters:
- handlers: Iterable of handler functions
- args, kwargs: Arguments to pass to handlers
Returns:
- First non-None handler result or None
"""Mock handlers accept (url, request) parameters and can return:
def handler(url, request):
return "Simple text response"def handler(url, request):
return {
'status_code': 404,
'content': 'Not Found',
'headers': {'Content-Type': 'text/plain'},
'elapsed': 0.1
}def handler(url, request):
return response(
status_code=403,
content={'message': 'API rate limit exceeded'},
headers={'content-type': 'application/json'},
request=request
)@urlmatch(netloc=r'api\.example\.com$', method='POST')
def api_handler(url, request):
if 'auth' not in request.headers:
return {'status_code': 401, 'content': 'Unauthorized'}
return {'status_code': 200, 'content': {'success': True}}# Type compatibility constants
text_type = str # Python 3: str, Python 2: unicode
binary_type = bytes # Python 3: bytes, Python 2: str
# Request and Response objects are from the requests library
# Handler functions receive:
# - url: urllib.parse.SplitResult (parsed URL components)
# - request: requests.PreparedRequest objectHTTMock raises TypeError for unsupported response types from handlers:
@all_requests
def bad_handler(url, request):
return 42 # Raises TypeError: "Don't know how to handle response of type <class 'int'>"Valid response types are:
str or bytes: Content-only response (status 200)dict: Response with status_code, content, headers, etc.requests.Response: Complete response objectNone: Fall through to next handler or real request