@@ -1192,6 +1192,80 @@ def __call__(self, code, offset):
11921192class TestLineAndInstructionEvents (CheckEvents ):
11931193 maxDiff = None
11941194
1195+ def test_disable_line_keeps_instruction_events (self ):
1196+ for local in (False , True ):
1197+ # Use the same tool or different tools for LINE and INSTRUCTION.
1198+ for line_tool , instr_tool in (
1199+ (TEST_TOOL , TEST_TOOL ),
1200+ (TEST_TOOL2 , TEST_TOOL ),
1201+ ):
1202+ with self .subTest (local = local , line_tool = line_tool ,
1203+ instr_tool = instr_tool ):
1204+ self .check_disable_line_keeps_instruction_events (
1205+ local , line_tool , instr_tool )
1206+
1207+ def check_disable_line_keeps_instruction_events (self , local , line_tool ,
1208+ instr_tool ):
1209+ def func (x ):
1210+ a = x + 1
1211+ # Split the assignment so line events also move backwards from
1212+ # the expression's line to the assignment's line.
1213+ b = (
1214+ a * 2
1215+ )
1216+ return b
1217+
1218+ code = func .__code__
1219+ instructions = []
1220+ lines = []
1221+ disable = False
1222+
1223+ def instruction (code_arg , offset ):
1224+ if code_arg is code :
1225+ instructions .append (offset )
1226+
1227+ def line (code_arg , lineno ):
1228+ if code_arg is code :
1229+ lines .append (lineno )
1230+ if disable :
1231+ return sys .monitoring .DISABLE
1232+
1233+ sys .monitoring .register_callback (instr_tool , E .INSTRUCTION , instruction )
1234+ sys .monitoring .register_callback (line_tool , E .LINE , line )
1235+ events = {instr_tool : E .INSTRUCTION }
1236+ events [line_tool ] = events .get (line_tool , 0 ) | E .LINE
1237+ try :
1238+ for tool , mask in events .items ():
1239+ if local :
1240+ sys .monitoring .set_local_events (tool , code , mask )
1241+ else :
1242+ sys .monitoring .set_events (tool , mask )
1243+ func (1 )
1244+ expected_instructions = instructions [:]
1245+ expected_lines = lines [:]
1246+ self .assertEqual (expected_instructions , [
1247+ inst .offset for inst in dis .get_instructions (func )
1248+ if inst .opname != "RESUME"
1249+ ])
1250+ self .assertTrue (expected_lines )
1251+ disable = True
1252+ for restart in (False , True ):
1253+ if restart :
1254+ sys .monitoring .restart_events ()
1255+ for call in range (2 ):
1256+ instructions .clear ()
1257+ lines .clear ()
1258+ func (1 )
1259+ self .assertEqual (instructions , expected_instructions )
1260+ self .assertEqual (lines , expected_lines if call == 0 else [])
1261+ finally :
1262+ for tool in events :
1263+ sys .monitoring .set_local_events (tool , code , 0 )
1264+ sys .monitoring .set_events (tool , 0 )
1265+ sys .monitoring .register_callback (instr_tool , E .INSTRUCTION , None )
1266+ sys .monitoring .register_callback (line_tool , E .LINE , None )
1267+ sys .monitoring .restart_events ()
1268+
11951269 def test_simple (self ):
11961270
11971271 def func1 ():
0 commit comments