@@ -767,6 +767,168 @@ def func3():
767
767
('line' , 'check_events' , 11 ),
768
768
('call' , 'set_events' , 2 )])
769
769
770
+ class InstructionRecorder :
771
+
772
+ event_type = E .INSTRUCTION
773
+
774
+ def __init__ (self , events ):
775
+ self .events = events
776
+
777
+ def __call__ (self , code , offset ):
778
+ # Filter out instructions in check_events to lower noise
779
+ if code .co_name != "check_events" :
780
+ self .events .append (("instruction" , code .co_name , offset ))
781
+
782
+
783
+ LINE_AND_INSTRUCTION_RECORDERS = InstructionRecorder , LineRecorder
784
+
785
+ class TestLineAndInstructionEvents (CheckEvents ):
786
+ maxDiff = None
787
+
788
+ def test_simple (self ):
789
+
790
+ def func1 ():
791
+ line1 = 1
792
+ line2 = 2
793
+ line3 = 3
794
+
795
+ self .check_events (func1 , recorders = LINE_AND_INSTRUCTION_RECORDERS , expected = [
796
+ ('line' , 'check_events' , 10 ),
797
+ ('instruction' , 'func1' , 1 ),
798
+ ('line' , 'func1' , 1 ),
799
+ ('instruction' , 'func1' , 2 ),
800
+ ('instruction' , 'func1' , 3 ),
801
+ ('line' , 'func1' , 2 ),
802
+ ('instruction' , 'func1' , 4 ),
803
+ ('instruction' , 'func1' , 5 ),
804
+ ('line' , 'func1' , 3 ),
805
+ ('instruction' , 'func1' , 6 ),
806
+ ('instruction' , 'func1' , 7 ),
807
+ ('line' , 'check_events' , 11 )])
808
+
809
+ def test_c_call (self ):
810
+
811
+ def func2 ():
812
+ line1 = 1
813
+ [].append (2 )
814
+ line3 = 3
815
+
816
+ self .check_events (func2 , recorders = LINE_AND_INSTRUCTION_RECORDERS , expected = [
817
+ ('line' , 'check_events' , 10 ),
818
+ ('instruction' , 'func2' , 1 ),
819
+ ('line' , 'func2' , 1 ),
820
+ ('instruction' , 'func2' , 2 ),
821
+ ('instruction' , 'func2' , 3 ),
822
+ ('line' , 'func2' , 2 ),
823
+ ('instruction' , 'func2' , 4 ),
824
+ ('instruction' , 'func2' , 14 ),
825
+ ('instruction' , 'func2' , 15 ),
826
+ ('instruction' , 'func2' , 20 ),
827
+ ('instruction' , 'func2' , 21 ),
828
+ ('line' , 'func2' , 3 ),
829
+ ('instruction' , 'func2' , 22 ),
830
+ ('instruction' , 'func2' , 23 ),
831
+ ('line' , 'check_events' , 11 )])
832
+
833
+ def test_try_except (self ):
834
+
835
+ def func3 ():
836
+ try :
837
+ line = 2
838
+ raise KeyError
839
+ except :
840
+ line = 5
841
+ line = 6
842
+
843
+ self .check_events (func3 , recorders = LINE_AND_INSTRUCTION_RECORDERS , expected = [
844
+ ('line' , 'check_events' , 10 ),
845
+ ('instruction' , 'func3' , 1 ),
846
+ ('line' , 'func3' , 1 ),
847
+ ('instruction' , 'func3' , 2 ),
848
+ ('line' , 'func3' , 2 ),
849
+ ('instruction' , 'func3' , 3 ),
850
+ ('instruction' , 'func3' , 4 ),
851
+ ('line' , 'func3' , 3 ),
852
+ ('instruction' , 'func3' , 9 ),
853
+ ('instruction' , 'func3' , 10 ),
854
+ ('instruction' , 'func3' , 11 ),
855
+ ('line' , 'func3' , 4 ),
856
+ ('instruction' , 'func3' , 12 ),
857
+ ('line' , 'func3' , 5 ),
858
+ ('instruction' , 'func3' , 13 ),
859
+ ('instruction' , 'func3' , 14 ),
860
+ ('instruction' , 'func3' , 15 ),
861
+ ('line' , 'func3' , 6 ),
862
+ ('instruction' , 'func3' , 16 ),
863
+ ('instruction' , 'func3' , 17 ),
864
+ ('line' , 'check_events' , 11 )])
865
+
866
+ class TestInstallIncrementallly (unittest .TestCase ):
867
+
868
+ def check_events (self , func , must_include , tool = TEST_TOOL , recorders = (ExceptionRecorder ,)):
869
+ try :
870
+ self .assertEqual (sys .monitoring ._all_events (), {})
871
+ event_list = []
872
+ all_events = 0
873
+ for recorder in recorders :
874
+ all_events |= recorder .event_type
875
+ sys .monitoring .set_events (tool , all_events )
876
+ for recorder in recorders :
877
+ sys .monitoring .register_callback (tool , recorder .event_type , recorder (event_list ))
878
+ func ()
879
+ sys .monitoring .set_events (tool , 0 )
880
+ for recorder in recorders :
881
+ sys .monitoring .register_callback (tool , recorder .event_type , None )
882
+ for line in must_include :
883
+ self .assertIn (line , event_list )
884
+ finally :
885
+ sys .monitoring .set_events (tool , 0 )
886
+ for recorder in recorders :
887
+ sys .monitoring .register_callback (tool , recorder .event_type , None )
888
+
889
+ @staticmethod
890
+ def func1 ():
891
+ line1 = 1
892
+
893
+ MUST_INCLUDE_LI = [
894
+ ('instruction' , 'func1' , 1 ),
895
+ ('line' , 'func1' , 1 ),
896
+ ('instruction' , 'func1' , 2 ),
897
+ ('instruction' , 'func1' , 3 )]
898
+
899
+ def test_line_then_instruction (self ):
900
+ recorders = [ LineRecorder , InstructionRecorder ]
901
+ self .check_events (self .func1 ,
902
+ recorders = recorders , must_include = self .EXPECTED_LI )
903
+
904
+ def test_instruction_then_line (self ):
905
+ recorders = [ InstructionRecorder , LineRecorderLowNoise ]
906
+ self .check_events (self .func1 ,
907
+ recorders = recorders , must_include = self .EXPECTED_LI )
908
+
909
+ @staticmethod
910
+ def func2 ():
911
+ len (())
912
+
913
+ MUST_INCLUDE_CI = [
914
+ ('instruction' , 'func2' , 1 ),
915
+ ('call' , 'func2' , sys .monitoring .MISSING ),
916
+ ('call' , 'len' , ()),
917
+ ('instruction' , 'func2' , 6 ),
918
+ ('instruction' , 'func2' , 7 )]
919
+
920
+
921
+
922
+ def test_line_then_instruction (self ):
923
+ recorders = [ CallRecorder , InstructionRecorder ]
924
+ self .check_events (self .func2 ,
925
+ recorders = recorders , must_include = self .MUST_INCLUDE_CI )
926
+
927
+ def test_instruction_then_line (self ):
928
+ recorders = [ InstructionRecorder , CallRecorder ]
929
+ self .check_events (self .func2 ,
930
+ recorders = recorders , must_include = self .MUST_INCLUDE_CI )
931
+
770
932
class TestLocalEvents (unittest .TestCase ):
771
933
772
934
def check_events (self , func , expected , tool = TEST_TOOL , recorders = (ExceptionRecorder ,)):
0 commit comments