Skip to content

Commit bd6af2c

Browse files
committed
add tests for dis command-line interface
1 parent 1503fc8 commit bd6af2c

File tree

2 files changed

+104
-4
lines changed

2 files changed

+104
-4
lines changed

Lib/dis.py

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

11171117

1118-
def main():
1118+
def main(args=None):
11191119
import argparse
11201120

11211121
parser = argparse.ArgumentParser()
@@ -1128,7 +1128,7 @@ def main():
11281128
parser.add_argument('-S', '--specialized', action='store_true',
11291129
help='show specialized bytecode')
11301130
parser.add_argument('infile', nargs='?', default='-')
1131-
args = parser.parse_args()
1131+
args = parser.parse_args(args=args)
11321132
if args.infile == '-':
11331133
name = '<stdin>'
11341134
source = sys.stdin.buffer.read()

Lib/test/test_dis.py

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,19 @@
55
import dis
66
import functools
77
import io
8+
import itertools
9+
import opcode
810
import re
911
import sys
12+
import tempfile
13+
import textwrap
1014
import types
1115
import unittest
1216
from test.support import (captured_stdout, requires_debug_ranges,
13-
requires_specialization, cpython_only)
17+
requires_specialization, cpython_only,
18+
os_helper)
1419
from test.support.bytecode_helper import BytecodeTestCase
1520

16-
import opcode
1721

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

@@ -2426,5 +2430,101 @@ def _unroll_caches_as_Instructions(instrs, show_caches=False):
24262430
False, None, None, instr.positions)
24272431

24282432

2433+
class TestDisCLI(unittest.TestCase):
2434+
2435+
def infile(self, content):
2436+
filename = tempfile.mktemp()
2437+
self.addCleanup(os_helper.unlink, filename)
2438+
with open(filename, 'w') as fp:
2439+
fp.write(content)
2440+
return filename
2441+
2442+
def invoke_dis(self, infile, *flags):
2443+
output = io.StringIO()
2444+
with contextlib.redirect_stdout(output):
2445+
dis.main(args=[*flags, infile])
2446+
return output.getvalue()
2447+
2448+
def check_output(self, source, expect, *flags):
2449+
with self.subTest(flags):
2450+
infile = self.infile(source)
2451+
res = self.invoke_dis(infile, *flags)
2452+
res = textwrap.dedent(res)
2453+
expect = textwrap.dedent(expect)
2454+
self.assertListEqual(res.splitlines(), expect.splitlines())
2455+
2456+
def test_invokation(self):
2457+
# test various combinations of parameters
2458+
base_flags = [
2459+
('-C', '--show-caches'),
2460+
('-O', '--show-offsets'),
2461+
('-P', '--show-positions'),
2462+
('-S', '--specialized'),
2463+
]
2464+
2465+
infile = self.infile('def f():\n\tprint(x)\n\treturn None')
2466+
2467+
for r in range(1, len(base_flags) + 1):
2468+
for choices in itertools.combinations(base_flags, r=r):
2469+
for args in itertools.product(*choices):
2470+
with self.subTest(args=args[1:]):
2471+
_ = self.invoke_dis(infile, *args)
2472+
2473+
def test_show_cache(self):
2474+
# test 'python -m dis -C/--show-caches'
2475+
source = 'print()'
2476+
expect = '''\
2477+
0 RESUME 0
2478+
2479+
1 LOAD_NAME 0 (print)
2480+
PUSH_NULL
2481+
CALL 0
2482+
CACHE 0 (counter: 0)
2483+
CACHE 0 (func_version: 0)
2484+
CACHE 0
2485+
POP_TOP
2486+
LOAD_CONST 0 (None)
2487+
RETURN_VALUE
2488+
'''
2489+
for flag in ['-C', '--show-caches']:
2490+
self.check_output(source, expect, flag)
2491+
2492+
def test_show_offsets(self):
2493+
# test 'python -m dis -O/--show-offsets'
2494+
source = 'pass'
2495+
expect = '''\
2496+
0 0 RESUME 0
2497+
2498+
1 2 LOAD_CONST 0 (None)
2499+
4 RETURN_VALUE
2500+
'''
2501+
for flag in ['-O', '--show-offsets']:
2502+
self.check_output(source, expect, flag)
2503+
2504+
def test_show_positions(self):
2505+
# test 'python -m dis -P/--show-positions'
2506+
source = 'pass'
2507+
expect = '''\
2508+
0:0-1:0 RESUME 0
2509+
2510+
1:0-1:4 LOAD_CONST 0 (None)
2511+
1:0-1:4 RETURN_VALUE
2512+
'''
2513+
for flag in ['-P', '--show-positions']:
2514+
self.check_output(source, expect, flag)
2515+
2516+
def test_specialized_code(self):
2517+
# test 'python -m dis -S/--specialized'
2518+
source = 'pass'
2519+
expect = '''\
2520+
0 RESUME 0
2521+
2522+
1 LOAD_CONST_IMMORTAL 0 (None)
2523+
RETURN_VALUE
2524+
'''
2525+
for flag in ['-S', '--specialized']:
2526+
self.check_output(source, expect, flag)
2527+
2528+
24292529
if __name__ == "__main__":
24302530
unittest.main()

0 commit comments

Comments
 (0)