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
Pillowon PyPI but exposes thePILpackage, so all code written against the originalPILworks without modification. - opencv-python / cv2 — The PyPI package is
opencv-python; the module iscv2. - pyyaml / yaml — The PyPI package is
pyyaml; the module isyaml.
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"
or just add this to your pytest.ini if you're using that.
With this in place:
import httpxanywhere in your test suite returns HTTPXYZ.respxsees HTTPXYZ ashttpx, so allisinstancechecks pass.- The
respx_mockfixture and@pytest.mark.respxmarker remain available. - No need for
-p no:respx.
Using pytest-httpx in pytest
pytest-httpx has the same import-order
problem as respx, but with an additional wrinkle: it directly imports
httpcore (the low-level transport layer
that httpx uses internally), not just httpx itself. We now also support
this from our pytest plugin, which you configure using addopts:
# pyproject.toml
[tool.pytest.ini_options]
addopts = "-p httpxyz"
With this in place:
import httpxreturns HTTPXYZ.import httpcorereturns httpcorexyz.- The
httpx_mockfixture remains available and works unchanged.
Removing httpx from the dependency graph entirely (uv)
If you use uv and want to remove httpx from your
resolved dependencies entirely, you can override pytest-httpx's declared
dependency on httpx with a uv metadata override:
# pyproject.toml
[[tool.uv.dependency-metadata]]
name = "pytest-httpx"
requires-dist = ["httpxyz>=0.31", "pytest==8.*"]
This tells uv to treat pytest-httpx as if it depends on httpxyz rather than
httpx, so httpx is never added to the lockfile. At runtime the aliases
established by -p httpxyz ensure pytest-httpx still works correctly.