def test_continue_in_finally_with_exception(tracer, rpc_stub): """Tests POP_FINALLY when tos is an exception.""" tracer.start() # If the finally clause executes a return, break or continue statement, the saved # exception is discarded. for x in range(2): try: raise IndexError finally: continue # BREAK_LOOP (3.7) POP_FINALLY (3.8) tracer.stop() assert tracer.events == [ Binding(target=Symbol("x"), value=0, lineno=52), JumpBackToLoopStart(lineno=56, jump_target=16), Binding(target=Symbol("x"), value=1, lineno=52), JumpBackToLoopStart(lineno=56, jump_target=16), ] assert tracer.loops == [ Loop(start_offset=16, end_offset=36, start_lineno=52) ] assert_GetFrame(rpc_stub, "test_continue_in_finally_with_exception")
def test_continue_in_finally_with_exception(tracer, test_server): """Tests POP_FINALLY when tos is an exception.""" tracer.start() # If the finally clause executes a return, break or continue statement, the saved # exception is discarded. for x in range(2): try: raise IndexError finally: continue # BREAK_LOOP (3.7) POP_FINALLY (3.8) tracer.stop() assert tracer.events == [ Binding(target=Symbol("x"), value="0", lineno=58), JumpBackToLoopStart(lineno=62, jump_target=16), Binding(target=Symbol("x"), value="1", lineno=58), JumpBackToLoopStart(lineno=62, jump_target=16), ] assert tracer.loops == [ Loop( start_offset=16, end_offset=get_value({"py38": 36, "default": 40}), start_lineno=58, ) ] test_server.assert_frame_sent("test_continue_in_finally_with_exception")
def test_continue_in_finally(tracer, test_server): tracer.start() for x in range(2): try: pass finally: continue # 3.8: POP_FINALLY, >= 3.9: POP_EXCEPT, RERAISE tracer.stop() assert tracer.events == [ Binding(target=Symbol("x"), value="0", lineno=22), JumpBackToLoopStart(lineno=26, jump_target=16), Binding(target=Symbol("x"), value="1", lineno=22), JumpBackToLoopStart(lineno=26, jump_target=16), ] assert tracer.loops == [ Loop( start_offset=16, end_offset=get_value({"py38": 32, "default": 24}), start_lineno=22, ) ] test_server.assert_frame_sent("test_continue_in_finally")
def test_while_jump_to_zero(trace): @trace def while_jump_to_zero(count): while count > 0: count -= 1 while_jump_to_zero(2) assert trace.events == [ InitialValue( lineno=103, target=Symbol("count"), value="2", repr="2", ), Binding( lineno=104, target=Symbol("count"), value="1", repr="1", sources={Symbol("count")}, ), JumpBackToLoopStart(lineno=104, jump_target=get_value({ "py37": 2, "default": 0 })), Binding( lineno=104, target=Symbol("count"), value="0", repr="0", sources={Symbol("count")}, ), JumpBackToLoopStart(lineno=104, jump_target=get_value({ "py37": 2, "default": 0 })), Return( lineno=104, value="null", repr="None", sources=set(), ), ]
def test_continue_in_finally(tracer, rpc_stub): tracer.start() for x in range(2): try: pass finally: continue # BREAK_LOOP (3.7) POP_FINALLY (3.8) tracer.stop() assert tracer.events == [ Binding(target=Symbol("x"), value=0, lineno=22), JumpBackToLoopStart(lineno=26, jump_target=16), Binding(target=Symbol("x"), value=1, lineno=22), JumpBackToLoopStart(lineno=26, jump_target=16), ] assert tracer.loops == [ Loop(start_offset=16, end_offset=32, start_lineno=22) ] assert_GetFrame(rpc_stub, "test_continue_in_finally")
def test_for_loop(tracer, rpc_stub): tracer.start() for i in range(2): # SETUP_LOOP (3.7), GET_ITER, FOR_ITER a = i # POP_BLOCK (3.7) for i in range(2): break # BREAK_LOOP (3.7), JUMP_ABSOLUTE (>=3.8) a = 1 for i in range(1): continue # CONTINUE_LOOP (3.7), JUMP_ABSOLUTE (>=3.8) a = 1 for i in range(2): if i == 0: # This jumps directly to FOR_ITER continue for i in range(2): if i == 1: break for i in range(1): break else: a = 1 for i in range(1): # One iteration loop. pass else: a = 1 tracer.stop() from cyberbrain import pprint pprint(tracer.events) expected_events = [ Binding(target=Symbol("i"), value="0", lineno=8), Binding(target=Symbol("a"), value="0", lineno=9, sources={Symbol("i")}), JumpBackToLoopStart(jump_target=get_value({ "py38": 16, "py37": 18 }), lineno=9), Binding(target=Symbol("i"), value="1", lineno=8), Binding(target=Symbol("a"), value="1", lineno=9, sources={Symbol("i")}), JumpBackToLoopStart(jump_target=get_value({ "py38": 16, "py37": 18 }), lineno=9), Binding(target=Symbol("i"), value="0", lineno=11), Binding(target=Symbol("i"), value="0", lineno=15), JumpBackToLoopStart(jump_target=get_value({ "py38": 56, "py37": 64 }), lineno=16), Binding(target=Symbol("i"), value="0", lineno=19), JumpBackToLoopStart(jump_target=get_value({ "py38": 76, "py37": 88 }), lineno=21), Binding(target=Symbol("i"), value="1", lineno=19), JumpBackToLoopStart(jump_target=get_value({ "py38": 76, "py37": 88 }), lineno=20), Binding(target=Symbol("i"), value="0", lineno=23), JumpBackToLoopStart(jump_target=get_value({ "py38": 100, "py37": 116 }), lineno=24), Binding(target=Symbol("i"), value="1", lineno=23), Binding(target=Symbol("i"), value="0", lineno=27), Binding(target=Symbol("i"), value="0", lineno=32), JumpBackToLoopStart(jump_target=get_value({ "py38": 148, "py37": 168 }), lineno=33), Binding(target=Symbol("a"), value="1", lineno=35), ] for index, event in enumerate(tracer.events): assert event == expected_events[ index], f"{event} {expected_events[index]}" print(tracer.loops) assert tracer.loops == [ Loop( start_offset=get_value({ "py38": 16, "py37": 18 }), end_offset=get_value({ "py38": 24, "py37": 26 }), start_lineno=8, ), Loop( start_offset=get_value({ "py38": 56, "py37": 64 }), end_offset=get_value({ "py38": 60, "py37": 68 }), start_lineno=15, ), Loop( start_offset=get_value({ "py38": 76, "py37": 88 }), end_offset=get_value({ "py38": 88, "py37": 100 }), start_lineno=19, ), Loop( start_offset=get_value({ "py38": 100, "py37": 116 }), end_offset=get_value({ "py38": 110, "py37": 126 }), start_lineno=23, ), Loop( start_offset=get_value({ "py38": 148, "py37": 168 }), end_offset=get_value({ "py38": 152, "py37": 172 }), start_lineno=32, ), ] assert_GetFrame(rpc_stub, "test_for_loop")
def test_while_loop(tracer, test_server): tracer.start() i = 0 while i < 2: a = i i += 1 i = 0 while i < 2: break # BREAK_LOOP (3.7), JUMP_ABSOLUTE (>=3.8) i = 0 while i < 1: i += 1 continue # CONTINUE_LOOP (3.7), JUMP_ABSOLUTE (>=3.8) i = 0 while i < 2: i += 1 if i == 1: # This jumps to the end of the iteration, not out of loop. continue i = 0 while i < 2: i += 1 if i == 1: break while True: break else: a = 1 while False: pass else: a = 1 tracer.stop() assert tracer.events == [ Binding(lineno=8, target=Symbol("i"), value="0"), Binding(lineno=10, target=Symbol("a"), value="0", sources={Symbol("i")}), Binding(lineno=11, target=Symbol("i"), value="1", sources={Symbol("i")}), JumpBackToLoopStart(lineno=11, jump_target=get_value({ "default": 12, "py37": 14 })), Binding(lineno=10, target=Symbol("a"), value="1", sources={Symbol("i")}), Binding(lineno=11, target=Symbol("i"), value="2", sources={Symbol("i")}), JumpBackToLoopStart(lineno=11, jump_target=get_value({ "default": 12, "py37": 14 })), ## Binding(lineno=13, target=Symbol("i"), value="0"), Binding(lineno=17, target=Symbol("i"), value="0"), Binding(lineno=19, target=Symbol("i"), value="1", sources={Symbol("i")}), JumpBackToLoopStart(lineno=20, jump_target=get_value({ "default": 54, "py37": 64 })), ## Binding(lineno=22, target=Symbol("i"), value="0"), Binding(lineno=24, target=Symbol("i"), value="1", sources={Symbol("i")}), JumpBackToLoopStart(lineno=26, jump_target=get_value({ "default": 78, "py37": 92 })), Binding(lineno=24, target=Symbol("i"), value="2", sources={Symbol("i")}), JumpBackToLoopStart(lineno=25, jump_target=get_value({ "default": 78, "py37": 92 })), ## Binding(lineno=28, target=Symbol("i"), value="0"), Binding(lineno=30, target=Symbol("i"), value="1", sources={Symbol("i")}), Binding(lineno=42, target=Symbol("a"), value="1"), ] assert tracer.loops == [ Loop( start_offset=get_value({ "default": 12, "py37": 14 }), end_offset=get_value({ "default": 32, "py37": 34 }), start_lineno=9, ), Loop( start_offset=get_value({ "default": 54, "py37": 64 }), end_offset=get_value({ "default": 70, "py37": 80 }), start_lineno=18, ), Loop( start_offset=get_value({ "default": 78, "py37": 92 }), end_offset=get_value({ "default": 102, "py37": 116 }), start_lineno=23, ), ] test_server.assert_frame_sent("test_while_loop")
from cyberbrain import Binding, Symbol, JumpBackToLoopStart def test_walrus_in_while(trace, check_golden_file): @trace def walrus_in_while(): i = 0 while (i := i + 1) < 3: a = i walrus_in_while() # This test is for demonstrating https://git.io/JSX25 if sys.version_info < (3, 10): assert trace.events[3:5] == [ JumpBackToLoopStart(lineno=10, index=3, jump_target=4), Binding( lineno=9, index=4, target=Symbol("i"), value="2", sources={Symbol("i")}, ), ] else: assert trace.events[3:5] == [ Binding( lineno=9, index=3, target=Symbol("i"), value="2",
def test_with(tracer, mocked_responses): class ContextManagerNoReturn: def __enter__(self): pass def __exit__(self, *unused): pass class ContextManagerWithReturn: def __enter__(self): return 2 def __exit__(self, *unused): pass tracer.start() with ContextManagerNoReturn( ): # SETUP_WITH,WITH_CLEANUP_START,WITH_CLEANUP_FINISH a = 1 with ContextManagerWithReturn() as b: pass with ContextManagerWithReturn() as c, ContextManagerNoReturn() as d: pass with ContextManagerWithReturn() as e: with ContextManagerWithReturn() as f: pass with ContextManagerNoReturn(): try: g = 1 raise RuntimeError except RuntimeError: pass for i in range(1): with ContextManagerNoReturn(): continue tracer.stop() expected_events = [ InitialValue( lineno=21, target=Symbol("ContextManagerNoReturn"), value= '{"py/type":"test_with.test_with.<locals>.ContextManagerNoReturn"}', ), Binding(lineno=22, target=Symbol("a"), value="1", sources=set()), InitialValue( lineno=24, target=Symbol("ContextManagerWithReturn"), value= '{"py/type":"test_with.test_with.<locals>.ContextManagerWithReturn"}', ), Binding( lineno=24, target=Symbol("b"), value="2", sources={Symbol("ContextManagerWithReturn")}, ), Binding( lineno=27, target=Symbol("c"), value="2", sources={Symbol("ContextManagerWithReturn")}, ), Binding( lineno=27, target=Symbol("d"), value="null", sources={Symbol("ContextManagerNoReturn")}, ), Binding( lineno=30, target=Symbol("e"), value="2", sources={Symbol("ContextManagerWithReturn")}, ), Binding( lineno=31, target=Symbol("f"), value="2", sources={Symbol("ContextManagerWithReturn")}, ), Binding(lineno=36, target=Symbol("g"), value="1", sources=set()), Binding(lineno=41, target=Symbol("i"), value="0", sources=set()), ] from utils import python_version, get_value if python_version >= "py38": expected_events.append( JumpBackToLoopStart(lineno=43, jump_target=get_value({ "py38": 208, "default": 352 }))) assert tracer.events == expected_events
def test_nested_loop(tracer, test_server): tracer.start() for i in range(2): for j in range(2): a = i + j tracer.stop() assert tracer.events == [ Binding(lineno=8, target=Symbol("i"), value="0"), Binding(lineno=9, target=Symbol("j"), value="0"), Binding(lineno=10, target=Symbol("a"), value="0", sources={Symbol("i"), Symbol("j")}), JumpBackToLoopStart(lineno=10, jump_target=get_value({ "default": 28, "py37": 32 })), Binding(lineno=9, target=Symbol("j"), value="1"), Binding(lineno=10, target=Symbol("a"), value="1", sources={Symbol("i"), Symbol("j")}), JumpBackToLoopStart(lineno=10, jump_target=get_value({ "default": 28, "py37": 32 })), JumpBackToLoopStart(lineno=10, jump_target=get_value({ "default": 16, "py37": 18 })), Binding(lineno=8, target=Symbol("i"), value="1"), Binding(lineno=9, target=Symbol("j"), value="0"), Binding(lineno=10, target=Symbol("a"), value="1", sources={Symbol("i"), Symbol("j")}), JumpBackToLoopStart(lineno=10, jump_target=get_value({ "default": 28, "py37": 32 })), Binding(lineno=9, target=Symbol("j"), value="1"), Binding(lineno=10, target=Symbol("a"), value="2", sources={Symbol("i"), Symbol("j")}), JumpBackToLoopStart(lineno=10, jump_target=get_value({ "default": 28, "py37": 32 })), JumpBackToLoopStart(lineno=10, jump_target=get_value({ "default": 16, "py37": 18 })), ] assert tracer.loops == [ Loop( start_offset=get_value({ "default": 28, "py37": 32 }), end_offset=get_value({ "default": 40, "py37": 44 }), start_lineno=9, ), Loop( start_offset=get_value({ "default": 16, "py37": 18 }), end_offset=get_value({ "default": 42, "py37": 48 }), start_lineno=8, ), ] test_server.assert_frame_sent("test_nested_loop")
def test_generator_function(trace, mocked_responses): @trace def generator_function(count): while count > 0: x = yield count # YIELD_VALUE, POP_TOP, triggers a return event. count -= 1 gen = generator_function(2) for _ in gen: gen.send("foo") # Remember that .send will yield the next value. trace.stop() assert trace.events == [ InitialValue( lineno=8, target=Symbol("count"), value="2", repr="2", ), Binding( lineno=9, target=Symbol("x"), value='"foo"', repr='"foo"', sources=set(), ), Binding( lineno=10, target=Symbol("count"), value="1", repr="1", sources={Symbol("count")}, ), JumpBackToLoopStart(lineno=10, jump_target=get_value({ "py37": 2, "default": 0 })), Binding( lineno=9, target=Symbol("x"), value="null", repr="None", sources=set(), ), Binding( lineno=10, target=Symbol("count"), value="0", repr="0", sources={Symbol("count")}, ), JumpBackToLoopStart(lineno=10, jump_target=get_value({ "py37": 2, "default": 0 })), Return( lineno=10, value="null", repr="None", sources=set(), ), ]