|
13 | 13 | import sys
|
14 | 14 | import textwrap
|
15 | 15 | import traceback
|
| 16 | +from functools import partial |
16 | 17 | from inspect import getframeinfo
|
17 | 18 | from pathlib import Path
|
18 |
| -from typing import Dict, NamedTuple, Optional, Type |
| 19 | +from typing import Dict, NamedTuple, Optional, Tuple, Type |
19 | 20 |
|
20 | 21 | import hypothesis
|
21 | 22 | from hypothesis.errors import _Trimmable
|
@@ -107,20 +108,27 @@ def __str__(self) -> str:
|
107 | 108 | return f"{self.exc_type.__name__} at {self.filename}:{self.lineno}{ctx}{group}"
|
108 | 109 |
|
109 | 110 | @classmethod
|
110 |
| - def from_exception(cls, exception: BaseException, /) -> "InterestingOrigin": |
| 111 | + def from_exception( |
| 112 | + cls, exception: BaseException, /, seen: Tuple[BaseException, ...] = () |
| 113 | + ) -> "InterestingOrigin": |
111 | 114 | filename, lineno = None, None
|
112 | 115 | if tb := get_trimmed_traceback(exception):
|
113 | 116 | filename, lineno, *_ = traceback.extract_tb(tb)[-1]
|
| 117 | + seen = (*seen, exception) |
| 118 | + make = partial(cls.from_exception, seen=seen) |
| 119 | + context: "InterestingOrigin | tuple[()]" = () |
| 120 | + if exception.__context__ is not None and exception.__context__ not in seen: |
| 121 | + context = make(exception.__context__) |
114 | 122 | return cls(
|
115 | 123 | type(exception),
|
116 | 124 | filename,
|
117 | 125 | lineno,
|
118 | 126 | # Note that if __cause__ is set it is always equal to __context__, explicitly
|
119 | 127 | # to support introspection when debugging, so we can use that unconditionally.
|
120 |
| - cls.from_exception(exception.__context__) if exception.__context__ else (), |
| 128 | + context, |
121 | 129 | # We distinguish exception groups by the inner exceptions, as for __context__
|
122 | 130 | (
|
123 |
| - tuple(map(cls.from_exception, exception.exceptions)) |
| 131 | + tuple(make(exc) for exc in exception.exceptions if exc not in seen) |
124 | 132 | if isinstance(exception, BaseExceptionGroup)
|
125 | 133 | else ()
|
126 | 134 | ),
|
|
0 commit comments