Update brotli support to use the brotlicffi package (#1605)
* Update brotli support to use the brotlicffi package
This commit is contained in:
parent
0c2cb240df
commit
760af43b4f
@ -123,7 +123,7 @@ The HTTPX project relies on these excellent libraries:
|
||||
* `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
|
||||
|
||||
@ -115,7 +115,7 @@ The HTTPX project relies on these excellent libraries:
|
||||
* `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
|
||||
|
||||
@ -11,9 +11,9 @@ import zlib
|
||||
from ._exceptions import DecodingError
|
||||
|
||||
try:
|
||||
import brotli
|
||||
import brotlicffi
|
||||
except ImportError: # pragma: nocover
|
||||
brotli = None
|
||||
brotlicffi = None
|
||||
|
||||
|
||||
class ContentDecoder:
|
||||
@ -99,14 +99,14 @@ class BrotliDecoder(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
|
||||
@ -118,8 +118,8 @@ class BrotliDecoder(ContentDecoder):
|
||||
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:
|
||||
@ -129,7 +129,7 @@ class BrotliDecoder(ContentDecoder):
|
||||
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
|
||||
|
||||
|
||||
@ -365,5 +365,5 @@ SUPPORTED_DECODERS = {
|
||||
}
|
||||
|
||||
|
||||
if brotli is None:
|
||||
if brotlicffi is None:
|
||||
SUPPORTED_DECODERS.pop("br") # pragma: nocover
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
-e .[http2]
|
||||
|
||||
# Optional
|
||||
brotlipy==0.7.*
|
||||
-e .[http2,brotli]
|
||||
|
||||
# Documentation
|
||||
mkdocs
|
||||
|
||||
2
setup.py
2
setup.py
@ -64,7 +64,7 @@ setup(
|
||||
],
|
||||
extras_require={
|
||||
"http2": "h2==3.*",
|
||||
"brotli": "brotlipy==0.7.*",
|
||||
"brotli": "brotlicffi==1.*",
|
||||
},
|
||||
classifiers=[
|
||||
"Development Status :: 4 - Beta",
|
||||
|
||||
@ -2,7 +2,7 @@ import json
|
||||
import pickle
|
||||
from unittest import mock
|
||||
|
||||
import brotli
|
||||
import brotlicffi
|
||||
import pytest
|
||||
|
||||
import httpx
|
||||
@ -788,7 +788,7 @@ def test_link_headers(headers, expected):
|
||||
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,
|
||||
@ -809,7 +809,7 @@ def test_decode_error_with_request(header_value):
|
||||
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)
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import zlib
|
||||
|
||||
import brotli
|
||||
import brotlicffi
|
||||
import pytest
|
||||
|
||||
import httpx
|
||||
@ -69,7 +69,7 @@ def test_gzip():
|
||||
|
||||
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(
|
||||
@ -102,7 +102,7 @@ def test_multi():
|
||||
|
||||
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(
|
||||
@ -165,7 +165,7 @@ def test_decoders_empty_cases(decoder):
|
||||
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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user