diff --git a/CHANGELOG.md b/CHANGELOG.md index 3584e33..9c5015b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Sending a non UTF8 body while having a `json` matcher registered will not raise a `UnicodeDecodeError` anymore. - `match_params` is now handling `bool`, `int` and `float` values in addition to `str`. Only str values were previously expected. - A meaningful error will now be returned when a callback that does not return an `httpx.Response` is called. +- Responses with a `Content-Encoding` (such as `gzip`) provided via `content` can now be read by the client. They previously failed with `httpx.DecodingError`. ### Removed - python `3.10` is not supported anymore. diff --git a/README.md b/README.md index 33ff065..f1fd4e4 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ pypi version Build status Coverage -Number of tests +Number of tests Number of downloads

diff --git a/pytest_httpx/_httpx_mock.py b/pytest_httpx/_httpx_mock.py index 5b7468d..e35ac4f 100644 --- a/pytest_httpx/_httpx_mock.py +++ b/pytest_httpx/_httpx_mock.py @@ -369,4 +369,6 @@ def _unread(response: httpx.Response) -> httpx.Response: response.is_closed = False if hasattr(response, "_content"): del response._content + if hasattr(response, "_decoder"): + del response._decoder return response diff --git a/tests/test_httpx_async.py b/tests/test_httpx_async.py index f045bd8..8dfa039 100644 --- a/tests/test_httpx_async.py +++ b/tests/test_httpx_async.py @@ -1,4 +1,5 @@ import asyncio +import gzip import math import os import re @@ -921,6 +922,51 @@ async def test_with_headers(httpx_mock: HTTPXMock) -> None: ) +@pytest.mark.asyncio +async def test_with_gzip_content_encoding(httpx_mock: HTTPXMock) -> None: + httpx_mock.add_response( + url="https://test_url", + content=gzip.compress(b"test content 1"), + headers={"Content-Encoding": "gzip"}, + ) + + async with httpx.AsyncClient() as client: + response = await client.get("https://test_url") + assert response.content == b"test content 1" + + +@pytest.mark.asyncio +async def test_stream_with_gzip_content_encoding(httpx_mock: HTTPXMock) -> None: + httpx_mock.add_response( + url="https://test_url", + content=gzip.compress(b"test content 1"), + headers={"Content-Encoding": "gzip"}, + ) + + async with ( + httpx.AsyncClient() as client, + client.stream(method="GET", url="https://test_url") as response, + ): + chunks = [chunk async for chunk in response.aiter_bytes()] + assert b"".join(chunks) == b"test content 1" + + +@pytest.mark.asyncio +async def test_callback_with_gzip_content_encoding(httpx_mock: HTTPXMock) -> None: + def custom_response(request: httpx.Request) -> httpx.Response: + return httpx.Response( + status_code=200, + content=gzip.compress(b"test content 1"), + headers={"Content-Encoding": "gzip"}, + ) + + httpx_mock.add_callback(custom_response, url="https://test_url") + + async with httpx.AsyncClient() as client: + response = await client.get("https://test_url") + assert response.content == b"test content 1" + + @pytest.mark.asyncio async def test_requests_retrieval(httpx_mock: HTTPXMock) -> None: httpx_mock.add_response( diff --git a/tests/test_httpx_sync.py b/tests/test_httpx_sync.py index 9f837ca..da52f61 100644 --- a/tests/test_httpx_sync.py +++ b/tests/test_httpx_sync.py @@ -1,3 +1,4 @@ +import gzip import os import re from collections.abc import Iterable @@ -834,6 +835,47 @@ def test_with_headers(httpx_mock: HTTPXMock) -> None: ) +def test_with_gzip_content_encoding(httpx_mock: HTTPXMock) -> None: + httpx_mock.add_response( + url="https://test_url", + content=gzip.compress(b"test content 1"), + headers={"Content-Encoding": "gzip"}, + ) + + with httpx.Client() as client: + response = client.get("https://test_url") + assert response.content == b"test content 1" + + +def test_stream_with_gzip_content_encoding(httpx_mock: HTTPXMock) -> None: + httpx_mock.add_response( + url="https://test_url", + content=gzip.compress(b"test content 1"), + headers={"Content-Encoding": "gzip"}, + ) + + with ( + httpx.Client() as client, + client.stream(method="GET", url="https://test_url") as response, + ): + assert b"".join(response.iter_bytes()) == b"test content 1" + + +def test_callback_with_gzip_content_encoding(httpx_mock: HTTPXMock) -> None: + def custom_response(request: httpx.Request) -> httpx.Response: + return httpx.Response( + status_code=200, + content=gzip.compress(b"test content 1"), + headers={"Content-Encoding": "gzip"}, + ) + + httpx_mock.add_callback(custom_response, url="https://test_url") + + with httpx.Client() as client: + response = client.get("https://test_url") + assert response.content == b"test content 1" + + def test_requests_retrieval(httpx_mock: HTTPXMock) -> None: httpx_mock.add_response( url="https://test_url", method="GET", content=b"test content 1"