def test_unary_operations(tracer, rpc_stub): a = 1 tracer.start() b = +a # UNARY_POSITIVE b = -a # UNARY_NEGATIVE b = not a # UNARY_NOT b = ~a # UNARY_INVERT tracer.stop() assert tracer.events == [ InitialValue(target=Symbol("a"), value=1, lineno=10), Binding(target=Symbol("b"), value=1, sources={Symbol("a")}, lineno=10), Binding(target=Symbol("b"), value=-1, sources={Symbol("a")}, lineno=11), Binding(target=Symbol("b"), value=False, sources={Symbol("a")}, lineno=12), Binding(target=Symbol("b"), value=-2, sources={Symbol("a")}, lineno=13), ] assert_GetFrame(rpc_stub, "test_unary_operations")
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_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_closure(tracer, mocked_responses): tracer.start() a = 1 # LOAD_CLASSDEREF class Foo: print(a) # LOAD_CLOSURE class Bar( Foo ): # LOAD_CLOSURE. If we remove super(Bar, self) it becomes LOAD_CONST def __init__(self): super(Bar, self).__init__() tracer.stop() assert tracer.events == [ Binding(lineno=28, target=Symbol("a"), value="1"), Binding( lineno=30, target=Symbol("Foo"), value='{"py/type":"test_cellvar.test_closure.<locals>.Foo"}', sources={Symbol("a")}, ), Binding( lineno=33, target=Symbol("Bar"), value='{"py/type":"test_cellvar.test_closure.<locals>.Bar"}', repr="<class 'test_cellvar.test_closure.<locals>.Bar'>", sources={Symbol("Foo")}, ), ]
def test_miscellaneous(tracer, test_server): a = "a" b = "b" c = "c" d = "d" e = [1, 2, 3] tracer.start() x = f"{a} {b:4} {c!r} {d!r:4}" # FORMAT_VALUE, BUILD_STRING x = a == b == c # ROT_THREE, _COMPARE_OP e[0] += e.pop() # DUP_TOP_TWO del e # DELETE_FAST global g x = g g = 1 # STORE_GLOBAL del g # DELETE_GLOBAL tracer.stop() assert tracer.events == [ InitialValue(target=Symbol("a"), value='"a"', lineno=15), InitialValue(target=Symbol("b"), value='"b"', lineno=15), InitialValue(target=Symbol("c"), value='"c"', lineno=15), InitialValue(target=Symbol("d"), value='"d"', lineno=15), Binding( target=Symbol("x"), value="\"a b 'c' 'd' \"", sources={Symbol("a"), Symbol("b"), Symbol("d"), Symbol("c")}, lineno=15, ), Binding( target=Symbol("x"), value="false", sources={Symbol("a"), Symbol("b")}, lineno=16, ), InitialValue(target=Symbol("e"), value="[1, 2, 3]", lineno=17), Mutation(target=Symbol("e"), value="[1, 2]", sources={Symbol("e")}, lineno=17), Mutation(target=Symbol("e"), value="[4, 2]", sources={Symbol("e")}, lineno=17), Deletion(target=Symbol("e"), lineno=18), InitialValue(target=Symbol("g"), value="0", lineno=20), Binding(target=Symbol("x"), value="0", sources={Symbol("g")}, lineno=20), Binding(target=Symbol("g"), value="1", lineno=21), Deletion(target=Symbol("g"), lineno=22), ] test_server.assert_frame_sent("test_miscellaneous")
def test_unary_operations(tracer, mocked_responses): a = 1 tracer.start() b = +a # UNARY_POSITIVE b = -a # UNARY_NEGATIVE b = not a # UNARY_NOT b = ~a # UNARY_INVERT tracer.stop() assert tracer.events == [ InitialValue(target=Symbol("a"), value="1", lineno=-1), Binding(target=Symbol("b"), value="1", sources={Symbol("a")}, lineno=9), Binding(target=Symbol("b"), value="-1", sources={Symbol("a")}, lineno=10), Binding(target=Symbol("b"), value="false", sources={Symbol("a")}, lineno=11), Binding(target=Symbol("b"), value="-2", sources={Symbol("a")}, lineno=12), ]
def test_hello(tracer, rpc_stub): tracer.start() x = "hello world" # LOAD_CONST, STORE_FAST y = x # LOAD_FAST, STORE_FAST x, y = y, x # ROT_TWO, STORE_FAST tracer.stop() assert tracer.events == [ Binding(target=Symbol("x"), value="hello world", lineno=6), Binding(target=Symbol("y"), value="hello world", sources={Symbol("x")}, lineno=7), Binding(target=Symbol("x"), value="hello world", sources={Symbol("y")}, lineno=8), Binding(target=Symbol("y"), value="hello world", sources={Symbol("x")}, lineno=8), ] from utils import assert_GetFrame assert_GetFrame(rpc_stub, "test_hello")
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_list_comprehension(tracer, test_server): tracer.start() n = 2 x = [i for i in range(n)] # MAKE_FUNCTION, GET_ITER, CALL_FUNCTION lst = ["foo", "bar"] x = [e for e in lst] tracer.stop() assert tracer.events == [ Binding(target=Symbol("n"), value="2", lineno=7), Binding(target=Symbol("x"), value="[0, 1]", lineno=8, sources={Symbol("n")}), Binding(target=Symbol("lst"), value='["foo", "bar"]', lineno=9), Binding( target=Symbol("x"), value='["foo", "bar"]', lineno=10, sources={Symbol("lst")}, ), ] test_server.assert_frame_sent("test_list_comprehension")
def test_miscellaneous(tracer, rpc_stub): a = "a" b = "b" c = "c" d = "d" e = [1, 2, 3] tracer.start() x = f"{a} {b:4} {c!r} {d!r:4}" # FORMAT_VALUE, BUILD_STRING x = a == b == c # ROT_THREE, _COMPARE_OP e[0] += e.pop() # DUP_TOP_TWO del e # DELETE_FAST global g x = g g = 1 # STORE_GLOBAL del g # DELETE_GLOBAL tracer.stop() assert tracer.events == [ InitialValue(target=Symbol("a"), value="a", lineno=16), InitialValue(target=Symbol("b"), value="b", lineno=16), InitialValue(target=Symbol("c"), value="c", lineno=16), InitialValue(target=Symbol("d"), value="d", lineno=16), Binding( target=Symbol("x"), value="a b 'c' 'd' ", sources={Symbol("a"), Symbol("b"), Symbol("d"), Symbol("c")}, lineno=16, ), Binding( target=Symbol("x"), value=False, sources={Symbol("a"), Symbol("b")}, lineno=17, ), InitialValue(target=Symbol("e"), value=[1, 2, 3], lineno=18), Mutation(target=Symbol("e"), value=[1, 2], sources={Symbol("e")}, lineno=18), Mutation(target=Symbol("e"), value=[4, 2], sources={Symbol("e")}, lineno=18), Deletion(target=Symbol("e"), lineno=19), InitialValue(target=Symbol("g"), value=0, lineno=21), Binding(target=Symbol("x"), value=0, sources={Symbol("g")}, lineno=21), Binding(target=Symbol("g"), value=1, lineno=22), Deletion(target=Symbol("g"), lineno=23), ] assert_GetFrame(rpc_stub, "test_miscellaneous")
def test_mutation(tracer): text = "AAAA" tracer.start() lower_text = text.lower( ) # Test this line does not emit a mutation of `text`. tracer.stop() assert tracer.events == [ InitialValue( lineno=-1, target=Symbol("text"), value='"AAAA"', repr='"AAAA"', ), Binding( lineno=9, target=Symbol("lower_text"), value='"aaaa"', repr='"aaaa"', sources={Symbol("text")}, ), ]
def test_trace_decorated_function(trace): def my_decorator(f): def inner(*args): a = 1 f(*args) b = a return inner @my_decorator @trace def original_func(): a = [1, 2, 3] original_func() assert trace.events == [ Binding( lineno=16, target=Symbol("a"), value="[1,2,3]", repr="[1, 2, 3]", sources=set(), ), Return( lineno=16, value="null", repr="None", sources=set(), ), ]
def test_decorator_multiple_times(trace, rpc_stub): @trace def func(b): a = b return a func(1) # Test that server wait does not block user code execution. trace._wait_for_termination() assert func(2) == 2 from cyberbrain import pprint pprint(trace.events) assert trace.events == [ InitialValue( lineno=21, target=Symbol("b"), value="1", ), Binding(lineno=21, target=Symbol("a"), value="1", sources={Symbol("b")}), Return(lineno=22, value="1", sources={Symbol("a")}), ] trace.server.stop()
def test_numpy(tracer, test_server): tracer.start() x = np.array([6, 7, 8]) tracer.stop() from utils import get_os_type, get_value int_type = get_value({ "windows": "int32", "linux": "int64", "mac": "int64" }) assert tracer.events == [ Binding( lineno=8, target=Symbol("x"), value=f'{{"dtype":"{int_type}","values":[6,7,8]}}', repr="array([6,7,8])", sources=set(), ) ] if get_os_type() != "windows": test_server.assert_frame_sent("test_numpy")
def test_pandas(tracer, mocked_responses): tracer.start() baby_data_set = [ ("Bob", 968), ("Jessica", 155), ("Mary", 77), ("John", 578), ("Mel", 973), ] df = pd.DataFrame(data=baby_data_set, columns=["Names", "Births"]) tracer.stop() from utils import get_value eol = get_value({"windows": r"\r\n", "linux": r"\n", "mac": "\\n"}) assert tracer.events == [ Binding( lineno=get_value({"py37": 13, "default": 8}), target=Symbol("baby_data_set"), value='[["Bob",968],["Jessica",155],["Mary",77],["John",578],["Mel",973]]', repr=( "[('Bob', 968), ('Jessica', 155), " "('Mary', 77), ('John', 578), ('Mel', 973)]" ), sources=set(), ), Binding( lineno=15, target=Symbol("df"), value=( f'{{"values":"Names,Births{eol}Bob,968{eol}Jessica,155{eol}' f'Mary,77{eol}John,578{eol}Mel,973{eol}"' ',"txt":true,"meta":{"dtypes":{"Names":"object","Births":"int64"},' '"index":"{\\"py/object\\":\\"pandas.core.indexes.range.RangeIndex\\"' ',\\"values\\":\\"[0,1,2,3,4]\\",\\"txt\\":true,\\"meta\\":{\\"dtype\\"' ':\\"int64\\",\\"name\\":null}}",' '"column_level_names":[null],"header":[0]}}' ), repr=( " Names Births\n0 Bob 968\n1 Jessica 155\n2" " Mary 77\n3 John 578\n4 Mel 973" ), sources={Symbol("baby_data_set")}, ), ]
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_api_tracer(tracer, mocked_responses): tracer.start() a = 1 tracer.stop() assert tracer.events == [ Binding(lineno=6, target=Symbol("a"), value="1", sources=set()) ]
def test_jump(tracer, rpc_stub): a = [] b = "b" c = "c" tracer.start() if a: # POP_JUMP_IF_FALSE pass # JUMP_FORWARD else: x = 1 if not a: # POP_JUMP_IF_TRUE x = 2 x = a != b != c # JUMP_IF_FALSE_OR_POP x = a == b or c # JUMP_IF_TRUE_OR_POP # TODO: Test JUMP_ABSOLUTE. This requires loop instructions to be Implemented. tracer.stop() assert tracer.events == [ InitialValue(target=Symbol("a"), value=[], lineno=12), Binding(target=Symbol("x"), value=1, lineno=15), Binding(target=Symbol("x"), value=2, lineno=18), InitialValue(target=Symbol("b"), value="b", lineno=20), InitialValue(target=Symbol("c"), value="c", lineno=20), # This is a known defect. We have no way to know `x` comes from `a`, because # the result of `a != b` only determines whether to jump to execute `b != c` # I think it's fine though. Binding( target=Symbol("x"), value=True, sources={Symbol("b"), Symbol("c")}, lineno=20, ), # Same defect here. Binding(target=Symbol("x"), value="c", sources={Symbol("c")}, lineno=21), ] assert_GetFrame(rpc_stub, "test_jump")
def test_jump(tracer, mocked_responses): a = [] b = "b" c = "c" tracer.start() if a: # POP_JUMP_IF_FALSE pass # JUMP_FORWARD else: x = 1 if not a: # POP_JUMP_IF_TRUE x = 2 x = a != b != c # JUMP_IF_FALSE_OR_POP x = a == b or c # JUMP_IF_TRUE_OR_POP # TODO: Test JUMP_ABSOLUTE. This requires loop instructions to be Implemented. tracer.stop() assert tracer.events == [ InitialValue(target=Symbol("a"), value="[]", lineno=-1), Binding(target=Symbol("x"), value="1", lineno=14), Binding(target=Symbol("x"), value="2", lineno=17), InitialValue(target=Symbol("b"), value='"b"', lineno=-1), InitialValue(target=Symbol("c"), value='"c"', lineno=-1), # This is a known defect. We have no way to know `x` comes from `a`, because # the result of `a != b` only determines whether to jump to execute `b != c` # I think it's fine though. Binding( target=Symbol("x"), value="true", sources={Symbol("b"), Symbol("c")}, lineno=19, ), # Same defect here. Binding(target=Symbol("x"), value='"c"', sources={Symbol("c")}, lineno=20), ]
def test_closure(tracer, rpc_stub): tracer.start() a = 1 # LOAD_CLASSDEREF class Foo: print(a) # LOAD_CLOSURE tracer.stop() assert tracer.events == [ Binding(lineno=31, target=Symbol("a"), value=1), Binding(lineno=33, target=Symbol("Foo"), value=Foo, sources={Symbol("a")}), ] assert_GetFrame(rpc_stub, "test_closure")
def test_api_tracer(tracer, test_server): tracer.start() a = 1 tracer.stop() assert tracer.events == [ Binding(lineno=6, target=Symbol("a"), value="1", sources=set()) ] test_server.assert_frame_sent("test_api_tracer")
def test_call_tracer_multiple_times(tracer): tracer.start() a = 1 tracer.stop() tracer.start() # This should have no effect a = 2 tracer.stop() # This should have no effect assert tracer.events == [ Binding(lineno=6, target=Symbol("a"), value="1", sources=set()) ]
def test_closure(tracer, test_server): tracer.start() a = 1 # LOAD_CLASSDEREF class Foo: print(a) # LOAD_CLOSURE tracer.stop() assert tracer.events == [ Binding(lineno=30, target=Symbol("a"), value="1"), Binding( lineno=32, target=Symbol("Foo"), value='{"py/type": "test_cellvar.test_closure.<locals>.Foo"}', sources={Symbol("a")}, ), ] test_server.assert_frame_sent("test_closure")
def test_api_tracer(tracer, rpc_stub): tracer.start() a = 1 tracer.stop() assert tracer.events == [ Binding(lineno=6, target=Symbol("a"), value="1", sources=set()) ] from utils import assert_GetFrame assert_GetFrame(rpc_stub, "test_api_tracer")
def test_break_in_finally(tracer, mocked_responses): tracer.start() for _ in range(2): try: pass finally: break # BREAK_LOOP (3.7) POP_FINALLY (3.8) tracer.stop() assert tracer.events == [Binding(target=Symbol("x"), value="0", lineno=56)]
def test_existing_variable_emit_initial_value(tracer, test_server): x = "foo" tracer.start() y = x tracer.stop() assert tracer.events == [ InitialValue(target=Symbol("x"), value='"foo"', lineno=7), Binding(target=Symbol("y"), value='"foo"', sources={Symbol("x")}, lineno=7), ] test_server.assert_frame_sent("test_existing_variable_emit_initial_value")
def test_closure(tracer, rpc_stub): tracer.start() a = 1 # LOAD_CLASSDEREF class Foo: print(a) # LOAD_CLOSURE tracer.stop() assert tracer.events == [ Binding(lineno=31, target=Symbol("a"), value="1"), Binding( lineno=33, target=Symbol("Foo"), value='{"py/type": "test_cellvar.test_closure.<locals>.Foo"}', sources={Symbol("a")}, ), ] assert_GetFrame(rpc_stub, "test_closure")
def test_ref_outside(trace, mocked_responses): @trace def test_ref_outside_inner(): a = f() test_ref_outside_inner() assert trace.events == [ InitialValue(lineno=-1, target=Symbol("f"), value='{"repr": "<function f>"}'), Binding(lineno=11, target=Symbol("a"), value="1", sources={Symbol("f")}), Return(lineno=11, value="null", 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_existing_variable_emit_initial_value(tracer, mocked_responses): x = "foo" tracer.start() y = x tracer.stop() assert tracer.events == [ InitialValue(target=Symbol("x"), value='"foo"', lineno=7), Binding(target=Symbol("y"), value='"foo"', sources={Symbol("x")}, lineno=7), ]