示例#1
0
    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)
示例#2
0
 def test_from_code(self):
     code = get_code(
         """
         if test:
             x = 1
         else:
             x = 2
     """
     )
     bytecode = Bytecode.from_code(code)
     label_else = Label()
     label_exit = Label()
     self.assertEqual(
         bytecode,
         [
             Instr("LOAD_NAME", "test", lineno=1),
             Instr("POP_JUMP_IF_FALSE", label_else, lineno=1),
             Instr("LOAD_CONST", 1, lineno=2),
             Instr("STORE_NAME", "x", lineno=2),
             Instr("JUMP_FORWARD", label_exit, lineno=2),
             label_else,
             Instr("LOAD_CONST", 2, lineno=4),
             Instr("STORE_NAME", "x", lineno=4),
             label_exit,
             Instr("LOAD_CONST", None, lineno=4),
             Instr("RETURN_VALUE", lineno=4),
         ],
     )
示例#3
0
    def test_extended_arg(self):
        # Create a code object from arbitrary bytecode
        co_code = 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)
        self.assertListEqual(list(bytecode),
                             [ConcreteInstr('EXTENDED_ARG', 0x1234, lineno=1),
                              ConcreteInstr('LOAD_CONST', 0xabcd, lineno=1)])
示例#4
0
    def test_extended_arg_make_function(self):
        code_obj = get_code('''
            def foo(x: int, y: int):
                pass
        ''')

        # without EXTENDED_ARG
        concrete = ConcreteBytecode.from_code(code_obj)
        func_code = concrete.consts[1]
        self.assertEqual(concrete.names, ['int', 'foo'])
        self.assertEqual(concrete.consts, [('x', 'y'), func_code, 'foo', None])
        if WORDCODE:
            expected = [
                ConcreteInstr("LOAD_NAME", 0, lineno=1),
                ConcreteInstr("LOAD_NAME", 0, lineno=1),
                ConcreteInstr("LOAD_CONST", 0, lineno=1),
                ConcreteInstr("BUILD_CONST_KEY_MAP", 2, lineno=1),
                ConcreteInstr("LOAD_CONST", 1, lineno=1),
                ConcreteInstr("LOAD_CONST", 2, lineno=1),
                ConcreteInstr("MAKE_FUNCTION", 4, lineno=1),
                ConcreteInstr("STORE_NAME", 1, lineno=1),
                ConcreteInstr("LOAD_CONST", 3, lineno=1),
                ConcreteInstr("RETURN_VALUE", lineno=1)
            ]
        else:
            expected = [
                ConcreteInstr("LOAD_NAME", 0, lineno=1),
                ConcreteInstr("LOAD_NAME", 0, lineno=1),
                ConcreteInstr("LOAD_CONST", 0, lineno=1),
                ConcreteInstr("LOAD_CONST", 1, lineno=1),
                ConcreteInstr("LOAD_CONST", 2, lineno=1),
                ConcreteInstr("MAKE_FUNCTION", 3 << 16, lineno=1),
                ConcreteInstr("STORE_NAME", 1, lineno=1),
                ConcreteInstr("LOAD_CONST", 3, lineno=1),
                ConcreteInstr("RETURN_VALUE", lineno=1)
            ]
        self.assertListEqual(list(concrete), expected)

        # with EXTENDED_ARG
        concrete = ConcreteBytecode.from_code(code_obj, extended_arg=True)
        func_code = concrete.consts[1]
        self.assertEqual(concrete.names, ['int', 'foo'])
        self.assertEqual(concrete.consts, [('x', 'y'), func_code, 'foo', None])
        if not WORDCODE:
            expected = [
                ConcreteInstr("LOAD_NAME", 0, lineno=1),
                ConcreteInstr("LOAD_NAME", 0, lineno=1),
                ConcreteInstr("LOAD_CONST", 0, lineno=1),
                ConcreteInstr("LOAD_CONST", 1, lineno=1),
                ConcreteInstr("LOAD_CONST", 2, lineno=1),
                ConcreteInstr("EXTENDED_ARG", 3, lineno=1),
                ConcreteInstr("MAKE_FUNCTION", 0, lineno=1),
                ConcreteInstr("STORE_NAME", 1, lineno=1),
                ConcreteInstr("LOAD_CONST", 3, lineno=1),
                ConcreteInstr("RETURN_VALUE", lineno=1)
            ]
        self.assertListEqual(list(concrete), expected)
