From cd9d3a56204b36d342e488ee35868d8d33385d5d Mon Sep 17 00:00:00 2001 From: jakkdl Date: Sat, 9 Dec 2023 14:23:54 +0100 Subject: [PATCH] add test for _ExceptionInfo (and fix it) --- src/trio/_tests/test_testing_raisesgroup.py | 15 +++++++++++ src/trio/testing/_raises_group.py | 28 +++++++++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/trio/_tests/test_testing_raisesgroup.py b/src/trio/_tests/test_testing_raisesgroup.py index 274484aad6..87bd36f3b3 100644 --- a/src/trio/_tests/test_testing_raisesgroup.py +++ b/src/trio/_tests/test_testing_raisesgroup.py @@ -2,10 +2,12 @@ import re import sys +from types import TracebackType from typing import TYPE_CHECKING import pytest +import trio from trio.testing import Matcher, RaisesGroup # TODO: make a public export @@ -195,6 +197,19 @@ def check_errno_is_5(e: OSError) -> bool: raise ExceptionGroup("", (OSError(6, ""),)) +def test__ExceptionInfo(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setattr( + trio.testing._raises_group, + "ExceptionInfo", + trio.testing._raises_group._ExceptionInfo, + ) + with trio.testing.RaisesGroup(ValueError) as excinfo: + raise ExceptionGroup("", (ValueError("hello"),)) + assert excinfo.type is ExceptionGroup + assert excinfo.value.exceptions[0].args == ("hello",) + assert isinstance(excinfo.tb, TracebackType) + + if TYPE_CHECKING: # getting the typing working satisfactory is very tricky # but with RaisesGroup being seen as a subclass of BaseExceptionGroup diff --git a/src/trio/testing/_raises_group.py b/src/trio/testing/_raises_group.py index 127fb42678..3acf243b76 100644 --- a/src/trio/testing/_raises_group.py +++ b/src/trio/testing/_raises_group.py @@ -32,7 +32,7 @@ class _ExceptionInfo(Generic[E]): _excinfo: tuple[type[E], E, TracebackType] | None def __init__(self, excinfo: tuple[type[E], E, TracebackType] | None): - self._exc_info = excinfo + self._excinfo = excinfo def fill_unfilled(self, exc_info: tuple[type[E], E, TracebackType]) -> None: """Fill an unfilled ExceptionInfo created with ``for_later()``.""" @@ -44,6 +44,30 @@ def for_later(cls) -> _ExceptionInfo[E]: """Return an unfilled ExceptionInfo.""" return cls(None) + @property + def type(self) -> type[E]: + """The exception class.""" + assert ( + self._excinfo is not None + ), ".type can only be used after the context manager exits" + return self._excinfo[0] + + @property + def value(self) -> E: + """The exception value.""" + assert ( + self._excinfo is not None + ), ".value can only be used after the context manager exits" + return self._excinfo[1] + + @property + def tb(self) -> TracebackType: + """The exception raw traceback.""" + assert ( + self._excinfo is not None + ), ".tb can only be used after the context manager exits" + return self._excinfo[2] + # this may bite users with type checkers not using pytest, but that should # be rare and give quite obvious errors in tests trying to do so. @@ -53,7 +77,7 @@ def for_later(cls) -> _ExceptionInfo[E]: else: try: from pytest import ExceptionInfo - except ImportError: + except ImportError: # pragma: no cover ExceptionInfo = _ExceptionInfo