Skip to content

Commit

Permalink
Add ClientConnectorDNSError for differentiating DNS errors from others (
Browse files Browse the repository at this point in the history
#8456)

Co-authored-by: J. Nick Koston <[email protected]>
(cherry picked from commit b09d7cc)
  • Loading branch information
mstojcevich-cisco authored and bdraco committed Oct 10, 2024
1 parent f48f210 commit fc660d1
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 2 deletions.
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 @@ -223,6 +223,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 @@ -128,6 +129,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 @@ -109,6 +110,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 @@ -38,6 +38,7 @@
from .client_exceptions import (
ClientConnectionError,
ClientConnectorCertificateError,
ClientConnectorDNSError,
ClientConnectorError,
ClientConnectorSSLError,
ClientHttpProxyError,
Expand Down Expand Up @@ -1328,7 +1329,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 @@ -2272,6 +2272,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 @@ -2353,6 +2359,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 @@ -3248,7 +3248,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

0 comments on commit fc660d1

Please sign in to comment.