示例#5
0
 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)])
示例#6
0
 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)])
示例#7
0
    def check(self, source, function=False):
        ref_code = get_code(source, function=function)

        code = ConcreteBytecode.from_code(ref_code).to_code()
        self.assertEqual(code, ref_code)

        code = Bytecode.from_code(ref_code).to_code()
        self.assertEqual(code, ref_code)

        bytecode = Bytecode.from_code(ref_code)
        blocks = ControlFlowGraph.from_bytecode(bytecode)
        code = blocks.to_bytecode().to_code()
        self.assertEqual(code, ref_code)
示例#8
0
    def test_extended_arg_make_function(self):
        code_obj = get_code('''
            def foo(x: int, y: int):
                pass
        ''')

        # without EXTENDED_ARG
        concrete = ConcreteBytecode.from_code(code_obj)
        func_code = concrete.consts[1]
        self.assertEqual(concrete.names, ['int', 'foo'])
        self.assertEqual(concrete.consts, [('x', 'y'), func_code, 'foo', None])
        if WORDCODE:
            expected = [ConcreteInstr("LOAD_NAME", 0, lineno=1),
                        ConcreteInstr("LOAD_NAME", 0, lineno=1),
                        ConcreteInstr("LOAD_CONST", 0, lineno=1),
                        ConcreteInstr("BUILD_CONST_KEY_MAP", 2, lineno=1),
                        ConcreteInstr("LOAD_CONST", 1, lineno=1),
                        ConcreteInstr("LOAD_CONST", 2, lineno=1),
                        ConcreteInstr("MAKE_FUNCTION", 4, lineno=1),
                        ConcreteInstr("STORE_NAME", 1, lineno=1),
                        ConcreteInstr("LOAD_CONST", 3, lineno=1),
                        ConcreteInstr("RETURN_VALUE", lineno=1)]
        else:
            expected = [ConcreteInstr("LOAD_NAME", 0, lineno=1),
                        ConcreteInstr("LOAD_NAME", 0, lineno=1),
                        ConcreteInstr("LOAD_CONST", 0, lineno=1),
                        ConcreteInstr("LOAD_CONST", 1, lineno=1),
                        ConcreteInstr("LOAD_CONST", 2, lineno=1),
                        ConcreteInstr("MAKE_FUNCTION", 3 << 16, lineno=1),
                        ConcreteInstr("STORE_NAME", 1, lineno=1),
                        ConcreteInstr("LOAD_CONST", 3, lineno=1),
                        ConcreteInstr("RETURN_VALUE", lineno=1)]
        self.assertListEqual(list(concrete), expected)

        # with EXTENDED_ARG
        concrete = ConcreteBytecode.from_code(code_obj, extended_arg=True)
        func_code = concrete.consts[1]
        self.assertEqual(concrete.names, ['int', 'foo'])
        self.assertEqual(concrete.consts, [('x', 'y'), func_code, 'foo', None])
        if not WORDCODE:
            expected = [ConcreteInstr("LOAD_NAME", 0, lineno=1),
                        ConcreteInstr("LOAD_NAME", 0, lineno=1),
                        ConcreteInstr("LOAD_CONST", 0, lineno=1),
                        ConcreteInstr("LOAD_CONST", 1, lineno=1),
                        ConcreteInstr("LOAD_CONST", 2, lineno=1),
                        ConcreteInstr("EXTENDED_ARG", 3, lineno=1),
                        ConcreteInstr("MAKE_FUNCTION", 0, lineno=1),
                        ConcreteInstr("STORE_NAME", 1, lineno=1),
                        ConcreteInstr("LOAD_CONST", 3, lineno=1),
                        ConcreteInstr("RETURN_VALUE", lineno=1)]
        self.assertListEqual(list(concrete), expected)
