-
Notifications
You must be signed in to change notification settings - Fork 418
Description
I am using httpx-aiohttp to get the interface of httpx with the performance of aiohttp.
Unfortunately the httpx_aiohttp.HttpxAiohttpClient doesn't work out-of-the box with vcrpy because:
httpx-aiohttphas a few details- It propagates headers (link) and leaves content compressed (link)
- It does not yet handle already-exhausted streams:
AiohttpResponseStreamdoes not work if theaiohttpresponse wasreadkarpetrosyan/httpx-aiohttp#23
vcrpyrecords both request/response pairs:- Once for the inner request/
aiohttp.ClientResponse(which can be compressed) - Once for the outer request/
httpx.Responsepair
- Once for the inner request/
For example, with this code:
import httpx_aiohttp
import pytest
@pytest.mark.vcr
@pytest.mark.asyncio
async def test_compressed_get() -> None:
"""Make a GET request, with gzip compression."""
async with httpx_aiohttp.HttpxAiohttpClient(timeout=60) as client:
# Can also use https://httpbin.org/gzip, but it can be flaky
response = await client.get("https://httpbingo.org/gzip")
response.raise_for_status()
assert response.status_code == 200
assert response.json()["gzipped"]Running this code with Python 3.13, pytest==8.4.1, pytest-asyncio==1.1.0, pytest-recording==0.13.4, vcrpy==7.0.0, httpx==0.28.1, and httpx-aiohttp==0.1.8, httpcore==1.0.9, and no-prerecorded VCR cassette, the .json() call at the end leads to:
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
This exposes a failure in httpx-aiohttp (karpetrosyan/httpx-aiohttp#23, also linked above), but it also exposes a duplicated cassette issue in vcrpy (also reported in #938).
vcrpy records 2 VCR cassettes: one for the inner aiohttp request, one for the outer httpx request. These cassettes will be identical with respect to matchers such as ["method", "host", "path", "query"], and note also the headers are identical too. As an example with the above minimal reproducer, they share the same GET method, httpbingo.org host, /gzip path, and [] query.
The request is, can vcrpy expose some way to disable httpx_stubs's async patching, so I can only record one request (the inner aiohttp request)?
The workaround, for those who need it, is in conftest.py just permanently-bypass vcrpy.stubs.httpx_stubs._record_responses:
import vcr.stubs.httpx_stubs
async def _async_vcr_send(cassette, real_send, *args, **kwargs): # noqa: ARG001
"""VCR send that only sends, not possibly recording or playing back responses."""
return await real_send(*args, **kwargs)
vcr.stubs.httpx_stubs._async_vcr_send = _async_vcr_send