Skip to content

HTTPX Compatibility

HTTPXYZ is a fork of HTTPX. While most code can be migrated simply by replacing import httpx with import httpxyz, there are situations where you cannot easily change every dependency — for example, when a third-party library such as RESPX checks isinstance(response, httpx.Response) internally.

To handle this, importing httpxyz automatically registers it under the httpx name in sys.modules:

import sys
import httpxyz

assert sys.modules["httpx"] is sys.modules["httpxyz"]  # True

This means any subsequent import httpx in the same process will resolve to httpxyz, and isinstance checks against httpx classes will pass for httpxyz objects:

import httpx   # resolves to httpxyz after the above
import httpxyz

response = httpxyz.Response(200)
assert isinstance(response, httpx.Response)  # True

Prior art

This pattern — where the installable PyPI name differs from the importable module name, or where a fork registers itself under its predecessor's name — is well-established in the Python ecosystem:

  • Pillow / PIL — The actively maintained fork of the Python Imaging Library. It installs as Pillow on PyPI but exposes the PIL package, so all code written against the original PIL works without modification.
  • opencv-python / cv2 — The PyPI package is opencv-python; the module is cv2.
  • pyyaml / yaml — The PyPI package is pyyaml; the module is yaml.

Important caveat

The aliasing uses sys.modules.setdefault, which means it only takes effect if httpx has not already been imported before httpxyz. If both packages are installed and httpx is imported first, the alias will not be established.

For this reason, ensure that nothing in your codebase (or its dependencies) imports httpx before httpxyz is imported. In practice, the simplest way to guarantee this is to import httpxyz early — for example, at the top of your application's entry point — before any other imports that might pull in httpx.

Using respx in pytest

respx registers itself as a pytest plugin via a pytest11 entry point. Pytest loads all such entry points before it reads your conftest.py, so respx imports the real httpx first and the setdefault becomes a no-op — breaking respx.mock with HTTPXYZ objects.

HTTPXYZ ships its own pytest11 entry point to solve this. Because -p flags in addopts are processed by pytest before entry-point plugins are loaded, adding -p httpxyz guarantees HTTPXYZ wins the race:

# pyproject.toml
[tool.pytest.ini_options]
addopts = "-p httpxyz"

With this in place:

  • import httpx anywhere in your test suite returns HTTPXYZ.
  • respx sees HTTPXYZ as httpx, so all isinstance checks pass.
  • The respx_mock fixture and @pytest.mark.respx marker remain available.
  • No need for -p no:respx.