From 1fc74251341ffca1d524f30751f77cccad363c7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Robert?= Date: Mon, 29 Jan 2024 09:26:15 +0100 Subject: [PATCH] Change to be specific to urllib --- src/_pytest/_code/code.py | 13 ++++++++++++- testing/acceptance_test.py | 8 -------- testing/python/raises.py | 13 +++++++++++++ 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/_pytest/_code/code.py b/src/_pytest/_code/code.py index e5b2ea06b..a3a7e16d3 100644 --- a/src/_pytest/_code/code.py +++ b/src/_pytest/_code/code.py @@ -700,10 +700,21 @@ class ExceptionInfo(Generic[E]): return fmt.repr_excinfo(self) def _stringify_exception(self, exc: BaseException) -> str: + try: + notes = getattr(exc, "__notes__", []) + except KeyError: + # Workaround for https://github.com/python/cpython/issues/98778 on + # Python <= 3.9, and some 3.10 and 3.11 patch versions. + HTTPError = getattr(sys.modules.get("urllib.error", None), "HTTPError", ()) + if sys.version_info[:2] <= (3, 11) and isinstance(exc, HTTPError): + notes = [] + else: + raise + return "\n".join( [ str(exc), - *safe_getattr(exc, "__notes__", []), + *notes, ] ) diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index cce504167..64e65f313 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -1450,11 +1450,3 @@ def test_issue_9765(pytester: Pytester) -> None: raise AssertionError( f"pytest command failed:\n{exc.stdout=!s}\n{exc.stderr=!s}" ) from exc - - -def test_issue_11872() -> None: - # see https://github.com/pytest-dev/pytest/issues/11872 - from urllib.error import HTTPError - - with pytest.raises(HTTPError, match="Not Found"): - raise HTTPError(code=404, msg="Not Found", fp=None, hdrs=None, url="") # type: ignore [arg-type] diff --git a/testing/python/raises.py b/testing/python/raises.py index 47b22f28a..369a66a9f 100644 --- a/testing/python/raises.py +++ b/testing/python/raises.py @@ -302,3 +302,16 @@ class TestRaises: with pytest.raises(("hello", NotAnException)): # type: ignore[arg-type] pass # pragma: no cover assert "must be a BaseException type, not str" in str(excinfo.value) + + def test_issue_11872(self) -> None: + """Regression test for #11872. + + urllib.error.HTTPError on Python<=3.9 raises KeyError instead of + AttributeError on invalid attribute access. + + https://github.com/python/cpython/issues/98778 + """ + from urllib.error import HTTPError + + with pytest.raises(HTTPError, match="Not Found"): + raise HTTPError(code=404, msg="Not Found", fp=None, hdrs=None, url="") # type: ignore [arg-type]