| import types |
| |
| from test.support.bytecode_helper import AssemblerTestCase |
| |
| |
| # Tests for the code-object creation stage of the compiler. |
| |
| class IsolatedAssembleTests(AssemblerTestCase): |
| |
| def complete_metadata(self, metadata, filename="myfile.py"): |
| if metadata is None: |
| metadata = {} |
| for key in ['name', 'qualname']: |
| metadata.setdefault(key, key) |
| for key in ['consts']: |
| metadata.setdefault(key, []) |
| for key in ['names', 'varnames', 'cellvars', 'freevars', 'fasthidden']: |
| metadata.setdefault(key, {}) |
| for key in ['argcount', 'posonlyargcount', 'kwonlyargcount']: |
| metadata.setdefault(key, 0) |
| metadata.setdefault('firstlineno', 1) |
| metadata.setdefault('filename', filename) |
| return metadata |
| |
| def assemble_test(self, insts, metadata, expected): |
| metadata = self.complete_metadata(metadata) |
| insts = self.complete_insts_info(insts) |
| |
| co = self.get_code_object(metadata['filename'], insts, metadata) |
| self.assertIsInstance(co, types.CodeType) |
| |
| expected_metadata = {} |
| for key, value in metadata.items(): |
| if key == "fasthidden": |
| # not exposed on code object |
| continue |
| if isinstance(value, list): |
| expected_metadata[key] = tuple(value) |
| elif isinstance(value, dict): |
| expected_metadata[key] = tuple(value.keys()) |
| else: |
| expected_metadata[key] = value |
| |
| for key, value in expected_metadata.items(): |
| self.assertEqual(getattr(co, "co_" + key), value) |
| |
| f = types.FunctionType(co, {}) |
| for args, res in expected.items(): |
| self.assertEqual(f(*args), res) |
| |
| def test_simple_expr(self): |
| metadata = { |
| 'filename' : 'avg.py', |
| 'name' : 'avg', |
| 'qualname' : 'stats.avg', |
| 'consts' : {2 : 0}, |
| 'argcount' : 2, |
| 'varnames' : {'x' : 0, 'y' : 1}, |
| } |
| |
| # code for "return (x+y)/2" |
| insts = [ |
| ('RESUME', 0), |
| ('LOAD_FAST', 0, 1), # 'x' |
| ('LOAD_FAST', 1, 1), # 'y' |
| ('BINARY_OP', 0, 1), # '+' |
| ('LOAD_CONST', 0, 1), # 2 |
| ('BINARY_OP', 11, 1), # '/' |
| ('RETURN_VALUE', 1), |
| ] |
| expected = {(3, 4) : 3.5, (-100, 200) : 50, (10, 18) : 14} |
| self.assemble_test(insts, metadata, expected) |
| |
| |
| def test_expression_with_pseudo_instruction_load_closure(self): |
| |
| def mod_two(x): |
| def inner(): |
| return x |
| return inner() % 2 |
| |
| inner_code = mod_two.__code__.co_consts[1] |
| assert isinstance(inner_code, types.CodeType) |
| |
| metadata = { |
| 'filename' : 'mod_two.py', |
| 'name' : 'mod_two', |
| 'qualname' : 'nested.mod_two', |
| 'cellvars' : {'x' : 0}, |
| 'consts': {None: 0, inner_code: 1, 2: 2}, |
| 'argcount' : 1, |
| 'varnames' : {'x' : 0}, |
| } |
| |
| instructions = [ |
| ('RESUME', 0,), |
| ('LOAD_CLOSURE', 0, 1), |
| ('BUILD_TUPLE', 1, 1), |
| ('LOAD_CONST', 1, 1), |
| ('MAKE_FUNCTION', 0, 2), |
| ('SET_FUNCTION_ATTRIBUTE', 8, 2), |
| ('PUSH_NULL', 0, 1), |
| ('CALL', 0, 2), # (lambda: x)() |
| ('LOAD_CONST', 2, 2), # 2 |
| ('BINARY_OP', 6, 2), # % |
| ('RETURN_VALUE', 0, 2) |
| ] |
| |
| expected = {(0,): 0, (1,): 1, (2,): 0, (120,): 0, (121,): 1} |
| self.assemble_test(instructions, metadata, expected) |