Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test and Document Exception.__cause__ on NetworkError #3792

Merged
merged 9 commits into from Jul 18, 2023
7 changes: 7 additions & 0 deletions telegram/error.py
Expand Up @@ -118,6 +118,13 @@ def __init__(self, message: Optional[str] = None) -> None:
class NetworkError(TelegramError):
"""Base class for exceptions due to networking errors.

Tip:
This exception (and its subclasses) usually originate from the networking backend
Bibo-Joshi marked this conversation as resolved.
Show resolved Hide resolved
used by :class:`~telegram.request.HTTPXRequest`/a custom implementation of
Bibo-Joshi marked this conversation as resolved.
Show resolved Hide resolved
:class:`~telegram.request.BaseRequest`. In this case, the original exception can be
accessed via the ``__cause__``
`attribute <https://docs.python.org/3/library/exceptions.html#exception-context>`_.

Examples:
:any:`Raw API Bot <examples.rawapibot>`
"""
Expand Down
29 changes: 19 additions & 10 deletions tests/request/test_request.py
Expand Up @@ -295,7 +295,7 @@ async def test_special_errors(
(TelegramError("TelegramError"), TelegramError, "TelegramError"),
(
RuntimeError("CustomError"),
Exception,
NetworkError,
r"HTTP implementation: RuntimeError\('CustomError'\)",
),
],
Expand All @@ -312,9 +312,12 @@ async def do_request(*args, **kwargs):
do_request,
)

with pytest.raises(catch_class, match=match):
with pytest.raises(catch_class, match=match) as exc_info:
await httpx_request.post(None, None, None)

if catch_class is NetworkError:
assert exc_info.value.__cause__ is exception

async def test_retrieve(self, monkeypatch, httpx_request):
"""Here we just test that retrieve gives us the raw bytes instead of trying to parse them
as json
Expand Down Expand Up @@ -571,43 +574,49 @@ async def make_assertion(self, method, url, headers, timeout, files, data):
assert content == b"content"

@pytest.mark.parametrize(
("raised_class", "expected_class", "expected_message"),
("raised_exception", "expected_class", "expected_message"),
[
(httpx.TimeoutException, TimedOut, "Timed out"),
(httpx.ReadError, NetworkError, "httpx.ReadError: message"),
(httpx.TimeoutException("timeout"), TimedOut, "Timed out"),
(httpx.ReadError("read_error"), NetworkError, "httpx.ReadError: read_error"),
],
)
async def test_do_request_exceptions(
self, monkeypatch, httpx_request, raised_class, expected_class, expected_message
self, monkeypatch, httpx_request, raised_exception, expected_class, expected_message
):
async def make_assertion(self, method, url, headers, timeout, files, data):
raise raised_class("message")
raise raised_exception

monkeypatch.setattr(httpx.AsyncClient, "request", make_assertion)

with pytest.raises(expected_class, match=expected_message):
with pytest.raises(expected_class, match=expected_message) as exc_info:
await httpx_request.do_request(
"method",
"url",
)

assert exc_info.value.__cause__ is raised_exception

async def test_do_request_pool_timeout(self, monkeypatch):
pool_timeout = httpx.PoolTimeout("pool timeout")

async def request(_, **kwargs):
if self.test_flag is None:
self.test_flag = True
else:
raise httpx.PoolTimeout("pool timeout")
raise pool_timeout
return httpx.Response(HTTPStatus.OK)

monkeypatch.setattr(httpx.AsyncClient, "request", request)

async with HTTPXRequest(pool_timeout=0.02) as httpx_request:
with pytest.raises(TimedOut, match="Pool timeout"):
with pytest.raises(TimedOut, match="Pool timeout") as exc_info:
await asyncio.gather(
httpx_request.do_request(method="GET", url="URL"),
httpx_request.do_request(method="GET", url="URL"),
)

assert exc_info.value.__cause__ is pool_timeout


@pytest.mark.skipif(not TEST_WITH_OPT_DEPS, reason="No need to run this twice")
class TestHTTPXRequestWithRequest:
Expand Down