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_legalize(self): concrete = ConcreteBytecode() concrete.first_lineno = 3 concrete.consts = [7, 8, 9] concrete.names = ["x", "y", "z"] concrete.extend( [ ConcreteInstr("LOAD_CONST", 0), ConcreteInstr("STORE_NAME", 0), ConcreteInstr("LOAD_CONST", 1, lineno=4), ConcreteInstr("STORE_NAME", 1), SetLineno(5), ConcreteInstr("LOAD_CONST", 2, lineno=6), ConcreteInstr("STORE_NAME", 2), ] ) concrete.legalize() 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_to_bytecode_consts(self): # x = -0.0 # x = +0.0 # # code optimized by the CPython 3.6 peephole optimizer which emits # duplicated constants (0.0 is twice in consts). code = ConcreteBytecode() code.consts = [0.0, None, -0.0, 0.0] code.names = ["x", "y"] code.extend([ ConcreteInstr("LOAD_CONST", 2, lineno=1), ConcreteInstr("STORE_NAME", 0, lineno=1), ConcreteInstr("LOAD_CONST", 3, lineno=2), ConcreteInstr("STORE_NAME", 1, lineno=2), ConcreteInstr("LOAD_CONST", 1, lineno=2), ConcreteInstr("RETURN_VALUE", lineno=2), ]) code = code.to_bytecode().to_concrete_bytecode() # the conversion changes the constant order: the order comes from # the order of LOAD_CONST instructions self.assertEqual(code.consts, [-0.0, 0.0, None]) code.names = ["x", "y"] self.assertListEqual( list(code), [ ConcreteInstr("LOAD_CONST", 0, lineno=1), ConcreteInstr("STORE_NAME", 0, lineno=1), ConcreteInstr("LOAD_CONST", 1, lineno=2), ConcreteInstr("STORE_NAME", 1, lineno=2), ConcreteInstr("LOAD_CONST", 2, lineno=2), ConcreteInstr("RETURN_VALUE", lineno=2), ], )
def test_load_classderef(self): concrete = ConcreteBytecode() concrete.cellvars = ['__class__'] concrete.freevars = ['__class__'] concrete.extend([ ConcreteInstr('LOAD_CLASSDEREF', 1), ConcreteInstr('STORE_DEREF', 1) ]) bytecode = concrete.to_bytecode() self.assertEqual(bytecode.freevars, ['__class__']) self.assertEqual(bytecode.cellvars, ['__class__']) self.assertEqual(list(bytecode), [ Instr('LOAD_CLASSDEREF', FreeVar('__class__'), lineno=1), Instr('STORE_DEREF', FreeVar('__class__'), lineno=1) ]) concrete = bytecode.to_concrete_bytecode() self.assertEqual(concrete.freevars, ['__class__']) self.assertEqual(concrete.cellvars, ['__class__']) self.assertEqual(list(concrete), [ ConcreteInstr('LOAD_CLASSDEREF', 1, lineno=1), ConcreteInstr('STORE_DEREF', 1, lineno=1) ]) code = concrete.to_code() self.assertEqual(code.co_freevars, ('__class__', )) self.assertEqual(code.co_cellvars, ('__class__', )) self.assertEqual( code.co_code, b'\x94\x01\x89\x01' if WORDCODE else b'\x94\x01\x00\x89\x01\x00')
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_load_classderef(self): concrete = ConcreteBytecode() concrete.cellvars = ['__class__'] concrete.freevars = ['__class__'] concrete.extend([ConcreteInstr('LOAD_CLASSDEREF', 1), ConcreteInstr('STORE_DEREF', 1)]) bytecode = concrete.to_bytecode() self.assertEqual(bytecode.freevars, ['__class__']) self.assertEqual(bytecode.cellvars, ['__class__']) self.assertEqual(list(bytecode), [Instr('LOAD_CLASSDEREF', FreeVar('__class__'), lineno=1), Instr('STORE_DEREF', FreeVar('__class__'), lineno=1)] ) concrete = bytecode.to_concrete_bytecode() self.assertEqual(concrete.freevars, ['__class__']) self.assertEqual(concrete.cellvars, ['__class__']) self.assertEqual(list(concrete), [ConcreteInstr('LOAD_CLASSDEREF', 1, lineno=1), ConcreteInstr('STORE_DEREF', 1, lineno=1)]) code = concrete.to_code() self.assertEqual(code.co_freevars, ('__class__',)) self.assertEqual(code.co_cellvars, ('__class__',)) self.assertEqual( code.co_code, b'\x94\x01\x89\x01' if WORDCODE else b'\x94\x01\x00\x89\x01\x00')
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_bytecode_consts(self): # x = -0.0 # x = +0.0 # # code optimized by the CPython 3.6 peephole optimizer which emits # duplicated constants (0.0 is twice in consts). code = ConcreteBytecode() code.consts = [0.0, None, -0.0, 0.0] code.names = ['x', 'y'] code.extend([ConcreteInstr('LOAD_CONST', 2, lineno=1), ConcreteInstr('STORE_NAME', 0, lineno=1), ConcreteInstr('LOAD_CONST', 3, lineno=2), ConcreteInstr('STORE_NAME', 1, lineno=2), ConcreteInstr('LOAD_CONST', 1, lineno=2), ConcreteInstr('RETURN_VALUE', lineno=2)]) code = code.to_bytecode().to_concrete_bytecode() # the conversion changes the constant order: the order comes from # the order of LOAD_CONST instructions self.assertEqual(code.consts, [-0.0, 0.0, None]) code.names = ['x', 'y'] self.assertListEqual(list(code), [ConcreteInstr('LOAD_CONST', 0, lineno=1), ConcreteInstr('STORE_NAME', 0, lineno=1), ConcreteInstr('LOAD_CONST', 1, lineno=2), ConcreteInstr('STORE_NAME', 1, lineno=2), ConcreteInstr('LOAD_CONST', 2, lineno=2), ConcreteInstr('RETURN_VALUE', lineno=2)])
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_negative_lnotab(self): # x = 7 # y = 8 concrete = ConcreteBytecode() concrete.consts = [7, 8] concrete.names = ['x', 'y'] concrete.first_lineno = 5 concrete.extend([ConcreteInstr("LOAD_CONST", 0), ConcreteInstr("STORE_NAME", 0), # line number goes backward! SetLineno(2), ConcreteInstr("LOAD_CONST", 1), ConcreteInstr("STORE_NAME", 1)]) if sys.version_info >= (3, 6): code = concrete.to_code() expected = (b'd\x00\x00' b'Z\x00\x00' b'd\x01\x00' b'Z\x01\x00') self.assertEqual(code.co_code, expected) self.assertEqual(code.co_firstlineno, 5) self.assertEqual(code.co_lnotab, b'\x06\xfd') else: with self.assertRaises(ValueError) as cm: code = concrete.to_code() self.assertEqual(str(cm.exception), "negative line number delta is not supported " "on Python < 3.6")
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_negative_lnotab(self): # x = 7 # y = 8 concrete = ConcreteBytecode() concrete.consts = [7, 8] concrete.names = ['x', 'y'] concrete.first_lineno = 5 concrete.extend([ConcreteInstr("LOAD_CONST", 0), ConcreteInstr("STORE_NAME", 0), # line number goes backward! SetLineno(2), ConcreteInstr("LOAD_CONST", 1), ConcreteInstr("STORE_NAME", 1)]) if sys.version_info >= (3, 6): 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') else: with self.assertRaises(ValueError) as cm: code = concrete.to_code() self.assertEqual(str(cm.exception), "negative line number delta is not supported " "on Python < 3.6")
def test_copy(self): concrete = ConcreteBytecode() concrete.first_lineno = 3 concrete.consts = [7, 8, 9] concrete.names = ["x", "y", "z"] 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), ]) self.assertEqual(concrete, concrete.copy())
def test_load_classderef(self): concrete = ConcreteBytecode() concrete.cellvars = ["__class__"] concrete.freevars = ["__class__"] concrete.extend([ ConcreteInstr("LOAD_CLASSDEREF", 1), ConcreteInstr("STORE_DEREF", 1) ]) bytecode = concrete.to_bytecode() self.assertEqual(bytecode.freevars, ["__class__"]) self.assertEqual(bytecode.cellvars, ["__class__"]) self.assertEqual( list(bytecode), [ Instr("LOAD_CLASSDEREF", FreeVar("__class__"), lineno=1), Instr("STORE_DEREF", FreeVar("__class__"), lineno=1), ], ) concrete = bytecode.to_concrete_bytecode() self.assertEqual(concrete.freevars, ["__class__"]) self.assertEqual(concrete.cellvars, ["__class__"]) self.assertEqual( list(concrete), [ ConcreteInstr("LOAD_CLASSDEREF", 1, lineno=1), ConcreteInstr("STORE_DEREF", 1, lineno=1), ], ) code = concrete.to_code() self.assertEqual(code.co_freevars, ("__class__", )) self.assertEqual(code.co_cellvars, ("__class__", )) self.assertEqual( code.co_code, b"\x94\x01\x89\x01" if WORDCODE else b"\x94\x01\x00\x89\x01\x00", )