55import linecache
66import sys
77import textwrap
8+ import warnings
89from contextlib import suppress
910
1011__all__ = ['extract_stack' , 'extract_tb' , 'format_exception' ,
@@ -719,7 +720,8 @@ class TracebackException:
719720 - :attr:`__suppress_context__` The *__suppress_context__* value from the
720721 original exception.
721722 - :attr:`stack` A `StackSummary` representing the traceback.
722- - :attr:`exc_type` The class of the original traceback.
723+ - :attr:`exc_type` (deprecated) The class of the original traceback.
724+ - :attr:`exc_type_str` String display of exc_type
723725 - :attr:`filename` For syntax errors - the filename where the error
724726 occurred.
725727 - :attr:`lineno` For syntax errors - the linenumber where the error
@@ -737,7 +739,7 @@ class TracebackException:
737739
738740 def __init__ (self , exc_type , exc_value , exc_traceback , * , limit = None ,
739741 lookup_lines = True , capture_locals = False , compact = False ,
740- max_group_width = 15 , max_group_depth = 10 , _seen = None ):
742+ max_group_width = 15 , max_group_depth = 10 , save_exc_type = True , _seen = None ):
741743 # NB: we need to accept exc_traceback, exc_value, exc_traceback to
742744 # permit backwards compat with the existing API, otherwise we
743745 # need stub thunk objects just to glue it together.
@@ -754,12 +756,23 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None,
754756 _walk_tb_with_full_positions (exc_traceback ),
755757 limit = limit , lookup_lines = lookup_lines ,
756758 capture_locals = capture_locals )
757- self .exc_type = exc_type
759+
760+ self ._exc_type = exc_type if save_exc_type else None
761+
758762 # Capture now to permit freeing resources: only complication is in the
759763 # unofficial API _format_final_exc_line
760764 self ._str = _safe_string (exc_value , 'exception' )
761765 self .__notes__ = getattr (exc_value , '__notes__' , None )
762766
767+ self ._is_syntax_error = False
768+ self ._have_exc_type = exc_type is not None
769+ if exc_type is not None :
770+ self .exc_type_qualname = exc_type .__qualname__
771+ self .exc_type_module = exc_type .__module__
772+ else :
773+ self .exc_type_qualname = None
774+ self .exc_type_module = None
775+
763776 if exc_type and issubclass (exc_type , SyntaxError ):
764777 # Handle SyntaxError's specially
765778 self .filename = exc_value .filename
@@ -771,6 +784,7 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None,
771784 self .offset = exc_value .offset
772785 self .end_offset = exc_value .end_offset
773786 self .msg = exc_value .msg
787+ self ._is_syntax_error = True
774788 elif exc_type and issubclass (exc_type , ImportError ) and \
775789 getattr (exc_value , "name_from" , None ) is not None :
776790 wrong_name = getattr (exc_value , "name_from" , None )
@@ -869,6 +883,24 @@ def from_exception(cls, exc, *args, **kwargs):
869883 """Create a TracebackException from an exception."""
870884 return cls (type (exc ), exc , exc .__traceback__ , * args , ** kwargs )
871885
886+ @property
887+ def exc_type (self ):
888+ warnings .warn ('Deprecated in 3.13. Use exc_type_str instead.' ,
889+ DeprecationWarning , stacklevel = 2 )
890+ return self ._exc_type
891+
892+ @property
893+ def exc_type_str (self ):
894+ if not self ._have_exc_type :
895+ return None
896+ stype = self .exc_type_qualname
897+ smod = self .exc_type_module
898+ if smod not in ("__main__" , "builtins" ):
899+ if not isinstance (smod , str ):
900+ smod = "<unknown>"
901+ stype = smod + '.' + stype
902+ return stype
903+
872904 def _load_lines (self ):
873905 """Private API. force all lines in the stack to be loaded."""
874906 for frame in self .stack :
@@ -901,18 +933,12 @@ def format_exception_only(self, *, show_group=False, _depth=0):
901933 """
902934
903935 indent = 3 * _depth * ' '
904- if self .exc_type is None :
936+ if not self ._have_exc_type :
905937 yield indent + _format_final_exc_line (None , self ._str )
906938 return
907939
908- stype = self .exc_type .__qualname__
909- smod = self .exc_type .__module__
910- if smod not in ("__main__" , "builtins" ):
911- if not isinstance (smod , str ):
912- smod = "<unknown>"
913- stype = smod + '.' + stype
914-
915- if not issubclass (self .exc_type , SyntaxError ):
940+ stype = self .exc_type_str
941+ if not self ._is_syntax_error :
916942 if _depth > 0 :
917943 # Nested exceptions needs correct handling of multiline messages.
918944 formatted = _format_final_exc_line (
0 commit comments