mirror of
https://github.com/python/cpython.git
synced 2025-08-31 22:18:28 +00:00
gh-127637: add tests for dis
command-line interface (#127759)
This commit is contained in:
parent
5eb7fd4d0f
commit
e85f2f1703
3 changed files with 123 additions and 4 deletions
|
@ -1115,7 +1115,7 @@ class Bytecode:
|
||||||
return output.getvalue()
|
return output.getvalue()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main(args=None):
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
@ -1128,7 +1128,7 @@ def main():
|
||||||
parser.add_argument('-S', '--specialized', action='store_true',
|
parser.add_argument('-S', '--specialized', action='store_true',
|
||||||
help='show specialized bytecode')
|
help='show specialized bytecode')
|
||||||
parser.add_argument('infile', nargs='?', default='-')
|
parser.add_argument('infile', nargs='?', default='-')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args(args=args)
|
||||||
if args.infile == '-':
|
if args.infile == '-':
|
||||||
name = '<stdin>'
|
name = '<stdin>'
|
||||||
source = sys.stdin.buffer.read()
|
source = sys.stdin.buffer.read()
|
||||||
|
|
|
@ -5,15 +5,19 @@ import contextlib
|
||||||
import dis
|
import dis
|
||||||
import functools
|
import functools
|
||||||
import io
|
import io
|
||||||
|
import itertools
|
||||||
|
import opcode
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import textwrap
|
||||||
import types
|
import types
|
||||||
import unittest
|
import unittest
|
||||||
from test.support import (captured_stdout, requires_debug_ranges,
|
from test.support import (captured_stdout, requires_debug_ranges,
|
||||||
requires_specialization, cpython_only)
|
requires_specialization, cpython_only,
|
||||||
|
os_helper)
|
||||||
from test.support.bytecode_helper import BytecodeTestCase
|
from test.support.bytecode_helper import BytecodeTestCase
|
||||||
|
|
||||||
import opcode
|
|
||||||
|
|
||||||
CACHE = dis.opmap["CACHE"]
|
CACHE = dis.opmap["CACHE"]
|
||||||
|
|
||||||
|
@ -2426,5 +2430,119 @@ def _unroll_caches_as_Instructions(instrs, show_caches=False):
|
||||||
False, None, None, instr.positions)
|
False, None, None, instr.positions)
|
||||||
|
|
||||||
|
|
||||||
|
class TestDisCLI(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.filename = tempfile.mktemp()
|
||||||
|
self.addCleanup(os_helper.unlink, self.filename)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def text_normalize(string):
|
||||||
|
"""Dedent *string* and strip it from its surrounding whitespaces.
|
||||||
|
|
||||||
|
This method is used by the other utility functions so that any
|
||||||
|
string to write or to match against can be freely indented.
|
||||||
|
"""
|
||||||
|
return textwrap.dedent(string).strip()
|
||||||
|
|
||||||
|
def set_source(self, content):
|
||||||
|
with open(self.filename, 'w') as fp:
|
||||||
|
fp.write(self.text_normalize(content))
|
||||||
|
|
||||||
|
def invoke_dis(self, *flags):
|
||||||
|
output = io.StringIO()
|
||||||
|
with contextlib.redirect_stdout(output):
|
||||||
|
dis.main(args=[*flags, self.filename])
|
||||||
|
return self.text_normalize(output.getvalue())
|
||||||
|
|
||||||
|
def check_output(self, source, expect, *flags):
|
||||||
|
with self.subTest(source=source, flags=flags):
|
||||||
|
self.set_source(source)
|
||||||
|
res = self.invoke_dis(*flags)
|
||||||
|
expect = self.text_normalize(expect)
|
||||||
|
self.assertListEqual(res.splitlines(), expect.splitlines())
|
||||||
|
|
||||||
|
def test_invocation(self):
|
||||||
|
# test various combinations of parameters
|
||||||
|
base_flags = [
|
||||||
|
('-C', '--show-caches'),
|
||||||
|
('-O', '--show-offsets'),
|
||||||
|
('-P', '--show-positions'),
|
||||||
|
('-S', '--specialized'),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.set_source('''
|
||||||
|
def f():
|
||||||
|
print(x)
|
||||||
|
return None
|
||||||
|
''')
|
||||||
|
|
||||||
|
for r in range(1, len(base_flags) + 1):
|
||||||
|
for choices in itertools.combinations(base_flags, r=r):
|
||||||
|
for args in itertools.product(*choices):
|
||||||
|
with self.subTest(args=args[1:]):
|
||||||
|
_ = self.invoke_dis(*args)
|
||||||
|
|
||||||
|
with self.assertRaises(SystemExit):
|
||||||
|
# suppress argparse error message
|
||||||
|
with contextlib.redirect_stderr(io.StringIO()):
|
||||||
|
_ = self.invoke_dis('--unknown')
|
||||||
|
|
||||||
|
def test_show_cache(self):
|
||||||
|
# test 'python -m dis -C/--show-caches'
|
||||||
|
source = 'print()'
|
||||||
|
expect = '''
|
||||||
|
0 RESUME 0
|
||||||
|
|
||||||
|
1 LOAD_NAME 0 (print)
|
||||||
|
PUSH_NULL
|
||||||
|
CALL 0
|
||||||
|
CACHE 0 (counter: 0)
|
||||||
|
CACHE 0 (func_version: 0)
|
||||||
|
CACHE 0
|
||||||
|
POP_TOP
|
||||||
|
LOAD_CONST 0 (None)
|
||||||
|
RETURN_VALUE
|
||||||
|
'''
|
||||||
|
for flag in ['-C', '--show-caches']:
|
||||||
|
self.check_output(source, expect, flag)
|
||||||
|
|
||||||
|
def test_show_offsets(self):
|
||||||
|
# test 'python -m dis -O/--show-offsets'
|
||||||
|
source = 'pass'
|
||||||
|
expect = '''
|
||||||
|
0 0 RESUME 0
|
||||||
|
|
||||||
|
1 2 LOAD_CONST 0 (None)
|
||||||
|
4 RETURN_VALUE
|
||||||
|
'''
|
||||||
|
for flag in ['-O', '--show-offsets']:
|
||||||
|
self.check_output(source, expect, flag)
|
||||||
|
|
||||||
|
def test_show_positions(self):
|
||||||
|
# test 'python -m dis -P/--show-positions'
|
||||||
|
source = 'pass'
|
||||||
|
expect = '''
|
||||||
|
0:0-1:0 RESUME 0
|
||||||
|
|
||||||
|
1:0-1:4 LOAD_CONST 0 (None)
|
||||||
|
1:0-1:4 RETURN_VALUE
|
||||||
|
'''
|
||||||
|
for flag in ['-P', '--show-positions']:
|
||||||
|
self.check_output(source, expect, flag)
|
||||||
|
|
||||||
|
def test_specialized_code(self):
|
||||||
|
# test 'python -m dis -S/--specialized'
|
||||||
|
source = 'pass'
|
||||||
|
expect = '''
|
||||||
|
0 RESUME 0
|
||||||
|
|
||||||
|
1 LOAD_CONST_IMMORTAL 0 (None)
|
||||||
|
RETURN_VALUE
|
||||||
|
'''
|
||||||
|
for flag in ['-S', '--specialized']:
|
||||||
|
self.check_output(source, expect, flag)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Add tests for the :mod:`dis` command-line interface. Patch by Bénédikt Tran.
|
Loading…
Add table
Add a link
Reference in a new issue