@@ -815,22 +815,33 @@ impl ExecutingFrame<'_> {
815815 exception. set_traceback_typed ( Some ( new_traceback. into_ref ( & vm. ctx ) ) ) ;
816816 }
817817
818- // Fire PY_THROW event before raising the exception in the generator
819- {
818+ // Fire PY_THROW and RAISE events before raising the exception in the
819+ // generator. do_monitor_exc in CPython replaces the active exception
820+ // when a callback fails, so we mirror that here.
821+ let exception = {
820822 use crate :: stdlib:: sys:: monitoring;
821823 let monitoring_mask = vm. state . monitoring_events . load ( ) ;
822- if monitoring_mask & monitoring:: EVENT_PY_THROW != 0 {
824+ let exception = if monitoring_mask & monitoring:: EVENT_PY_THROW != 0 {
823825 let offset = idx as u32 * 2 ;
824826 let exc_obj: PyObjectRef = exception. clone ( ) . into ( ) ;
825- let _ = monitoring:: fire_py_throw ( vm, self . code , offset, & exc_obj) ;
826- }
827- // Fire RAISE: the thrown exception is raised in this frame
827+ match monitoring:: fire_py_throw ( vm, self . code , offset, & exc_obj) {
828+ Ok ( ( ) ) => exception,
829+ Err ( monitor_exc) => monitor_exc,
830+ }
831+ } else {
832+ exception
833+ } ;
828834 if monitoring_mask & monitoring:: EVENT_RAISE != 0 {
829835 let offset = idx as u32 * 2 ;
830836 let exc_obj: PyObjectRef = exception. clone ( ) . into ( ) ;
831- let _ = monitoring:: fire_raise ( vm, self . code , offset, & exc_obj) ;
837+ match monitoring:: fire_raise ( vm, self . code , offset, & exc_obj) {
838+ Ok ( ( ) ) => exception,
839+ Err ( monitor_exc) => monitor_exc,
840+ }
841+ } else {
842+ exception
832843 }
833- }
844+ } ;
834845
835846 // when raising an exception, set __context__ to the current exception
836847 // This is done in _PyErr_SetObject
@@ -844,17 +855,23 @@ impl ExecutingFrame<'_> {
844855 Ok ( None ) => self . run ( vm) ,
845856 Ok ( Some ( result) ) => Ok ( result) ,
846857 Err ( exception) => {
847- // Fire PY_UNWIND: exception escapes the generator frame
848- if vm. state . monitoring_events . load ( )
858+ // Fire PY_UNWIND: exception escapes the generator frame.
859+ // do_monitor_exc replaces the exception on callback failure.
860+ let exception = if vm. state . monitoring_events . load ( )
849861 & crate :: stdlib:: sys:: monitoring:: EVENT_PY_UNWIND
850862 != 0
851863 {
852864 let offset = idx as u32 * 2 ;
853865 let exc_obj: PyObjectRef = exception. clone ( ) . into ( ) ;
854- let _ = crate :: stdlib:: sys:: monitoring:: fire_py_unwind (
866+ match crate :: stdlib:: sys:: monitoring:: fire_py_unwind (
855867 vm, self . code , offset, & exc_obj,
856- ) ;
857- }
868+ ) {
869+ Ok ( ( ) ) => exception,
870+ Err ( monitor_exc) => monitor_exc,
871+ }
872+ } else {
873+ exception
874+ } ;
858875 Err ( exception)
859876 }
860877 }
0 commit comments