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:

  • Return 3 a tuple (or list) with 3 values

    • int - HTTP Status Code

    • dict - Response Headers

    • st - Response Body

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