@@ -866,27 +866,16 @@ def exceptions_from_error(
866866 seen_exception_ids : "Optional[Set[int]]" = None ,
867867) -> "Tuple[int, List[Dict[str, Any]]]" :
868868 """
869- Creates the list of exceptions.
870- This can include chained exceptions and exceptions from an ExceptionGroup.
869+ Convert the given exception information into the Sentry "exception" format.
871870
872- See the Exception Interface documentation for more details:
873- https://develop.sentry.dev/sdk/event-payloads/exception/
874-
875- Args:
876- exception_id (int):
877-
878- Sequential counter for assigning ``mechanism.exception_id``
879- to each processed exception. Is NOT the result of calling `id()` on the exception itself.
880-
881- parent_id (int):
882-
883- The ``mechanism.exception_id`` of the parent exception.
884-
885- Written into ``mechanism.parent_id`` in the event payload so Sentry can
886- reconstruct the exception tree.
871+ This will return a list of exceptions (a flattened tree of exceptions) in the
872+ format of the Exception Interface documentation:
873+ https://develop.sentry.dev/sdk/telemetry/errors/#exception-interface
887874
888- Not to be confused with ``seen_exception_ids``, which tracks Python ``id()``
889- values for cycle detection.
875+ This function can handle:
876+ - simple exceptions
877+ - chained exceptions (raise .. from ..)
878+ - exception groups
890879 """
891880
892881 if seen_exception_ids is None :
@@ -902,7 +891,7 @@ def exceptions_from_error(
902891 seen_exceptions .append (exc_value )
903892 seen_exception_ids .add (id (exc_value ))
904893
905- parent = single_exception_from_error_tuple (
894+ base_exception = single_exception_from_error_tuple (
906895 exc_type = exc_type ,
907896 exc_value = exc_value ,
908897 tb = tb ,
@@ -913,70 +902,60 @@ def exceptions_from_error(
913902 source = source ,
914903 full_stack = full_stack ,
915904 )
916- exceptions = [parent ]
905+ exceptions = [base_exception ]
917906
918907 parent_id = exception_id
919908 exception_id += 1
920909
921- should_supress_context = (
910+ causing_exception = None
911+ exception_source = None
912+
913+ should_suppress_context = (
922914 hasattr (exc_value , "__suppress_context__" ) and exc_value .__suppress_context__ # type: ignore
923915 )
924- if should_supress_context :
925- # Add direct cause.
926- # The field `__cause__` is set when raised with the exception (using the `from` keyword).
927- exception_has_cause = (
916+ if should_suppress_context :
917+ has_explicit_causing_exception = (
928918 exc_value
929919 and hasattr (exc_value , "__cause__" )
930920 and exc_value .__cause__ is not None
931921 )
932- if exception_has_cause :
933- cause = exc_value .__cause__ # type: ignore
934- (exception_id , child_exceptions ) = exceptions_from_error (
935- exc_type = type (cause ),
936- exc_value = cause ,
937- tb = getattr (cause , "__traceback__" , None ),
938- client_options = client_options ,
939- mechanism = mechanism ,
940- exception_id = exception_id ,
941- source = "__cause__" ,
942- full_stack = full_stack ,
943- seen_exceptions = seen_exceptions ,
944- seen_exception_ids = seen_exception_ids ,
945- )
946- exceptions .extend (child_exceptions )
947-
922+ if has_explicit_causing_exception :
923+ exception_source = "__cause__"
924+ causing_exception = exc_value .__cause__ # type: ignore
948925 else :
949- # Add indirect cause.
950- # The field `__context__` is assigned if another exception occurs while handling the exception.
951- exception_has_content = (
926+ has_implicit_causing_exception = (
952927 exc_value
953928 and hasattr (exc_value , "__context__" )
954929 and exc_value .__context__ is not None
955930 )
956- if exception_has_content :
957- context = exc_value .__context__ # type: ignore
958- (exception_id , child_exceptions ) = exceptions_from_error (
959- exc_type = type (context ),
960- exc_value = context ,
961- tb = getattr (context , "__traceback__" , None ),
962- client_options = client_options ,
963- mechanism = mechanism ,
964- exception_id = exception_id ,
965- source = "__context__" ,
966- full_stack = full_stack ,
967- seen_exceptions = seen_exceptions ,
968- seen_exception_ids = seen_exception_ids ,
969- )
970- exceptions .extend (child_exceptions )
931+ if has_implicit_causing_exception :
932+ exception_source = "__context__"
933+ causing_exception = exc_value .__context__ # type: ignore
934+
935+ if causing_exception :
936+ (exception_id , child_exceptions ) = exceptions_from_error (
937+ exc_type = type (causing_exception ),
938+ exc_value = causing_exception ,
939+ tb = getattr (causing_exception , "__traceback__" , None ),
940+ client_options = client_options ,
941+ mechanism = mechanism ,
942+ exception_id = exception_id ,
943+ parent_id = parent_id ,
944+ source = exception_source ,
945+ full_stack = full_stack ,
946+ seen_exceptions = seen_exceptions ,
947+ seen_exception_ids = seen_exception_ids ,
948+ )
949+ exceptions .extend (child_exceptions )
971950
972- # Add exceptions from an ExceptionGroup.
951+ # Add child exceptions from an ExceptionGroup.
973952 is_exception_group = exc_value and hasattr (exc_value , "exceptions" )
974953 if is_exception_group :
975- for idx , e in enumerate (exc_value .exceptions ): # type: ignore
954+ for idx , causing_exception in enumerate (exc_value .exceptions ): # type: ignore
976955 (exception_id , child_exceptions ) = exceptions_from_error (
977- exc_type = type (e ),
978- exc_value = e ,
979- tb = getattr (e , "__traceback__" , None ),
956+ exc_type = type (causing_exception ),
957+ exc_value = causing_exception ,
958+ tb = getattr (causing_exception , "__traceback__" , None ),
980959 client_options = client_options ,
981960 mechanism = mechanism ,
982961 exception_id = exception_id ,
@@ -997,38 +976,25 @@ def exceptions_from_error_tuple(
997976 mechanism : "Optional[Dict[str, Any]]" = None ,
998977 full_stack : "Optional[list[dict[str, Any]]]" = None ,
999978) -> "List[Dict[str, Any]]" :
979+ """
980+ Convert an exception into Sentry's structured "exception" format.
981+
982+ See https://develop.sentry.dev/sdk/telemetry/errors/#exception-interface
983+ This is the entry point for exception handling.
984+ """
1000985 exc_type , exc_value , tb = exc_info
1001986
1002- is_exception_group = BaseExceptionGroup is not None and isinstance (
1003- exc_value , BaseExceptionGroup
987+ _ , exceptions = exceptions_from_error (
988+ exc_type = exc_type ,
989+ exc_value = exc_value ,
990+ tb = tb ,
991+ client_options = client_options ,
992+ mechanism = mechanism ,
993+ exception_id = 0 ,
994+ parent_id = 0 ,
995+ full_stack = full_stack ,
1004996 )
1005997
1006- if is_exception_group :
1007- (_ , exceptions ) = exceptions_from_error (
1008- exc_type = exc_type ,
1009- exc_value = exc_value ,
1010- tb = tb ,
1011- client_options = client_options ,
1012- mechanism = mechanism ,
1013- exception_id = 0 ,
1014- parent_id = 0 ,
1015- full_stack = full_stack ,
1016- )
1017-
1018- else :
1019- exceptions = []
1020- for exc_type , exc_value , tb in walk_exception_chain (exc_info ):
1021- exceptions .append (
1022- single_exception_from_error_tuple (
1023- exc_type = exc_type ,
1024- exc_value = exc_value ,
1025- tb = tb ,
1026- client_options = client_options ,
1027- mechanism = mechanism ,
1028- full_stack = full_stack ,
1029- )
1030- )
1031-
1032998 exceptions .reverse ()
1033999
10341000 return exceptions
0 commit comments