|  | 
| 5 | 5 | import dis | 
| 6 | 6 | import functools | 
| 7 | 7 | import io | 
|  | 8 | +import itertools | 
|  | 9 | +import opcode | 
| 8 | 10 | import re | 
| 9 | 11 | import sys | 
|  | 12 | +import tempfile | 
|  | 13 | +import textwrap | 
| 10 | 14 | import types | 
| 11 | 15 | import unittest | 
| 12 | 16 | from test.support import (captured_stdout, requires_debug_ranges, | 
| 13 |  | -                          requires_specialization, cpython_only) | 
|  | 17 | +                          requires_specialization, cpython_only, | 
|  | 18 | +                          os_helper) | 
| 14 | 19 | from test.support.bytecode_helper import BytecodeTestCase | 
| 15 | 20 | 
 | 
| 16 |  | -import opcode | 
| 17 | 21 | 
 | 
| 18 | 22 | CACHE = dis.opmap["CACHE"] | 
| 19 | 23 | 
 | 
| @@ -2426,5 +2430,101 @@ def _unroll_caches_as_Instructions(instrs, show_caches=False): | 
| 2426 | 2430 |                                   False, None, None, instr.positions) | 
| 2427 | 2431 | 
 | 
| 2428 | 2432 | 
 | 
|  | 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 | + | 
| 2429 | 2529 | if __name__ == "__main__": | 
| 2430 | 2530 |     unittest.main() | 
0 commit comments