def test_get_jump_target(self): jump_abs = ConcreteInstr("JUMP_ABSOLUTE", 3) self.assertEqual(jump_abs.get_jump_target(100), 3) jump_forward = ConcreteInstr("JUMP_FORWARD", 5) self.assertEqual(jump_forward.get_jump_target(10), 17 if WORDCODE else 18)
def test_label2(self): bytecode = Bytecode() label = Label() bytecode.extend([ Instr("LOAD_NAME", "test", lineno=1), Instr("POP_JUMP_IF_FALSE", label), Instr("LOAD_CONST", 5, lineno=2), Instr("STORE_NAME", "x"), Instr("JUMP_FORWARD", label), Instr("LOAD_CONST", 7, lineno=4), Instr("STORE_NAME", "x"), label, Instr("LOAD_CONST", None), Instr("RETURN_VALUE"), ]) concrete = bytecode.to_concrete_bytecode() expected = [ ConcreteInstr("LOAD_NAME", 0, lineno=1), ConcreteInstr("POP_JUMP_IF_FALSE", 14 if WORDCODE else 21, lineno=1), ConcreteInstr("LOAD_CONST", 0, lineno=2), ConcreteInstr("STORE_NAME", 1, lineno=2), ConcreteInstr("JUMP_FORWARD", 4 if WORDCODE else 6, lineno=2), ConcreteInstr("LOAD_CONST", 1, lineno=4), ConcreteInstr("STORE_NAME", 1, lineno=4), ConcreteInstr("LOAD_CONST", 2, lineno=4), ConcreteInstr("RETURN_VALUE", lineno=4), ] self.assertListEqual(list(concrete), expected) self.assertListEqual(concrete.consts, [5, 7, None]) self.assertListEqual(concrete.names, ["test", "x"]) self.assertListEqual(concrete.varnames, [])
def test_label2(self): bytecode = Bytecode() label = Label() bytecode.extend([ Instr('LOAD_NAME', 'test', lineno=1), Instr('POP_JUMP_IF_FALSE', label), Instr('LOAD_CONST', 5, lineno=2), Instr('STORE_NAME', 'x'), Instr('JUMP_FORWARD', label), Instr('LOAD_CONST', 7, lineno=4), Instr('STORE_NAME', 'x'), label, Instr('LOAD_CONST', None), Instr('RETURN_VALUE') ]) concrete = bytecode.to_concrete_bytecode() expected = [ ConcreteInstr('LOAD_NAME', 0, lineno=1), ConcreteInstr('POP_JUMP_IF_FALSE', 14 if WORDCODE else 21, lineno=1), ConcreteInstr('LOAD_CONST', 0, lineno=2), ConcreteInstr('STORE_NAME', 1, lineno=2), ConcreteInstr('JUMP_FORWARD', 4 if WORDCODE else 6, lineno=2), ConcreteInstr('LOAD_CONST', 1, lineno=4), ConcreteInstr('STORE_NAME', 1, lineno=4), ConcreteInstr('LOAD_CONST', 2, lineno=4), ConcreteInstr('RETURN_VALUE', lineno=4) ] self.assertListEqual(list(concrete), expected) self.assertListEqual(concrete.consts, [5, 7, None]) self.assertListEqual(concrete.names, ['test', 'x']) self.assertListEqual(concrete.varnames, [])
def test_constructor(self): with self.assertRaises(ValueError): # need an argument ConcreteInstr("LOAD_CONST") with self.assertRaises(ValueError): # must not have an argument ConcreteInstr("ROT_TWO", 33) # invalid argument with self.assertRaises(TypeError): ConcreteInstr("LOAD_CONST", 1.0) with self.assertRaises(ValueError): ConcreteInstr("LOAD_CONST", -1) with self.assertRaises(TypeError): ConcreteInstr("LOAD_CONST", 5, lineno=1.0) with self.assertRaises(ValueError): ConcreteInstr("LOAD_CONST", 5, lineno=-1) # test maximum argument with self.assertRaises(ValueError): ConcreteInstr("LOAD_CONST", 2147483647 + 1) instr = ConcreteInstr("LOAD_CONST", 2147483647) self.assertEqual(instr.arg, 2147483647) # test meaningless extended args instr = ConcreteInstr('LOAD_FAST', 8, lineno=3, extended_args=1) self.assertEqual(instr.name, 'LOAD_FAST') self.assertEqual(instr.arg, 8) self.assertEqual(instr.lineno, 3) self.assertEqual(instr.size, 4)
def test_flag_inference(self): # Check no loss of non-infered flags code = ControlFlowGraph() code.flags |= (CompilerFlags.NEWLOCALS | CompilerFlags.VARARGS | CompilerFlags.VARKEYWORDS | CompilerFlags.NESTED | CompilerFlags.FUTURE_GENERATOR_STOP) code.update_flags() for f in (CompilerFlags.NEWLOCALS, CompilerFlags.VARARGS, CompilerFlags.VARKEYWORDS, CompilerFlags.NESTED, CompilerFlags.NOFREE, CompilerFlags.OPTIMIZED, CompilerFlags.FUTURE_GENERATOR_STOP): self.assertTrue(bool(code.flags & f)) # Infer optimized and nofree code = Bytecode() flags = infer_flags(code) self.assertTrue(bool(flags & CompilerFlags.OPTIMIZED)) self.assertTrue(bool(flags & CompilerFlags.NOFREE)) code.append(ConcreteInstr('STORE_NAME', 1)) flags = infer_flags(code) self.assertFalse(bool(flags & CompilerFlags.OPTIMIZED)) self.assertTrue(bool(flags & CompilerFlags.NOFREE)) code.append(ConcreteInstr('STORE_DEREF', 2)) code.update_flags() self.assertFalse(bool(code.flags & CompilerFlags.OPTIMIZED)) self.assertFalse(bool(code.flags & CompilerFlags.NOFREE)) # Infer generator code = ConcreteBytecode() code.append(ConcreteInstr('YIELD_VALUE')) for is_async, expected in ((False, CompilerFlags.GENERATOR), (True, CompilerFlags.ASYNC_GENERATOR)): self.assertTrue(bool(infer_flags(code, is_async) & expected)) # Infer coroutine code = ConcreteBytecode() code.append(ConcreteInstr('GET_AWAITABLE')) iter_flags = CompilerFlags(CompilerFlags.ITERABLE_COROUTINE) for f, expected in ((CompilerFlags(0), True), (iter_flags, False)): code.flags = f self.assertEqual(bool(infer_flags(code) & CompilerFlags.COROUTINE), expected) # Test check flag sanity code.append(ConcreteInstr('YIELD_VALUE')) code.flags = CompilerFlags(CompilerFlags.GENERATOR | CompilerFlags.COROUTINE) infer_flags(code, is_async=True) # Just want to be sure it pases with self.assertRaises(ValueError): code.update_flags() with self.assertRaises(ValueError): infer_flags(None)
def test_cellvars(self): code = Bytecode() code.cellvars = ['x'] code.freevars = ['y'] code.extend([Instr('LOAD_DEREF', CellVar('x'), lineno=1), Instr('LOAD_DEREF', FreeVar('y'), lineno=1)]) concrete = code.to_concrete_bytecode() self.assertEqual(concrete.cellvars, ['x']) self.assertEqual(concrete.freevars, ['y']) code.extend([ConcreteInstr("LOAD_DEREF", 0, lineno=1), ConcreteInstr("LOAD_DEREF", 1, lineno=1)])
def test_disassemble(self): instr = ConcreteInstr.disassemble(1, b'\td\x03\x00', 0) self.assertEqual(instr, ConcreteInstr("NOP", lineno=1)) instr = ConcreteInstr.disassemble(2, b'\td\x03\x00', 1) self.assertEqual(instr, ConcreteInstr("LOAD_CONST", 3, lineno=2)) code = b'\x904\x12d\xcd\xab' instr = ConcreteInstr.disassemble(3, code, 0) self.assertEqual(instr, ConcreteInstr('EXTENDED_ARG', 0x1234, lineno=3))
def test_attr(self): code_obj = get_code("x = 5") code = ConcreteBytecode.from_code(code_obj) self.assertEqual(code.consts, [5, None]) self.assertEqual(code.names, ['x']) self.assertEqual(code.varnames, []) self.assertEqual(code.freevars, []) self.assertListEqual(list(code), [ConcreteInstr('LOAD_CONST', 0, lineno=1), ConcreteInstr('STORE_NAME', 0, lineno=1), ConcreteInstr('LOAD_CONST', 1, lineno=1), ConcreteInstr('RETURN_VALUE', lineno=1)])
def test_assemble(self): instr = ConcreteInstr("NOP") self.assertEqual(instr.assemble(), b'\t') instr = ConcreteInstr("LOAD_CONST", 3) self.assertEqual(instr.assemble(), b'd\x03\x00') instr = ConcreteInstr("LOAD_CONST", 0x1234abcd) self.assertEqual(instr.assemble(), b'\x904\x12d\xcd\xab')
def test_to_code_lnotab(self): # We use an actual function for the simple case to # ensure we get lnotab right def f(): # # x = 7 # noqa y = 8 # noqa z = 9 # noqa fl = f.__code__.co_firstlineno concrete = ConcreteBytecode() concrete.consts = [None, 7, 8, 9] concrete.varnames = ["x", "y", "z"] concrete.first_lineno = fl concrete.extend([ SetLineno(fl + 3), ConcreteInstr("LOAD_CONST", 1), ConcreteInstr("STORE_FAST", 0), SetLineno(fl + 4), ConcreteInstr("LOAD_CONST", 2), ConcreteInstr("STORE_FAST", 1), SetLineno(fl + 5), ConcreteInstr("LOAD_CONST", 3), ConcreteInstr("STORE_FAST", 2), ConcreteInstr("LOAD_CONST", 0), ConcreteInstr("RETURN_VALUE"), ]) code = concrete.to_code() self.assertEqual(code.co_code, f.__code__.co_code) self.assertEqual(code.co_lnotab, f.__code__.co_lnotab) if sys.version_info >= (3, 10): self.assertEqual(code.co_linetable, f.__code__.co_linetable)
def test_freevar(self): concrete = ConcreteBytecode() concrete.freevars = ["x"] concrete.append(ConcreteInstr("LOAD_DEREF", 0)) code = concrete.to_code() concrete = ConcreteBytecode.from_code(code) self.assertEqual(concrete.cellvars, []) self.assertEqual(concrete.freevars, ["x"]) self.assertEqual(list(concrete), [ConcreteInstr("LOAD_DEREF", 0, lineno=1)]) bytecode = concrete.to_bytecode() self.assertEqual(bytecode.cellvars, []) self.assertEqual(list(bytecode), [Instr("LOAD_DEREF", FreeVar("x"), lineno=1)])
def test_label(self): code = Bytecode() label = Label() code.extend([Instr('LOAD_CONST', 'hello', lineno=1), Instr('JUMP_FORWARD', label, lineno=1), label, Instr('POP_TOP', lineno=1)]) code = code.to_concrete_bytecode() expected = [ConcreteInstr('LOAD_CONST', 0, lineno=1), ConcreteInstr('JUMP_FORWARD', 0, lineno=1), ConcreteInstr('POP_TOP', lineno=1)] self.assertListEqual(list(code), expected) self.assertListEqual(code.consts, ['hello'])
def test_dont_merge_constants(self): # test two constants which are equal but have a different type code = Bytecode() code.extend([Instr('LOAD_CONST', 5, lineno=1), Instr('LOAD_CONST', 5.0, lineno=1), Instr('LOAD_CONST', -0.0, lineno=1), Instr('LOAD_CONST', +0.0, lineno=1)]) code = code.to_concrete_bytecode() expected = [ConcreteInstr('LOAD_CONST', 0, lineno=1), ConcreteInstr('LOAD_CONST', 1, lineno=1), ConcreteInstr('LOAD_CONST', 2, lineno=1), ConcreteInstr('LOAD_CONST', 3, lineno=1)] self.assertListEqual(list(code), expected) self.assertListEqual(code.consts, [5, 5.0, -0.0, +0.0])
def test_disassemble(self): code = b'\t\x00d\x03' if WORDCODE else b'\td\x03\x00' instr = ConcreteInstr.disassemble(1, code, 0) self.assertEqual(instr, ConcreteInstr("NOP", lineno=1)) instr = ConcreteInstr.disassemble(2, code, 2 if WORDCODE else 1) self.assertEqual(instr, ConcreteInstr("LOAD_CONST", 3, lineno=2)) code = (b'\x90\x12\x904\x90\xabd\xcd' if WORDCODE else b'\x904\x12d\xcd\xab') instr = ConcreteInstr.disassemble(3, code, 0) self.assertEqual(instr, ConcreteInstr('EXTENDED_ARG', 0x12 if WORDCODE else 0x1234, lineno=3))
def test_cellvars(self): code = Bytecode() code.cellvars = ["x"] code.freevars = ["y"] code.extend([ Instr("LOAD_DEREF", CellVar("x"), lineno=1), Instr("LOAD_DEREF", FreeVar("y"), lineno=1), ]) concrete = code.to_concrete_bytecode() self.assertEqual(concrete.cellvars, ["x"]) self.assertEqual(concrete.freevars, ["y"]) code.extend([ ConcreteInstr("LOAD_DEREF", 0, lineno=1), ConcreteInstr("LOAD_DEREF", 1, lineno=1), ])
def test_cellvar(self): concrete = ConcreteBytecode() concrete.cellvars = ['x'] concrete.append(ConcreteInstr('LOAD_DEREF', 0)) code = concrete.to_code() concrete = ConcreteBytecode.from_code(code) self.assertEqual(concrete.cellvars, ['x']) self.assertEqual(concrete.freevars, []) self.assertEqual(list(concrete), [ConcreteInstr('LOAD_DEREF', 0, lineno=1)]) bytecode = concrete.to_bytecode() self.assertEqual(bytecode.cellvars, ['x']) self.assertEqual(list(bytecode), [Instr('LOAD_DEREF', CellVar('x'), lineno=1)])
def test_eq(self): code = ConcreteBytecode() self.assertFalse(code == 1) for name, val in ( ("names", ["a"]), ("varnames", ["a"]), ("consts", [1]), ("argcount", 1), ("kwonlyargcount", 2), ("flags", CompilerFlags(CompilerFlags.GENERATOR)), ("first_lineno", 10), ("filename", "xxxx.py"), ("name", "__x"), ("docstring", "x-x-x"), ("cellvars", [CellVar("x")]), ("freevars", [FreeVar("x")]), ): c = ConcreteBytecode() setattr(c, name, val) # For obscure reasons using assertNotEqual here fail self.assertFalse(code == c) if sys.version_info > (3, 8): c = ConcreteBytecode() c.posonlyargcount = 10 self.assertFalse(code == c) c = ConcreteBytecode() c.consts = [1] code.consts = [1] c.append(ConcreteInstr("LOAD_CONST", 0)) self.assertFalse(code == c)
def test_attr(self): code_obj = get_code("x = 5") code = ConcreteBytecode.from_code(code_obj) self.assertEqual(code.consts, [5, None]) self.assertEqual(code.names, ["x"]) self.assertEqual(code.varnames, []) self.assertEqual(code.freevars, []) self.assertListEqual( list(code), [ ConcreteInstr("LOAD_CONST", 0, lineno=1), ConcreteInstr("STORE_NAME", 0, lineno=1), ConcreteInstr("LOAD_CONST", 1, lineno=1), ConcreteInstr("RETURN_VALUE", lineno=1), ], )
def test_async_gen_no_flag_is_async_False(self): # Test inference when we request a non-async function # Infer generator code = ConcreteBytecode() code.append(ConcreteInstr("YIELD_VALUE")) code.flags = CompilerFlags(CompilerFlags.COROUTINE) code.update_flags(is_async=False) self.assertTrue(bool(code.flags & CompilerFlags.GENERATOR)) # Abort on coroutine code = ConcreteBytecode() code.append(ConcreteInstr("GET_AWAITABLE")) code.flags = CompilerFlags(CompilerFlags.COROUTINE) with self.assertRaises(ValueError): code.update_flags(is_async=False)
def test_attr(self): instr = ConcreteInstr("LOAD_CONST", 5, lineno=12) self.assertEqual(instr.name, "LOAD_CONST") self.assertEqual(instr.opcode, 100) self.assertEqual(instr.arg, 5) self.assertEqual(instr.lineno, 12) self.assertEqual(instr.size, 2)
def test_extended_arg(self): # Create a code object from arbitrary bytecode co_code = (b'\x90\x12\x904\x90\xabd\xcd' if WORDCODE else b'\x904\x12d\xcd\xab') code = get_code('x=1') code = types.CodeType(code.co_argcount, code.co_kwonlyargcount, code.co_nlocals, code.co_stacksize, code.co_flags, co_code, code.co_consts, code.co_names, code.co_varnames, code.co_filename, code.co_name, code.co_firstlineno, code.co_lnotab, code.co_freevars, code.co_cellvars) # without EXTENDED_ARG opcode bytecode = ConcreteBytecode.from_code(code) self.assertListEqual( list(bytecode), [ConcreteInstr("LOAD_CONST", 0x1234abcd, lineno=1)]) # with EXTENDED_ARG opcode bytecode = ConcreteBytecode.from_code(code, extended_arg=True) if WORDCODE: expected = [ ConcreteInstr('EXTENDED_ARG', 0x12, lineno=1), ConcreteInstr('EXTENDED_ARG', 0x34, lineno=1), ConcreteInstr('EXTENDED_ARG', 0xab, lineno=1), ConcreteInstr('LOAD_CONST', 0xcd, lineno=1) ] else: expected = [ ConcreteInstr('EXTENDED_ARG', 0x1234, lineno=1), ConcreteInstr('LOAD_CONST', 0xabcd, lineno=1) ] self.assertListEqual(list(bytecode), expected)
def test_set(self): instr = ConcreteInstr('LOAD_CONST', 5, lineno=3) instr.set('NOP') self.assertEqual(instr.name, 'NOP') self.assertIs(instr.arg, UNSET) self.assertEqual(instr.lineno, 3) instr.set('LOAD_FAST', 8) self.assertEqual(instr.name, 'LOAD_FAST') self.assertEqual(instr.arg, 8) self.assertEqual(instr.lineno, 3) # invalid with self.assertRaises(ValueError): instr.set('LOAD_CONST') with self.assertRaises(ValueError): instr.set('NOP', 5)
def test_label(self): code = Bytecode() label = Label() code.extend([ Instr("LOAD_CONST", "hello", lineno=1), Instr("JUMP_FORWARD", label, lineno=1), label, Instr("POP_TOP", lineno=1), ]) code = code.to_concrete_bytecode() expected = [ ConcreteInstr("LOAD_CONST", 0, lineno=1), ConcreteInstr("JUMP_FORWARD", 0, lineno=1), ConcreteInstr("POP_TOP", lineno=1), ] self.assertListEqual(list(code), expected) self.assertListEqual(code.consts, ["hello"])
def test_set(self): instr = ConcreteInstr("LOAD_CONST", 5, lineno=3) instr.set("NOP") self.assertEqual(instr.name, "NOP") self.assertIs(instr.arg, UNSET) self.assertEqual(instr.lineno, 3) instr.set("LOAD_FAST", 8) self.assertEqual(instr.name, "LOAD_FAST") self.assertEqual(instr.arg, 8) self.assertEqual(instr.lineno, 3) # invalid with self.assertRaises(ValueError): instr.set("LOAD_CONST") with self.assertRaises(ValueError): instr.set("NOP", 5)
def test_extended_arg(self): # Create a code object from arbitrary bytecode co_code = b"\x90\x12\x904\x90\xabd\xcd" code = get_code("x=1") args = ( (code.co_argcount,) if sys.version_info < (3, 8) else (code.co_argcount, code.co_posonlyargcount) ) args += ( code.co_kwonlyargcount, code.co_nlocals, code.co_stacksize, code.co_flags, co_code, code.co_consts, code.co_names, code.co_varnames, code.co_filename, code.co_name, code.co_firstlineno, code.co_lnotab, code.co_freevars, code.co_cellvars, ) code = types.CodeType(*args) # without EXTENDED_ARG opcode bytecode = ConcreteBytecode.from_code(code) self.assertListEqual( list(bytecode), [ConcreteInstr("LOAD_CONST", 0x1234ABCD, lineno=1)] ) # with EXTENDED_ARG opcode bytecode = ConcreteBytecode.from_code(code, extended_arg=True) expected = [ ConcreteInstr("EXTENDED_ARG", 0x12, lineno=1), ConcreteInstr("EXTENDED_ARG", 0x34, lineno=1), ConcreteInstr("EXTENDED_ARG", 0xAB, lineno=1), ConcreteInstr("LOAD_CONST", 0xCD, lineno=1), ] self.assertListEqual(list(bytecode), expected)
def test_negative_lnotab(self): # x = 7 # y = 8 concrete = ConcreteBytecode([ ConcreteInstr("LOAD_CONST", 0), ConcreteInstr("STORE_NAME", 0), # line number goes backward! SetLineno(2), ConcreteInstr("LOAD_CONST", 1), ConcreteInstr("STORE_NAME", 1), ]) concrete.consts = [7, 8] concrete.names = ["x", "y"] concrete.first_lineno = 5 code = concrete.to_code() expected = b"d\x00Z\x00d\x01Z\x01" self.assertEqual(code.co_code, expected) self.assertEqual(code.co_firstlineno, 5) self.assertEqual(code.co_lnotab, b"\x04\xfd")
def test_setlineno(self): # x = 7 # y = 8 # z = 9 code = Bytecode() code.first_lineno = 3 code.extend([ Instr("LOAD_CONST", 7), Instr("STORE_NAME", 'x'), SetLineno(4), Instr("LOAD_CONST", 8), Instr("STORE_NAME", 'y'), SetLineno(5), Instr("LOAD_CONST", 9), Instr("STORE_NAME", 'z') ]) concrete = code.to_concrete_bytecode() self.assertEqual(concrete.consts, [7, 8, 9]) self.assertEqual(concrete.names, ['x', 'y', 'z']) code.extend([ ConcreteInstr("LOAD_CONST", 0, lineno=3), ConcreteInstr("STORE_NAME", 0, lineno=3), ConcreteInstr("LOAD_CONST", 1, lineno=4), ConcreteInstr("STORE_NAME", 1, lineno=4), ConcreteInstr("LOAD_CONST", 2, lineno=5), ConcreteInstr("STORE_NAME", 2, lineno=5) ])
def test_extended_lnotab2(self): # x = 7 # 200 blank lines # y = 8 base_code = compile("x = 7" + "\n" * 200 + "y = 8", "", "exec") concrete = ConcreteBytecode( [ ConcreteInstr("LOAD_CONST", 0), ConcreteInstr("STORE_NAME", 0), SetLineno(201), ConcreteInstr("LOAD_CONST", 1), ConcreteInstr("STORE_NAME", 1), ConcreteInstr("LOAD_CONST", 2), ConcreteInstr("RETURN_VALUE"), ] ) concrete.consts = [None, 7, 8] concrete.names = ["x", "y"] concrete.first_lineno = 1 code = concrete.to_code() self.assertEqual(code.co_code, base_code.co_code) self.assertEqual(code.co_firstlineno, base_code.co_firstlineno) self.assertEqual(code.co_lnotab, base_code.co_lnotab) if sys.version_info >= (3, 10): self.assertEqual(code.co_linetable, base_code.co_linetable)
def test_to_code_lnotab(self): # x = 7 # y = 8 # z = 9 concrete = ConcreteBytecode() concrete.consts = [7, 8, 9] concrete.names = ['x', 'y', 'z'] concrete.first_lineno = 3 concrete.extend([ ConcreteInstr("LOAD_CONST", 0), ConcreteInstr("STORE_NAME", 0), SetLineno(4), ConcreteInstr("LOAD_CONST", 1), ConcreteInstr("STORE_NAME", 1), SetLineno(5), ConcreteInstr("LOAD_CONST", 2), ConcreteInstr("STORE_NAME", 2) ]) code = concrete.to_code() if WORDCODE: expected = b'd\x00Z\x00d\x01Z\x01d\x02Z\x02' else: expected = (b'd\x00\x00' b'Z\x00\x00' b'd\x01\x00' b'Z\x01\x00' b'd\x02\x00' b'Z\x02\x00') self.assertEqual(code.co_code, expected) self.assertEqual(code.co_firstlineno, 3) self.assertEqual( code.co_lnotab, b'\x04\x01\x04\x01' if WORDCODE else b'\x06\x01\x06\x01')
def test_setlineno(self): # x = 7 # y = 8 # z = 9 concrete = ConcreteBytecode() concrete.consts = [7, 8, 9] concrete.names = ["x", "y", "z"] concrete.first_lineno = 3 concrete.extend( [ ConcreteInstr("LOAD_CONST", 0), ConcreteInstr("STORE_NAME", 0), SetLineno(4), ConcreteInstr("LOAD_CONST", 1), ConcreteInstr("STORE_NAME", 1), SetLineno(5), ConcreteInstr("LOAD_CONST", 2), ConcreteInstr("STORE_NAME", 2), ] ) code = concrete.to_bytecode() self.assertEqual( code, [ Instr("LOAD_CONST", 7, lineno=3), Instr("STORE_NAME", "x", lineno=3), Instr("LOAD_CONST", 8, lineno=4), Instr("STORE_NAME", "y", lineno=4), Instr("LOAD_CONST", 9, lineno=5), Instr("STORE_NAME", "z", lineno=5), ], )
def test_to_code_lnotab(self): # x = 7 # y = 8 # z = 9 concrete = ConcreteBytecode() concrete.consts = [7, 8, 9] concrete.names = ["x", "y", "z"] concrete.first_lineno = 3 concrete.extend([ ConcreteInstr("LOAD_CONST", 0), ConcreteInstr("STORE_NAME", 0), SetLineno(4), ConcreteInstr("LOAD_CONST", 1), ConcreteInstr("STORE_NAME", 1), SetLineno(5), ConcreteInstr("LOAD_CONST", 2), ConcreteInstr("STORE_NAME", 2), ]) code = concrete.to_code() expected = (b"d\x00\x00" b"Z\x00\x00" b"d\x01\x00" b"Z\x01\x00" b"d\x02\x00" b"Z\x02\x00") self.assertEqual(code.co_code, expected) self.assertEqual(code.co_firstlineno, 3) self.assertEqual(code.co_lnotab, b"\x06\x01\x06\x01")
def test_setlineno(self): # x = 7 # y = 8 # z = 9 code = Bytecode() code.first_lineno = 3 code.extend( [ Instr("LOAD_CONST", 7), Instr("STORE_NAME", "x"), SetLineno(4), Instr("LOAD_CONST", 8), Instr("STORE_NAME", "y"), SetLineno(5), Instr("LOAD_CONST", 9), Instr("STORE_NAME", "z"), ] ) concrete = code.to_concrete_bytecode() self.assertEqual(concrete.consts, [7, 8, 9]) self.assertEqual(concrete.names, ["x", "y", "z"]) self.assertListEqual( list(concrete), [ ConcreteInstr("LOAD_CONST", 0, lineno=3), ConcreteInstr("STORE_NAME", 0, lineno=3), ConcreteInstr("LOAD_CONST", 1, lineno=4), ConcreteInstr("STORE_NAME", 1, lineno=4), ConcreteInstr("LOAD_CONST", 2, lineno=5), ConcreteInstr("STORE_NAME", 2, lineno=5), ], )
def test_assemble(self): instr = ConcreteInstr("NOP") self.assertEqual(instr.assemble(), b'\t\x00' if WORDCODE else b'\t') instr = ConcreteInstr("LOAD_CONST", 3) self.assertEqual(instr.assemble(), b'd\x03' if WORDCODE else b'd\x03\x00') instr = ConcreteInstr("LOAD_CONST", 0x1234abcd) self.assertEqual(instr.assemble(), (b'\x90\x12\x904\x90\xabd\xcd' if WORDCODE else b'\x904\x12d\xcd\xab')) instr = ConcreteInstr("LOAD_CONST", 3, extended_args=1) self.assertEqual(instr.assemble(), (b'\x90\x00d\x03' if WORDCODE else b'\x90\x00\x00d\x03\x00'))
def test_set_attr(self): instr = ConcreteInstr("LOAD_CONST", 5, lineno=12) # operator name instr.name = 'LOAD_FAST' self.assertEqual(instr.name, 'LOAD_FAST') self.assertEqual(instr.opcode, 124) self.assertRaises(TypeError, setattr, instr, 'name', 3) self.assertRaises(ValueError, setattr, instr, 'name', 'xxx') # operator code instr.opcode = 100 self.assertEqual(instr.name, 'LOAD_CONST') self.assertEqual(instr.opcode, 100) self.assertRaises(ValueError, setattr, instr, 'opcode', -12) self.assertRaises(TypeError, setattr, instr, 'opcode', 'abc') # extended argument instr.arg = 0x1234abcd self.assertEqual(instr.arg, 0x1234abcd) self.assertEqual(instr.size, 8 if WORDCODE else 6) # small argument instr.arg = 0 self.assertEqual(instr.arg, 0) self.assertEqual(instr.size, 2 if WORDCODE else 3) # invalid argument self.assertRaises(ValueError, setattr, instr, 'arg', -1) self.assertRaises(ValueError, setattr, instr, 'arg', 2147483647 + 1) # size attribute is read-only self.assertRaises(AttributeError, setattr, instr, 'size', 3) # lineno instr.lineno = 33 self.assertEqual(instr.lineno, 33) self.assertRaises(TypeError, setattr, instr, 'lineno', 1.0) self.assertRaises(ValueError, setattr, instr, 'lineno', -1)