Skip to main content

aiointercept

PyPI Python Docs CI License: MIT

Mock aiohttp HTTP requests by routing them through a real aiohttp.web test server. Inspired by aioresponses, with a largely compatible API.

import aiohttp
from aiointercept import aiointercept

async with aiointercept() as m:
    m.get(f"{m.server_url}/users", payload=[{"id": 1}])

    async with aiohttp.ClientSession() as session:
        resp = await session.get(f"{m.server_url}/users")
        assert await resp.json() == [{"id": 1}]

Why aiointercept?

Testing code that makes HTTP requests usually means either hitting a real server (slow, fragile, requires network) or replacing the HTTP layer with fake objects (fast, but disconnected from reality).

aiointercept takes a third path: it starts a real aiohttp.web server on localhost and redirects your client's requests to it — either by pointing the client at m.server_url directly, or by patching the DNS resolver so existing URLs are transparently intercepted. Your code runs its full HTTP stack; only the remote endpoint is replaced.

  • Real serialization. Headers, body encoding, and content-type negotiation all go through the actual aiohttp stack.
  • Inspectable requests. Callbacks receive a real aiohttp.web.Request — read the body, headers, and query params the server saw.
  • Minimal patching. The default mode touches nothing globally. When you need to intercept hardcoded URLs, only the DNS resolver is patched, so redirects and connection pooling still behave as in production.

Using other HTTP clients

With the default mock_external_urls=False, the mock is a plain HTTP server, so requests, httpx (sync or async), or any other client can call m.server_url. The server runs on its own thread, so blocking clients work directly from async tests with static responses or synchronous callbacks. When using an async callback, offload the blocking client call so the test's event loop remains available:

import httpx
import requests

async with aiointercept() as m:
    m.get(f"{m.server_url}/users", payload=[{"id": 1}], repeat=True)

    assert requests.get(f"{m.server_url}/users").json() == [{"id": 1}]

    async with httpx.AsyncClient() as client:
        resp = await client.get(f"{m.server_url}/users")
        assert resp.json() == [{"id": 1}]

aiointercept is built primarily for aiohttp: its API mirrors aioresponses, and intercepting hardcoded URLs (mock_external_urls=True) only works with aiohttp.

Installation

pip install aiointercept

Requirements: Python ≥ 3.11, aiohttp ≥ 3.13.

For the bundled pytest fixtures, install the pytest-asyncio extra:

pip install 'aiointercept[pytest-asyncio]'

The extra requires pytest-asyncio 0.24 or newer. The plugin registers its fixtures only when a compatible pytest-asyncio is installed; otherwise it is inactive.

Documentation

Full documentation is at aiointercept.readthedocs.io:

  • Quickstart — context manager, decorator, pytest fixture, and start()/stop() usage.
  • Usage guide — interception modes, registering responses, regex patterns, callbacks, and passthrough.
  • Assertions — assert_called_with and friends.
  • API reference — every public class and method.

Sharing the server across tests

Starting and stopping a server for every test adds up. aiointercept ships an auto-discovered pytest plugin that starts the server once per session and hands each test a cleared mock via the aiointercept_mock fixture:

async def test_users(aiointercept_mock):
    m = aiointercept_mock
    m.get(f"{m.server_url}/users", payload=[{"id": 1}])

    async with aiohttp.ClientSession() as session:
        resp = await session.get(f"{m.server_url}/users")
        assert await resp.json() == [{"id": 1}]

The fixture calls m.clear() between tests, so registered handlers and recorded requests never leak from one test to the next. The session-scoped server itself is exposed as aiointercept_server if you need it directly.

Coming from aioresponses?

aiointercept aims to be a near drop-in replacement. The migration guide (MIGRATING.md) covers every breaking change. If you hit an incompatibility it doesn't cover, please open an issue.

Contributing

uv sync --group dev --group tests   # install everything
uv run pytest tests/                 # run the suite
uv run ruff check .                  # lint
uv run mypy aiointercept             # type check

Pre-commit hooks run ruff and mypy on every commit; do not bypass them with --no-verify.

License

aiointercept is released under the MIT License.

Attribution

Built on ideas and API conventions from aioresponses by Pawel Nuckowski (MIT License). tests/test_aioresponse.py is a lightly adapted port of the original test suite, used to verify compatibility.

Metadata

Release files for aiointercept 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aiointercept 1.0.0
File Size Uploaded
aiointercept-1.0.0.tar.gz 188.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for aiointercept 1.0.0
File Interpreter ABI Platform
aiointercept-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 208.8 kB

Release files / aiointercept-1.0.0.tar.gz

Download URL aiointercept-1.0.0.tar.gz
Size 188.5 kB
Tags Source
SHA-256 checksum
How to use checksums
99c52ba2d6c282f1e0cbeba2225279eca581cf24b6a3c893929bacf8774e8f70
BLAKE2b-256 checksum
How to use checksums
2c880e6de3b67ecb42e8e4451f5f3c57ccb5f8e4b6cde657d197e22600dad4f0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / aiointercept-1.0.0-py3-none-any.whl

Download URL aiointercept-1.0.0-py3-none-any.whl
Size 20.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1c6b5543a611d29cc899f6c9b117ad61cb657dd2fb8c95ab8199cb8a5842b616
BLAKE2b-256 checksum
How to use checksums
6a28042b1a6e3e70043919cd197a5a99af0eec510d6d87a8ddb175c350590984
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

0.1.12

2 release files

0.1.11

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page