Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit e85f2f1

Browse filesBrowse files
authored
gh-127637: add tests for dis command-line interface (#127759)
1 parent 5eb7fd4 commit e85f2f1
Copy full SHA for e85f2f1

File tree

3 files changed

+123
-4
lines changed
Filter options

3 files changed

+123
-4
lines changed

‎Lib/dis.py

Copy file name to clipboardExpand all lines: Lib/dis.py
+2-2Lines 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

Copy file name to clipboardExpand all lines: Lib/test/test_dis.py
+120-2Lines changed: 120 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,119 @@ 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 setUp(self):
2436+
self.filename = tempfile.mktemp()
2437+
self.addCleanup(os_helper.unlink, self.filename)
2438+
2439+
@staticmethod
2440+
def text_normalize(string):
2441+
"""Dedent *string* and strip it from its surrounding whitespaces.
2442+
2443+
This method is used by the other utility functions so that any
2444+
string to write or to match against can be freely indented.
2445+
"""
2446+
return textwrap.dedent(string).strip()
2447+
2448+
def set_source(self, content):
2449+
with open(self.filename, 'w') as fp:
2450+
fp.write(self.text_normalize(content))
2451+
2452+
def invoke_dis(self, *flags):
2453+
output = io.StringIO()
2454+
with contextlib.redirect_stdout(output):
2455+
dis.main(args=[*flags, self.filename])
2456+
return self.text_normalize(output.getvalue())
2457+
2458+
def check_output(self, source, expect, *flags):
2459+
with self.subTest(source=source, flags=flags):
2460+
self.set_source(source)
2461+
res = self.invoke_dis(*flags)
2462+
expect = self.text_normalize(expect)
2463+
self.assertListEqual(res.splitlines(), expect.splitlines())
2464+
2465+
def test_invocation(self):
2466+
# test various combinations of parameters
2467+
base_flags = [
2468+
('-C', '--show-caches'),
2469+
('-O', '--show-offsets'),
2470+
('-P', '--show-positions'),
2471+
('-S', '--specialized'),
2472+
]
2473+
2474+
self.set_source('''
2475+
def f():
2476+
print(x)
2477+
return None
2478+
''')
2479+
2480+
for r in range(1, len(base_flags) + 1):
2481+
for choices in itertools.combinations(base_flags, r=r):
2482+
for args in itertools.product(*choices):
2483+
with self.subTest(args=args[1:]):
2484+
_ = self.invoke_dis(*args)
2485+
2486+
with self.assertRaises(SystemExit):
2487+
# suppress argparse error message
2488+
with contextlib.redirect_stderr(io.StringIO()):
2489+
_ = self.invoke_dis('--unknown')
2490+
2491+
def test_show_cache(self):
2492+
# test 'python -m dis -C/--show-caches'
2493+
source = 'print()'
2494+
expect = '''
2495+
0 RESUME 0
2496+
2497+
1 LOAD_NAME 0 (print)
2498+
PUSH_NULL
2499+
CALL 0
2500+
CACHE 0 (counter: 0)
2501+
CACHE 0 (func_version: 0)
2502+
CACHE 0
2503+
POP_TOP
2504+
LOAD_CONST 0 (None)
2505+
RETURN_VALUE
2506+
'''
2507+
for flag in ['-C', '--show-caches']:
2508+
self.check_output(source, expect, flag)
2509+
2510+
def test_show_offsets(self):
2511+
# test 'python -m dis -O/--show-offsets'
2512+
source = 'pass'
2513+
expect = '''
2514+
0 0 RESUME 0
2515+
2516+
1 2 LOAD_CONST 0 (None)
2517+
4 RETURN_VALUE
2518+
'''
2519+
for flag in ['-O', '--show-offsets']:
2520+
self.check_output(source, expect, flag)
2521+
2522+
def test_show_positions(self):
2523+
# test 'python -m dis -P/--show-positions'
2524+
source = 'pass'
2525+
expect = '''
2526+
0:0-1:0 RESUME 0
2527+
2528+
1:0-1:4 LOAD_CONST 0 (None)
2529+
1:0-1:4 RETURN_VALUE
2530+
'''
2531+
for flag in ['-P', '--show-positions']:
2532+
self.check_output(source, expect, flag)
2533+
2534+
def test_specialized_code(self):
2535+
# test 'python -m dis -S/--specialized'
2536+
source = 'pass'
2537+
expect = '''
2538+
0 RESUME 0
2539+
2540+
1 LOAD_CONST_IMMORTAL 0 (None)
2541+
RETURN_VALUE
2542+
'''
2543+
for flag in ['-S', '--specialized']:
2544+
self.check_output(source, expect, flag)
2545+
2546+
24292547
if __name__ == "__main__":
24302548
unittest.main()
+1Lines 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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.