@@ -476,29 +476,38 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None,
476
476
_seen .add (id (exc_value ))
477
477
# Gracefully handle (the way Python 2.4 and earlier did) the case of
478
478
# being called with no type or value (None, None, None).
479
- if (exc_value and exc_value .__cause__ is not None
480
- and id (exc_value .__cause__ ) not in _seen ):
481
- cause = TracebackException (
482
- type (exc_value .__cause__ ),
483
- exc_value .__cause__ ,
484
- exc_value .__cause__ .__traceback__ ,
485
- limit = limit ,
486
- lookup_lines = False ,
487
- capture_locals = capture_locals ,
488
- _seen = _seen )
489
- else :
479
+ self ._truncated = False
480
+ try :
481
+ if (exc_value and exc_value .__cause__ is not None
482
+ and id (exc_value .__cause__ ) not in _seen ):
483
+ cause = TracebackException (
484
+ type (exc_value .__cause__ ),
485
+ exc_value .__cause__ ,
486
+ exc_value .__cause__ .__traceback__ ,
487
+ limit = limit ,
488
+ lookup_lines = False ,
489
+ capture_locals = capture_locals ,
490
+ _seen = _seen )
491
+ else :
492
+ cause = None
493
+ if (exc_value and exc_value .__context__ is not None
494
+ and id (exc_value .__context__ ) not in _seen ):
495
+ context = TracebackException (
496
+ type (exc_value .__context__ ),
497
+ exc_value .__context__ ,
498
+ exc_value .__context__ .__traceback__ ,
499
+ limit = limit ,
500
+ lookup_lines = False ,
501
+ capture_locals = capture_locals ,
502
+ _seen = _seen )
503
+ else :
504
+ context = None
505
+ except RecursionError :
506
+ # The recursive call to the constructors above
507
+ # may result in a stack overflow for long exception chains,
508
+ # so we must truncate.
509
+ self ._truncated = True
490
510
cause = None
491
- if (exc_value and exc_value .__context__ is not None
492
- and id (exc_value .__context__ ) not in _seen ):
493
- context = TracebackException (
494
- type (exc_value .__context__ ),
495
- exc_value .__context__ ,
496
- exc_value .__context__ .__traceback__ ,
497
- limit = limit ,
498
- lookup_lines = False ,
499
- capture_locals = capture_locals ,
500
- _seen = _seen )
501
- else :
502
511
context = None
503
512
self .__cause__ = cause
504
513
self .__context__ = context
@@ -620,6 +629,10 @@ def format(self, *, chain=True):
620
629
not self .__suppress_context__ ):
621
630
yield from self .__context__ .format (chain = chain )
622
631
yield _context_message
632
+ if self ._truncated :
633
+ yield (
634
+ 'Chained exceptions have been truncated to avoid '
635
+ 'stack overflow in traceback formatting:\n ' )
623
636
if self .stack :
624
637
yield 'Traceback (most recent call last):\n '
625
638
yield from self .stack .format ()
0 commit comments