示例#9
0
 def test_from_code_load_fast(self):
     code = get_code("""
         def func():
             x = 33
             y = x
     """, function=True)
     code = Bytecode.from_code(code)
     self.assertEqual(code,
                      [Instr('LOAD_CONST', 33, lineno=2),
                       Instr('STORE_FAST', 'x', lineno=2),
                       Instr('LOAD_FAST', 'x', lineno=3),
                       Instr('STORE_FAST', 'y', lineno=3),
                       Instr('LOAD_CONST', None, lineno=3),
                       Instr('RETURN_VALUE', lineno=3)])
示例#10
0
 def test_from_code_load_fast(self):
     code = get_code("""
         def func():
             x = 33
             y = x
     """, function=True)
     code = Bytecode.from_code(code)
     self.assertEqual(code,
                      [Instr('LOAD_CONST', 33, lineno=2),
                       Instr('STORE_FAST', 'x', lineno=2),
                       Instr('LOAD_FAST', 'x', lineno=3),
                       Instr('STORE_FAST', 'y', lineno=3),
                       Instr('LOAD_CONST', None, lineno=3),
                       Instr('RETURN_VALUE', lineno=3)])
示例#11
0
 def test_label3(self):
     """
     When you delete ``extended_arg`` that have a value of 0, the following
     will fail when calling ``Bytecode.to_concrete_bytecode()`` because
     it cant find a label to correspond to the jump target
     """
     code = get_code("""
         def func(x):
             if x == 1:
                 return x +1
             elif x == 2:
                 return x + 1
             elif x == 3:
                 return x + 1
             elif x == 4:
                 return x + 1
             elif x == 5:
                 return x + 1
             elif x == 6:
                 return x + 1
             elif x == 7:
                 return x + 1
             elif x == 8:
                 return x + 1
             elif x == 9:
                 return x + 1
             elif x == 10:
                 return x + 1
             elif x == 11:
                 return x + 1
             elif x == 12:
                 return x + 1
             elif x == 13:
                 return x + 1
             elif x == 14:
                 return x + 1
             elif x == 15:
                 return x + 1
             elif x == 16:
                 return x + 1
             elif x == 17:
                 return x + 1
             return -1
     """,
                     function=True)
     code = Bytecode.from_code(code)
     concrete = code.to_concrete_bytecode()
     self.assertIsInstance(concrete, ConcreteBytecode)
示例#12
0
 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),
         ],
     )
示例#13
0
    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")
        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)
        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)
示例#14
0
 def test_from_code(self):
     code = get_code("""
         if test:
             x = 1
         else:
             x = 2
     """)
     bytecode = Bytecode.from_code(code)
     label_else = Label()
     label_exit = Label()
     if sys.version_info < (3, 10):
         self.assertEqual(
             bytecode,
             [
                 Instr("LOAD_NAME", "test", lineno=1),
                 Instr("POP_JUMP_IF_FALSE", label_else, lineno=1),
                 Instr("LOAD_CONST", 1, lineno=2),
                 Instr("STORE_NAME", "x", lineno=2),
                 Instr("JUMP_FORWARD", label_exit, lineno=2),
                 label_else,
                 Instr("LOAD_CONST", 2, lineno=4),
                 Instr("STORE_NAME", "x", lineno=4),
                 label_exit,
                 Instr("LOAD_CONST", None, lineno=4),
                 Instr("RETURN_VALUE", lineno=4),
             ],
         )
     # Control flow handling appears to have changed under Python 3.10
     else:
         self.assertEqual(
             bytecode,
             [
                 Instr("LOAD_NAME", "test", lineno=1),
                 Instr("POP_JUMP_IF_FALSE", label_else, lineno=1),
                 Instr("LOAD_CONST", 1, lineno=2),
                 Instr("STORE_NAME", "x", lineno=2),
                 Instr("LOAD_CONST", None, lineno=2),
                 Instr("RETURN_VALUE", lineno=2),
                 label_else,
                 Instr("LOAD_CONST", 2, lineno=4),
                 Instr("STORE_NAME", "x", lineno=4),
                 Instr("LOAD_CONST", None, lineno=4),
                 Instr("RETURN_VALUE", lineno=4),
             ],
         )
