# Contents

- Features
- Supported HTTP clients
- Installation
  - PyPI
  - GitHub
- How it works
  - HTTP traffic interception
  - HTTP request matching
  - Real networking mode
  - Volatile vs Persistent mocks
- Examples
  - Basic mocking example using requests
  - Chainable API DSL
  - Context manager for isolated mocking
  - Single mock context manager definition for isolated mocking
  - Declaring mocks as decorators
  - Activating the mock engine via decorator within the function context
  - Activating the mock engine via decorator within an async coroutine function context
  - Featured JSON body matching
  - JSONSchema based body matching
  - Enable real networking mode
  - Persistent mock
  - Time TTL limited mock
  - Regular expression matching
  - `unittest` integration
  - `py.test` integration
  - Simulated error exception on mock matching
  - Using `urllib3` as HTTP client
  - Using `urllib3` to return a chunked response
  - Asynchronous HTTP request using `aiohttp`
  - Using `http.client` standard Python package as HTTP client
  - Example using mocket Python library as underlying mock engine
  - Hy programming language example
- API Documentation
  - Core API
  - Matchers API
  - Interceptors API
- FAQ
  - How does it work?
  - What HTTP clients are supported?
  - Does `pook` mock out all the outgoing HTTP traffic from my app?
  - Can I use `pook` in a non testing environment?
  - Can I use `pook` with a custom HTTP traffic mock interceptor engine?
  - Can I use `pook` with any test framework?
- Development
- v1.1.0 / 2023-01-01
- v1.0.2 / 2021-09-10
  - v1.0.1 / 2020-03-24
  - v1.0.0 / 2020-03-18
  - v0.2.8 / 2019-10-31
  - v0.2.7 / 2019-10-21
  - v0.2.6 / 2019-02-01
  - v0.2.5 / 2017-10-19
  - v0.2.4 / 2017-10-03
  - v0.2.3 / 2017-04-28
  - v0.2.2 / 2017-04-03
  - v0.2.1 / 2017-03-25
  - v0.2.0 / 2017-03-18
  - v0.1.14 / 2017-03-17
  - v0.1.13 / 2017-01-29
  - v0.1.12 / 2017-01-28
  - v0.1.11 / 2017-01-14
  - v0.1.10 / 2017-01-13
  - v0.1.9 / 2017-01-06
  - v0.1.8 / 2016-12-24
  - v0.1.7 / 2016-12-18
  - v0.1.6 / 2016-12-14
  - 0.1.5 / 2016-12-12
  - 0.1.4 / 2016-12-08
  - 0.1.3 / 2016-12-08
  - 0.1.2 / 2016-12-01
  - 0.1.1 / 2016-12-01
  - 0.1.0 / 2016-11-30
  - 0.1.0-rc.1 / 2016-11-27

## pook

Versatile, expressive and hackable utility library for HTTP traffic mocking and expectations made easy in Python. Heavily inspired by gock.

To get started, see the documentation, how it works, FAQ or examples.

# Features

- Simple, expressive and fluent API.

- Provides both Pythonic and chainable DSL API styles.

- Full-featured HTTP response definitions and expectations.

- Matches any HTTP protocol primitive (URL, method, query params, headers, body…).

- Full regular expressions capable mock expectations matching.

- Supports most popular HTTP clients via interceptor adapters.

- Configurable volatile, persistent or TTL limited mocks.

- Works with any testing framework/engine (unittest, pytest, nosetests…).

- First-class JSON & XML support matching and responses.

- Supports JSON Schema body matching.

- Works in both runtime and testing environments.

- Can be used as decorator and/or via context managers.

- Supports real networking mode with optional traffic filtering.

- Map/filter mocks easily for generic or custom mock expectations.

- Custom user-defined mock matcher functions.

- Simulated raised error exceptions.

- Network delay simulation (only available for `aiohttp`).

- Pluggable and hackable API.

- Customizable HTTP traffic mock interceptor engine.

- Supports third-party mocking engines, such as mocket.

- Fits good for painless test doubles.

- Does not support WebSocket traffic mocking.

- Works with +3.5 (including PyPy).

- Dependency-less: just 2 small dependencies for JSONSchema and XML tree comparison.

# Supported HTTP clients

`pook` can work with multiple mock engines, however it provides a built-in one by default, which currently supports traffic mocking in the following HTTP clients:

- ✔ urllib3 v1+

