Skip to content

Commit 8bf5b89

Browse files
authored
[3.13] gh-127637: add tests for dis command-line interface (#127759) (#127781)
1 parent 00d6062 commit 8bf5b89

File tree

3 files changed

+95
-4
lines changed

3 files changed

+95
-4
lines changed

Lib/dis.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,7 @@ def dis(self):
10511051
return output.getvalue()
10521052

10531053

1054-
def main():
1054+
def main(args=None):
10551055
import argparse
10561056

10571057
parser = argparse.ArgumentParser()
@@ -1060,7 +1060,7 @@ def main():
10601060
parser.add_argument('-O', '--show-offsets', action='store_true',
10611061
help='show instruction offsets')
10621062
parser.add_argument('infile', nargs='?', default='-')
1063-
args = parser.parse_args()
1063+
args = parser.parse_args(args=args)
10641064
if args.infile == '-':
10651065
name = '<stdin>'
10661066
source = sys.stdin.buffer.read()

Lib/test/test_dis.py

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,19 @@
44
import dis
55
import functools
66
import io
7+
import itertools
8+
import opcode
79
import re
810
import sys
11+
import tempfile
12+
import textwrap
913
import types
1014
import unittest
1115
from test.support import (captured_stdout, requires_debug_ranges,
12-
requires_specialization, cpython_only)
16+
requires_specialization, cpython_only,
17+
os_helper)
1318
from test.support.bytecode_helper import BytecodeTestCase
1419

15-
import opcode
1620

1721
CACHE = dis.opmap["CACHE"]
1822

@@ -2281,5 +2285,91 @@ def _unroll_caches_as_Instructions(instrs, show_caches=False):
22812285
False, None, None, instr.positions)
22822286

22832287

2288+
class TestDisCLI(unittest.TestCase):
2289+
2290+
def setUp(self):
2291+
self.filename = tempfile.mktemp()
2292+
self.addCleanup(os_helper.unlink, self.filename)
2293+
2294+
@staticmethod
2295+
def text_normalize(string):
2296+
"""Dedent *string* and strip it from its surrounding whitespaces.
2297+
2298+
This method is used by the other utility functions so that any
2299+
string to write or to match against can be freely indented.
2300+
"""
2301+
return textwrap.dedent(string).strip()
2302+
2303+
def set_source(self, content):
2304+
with open(self.filename, 'w') as fp:
2305+
fp.write(self.text_normalize(content))
2306+
2307+
def invoke_dis(self, *flags):
2308+
output = io.StringIO()
2309+
with contextlib.redirect_stdout(output):
2310+
dis.main(args=[*flags, self.filename])
2311+
return self.text_normalize(output.getvalue())
2312+
2313+
def check_output(self, source, expect, *flags):
2314+
with self.subTest(source=source, flags=flags):
2315+
self.set_source(source)
2316+
res = self.invoke_dis(*flags)
2317+
expect = self.text_normalize(expect)
2318+
self.assertListEqual(res.splitlines(), expect.splitlines())
2319+
2320+
def test_invocation(self):
2321+
# test various combinations of parameters
2322+
base_flags = [
2323+
('-C', '--show-caches'),
2324+
('-O', '--show-offsets'),
2325+
]
2326+
2327+
self.set_source('''
2328+
def f():
2329+
print(x)
2330+
return None
2331+
''')
2332+
2333+
for r in range(1, len(base_flags) + 1):
2334+
for choices in itertools.combinations(base_flags, r=r):
2335+
for args in itertools.product(*choices):
2336+
with self.subTest(args=args[1:]):
2337+
_ = self.invoke_dis(*args)
2338+
2339+
with self.assertRaises(SystemExit):
2340+
# suppress argparse error message
2341+
with contextlib.redirect_stderr(io.StringIO()):
2342+
_ = self.invoke_dis('--unknown')
2343+
2344+
def test_show_cache(self):
2345+
# test 'python -m dis -C/--show-caches'
2346+
source = 'print()'
2347+
expect = '''
2348+
0 RESUME 0
2349+
2350+
1 LOAD_NAME 0 (print)
2351+
PUSH_NULL
2352+
CALL 0
2353+
CACHE 0 (counter: 0)
2354+
CACHE 0 (func_version: 0)
2355+
CACHE 0
2356+
POP_TOP
2357+
RETURN_CONST 0 (None)
2358+
'''
2359+
for flag in ['-C', '--show-caches']:
2360+
self.check_output(source, expect, flag)
2361+
2362+
def test_show_offsets(self):
2363+
# test 'python -m dis -O/--show-offsets'
2364+
source = 'pass'
2365+
expect = '''
2366+
0 0 RESUME 0
2367+
2368+
1 2 RETURN_CONST 0 (None)
2369+
'''
2370+
for flag in ['-O', '--show-offsets']:
2371+
self.check_output(source, expect, flag)
2372+
2373+
22842374
if __name__ == "__main__":
22852375
unittest.main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add tests for the :mod:`dis` command-line interface. Patch by Bénédikt Tran.

0 commit comments

Comments
 (0)