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