From 1a50b0f87a651fe9113d3d694e13baec4e0969ef Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 10 Oct 2024 09:08:28 -0500 Subject: [PATCH] Fix AsyncResolver swallowing the error message (#9451) (cherry picked from commit 216e082807d02fafaacca57fc883c86826b126d3) --- CHANGES/9451.bugfix.rst | 1 + aiohttp/resolver.py | 4 ++-- tests/test_resolver.py | 30 +++++++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 CHANGES/9451.bugfix.rst diff --git a/CHANGES/9451.bugfix.rst b/CHANGES/9451.bugfix.rst new file mode 100644 index 00000000000..2adcbc66273 --- /dev/null +++ b/CHANGES/9451.bugfix.rst @@ -0,0 +1 @@ +Fixed error messages from :py:class:`~aiohttp.resolver.AsyncResolver` being swallowed -- by :user:`bdraco`. diff --git a/aiohttp/resolver.py b/aiohttp/resolver.py index 4f15e84071d..5240bfbd8d8 100644 --- a/aiohttp/resolver.py +++ b/aiohttp/resolver.py @@ -109,7 +109,7 @@ async def resolve( ) except aiodns.error.DNSError as exc: msg = exc.args[1] if len(exc.args) >= 1 else "DNS lookup failed" - raise OSError(msg) from exc + raise OSError(None, msg) from exc hosts: List[ResolveResult] = [] for node in resp.nodes: address: Union[Tuple[bytes, int], Tuple[bytes, int, int, int]] = node.addr @@ -143,7 +143,7 @@ async def resolve( ) if not hosts: - raise OSError("DNS lookup failed") + raise OSError(None, "DNS lookup failed") return hosts diff --git a/tests/test_resolver.py b/tests/test_resolver.py index e0e843f4782..842618c3053 100644 --- a/tests/test_resolver.py +++ b/tests/test_resolver.py @@ -332,7 +332,35 @@ async def test_async_resolver_query_ipv6_positive_lookup(loop) -> None: mock().query.assert_called_with("www.python.org", "AAAA") -async def test_async_resolver_aiodns_not_present(loop, monkeypatch) -> None: +@pytest.mark.skipif(not getaddrinfo, reason="aiodns >=3.2.0 required") +async def test_async_resolver_error_messages_passed( + loop: asyncio.AbstractEventLoop, +) -> None: + """Ensure error messages are passed through from aiodns.""" + with patch("aiodns.DNSResolver", autospec=True, spec_set=True) as mock: + mock().getaddrinfo.side_effect = aiodns.error.DNSError(1, "Test error message") + resolver = AsyncResolver() + with pytest.raises(OSError, match="Test error message") as excinfo: + await resolver.resolve("x.org") + + assert excinfo.value.strerror == "Test error message" + + +@pytest.mark.skipif(not getaddrinfo, reason="aiodns >=3.2.0 required") +async def test_async_resolver_error_messages_passed_no_hosts( + loop: asyncio.AbstractEventLoop, +) -> None: + """Ensure error messages are passed through from aiodns.""" + with patch("aiodns.DNSResolver", autospec=True, spec_set=True) as mock: + mock().getaddrinfo.return_value = fake_aiodns_getaddrinfo_ipv6_result([]) + resolver = AsyncResolver() + with pytest.raises(OSError, match="DNS lookup failed") as excinfo: + await resolver.resolve("x.org") + + assert excinfo.value.strerror == "DNS lookup failed" + + +async def test_async_resolver_aiodns_not_present(loop: Any, monkeypatch: Any) -> None: monkeypatch.setattr("aiohttp.resolver.aiodns", None) with pytest.raises(RuntimeError): AsyncResolver(loop=loop)