httpx/tests/test_exceptions.py
Tom Christie 1a6e254f72
Transport API (#1522)
* Added httpx.BaseTransport and httpx.AsyncBaseTransport

* Test coverage and default transports to calling .close on __exit__

* BaseTransport documentation

* Use 'handle_request' for the transport API.

* Docs tweaks

* Docs tweaks

* Minor docstring tweak

* Transport API docs

* Drop 'Optional' on Transport API

* Docs tweaks

* Tweak CHANGELOG

* Drop erronous example.py

* Push httpcore exception wrapping out of client into transport (#1524)

* Push httpcore exception wrapping out of client into transport

* Include close/aclose extensions in docstring

* Comment about the request property on RequestError exceptions

* Extensions reason_phrase and http_version as bytes (#1526)

* Extensions reason_phrase and http_version as bytes

* Update BaseTransport docstring

* Neaten up our try...except structure for ensuring responses (#1525)

* Fix CHANGELOG typo

Co-authored-by: Florimond Manca <florimond.manca@gmail.com>

* Fix CHANGELOG typo

Co-authored-by: Florimond Manca <florimond.manca@gmail.com>

* stream: Iterator[bytes] -> stream: Iterable[bytes]

* Use proper bytestream interfaces when calling into httpcore

* Grungy typing workaround due to httpcore using Iterator instead of Iterable in bytestream types

* Update docs/advanced.md

Co-authored-by: Florimond Manca <florimond.manca@gmail.com>

* Consistent typing imports across tranports

* Update docs/advanced.md

Co-authored-by: Florimond Manca <florimond.manca@gmail.com>

Co-authored-by: Florimond Manca <florimond.manca@gmail.com>
2021-03-24 12:36:34 +00:00

96 lines
2.5 KiB
Python

from unittest import mock
import httpcore
import pytest
import httpx
from httpx._transports.default import HTTPCORE_EXC_MAP
def test_httpcore_all_exceptions_mapped() -> None:
"""
All exception classes exposed by HTTPCore are properly mapped to an HTTPX-specific
exception class.
"""
not_mapped = [
value
for name, value in vars(httpcore).items()
if isinstance(value, type)
and issubclass(value, Exception)
and value not in HTTPCORE_EXC_MAP
]
if not_mapped: # pragma: nocover
pytest.fail(f"Unmapped httpcore exceptions: {not_mapped}")
def test_httpcore_exception_mapping(server) -> None:
"""
HTTPCore exception mapping works as expected.
"""
def connect_failed(*args, **kwargs):
raise httpcore.ConnectError()
class TimeoutStream:
def __iter__(self):
raise httpcore.ReadTimeout()
def close(self):
pass
class CloseFailedStream:
def __iter__(self):
yield b""
def close(self):
raise httpcore.CloseError()
with mock.patch("httpcore.SyncConnectionPool.request", side_effect=connect_failed):
with pytest.raises(httpx.ConnectError):
httpx.get(server.url)
with mock.patch(
"httpcore.SyncConnectionPool.request",
return_value=(200, [], TimeoutStream(), {}),
):
with pytest.raises(httpx.ReadTimeout):
httpx.get(server.url)
with mock.patch(
"httpcore.SyncConnectionPool.request",
return_value=(200, [], CloseFailedStream(), {}),
):
with pytest.raises(httpx.CloseError):
httpx.get(server.url)
def test_httpx_exceptions_exposed() -> None:
"""
All exception classes defined in `httpx._exceptions`
are exposed as public API.
"""
not_exposed = [
value
for name, value in vars(httpx._exceptions).items()
if isinstance(value, type)
and issubclass(value, Exception)
and not hasattr(httpx, name)
]
if not_exposed: # pragma: nocover
pytest.fail(f"Unexposed HTTPX exceptions: {not_exposed}")
def test_request_attribute() -> None:
# Exception without request attribute
exc = httpx.ReadTimeout("Read operation timed out")
with pytest.raises(RuntimeError):
exc.request
# Exception with request attribute
request = httpx.Request("GET", "https://www.example.com")
exc = httpx.ReadTimeout("Read operation timed out", request=request)
assert exc.request == request