* `idna` - Internationalized domain name support.
* `sniffio` - Async library autodetection.
* `async_generator` - Backport support for `contextlib.asynccontextmanager`. *(Only required for Python 3.6)*
-* `brotlipy` - Decoding for "brotli" compressed responses. *(Optional)*
+* `brotlicffi` - Decoding for "brotli" compressed responses. *(Optional)*
A huge amount of credit is due to `requests` for the API layout that
much of this work follows, as well as to `urllib3` for plenty of design
* `idna` - Internationalized domain name support.
* `sniffio` - Async library autodetection.
* `async_generator` - Backport support for `contextlib.asynccontextmanager`. *(Only required for Python 3.6)*
-* `brotlipy` - Decoding for "brotli" compressed responses. *(Optional)*
+* `brotlicffi` - Decoding for "brotli" compressed responses. *(Optional)*
A huge amount of credit is due to `requests` for the API layout that
much of this work follows, as well as to `urllib3` for plenty of design
from ._exceptions import DecodingError
try:
- import brotli
+ import brotlicffi
except ImportError: # pragma: nocover
- brotli = None
+ brotlicffi = None
class ContentDecoder:
"""
def __init__(self) -> None:
- if brotli is None: # pragma: nocover
+ if brotlicffi is None: # pragma: nocover
raise ImportError(
- "Using 'BrotliDecoder', but the 'brotlipy' or 'brotli' library "
+ "Using 'BrotliDecoder', but the 'brotlicffi' library "
"is not installed."
"Make sure to install httpx using `pip install httpx[brotli]`."
) from None
- self.decompressor = brotli.Decompressor()
+ self.decompressor = brotlicffi.Decompressor()
self.seen_data = False
if hasattr(self.decompressor, "decompress"):
self._decompress = self.decompressor.decompress
return b""
self.seen_data = True
try:
- return self._decompress(data)
- except brotli.error as exc:
+ return self.decompressor.decompress(data)
+ except brotlicffi.Error as exc:
raise DecodingError(str(exc)) from exc
def flush(self) -> bytes:
if hasattr(self.decompressor, "finish"):
self.decompressor.finish()
return b""
- except brotli.error as exc: # pragma: nocover
+ except brotlicffi.Error as exc: # pragma: nocover
raise DecodingError(str(exc)) from exc
}
-if brotli is None:
+if brotlicffi is None:
SUPPORTED_DECODERS.pop("br") # pragma: nocover
--e .[http2]
-
-# Optional
-brotlipy==0.7.*
+-e .[http2,brotli]
# Documentation
mkdocs
],
extras_require={
"http2": "h2==3.*",
- "brotli": "brotlipy==0.7.*",
+ "brotli": "brotlicffi==1.*",
},
classifiers=[
"Development Status :: 4 - Beta",
import pickle
from unittest import mock
-import brotli
+import brotlicffi
import pytest
import httpx
def test_decode_error_with_request(header_value):
headers = [(b"Content-Encoding", header_value)]
body = b"test 123"
- compressed_body = brotli.compress(body)[3:]
+ compressed_body = brotlicffi.compress(body)[3:]
with pytest.raises(httpx.DecodingError):
httpx.Response(
200,
def test_value_error_without_request(header_value):
headers = [(b"Content-Encoding", header_value)]
body = b"test 123"
- compressed_body = brotli.compress(body)[3:]
+ compressed_body = brotlicffi.compress(body)[3:]
with pytest.raises(httpx.DecodingError):
httpx.Response(200, headers=headers, content=compressed_body)
import zlib
-import brotli
+import brotlicffi
import pytest
import httpx
def test_brotli():
body = b"test 123"
- compressed_body = brotli.compress(body)
+ compressed_body = brotlicffi.compress(body)
headers = [(b"Content-Encoding", b"br")]
response = httpx.Response(
def test_multi_with_identity():
body = b"test 123"
- compressed_body = brotli.compress(body)
+ compressed_body = brotlicffi.compress(body)
headers = [(b"Content-Encoding", b"br, identity")]
response = httpx.Response(
def test_decoding_errors(header_value):
headers = [(b"Content-Encoding", header_value)]
body = b"test 123"
- compressed_body = brotli.compress(body)[3:]
+ compressed_body = brotlicffi.compress(body)[3:]
with pytest.raises(httpx.DecodingError):
request = httpx.Request("GET", "https://example.org")
httpx.Response(200, headers=headers, content=compressed_body, request=request)