示例#15
0
    def test_explicit_stacksize(self):
        # Passing stacksize=... to ConcreteBytecode.to_code should result in a
        # code object with the specified stacksize.  We pass some silly values
        # and assert that they are honored.
        code_obj = get_code("print('%s' % (a,b,c))")
        original_stacksize = code_obj.co_stacksize
        concrete = ConcreteBytecode.from_code(code_obj)

        # First with something bigger than necessary.
        explicit_stacksize = original_stacksize + 42
        new_code_obj = concrete.to_code(stacksize=explicit_stacksize)
        self.assertEqual(new_code_obj.co_stacksize, explicit_stacksize)

        # Then with something bogus.  We probably don't want to advertise this
        # in the documentation.  If this fails then decide if it's for good
        # reason, and remove if so.
        explicit_stacksize = 0
        new_code_obj = concrete.to_code(stacksize=explicit_stacksize)
        self.assertEqual(new_code_obj.co_stacksize, explicit_stacksize)
示例#16
0
    def test_explicit_stacksize(self):
        # Passing stacksize=... to ConcreteBytecode.to_code should result in a
        # code object with the specified stacksize.  We pass some silly values
        # and assert that they are honored.
        code_obj = get_code("print('%s' % (a,b,c))")
        original_stacksize = code_obj.co_stacksize
        concrete = ConcreteBytecode.from_code(code_obj)

        # First with something bigger than necessary.
        explicit_stacksize = original_stacksize + 42
        new_code_obj = concrete.to_code(stacksize=explicit_stacksize)
        self.assertEqual(new_code_obj.co_stacksize, explicit_stacksize)

        # Then with something bogus.  We probably don't want to advertise this
        # in the documentation.  If this fails then decide if it's for good
        # reason, and remove if so.
        explicit_stacksize = 0
        new_code_obj = concrete.to_code(stacksize=explicit_stacksize)
        self.assertEqual(new_code_obj.co_stacksize, explicit_stacksize)
示例#17
0
 def test_from_code_load_fast(self):
     code = get_code(
         """
         def func():
             x = 33
             y = x
     """,
         function=True,
     )
     code = Bytecode.from_code(code)
     self.assertEqual(
         code,
         [
             Instr("LOAD_CONST", 33, lineno=2),
             Instr("STORE_FAST", "x", lineno=2),
             Instr("LOAD_FAST", "x", lineno=3),
             Instr("STORE_FAST", "y", lineno=3),
             Instr("LOAD_CONST", None, lineno=3),
             Instr("RETURN_VALUE", lineno=3),
         ],
     )
示例#18
0
 def test_from_code(self):
     code = get_code("""
         if test:
             x = 1
         else:
             x = 2
     """)
     bytecode = Bytecode.from_code(code)
     label_else = Label()
     label_exit = Label()
     self.assertEqual(bytecode, [
         Instr('LOAD_NAME', 'test', lineno=1),
         Instr('POP_JUMP_IF_FALSE', label_else, lineno=1),
         Instr('LOAD_CONST', 1, lineno=2),
         Instr('STORE_NAME', 'x', lineno=2),
         Instr('JUMP_FORWARD', label_exit, lineno=2), label_else,
         Instr('LOAD_CONST', 2, lineno=4),
         Instr('STORE_NAME', 'x', lineno=4), label_exit,
         Instr('LOAD_CONST', None, lineno=4),
         Instr('RETURN_VALUE', lineno=4)
     ])
