| 1190 | return traceback, extraline |
| 1191 | |
| 1192 | def repr_excinfo(self, excinfo: ExceptionInfo[BaseException]) -> ExceptionChainRepr: |
| 1193 | repr_chain: list[tuple[ReprTraceback, ReprFileLocation | None, str | None]] = [] |
| 1194 | e: BaseException | None = excinfo.value |
| 1195 | excinfo_: ExceptionInfo[BaseException] | None = excinfo |
| 1196 | description = None |
| 1197 | seen: set[int] = set() |
| 1198 | while e is not None and id(e) not in seen: |
| 1199 | seen.add(id(e)) |
| 1200 | |
| 1201 | if excinfo_: |
| 1202 | # Fall back to native traceback as a temporary workaround until |
| 1203 | # full support for exception groups added to ExceptionInfo. |
| 1204 | # See https://github.com/pytest-dev/pytest/issues/9159 |
| 1205 | reprtraceback: ReprTraceback | ReprTracebackNative |
| 1206 | if isinstance(e, BaseExceptionGroup): |
| 1207 | # don't filter any sub-exceptions since they shouldn't have any internal frames |
| 1208 | traceback = filter_excinfo_traceback(self.tbfilter, excinfo) |
| 1209 | extraline = ( |
| 1210 | "All traceback entries are hidden. Pass `--full-trace` to see hidden and internal frames." |
| 1211 | if not traceback |
| 1212 | else None |
| 1213 | ) |
| 1214 | reprtraceback = ReprTracebackNative( |
| 1215 | format_exception( |
| 1216 | type(excinfo.value), |
| 1217 | excinfo.value, |
| 1218 | traceback[0]._rawentry if traceback else None, |
| 1219 | ), |
| 1220 | extraline=extraline, |
| 1221 | ) |
| 1222 | |
| 1223 | else: |
| 1224 | reprtraceback = self.repr_traceback(excinfo_) |
| 1225 | reprcrash = excinfo_._getreprcrash() |
| 1226 | else: |
| 1227 | # Fallback to native repr if the exception doesn't have a traceback: |
| 1228 | # ExceptionInfo objects require a full traceback to work. |
| 1229 | reprtraceback = ReprTracebackNative(format_exception(type(e), e, None)) |
| 1230 | reprcrash = None |
| 1231 | repr_chain.append((reprtraceback, reprcrash, description)) |
| 1232 | |
| 1233 | if e.__cause__ is not None and self.chain: |
| 1234 | e = e.__cause__ |
| 1235 | excinfo_ = ExceptionInfo.from_exception(e) if e.__traceback__ else None |
| 1236 | description = "The above exception was the direct cause of the following exception:" |
| 1237 | elif ( |
| 1238 | e.__context__ is not None and not e.__suppress_context__ and self.chain |
| 1239 | ): |
| 1240 | e = e.__context__ |
| 1241 | excinfo_ = ExceptionInfo.from_exception(e) if e.__traceback__ else None |
| 1242 | description = "During handling of the above exception, another exception occurred:" |
| 1243 | else: |
| 1244 | e = None |
| 1245 | repr_chain.reverse() |
| 1246 | return ExceptionChainRepr(repr_chain) |
| 1247 | |
| 1248 | |
| 1249 | @dataclasses.dataclass(eq=False) |