| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- import dis
- import sys
- import textwrap
- import unittest
- from test.support import os_helper, verbose
- from test.support.script_helper import assert_python_ok
- def example():
- x = []
- for i in range(1):
- x.append(i)
- x = "this is"
- y = "an example"
- print(x, y)
- Py_DEBUG = hasattr(sys, 'gettotalrefcount')
- @unittest.skipUnless(Py_DEBUG, "lltrace requires Py_DEBUG")
- class TestLLTrace(unittest.TestCase):
- def run_code(self, code):
- code = textwrap.dedent(code).strip()
- with open(os_helper.TESTFN, 'w', encoding='utf-8') as fd:
- self.addCleanup(os_helper.unlink, os_helper.TESTFN)
- fd.write(code)
- status, stdout, stderr = assert_python_ok(os_helper.TESTFN)
- self.assertEqual(stderr, b"")
- self.assertEqual(status, 0)
- result = stdout.decode('utf-8')
- if verbose:
- print("\n\n--- code ---")
- print(code)
- print("\n--- stdout ---")
- print(result)
- print()
- return result
- def test_lltrace(self):
- stdout = self.run_code("""
- def dont_trace_1():
- a = "a"
- a = 10 * a
- def trace_me():
- for i in range(3):
- +i
- def dont_trace_2():
- x = 42
- y = -x
- dont_trace_1()
- __lltrace__ = 1
- trace_me()
- del __lltrace__
- dont_trace_2()
- """)
- self.assertIn("GET_ITER", stdout)
- self.assertIn("FOR_ITER", stdout)
- self.assertIn("UNARY_POSITIVE", stdout)
- self.assertIn("POP_TOP", stdout)
- self.assertNotIn("BINARY_OP", stdout)
- self.assertNotIn("UNARY_NEGATIVE", stdout)
- self.assertIn("'trace_me' in module '__main__'", stdout)
- self.assertNotIn("dont_trace_1", stdout)
- self.assertNotIn("'dont_trace_2' in module", stdout)
- def test_lltrace_different_module(self):
- stdout = self.run_code("""
- from test import test_lltrace
- test_lltrace.__lltrace__ = 1
- test_lltrace.example()
- """)
- self.assertIn("'example' in module 'test.test_lltrace'", stdout)
- self.assertIn('LOAD_CONST', stdout)
- self.assertIn('FOR_ITER', stdout)
- self.assertIn('this is an example', stdout)
- # check that offsets match the output of dis.dis()
- instr_map = {i.offset: i for i in dis.get_instructions(example)}
- for line in stdout.splitlines():
- offset, colon, opname_oparg = line.partition(":")
- if not colon:
- continue
- offset = int(offset)
- opname_oparg = opname_oparg.split()
- if len(opname_oparg) == 2:
- opname, oparg = opname_oparg
- oparg = int(oparg)
- else:
- (opname,) = opname_oparg
- oparg = None
- self.assertEqual(instr_map[offset].opname, opname)
- self.assertEqual(instr_map[offset].arg, oparg)
- def test_lltrace_does_not_crash_on_subscript_operator(self):
- # If this test fails, it will reproduce a crash reported as
- # bpo-34113. The crash happened at the command line console of
- # debug Python builds with __lltrace__ enabled (only possible in console),
- # when the internal Python stack was negatively adjusted
- stdout = self.run_code("""
- import code
- console = code.InteractiveConsole()
- console.push('__lltrace__ = 1')
- console.push('a = [1, 2, 3]')
- console.push('a[0] = 1')
- print('unreachable if bug exists')
- """)
- self.assertIn("unreachable if bug exists", stdout)
- if __name__ == "__main__":
- unittest.main()
|