示例#19
0
 def test_from_code(self):
     code = get_code("""
         if test:
             x = 1
         else:
             x = 2
     """)
     bytecode = Bytecode.from_code(code)
     label_else = Label()
     label_exit = Label()
     self.assertEqual(bytecode,
                      [Instr('LOAD_NAME', 'test', lineno=1),
                       Instr('POP_JUMP_IF_FALSE', label_else, lineno=1),
                       Instr('LOAD_CONST', 1, lineno=2),
                       Instr('STORE_NAME', 'x', lineno=2),
                       Instr('JUMP_FORWARD', label_exit, lineno=2),
                       label_else,
                       Instr('LOAD_CONST', 2, lineno=4),
                       Instr('STORE_NAME', 'x', lineno=4),
                       label_exit,
                       Instr('LOAD_CONST', None, lineno=4),
                       Instr('RETURN_VALUE', lineno=4)])
示例#20
0
    def test_extended_arg_make_function(self):
        if (3, 9) <= sys.version_info < (3, 10):
            from bytecode.tests.util_annotation import get_code as get_code_future

            code_obj = get_code_future(
                """
                def foo(x: int, y: int):
                    pass
                """
            )
        else:
            code_obj = get_code(
                """
                def foo(x: int, y: int):
                    pass
                """
            )

        # without EXTENDED_ARG
        concrete = ConcreteBytecode.from_code(code_obj)
        # With future annotation the int annotation is stringified and
        # stored as constant this the default behavior under Python 3.10
        if sys.version_info >= (3, 10):
            func_code = concrete.consts[3]
            names = ["foo"]
            consts = ["x", "int", "y", func_code, "foo", None, ("x", "int", "y", "int")]
            const_offset = 2
            first_instrs = [
                ConcreteInstr("LOAD_CONST", 6, lineno=1),
            ]
        elif (
            sys.version_info >= (3, 7)
            and concrete.flags & CompilerFlags.FUTURE_ANNOTATIONS
        ):
            func_code = concrete.consts[2]
            names = ["foo"]
            consts = ["int", ("x", "y"), func_code, "foo", None]
            const_offset = 1
            first_instrs = [
                ConcreteInstr("LOAD_CONST", 0, lineno=1),
                ConcreteInstr("LOAD_CONST", 0, lineno=1),
                ConcreteInstr("LOAD_CONST", 0 + const_offset, lineno=1),
                ConcreteInstr("BUILD_CONST_KEY_MAP", 2, lineno=1),
            ]
        else:
            func_code = concrete.consts[1]
            names = ["int", "foo"]
            consts = [("x", "y"), func_code, "foo", None]
            const_offset = 0
            first_instrs = [
                ConcreteInstr("LOAD_NAME", 0, lineno=1),
                ConcreteInstr("LOAD_NAME", 0, lineno=1),
                ConcreteInstr("LOAD_CONST", 0 + const_offset, lineno=1),
                ConcreteInstr("BUILD_CONST_KEY_MAP", 2, lineno=1),
            ]

        self.assertEqual(concrete.names, names)
        self.assertEqual(concrete.consts, consts)
        expected = first_instrs + [
            ConcreteInstr("LOAD_CONST", 1 + const_offset, lineno=1),
            ConcreteInstr("LOAD_CONST", 2 + const_offset, lineno=1),
            ConcreteInstr("MAKE_FUNCTION", 4, lineno=1),
            ConcreteInstr("STORE_NAME", 1 - bool(const_offset), lineno=1),
            ConcreteInstr("LOAD_CONST", 3 + const_offset, lineno=1),
            ConcreteInstr("RETURN_VALUE", lineno=1),
        ]
        self.assertListEqual(list(concrete), expected)

        # with EXTENDED_ARG
        concrete = ConcreteBytecode.from_code(code_obj, extended_arg=True)
        # With future annotation the int annotation is stringified and
        # stored as constant this the default behavior under Python 3.10
        if sys.version_info >= (3, 10):
            func_code = concrete.consts[3]
            names = ["foo"]
            consts = ["x", "int", "y", func_code, "foo", None, ("x", "int", "y", "int")]
        elif concrete.flags & CompilerFlags.FUTURE_ANNOTATIONS:
            func_code = concrete.consts[2]
            names = ["foo"]
            consts = ["int", ("x", "y"), func_code, "foo", None]
        else:
            func_code = concrete.consts[1]
            names = ["int", "foo"]
            consts = [("x", "y"), func_code, "foo", None]

        self.assertEqual(concrete.names, names)
        self.assertEqual(concrete.consts, consts)
        self.assertListEqual(list(concrete), expected)
