Guides¶
A series of guides to using HTTPretty for various interesting purposes.
Matching URLs via regular expressions¶
You can pass a compiled regular expression via re.compile()
,
for example for intercepting all requests to a specific host.
Example:
import re
import requests
import httpretty
@httpretty.activate(allow_net_connect=False, verbose=True)
def test_regex():
httpretty.register_uri(httpretty.GET, re.compile(r'.*'), status=418)
response1 = requests.get('http://foo.com')
assert response1.status_code == 418
response2 = requests.get('http://test.com')
assert response2.status_code == 418
Response Callbacks¶
You can use the body parameter of
register_uri()
in useful, practical
ways because it accepts a callable()
as value.
As matter of example, this is analogous to defining routes in Flask when combined with matching urls via regular expressions
This analogy breaks down, though, because HTTPretty does not provide tools to make it easy to handle cookies, parse querystrings etc.
So far this has been a deliberate decision to keep HTTPretty operating mostly at the TCP socket level.
Nothing prevents you from being creative with callbacks though, and as
you will see in the examples below, the request parameter is an
instance of HTTPrettyRequest
which has
everything you need to create elaborate fake APIs.
Defining callbacks¶
The body parameter callback must:
Accept 3 arguments:
request -
HTTPrettyRequest
uri -
str
headers -
dict
with default response headers (including the ones from the parametersadding_headers
andforcing_headers
ofregister_uri()
Return 3 a tuple (or list) with 3 values
Important
The Content-Length should match the byte length of the body.
Changing Content-Length it in your handler can cause your HTTP client to misbehave, be very intentional when modifying it in our callback.
The suggested way to manipulate headers is by modifying the response headers passed as argument and returning them in the tuple at the end.
from typing import Tuple
from httpretty.core import HTTPrettyRequest
def my_callback(
request: HTTPrettyRequest,
url: str,
headers: dict
) -> Tuple[int, dict, str]:
headers['Content-Type'] = 'text/plain'
return (200, headers, "the body")
HTTPretty.register_uri(HTTPretty.GET, "https://test.com", body=my_callback)
Debug requests interactively with ipdb¶
The library ipdb comes in handy to introspect the request interactively with auto-complete via IPython.
import re
import json
import requests
from httpretty import httprettified, HTTPretty
@httprettified(verbose=True, allow_net_connect=False)
def test_basic_body():
def my_callback(request, url, headers):
body = {}
import ipdb;ipdb.set_trace()
return (200, headers, json.dumps(body))
# Match any url via the regular expression
HTTPretty.register_uri(HTTPretty.GET, re.compile(r'.*'), body=my_callback)
HTTPretty.register_uri(HTTPretty.POST, re.compile(r'.*'), body=my_callback)
# will trigger ipdb
response = requests.post('https://test.com', data=json.dumps({'hello': 'world'}))
Emulating timeouts¶
In the bug report #430 the contributor @mariojonke provided a neat example of how to emulate read timeout errors by “waiting” inside of a body callback.
import requests, time
from threading import Event
from httpretty import httprettified
from httpretty import HTTPretty
@httprettified(allow_net_connect=False)
def test_read_timeout():
event = Event()
wait_seconds = 10
connect_timeout = 0.1
read_timeout = 0.1
def my_callback(request, url, headers):
event.wait(wait_seconds)
return 200, headers, "Received"
HTTPretty.register_uri(
HTTPretty.GET, "http://example.com",
body=my_callback
)
requested_at = time.time()
try:
requests.get(
"http://example.com",
timeout=(connect_timeout, read_timeout))
except requests.exceptions.ReadTimeout:
pass
event_set_at = time.time()
event.set()
now = time.time()
assert now - event_set_at < 0.2
total_duration = now - requested_at
assert total_duration < 0.2