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

[PR #8456/b09d7cc backport][3.10] Add ClientConnectorDNSError for differentiating DNS errors from others #9459

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES/8455.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added :exc:`aiohttp.ClientConnectorDNSError` for differentiating DNS resolution errors from other connector errors -- by :user:`mstojcevich`.
1 change: 1 addition & 0 deletions CONTRIBUTORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ Manuel Miranda
Marat Sharafutdinov
Marc Mueller
Marco Paolini
Marcus Stojcevich
Mariano Anaya
Mariusz Masztalerczuk
Marko Kohtala
Expand Down
2 changes: 2 additions & 0 deletions aiohttp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
ClientConnectionError,
ClientConnectionResetError,
ClientConnectorCertificateError,
ClientConnectorDNSError,
ClientConnectorError,
ClientConnectorSSLError,
ClientError,
Expand Down Expand Up @@ -127,6 +128,7 @@
"ClientConnectionError",
"ClientConnectionResetError",
"ClientConnectorCertificateError",
"ClientConnectorDNSError",
"ClientConnectorError",
"ClientConnectorSSLError",
"ClientError",
Expand Down
2 changes: 2 additions & 0 deletions aiohttp/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
ClientConnectionError,
ClientConnectionResetError,
ClientConnectorCertificateError,
ClientConnectorDNSError,
ClientConnectorError,
ClientConnectorSSLError,
ClientError,
Expand Down Expand Up @@ -105,6 +106,7 @@
"ClientConnectionError",
"ClientConnectionResetError",
"ClientConnectorCertificateError",
"ClientConnectorDNSError",
"ClientConnectorError",
"ClientConnectorSSLError",
"ClientError",
Expand Down
9 changes: 9 additions & 0 deletions aiohttp/client_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"ClientConnectorError",
"ClientProxyConnectionError",
"ClientSSLError",
"ClientConnectorDNSError",
"ClientConnectorSSLError",
"ClientConnectorCertificateError",
"ConnectionTimeoutError",
Expand Down Expand Up @@ -206,6 +207,14 @@ def __str__(self) -> str:
__reduce__ = BaseException.__reduce__


class ClientConnectorDNSError(ClientConnectorError):
"""DNS resolution failed during client connection.

Raised in :class:`aiohttp.connector.TCPConnector` if
DNS resolution fails.
"""


class ClientProxyConnectionError(ClientConnectorError):
"""Proxy connection error.

Expand Down
3 changes: 2 additions & 1 deletion aiohttp/connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from .client_exceptions import (
ClientConnectionError,
ClientConnectorCertificateError,
ClientConnectorDNSError,
ClientConnectorError,
ClientConnectorSSLError,
ClientHttpProxyError,
Expand Down Expand Up @@ -1319,7 +1320,7 @@ async def _create_direct_connection(
raise
# in case of proxy it is not ClientProxyConnectionError
# it is problem of resolving proxy ip itself
raise ClientConnectorError(req.connection_key, exc) from exc
raise ClientConnectorDNSError(req.connection_key, exc) from exc

last_exc: Optional[Exception] = None
addr_infos = self._convert_hosts_to_addr_infos(hosts)
Expand Down
8 changes: 8 additions & 0 deletions docs/client_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2228,6 +2228,12 @@ Connection errors

Derived from :exc:`ClientOSError`

.. class:: ClientConnectorDNSError

DNS resolution error.

Derived from :exc:`ClientConnectorError`

.. class:: ClientProxyConnectionError

Derived from :exc:`ClientConnectorError`
Expand Down Expand Up @@ -2309,6 +2315,8 @@ Hierarchy of exceptions

* :exc:`ClientProxyConnectionError`

* :exc:`ClientConnectorDNSError`

* :exc:`ClientSSLError`

* :exc:`ClientConnectorCertificateError`
Expand Down
33 changes: 32 additions & 1 deletion tests/test_client_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -3116,7 +3116,38 @@ async def test_aiohttp_request_ctx_manager_not_found() -> None:
assert False, "never executed" # pragma: no cover


async def test_yield_from_in_session_request(aiohttp_client) -> None:
async def test_raising_client_connector_dns_error_on_dns_failure() -> None:
"""Verify that the exception raised when a DNS lookup fails is specific to DNS."""
with mock.patch(
"aiohttp.connector.TCPConnector._resolve_host", autospec=True, spec_set=True
) as mock_resolve_host:
mock_resolve_host.side_effect = OSError(None, "DNS lookup failed")
with pytest.raises(aiohttp.ClientConnectorDNSError, match="DNS lookup failed"):
async with aiohttp.request("GET", "http://wrong-dns-name.com"):
assert False, "never executed"


async def test_aiohttp_request_coroutine(aiohttp_server: AiohttpServer) -> None:
async def handler(request: web.Request) -> web.Response:
return web.Response()

app = web.Application()
app.router.add_get("/", handler)
server = await aiohttp_server(app)

not_an_awaitable = aiohttp.request("GET", server.make_url("/"))
with pytest.raises(
TypeError,
match="^object _SessionRequestContextManager "
"can't be used in 'await' expression$",
):
await not_an_awaitable # type: ignore[misc]

await not_an_awaitable._coro # coroutine 'ClientSession._request' was never awaited
await server.close()


async def test_yield_from_in_session_request(aiohttp_client: AiohttpClient) -> None:
# a test for backward compatibility with yield from syntax
async def handler(request):
return web.Response()
Expand Down
Loading