@@ -97,6 +97,30 @@ def _exception_from_args(
9797 return details
9898
9999
100+ def _exception_type_from_args (
101+ exception_type : type [BaseException ],
102+ ) -> dict [str , _typing .Any ]:
103+ """
104+ Creates a JSON-safe representation of an exception class.
105+
106+ If the class matches the active exception from `sys.exc_info()`, include
107+ the current exception message and stack trace as well.
108+ """
109+
110+ details : dict [str , _typing .Any ] = {
111+ "type" : exception_type .__name__ ,
112+ "message" : exception_type .__name__ ,
113+ }
114+ exc_type , exc_value , exc_traceback = _sys .exc_info ()
115+ if exc_type is exception_type and exc_value is not None :
116+ details ["message" ] = _safe_exception_string (exc_value )
117+ if exc_traceback is not None :
118+ details ["stack_trace" ] = "" .join (
119+ _traceback .format_exception (exc_type , exc_value , exc_traceback )
120+ )
121+ return details
122+
123+
100124def _safe_exception_string (exception : BaseException ) -> str :
101125 """
102126 Returns a string representation of an exception without propagating repr/str errors.
@@ -128,6 +152,8 @@ def _remove_circular(obj: _typing.Any, refs: set[int] | None = None):
128152 result : _typing .Any
129153 if isinstance (obj , BaseException ):
130154 result = _exception_from_args (obj , refs )
155+ elif isinstance (obj , type ) and issubclass (obj , BaseException ):
156+ result = _exception_type_from_args (obj )
131157 elif isinstance (obj , dict ):
132158 result = {key : _remove_circular (value , refs ) for key , value in obj .items ()}
133159 elif isinstance (obj , list ):
0 commit comments