示例#21
0
    def test_label3(self):
        """
        CPython generates useless EXTENDED_ARG 0 in some cases. We need to
        properly track them as otherwise we can end up with broken offset for
        jumps.
        """
        source = """
            def func(x):
                if x == 1:
                    return x + 0
                elif x == 2:
                    return x + 1
                elif x == 3:
                    return x + 2
                elif x == 4:
                    return x + 3
                elif x == 5:
                    return x + 4
                elif x == 6:
                    return x + 5
                elif x == 7:
                    return x + 6
                elif x == 8:
                    return x + 7
                elif x == 9:
                    return x + 8
                elif x == 10:
                    return x + 9
                elif x == 11:
                    return x + 10
                elif x == 12:
                    return x + 11
                elif x == 13:
                    return x + 12
                elif x == 14:
                    return x + 13
                elif x == 15:
                    return x + 14
                elif x == 16:
                    return x + 15
                elif x == 17:
                    return x + 16
                return -1
        """
        code = get_code(source, function=True)
        bcode = Bytecode.from_code(code)
        concrete = bcode.to_concrete_bytecode()
        self.assertIsInstance(concrete, ConcreteBytecode)

        # Ensure that we do not generate broken code
        loc = {}
        exec(textwrap.dedent(source), loc)
        func = loc["func"]
        func.__code__ = bcode.to_code()
        for i, x in enumerate(range(1, 18)):
            self.assertEqual(func(x), x + i)
        self.assertEqual(func(18), -1)

        # Ensure that we properly round trip in such cases
        self.assertEqual(
            ConcreteBytecode.from_code(code).to_code().co_code, code.co_code
        )
示例#22
0
    def test_label3(self):
        """
        CPython generates useless EXTENDED_ARG 0 in some cases. We need to
        properly track them as otherwise we can end up with broken offset for
        jumps.
        """
        source = """
            def func(x):
                if x == 1:
                    return x + 0
                elif x == 2:
                    return x + 1
                elif x == 3:
                    return x + 2
                elif x == 4:
                    return x + 3
                elif x == 5:
                    return x + 4
                elif x == 6:
                    return x + 5
                elif x == 7:
                    return x + 6
                elif x == 8:
                    return x + 7
                elif x == 9:
                    return x + 8
                elif x == 10:
                    return x + 9
                elif x == 11:
                    return x + 10
                elif x == 12:
                    return x + 11
                elif x == 13:
                    return x + 12
                elif x == 14:
                    return x + 13
                elif x == 15:
                    return x + 14
                elif x == 16:
                    return x + 15
                elif x == 17:
                    return x + 16
                return -1
        """
        code = get_code(source, function=True)
        bcode = Bytecode.from_code(code)
        concrete = bcode.to_concrete_bytecode()
        self.assertIsInstance(concrete, ConcreteBytecode)

        # Ensure that we do not generate broken code
        loc = {}
        exec(textwrap.dedent(source), loc)
        func = loc['func']
        func.__code__ = bcode.to_code()
        for i, x in enumerate(range(1, 18)):
            self.assertEqual(func(x), x + i)
        self.assertEqual(func(18), -1)

        # Ensure that we properly round trip in such cases
        self.assertEqual(ConcreteBytecode.from_code(code).to_code().co_code,
                         code.co_code)