lst = traceback.format_exception_only(e.__class__, e)
self.assertEqual(lst, ['KeyboardInterrupt\n'])
+ def test_traceback_context_recursionerror(self):
+ # Test that for long traceback chains traceback does not itself
+ # raise a recursion error while printing (Issue43048)
+
+ # Calling f() creates a stack-overflowing __context__ chain.
+ def f():
+ try:
+ raise ValueError('hello')
+ except ValueError:
+ f()
+
+ try:
+ f()
+ except RecursionError:
+ exc_info = sys.exc_info()
+
+ traceback.format_exception(exc_info[0], exc_info[1], exc_info[2])
+
+ def test_traceback_cause_recursionerror(self):
+ # Same as test_traceback_context_recursionerror, but with
+ # a __cause__ chain.
+
+ def f():
+ e = None
+ try:
+ f()
+ except Exception as exc:
+ e = exc
+ raise Exception from e
+
+ try:
+ f()
+ except Exception:
+ exc_info = sys.exc_info()
+
+ traceback.format_exception(exc_info[0], exc_info[1], exc_info[2])
+
def test_format_exception_only_bad__str__(self):
class X(Exception):
def __str__(self):
_seen.add(id(exc_value))
# Gracefully handle (the way Python 2.4 and earlier did) the case of
# being called with no type or value (None, None, None).
- if (exc_value and exc_value.__cause__ is not None
- and id(exc_value.__cause__) not in _seen):
- cause = TracebackException(
- type(exc_value.__cause__),
- exc_value.__cause__,
- exc_value.__cause__.__traceback__,
- limit=limit,
- lookup_lines=False,
- capture_locals=capture_locals,
- _seen=_seen)
- else:
+ self._truncated = False
+ try:
+ if (exc_value and exc_value.__cause__ is not None
+ and id(exc_value.__cause__) not in _seen):
+ cause = TracebackException(
+ type(exc_value.__cause__),
+ exc_value.__cause__,
+ exc_value.__cause__.__traceback__,
+ limit=limit,
+ lookup_lines=False,
+ capture_locals=capture_locals,
+ _seen=_seen)
+ else:
+ cause = None
+ if (exc_value and exc_value.__context__ is not None
+ and id(exc_value.__context__) not in _seen):
+ context = TracebackException(
+ type(exc_value.__context__),
+ exc_value.__context__,
+ exc_value.__context__.__traceback__,
+ limit=limit,
+ lookup_lines=False,
+ capture_locals=capture_locals,
+ _seen=_seen)
+ else:
+ context = None
+ except RecursionError:
+ # The recursive call to the constructors above
+ # may result in a stack overflow for long exception chains,
+ # so we must truncate.
+ self._truncated = True
cause = None
- if (exc_value and exc_value.__context__ is not None
- and id(exc_value.__context__) not in _seen):
- context = TracebackException(
- type(exc_value.__context__),
- exc_value.__context__,
- exc_value.__context__.__traceback__,
- limit=limit,
- lookup_lines=False,
- capture_locals=capture_locals,
- _seen=_seen)
- else:
context = None
self.__cause__ = cause
self.__context__ = context
not self.__suppress_context__):
yield from self.__context__.format(chain=chain)
yield _context_message
+ if self._truncated:
+ yield (
+ 'Chained exceptions have been truncated to avoid '
+ 'stack overflow in traceback formatting:\n')
if self.stack:
yield 'Traceback (most recent call last):\n'
yield from self.stack.format()