- ✔ requests v2+

- ✔ aiohttp v1+ - v2+

- ✔ urllib / http.client v2/3

- ✘ pycurl (see #16)

More HTTP clients can be supported progressively.

Note: only recent HTTP client package versions were tested.

# Installation

Using `pip` package manager (requires pip 1.8+):

    pip install --upgrade pook

Or install the latest sources from Github:

    pip install -e git+git://github.com/h2non/pook.git#egg=pook

# Getting started

See ReadTheDocs documentation.

# API

See annotated API reference documention.

# Examples

See examples documentation for full featured code and use case examples.

Basic mocking:

    import pook
    import requests

    @pook.on
    def test_my_api():
        mock = pook.get('http://twitter.com/api/1/foobar', reply=404, response_json={'error': 'not found'})

        resp = requests.get('http://twitter.com/api/1/foobar')
        assert resp.status_code == 404
        assert resp.json() == {"error": "not found"}
        assert mock.calls == 1

Using the chainable API DSL:

    import pook
    import requests

    @pook.on
    def test_my_api():
        mock = (pook.get('http://twitter.com/api/1/foobar')
                  .reply(404)
                  .json({'error': 'not found'}))

        resp = requests.get('http://twitter.com/api/1/foobar')
        assert resp.json() == {"error": "not found"}
        assert mock.calls == 1

Using the decorator:

    import pook
    import requests

    @pook.get('http://httpbin.org/status/500', reply=204)
    @pook.get('http://httpbin.org/status/400', reply=200)
    def fetch(url):
        return requests.get(url)

    res = fetch('http://httpbin.org/status/400')
    print('#1 status:', res.status_code)

    res = fetch('http://httpbin.org/status/500')
    print('#2 status:', res.status_code)

Simple `unittest` integration:

    import pook
    import unittest
    import requests

    class TestUnitTestEngine(unittest.TestCase):

        @pook.on
        def test_request(self):
            pook.get('server.com/foo').reply(204)
            res = requests.get('http://server.com/foo')
            self.assertEqual(res.status_code, 204)

        def test_request_with_context_manager(self):
            with pook.use():
                pook.get('server.com/bar', reply=204)
                res = requests.get('http://server.com/bar')
                self.assertEqual(res.status_code, 204)

Using the context manager for isolated HTTP traffic interception blocks:

    import pook
    import requests

    # Enable HTTP traffic interceptor
    with pook.use():
        pook.get('http://httpbin.org/status/500', reply=204)

        res = requests.get('http://httpbin.org/status/500')
        print('#1 status:', res.status_code)

    # Interception-free HTTP traffic
    res = requests.get('http://httpbin.org/status/200')
    print('#2 status:', res.status_code)

Example using mocket Python library as underlying mock engine:

    import pook
    import requests
    from mocket.plugins.pook_mock_engine import MocketEngine

    # Use mocket library as underlying mock engine
    pook.set_mock_engine(MocketEngine)

    # Explicitly enable pook HTTP mocking (optional)
    pook.on()

    # Target server URL to mock out
    url = 'http://twitter.com/api/1/foobar'

    # Define your mock
    mock = pook.get(url,
                    reply=404, times=2,
                    headers={'content-type': 'application/json'},
                    response_json={'error': 'foo'})

    # Run first HTTP request
    requests.get(url)
    assert mock.calls == 1

    # Run second HTTP request
    res = requests.get(url)
    assert mock.calls == 2

    # Assert response data
    assert res.status_code == 404
    assert res.json() == {'error': 'foo'}

    # Explicitly disable pook (optional)
    pook.off()

Example using Hy language (Lisp dialect for Python):

    (import [pook])
    (import [requests])

    (defn request [url &optional [status 404]]
      (doto (.mock pook url) (.reply status))
      (let [res (.get requests url)]
        (. res status_code)))

    (defn run []
      (with [(.use pook)]
        (print "Status:" (request "http://server.com/foo" :status 204))))

    ;; Run test program
    (defmain [&args] (run))

# Development

Clone the repository:

    git clone git@github.com:h2non/pook.git

Install dependencies:

    pip install -r requirements.txt -r requirements-dev.txt

Install Python dependencies:

    make install

Lint code:

    make lint

Run tests:

    make test

Generate documentation:

    make htmldocs

# License

MIT - Tomas Aparicio

# Indices and tables

- Index

- Module Index

- Search Page