| 218 | |
| 219 | |
| 220 | class DebugTraceback: |
| 221 | __slots__ = ("_te", "_cache_all_tracebacks", "_cache_all_frames") |
| 222 | |
| 223 | def __init__( |
| 224 | self, |
| 225 | exc: BaseException, |
| 226 | te: traceback.TracebackException | None = None, |
| 227 | *, |
| 228 | skip: int = 0, |
| 229 | hide: bool = True, |
| 230 | ) -> None: |
| 231 | self._te = _process_traceback(exc, te, skip=skip, hide=hide) |
| 232 | |
| 233 | def __str__(self) -> str: |
| 234 | return f"<{type(self).__name__} {self._te}>" |
| 235 | |
| 236 | @cached_property |
| 237 | def all_tracebacks( |
| 238 | self, |
| 239 | ) -> list[tuple[str | None, traceback.TracebackException]]: |
| 240 | out: list[tuple[str | None, traceback.TracebackException]] = [] |
| 241 | current: traceback.TracebackException | None = self._te |
| 242 | |
| 243 | while current is not None: |
| 244 | if current.__cause__ is not None: |
| 245 | chained_msg = ( |
| 246 | "The above exception was the direct cause of the" |
| 247 | " following exception" |
| 248 | ) |
| 249 | chained_exc = current.__cause__ |
| 250 | elif current.__context__ is not None and not current.__suppress_context__: |
| 251 | chained_msg = ( |
| 252 | "During handling of the above exception, another exception occurred" |
| 253 | ) |
| 254 | chained_exc = current.__context__ |
| 255 | else: |
| 256 | chained_msg = None |
| 257 | chained_exc = None |
| 258 | |
| 259 | out.append((chained_msg, current)) |
| 260 | current = chained_exc |
| 261 | |
| 262 | return out |
| 263 | |
| 264 | @cached_property |
| 265 | def all_frames(self) -> list[DebugFrameSummary]: |
| 266 | return [ |
| 267 | f # type: ignore[misc] |
| 268 | for _, te in self.all_tracebacks |
| 269 | for f in te.stack |
| 270 | ] |
| 271 | |
| 272 | def render_traceback_text(self) -> str: |
| 273 | return "".join(self._te.format()) |
| 274 | |
| 275 | def render_traceback_html(self, include_title: bool = True) -> str: |
| 276 | library_frames = [f.is_library for f in self.all_frames] |
| 277 | mark_library = 0 < sum(library_frames) < len(library_frames) |
no outgoing calls