1# Minimal tests for dis module 2 3import contextlib 4import dis 5import io 6import re 7import sys 8import types 9import unittest 10from test.support import captured_stdout, requires_debug_ranges, cpython_only 11from test.support.bytecode_helper import BytecodeTestCase 12 13import opcode 14 15 16def get_tb(): 17 def _error(): 18 try: 19 1 / 0 20 except Exception as e: 21 tb = e.__traceback__ 22 return tb 23 24 tb = _error() 25 while tb.tb_next: 26 tb = tb.tb_next 27 return tb 28 29TRACEBACK_CODE = get_tb().tb_frame.f_code 30 31class _C: 32 def __init__(self, x): 33 self.x = x == 1 34 35 @staticmethod 36 def sm(x): 37 x = x == 1 38 39 @classmethod 40 def cm(cls, x): 41 cls.x = x == 1 42 43dis_c_instance_method = """\ 44%3d RESUME 0 45 46%3d LOAD_FAST 1 (x) 47 LOAD_CONST 1 (1) 48 COMPARE_OP 2 (==) 49 LOAD_FAST 0 (self) 50 STORE_ATTR 0 (x) 51 LOAD_CONST 0 (None) 52 RETURN_VALUE 53""" % (_C.__init__.__code__.co_firstlineno, _C.__init__.__code__.co_firstlineno + 1,) 54 55dis_c_instance_method_bytes = """\ 56 RESUME 0 57 LOAD_FAST 1 58 LOAD_CONST 1 59 COMPARE_OP 2 (==) 60 LOAD_FAST 0 61 STORE_ATTR 0 62 LOAD_CONST 0 63 RETURN_VALUE 64""" 65 66dis_c_class_method = """\ 67%3d RESUME 0 68 69%3d LOAD_FAST 1 (x) 70 LOAD_CONST 1 (1) 71 COMPARE_OP 2 (==) 72 LOAD_FAST 0 (cls) 73 STORE_ATTR 0 (x) 74 LOAD_CONST 0 (None) 75 RETURN_VALUE 76""" % (_C.cm.__code__.co_firstlineno, _C.cm.__code__.co_firstlineno + 2,) 77 78dis_c_static_method = """\ 79%3d RESUME 0 80 81%3d LOAD_FAST 0 (x) 82 LOAD_CONST 1 (1) 83 COMPARE_OP 2 (==) 84 STORE_FAST 0 (x) 85 LOAD_CONST 0 (None) 86 RETURN_VALUE 87""" % (_C.sm.__code__.co_firstlineno, _C.sm.__code__.co_firstlineno + 2,) 88 89# Class disassembling info has an extra newline at end. 90dis_c = """\ 91Disassembly of %s: 92%s 93Disassembly of %s: 94%s 95Disassembly of %s: 96%s 97""" % (_C.__init__.__name__, dis_c_instance_method, 98 _C.cm.__name__, dis_c_class_method, 99 _C.sm.__name__, dis_c_static_method) 100 101def _f(a): 102 print(a) 103 return 1 104 105dis_f = """\ 106%3d RESUME 0 107 108%3d LOAD_GLOBAL 1 (NULL + print) 109 LOAD_FAST 0 (a) 110 PRECALL 1 111 CALL 1 112 POP_TOP 113 114%3d LOAD_CONST 1 (1) 115 RETURN_VALUE 116""" % (_f.__code__.co_firstlineno, 117 _f.__code__.co_firstlineno + 1, 118 _f.__code__.co_firstlineno + 2) 119 120 121dis_f_co_code = """\ 122 RESUME 0 123 LOAD_GLOBAL 1 124 LOAD_FAST 0 125 PRECALL 1 126 CALL 1 127 POP_TOP 128 LOAD_CONST 1 129 RETURN_VALUE 130""" 131 132 133def bug708901(): 134 for res in range(1, 135 10): 136 pass 137 138dis_bug708901 = """\ 139%3d RESUME 0 140 141%3d LOAD_GLOBAL 1 (NULL + range) 142 LOAD_CONST 1 (1) 143 144%3d LOAD_CONST 2 (10) 145 146%3d PRECALL 2 147 CALL 2 148 GET_ITER 149 >> FOR_ITER 2 (to 40) 150 STORE_FAST 0 (res) 151 152%3d JUMP_BACKWARD 3 (to 34) 153 154%3d >> LOAD_CONST 0 (None) 155 RETURN_VALUE 156""" % (bug708901.__code__.co_firstlineno, 157 bug708901.__code__.co_firstlineno + 1, 158 bug708901.__code__.co_firstlineno + 2, 159 bug708901.__code__.co_firstlineno + 1, 160 bug708901.__code__.co_firstlineno + 3, 161 bug708901.__code__.co_firstlineno + 1) 162 163 164def bug1333982(x=[]): 165 assert 0, ([s for s in x] + 166 1) 167 pass 168 169dis_bug1333982 = """\ 170%3d RESUME 0 171 172%3d LOAD_ASSERTION_ERROR 173 LOAD_CONST 2 (<code object <listcomp> at 0x..., file "%s", line %d>) 174 MAKE_FUNCTION 0 175 LOAD_FAST 0 (x) 176 GET_ITER 177 PRECALL 0 178 CALL 0 179 180%3d LOAD_CONST 3 (1) 181 182%3d BINARY_OP 0 (+) 183 PRECALL 0 184 CALL 0 185 RAISE_VARARGS 1 186""" % (bug1333982.__code__.co_firstlineno, 187 bug1333982.__code__.co_firstlineno + 1, 188 __file__, 189 bug1333982.__code__.co_firstlineno + 1, 190 bug1333982.__code__.co_firstlineno + 2, 191 bug1333982.__code__.co_firstlineno + 1) 192 193 194def bug42562(): 195 pass 196 197 198# Set line number for 'pass' to None 199bug42562.__code__ = bug42562.__code__.replace(co_linetable=b'\xf8') 200 201 202dis_bug42562 = """\ 203 RESUME 0 204 LOAD_CONST 0 (None) 205 RETURN_VALUE 206""" 207 208# Extended arg followed by NOP 209code_bug_45757 = bytes([ 210 0x90, 0x01, # EXTENDED_ARG 0x01 211 0x09, 0xFF, # NOP 0xFF 212 0x90, 0x01, # EXTENDED_ARG 0x01 213 0x64, 0x29, # LOAD_CONST 0x29 214 0x53, 0x00, # RETURN_VALUE 0x00 215 ]) 216 217dis_bug_45757 = """\ 218 EXTENDED_ARG 1 219 NOP 220 EXTENDED_ARG 1 221 LOAD_CONST 297 222 RETURN_VALUE 223""" 224 225# [255, 255, 255, 252] is -4 in a 4 byte signed integer 226bug46724 = bytes([ 227 opcode.EXTENDED_ARG, 255, 228 opcode.EXTENDED_ARG, 255, 229 opcode.EXTENDED_ARG, 255, 230 opcode.opmap['JUMP_FORWARD'], 252, 231]) 232 233 234dis_bug46724 = """\ 235 >> EXTENDED_ARG 255 236 EXTENDED_ARG 65535 237 EXTENDED_ARG 16777215 238 JUMP_FORWARD -4 (to 0) 239""" 240 241_BIG_LINENO_FORMAT = """\ 242 1 RESUME 0 243 244%3d LOAD_GLOBAL 0 (spam) 245 POP_TOP 246 LOAD_CONST 0 (None) 247 RETURN_VALUE 248""" 249 250_BIG_LINENO_FORMAT2 = """\ 251 1 RESUME 0 252 253%4d LOAD_GLOBAL 0 (spam) 254 POP_TOP 255 LOAD_CONST 0 (None) 256 RETURN_VALUE 257""" 258 259dis_module_expected_results = """\ 260Disassembly of f: 261 4 RESUME 0 262 LOAD_CONST 0 (None) 263 RETURN_VALUE 264 265Disassembly of g: 266 5 RESUME 0 267 LOAD_CONST 0 (None) 268 RETURN_VALUE 269 270""" 271 272expr_str = "x + 1" 273 274dis_expr_str = """\ 275 0 RESUME 0 276 277 1 LOAD_NAME 0 (x) 278 LOAD_CONST 0 (1) 279 BINARY_OP 0 (+) 280 RETURN_VALUE 281""" 282 283simple_stmt_str = "x = x + 1" 284 285dis_simple_stmt_str = """\ 286 0 RESUME 0 287 288 1 LOAD_NAME 0 (x) 289 LOAD_CONST 0 (1) 290 BINARY_OP 0 (+) 291 STORE_NAME 0 (x) 292 LOAD_CONST 1 (None) 293 RETURN_VALUE 294""" 295 296annot_stmt_str = """\ 297 298x: int = 1 299y: fun(1) 300lst[fun(0)]: int = 1 301""" 302# leading newline is for a reason (tests lineno) 303 304dis_annot_stmt_str = """\ 305 0 RESUME 0 306 307 2 SETUP_ANNOTATIONS 308 LOAD_CONST 0 (1) 309 STORE_NAME 0 (x) 310 LOAD_NAME 1 (int) 311 LOAD_NAME 2 (__annotations__) 312 LOAD_CONST 1 ('x') 313 STORE_SUBSCR 314 315 3 PUSH_NULL 316 LOAD_NAME 3 (fun) 317 LOAD_CONST 0 (1) 318 PRECALL 1 319 CALL 1 320 LOAD_NAME 2 (__annotations__) 321 LOAD_CONST 2 ('y') 322 STORE_SUBSCR 323 324 4 LOAD_CONST 0 (1) 325 LOAD_NAME 4 (lst) 326 PUSH_NULL 327 LOAD_NAME 3 (fun) 328 LOAD_CONST 3 (0) 329 PRECALL 1 330 CALL 1 331 STORE_SUBSCR 332 LOAD_NAME 1 (int) 333 POP_TOP 334 LOAD_CONST 4 (None) 335 RETURN_VALUE 336""" 337 338compound_stmt_str = """\ 339x = 0 340while 1: 341 x += 1""" 342# Trailing newline has been deliberately omitted 343 344dis_compound_stmt_str = """\ 345 0 RESUME 0 346 347 1 LOAD_CONST 0 (0) 348 STORE_NAME 0 (x) 349 350 2 NOP 351 352 3 >> LOAD_NAME 0 (x) 353 LOAD_CONST 1 (1) 354 BINARY_OP 13 (+=) 355 STORE_NAME 0 (x) 356 357 2 JUMP_BACKWARD 6 (to 8) 358""" 359 360dis_traceback = """\ 361%3d RESUME 0 362 363%3d NOP 364 365%3d LOAD_CONST 1 (1) 366 LOAD_CONST 2 (0) 367 --> BINARY_OP 11 (/) 368 POP_TOP 369 JUMP_FORWARD 30 (to 76) 370 >> PUSH_EXC_INFO 371 372%3d LOAD_GLOBAL 0 (Exception) 373 CHECK_EXC_MATCH 374 POP_JUMP_FORWARD_IF_FALSE 17 (to 68) 375 STORE_FAST 0 (e) 376 377%3d LOAD_FAST 0 (e) 378 LOAD_ATTR 1 (__traceback__) 379 STORE_FAST 1 (tb) 380 POP_EXCEPT 381 LOAD_CONST 0 (None) 382 STORE_FAST 0 (e) 383 DELETE_FAST 0 (e) 384 JUMP_FORWARD 8 (to 76) 385 >> LOAD_CONST 0 (None) 386 STORE_FAST 0 (e) 387 DELETE_FAST 0 (e) 388 RERAISE 1 389 390%3d >> RERAISE 0 391 >> COPY 3 392 POP_EXCEPT 393 RERAISE 1 394 395%3d >> LOAD_FAST 1 (tb) 396 RETURN_VALUE 397ExceptionTable: 398""" % (TRACEBACK_CODE.co_firstlineno, 399 TRACEBACK_CODE.co_firstlineno + 1, 400 TRACEBACK_CODE.co_firstlineno + 2, 401 TRACEBACK_CODE.co_firstlineno + 3, 402 TRACEBACK_CODE.co_firstlineno + 4, 403 TRACEBACK_CODE.co_firstlineno + 3, 404 TRACEBACK_CODE.co_firstlineno + 5) 405 406def _fstring(a, b, c, d): 407 return f'{a} {b:4} {c!r} {d!r:4}' 408 409dis_fstring = """\ 410%3d RESUME 0 411 412%3d LOAD_FAST 0 (a) 413 FORMAT_VALUE 0 414 LOAD_CONST 1 (' ') 415 LOAD_FAST 1 (b) 416 LOAD_CONST 2 ('4') 417 FORMAT_VALUE 4 (with format) 418 LOAD_CONST 1 (' ') 419 LOAD_FAST 2 (c) 420 FORMAT_VALUE 2 (repr) 421 LOAD_CONST 1 (' ') 422 LOAD_FAST 3 (d) 423 LOAD_CONST 2 ('4') 424 FORMAT_VALUE 6 (repr, with format) 425 BUILD_STRING 7 426 RETURN_VALUE 427""" % (_fstring.__code__.co_firstlineno, _fstring.__code__.co_firstlineno + 1) 428 429def _tryfinally(a, b): 430 try: 431 return a 432 finally: 433 b() 434 435def _tryfinallyconst(b): 436 try: 437 return 1 438 finally: 439 b() 440 441dis_tryfinally = """\ 442%3d RESUME 0 443 444%3d NOP 445 446%3d LOAD_FAST 0 (a) 447 448%3d PUSH_NULL 449 LOAD_FAST 1 (b) 450 PRECALL 0 451 CALL 0 452 POP_TOP 453 RETURN_VALUE 454 >> PUSH_EXC_INFO 455 PUSH_NULL 456 LOAD_FAST 1 (b) 457 PRECALL 0 458 CALL 0 459 POP_TOP 460 RERAISE 0 461 >> COPY 3 462 POP_EXCEPT 463 RERAISE 1 464ExceptionTable: 465""" % (_tryfinally.__code__.co_firstlineno, 466 _tryfinally.__code__.co_firstlineno + 1, 467 _tryfinally.__code__.co_firstlineno + 2, 468 _tryfinally.__code__.co_firstlineno + 4, 469 ) 470 471dis_tryfinallyconst = """\ 472%3d RESUME 0 473 474%3d NOP 475 476%3d NOP 477 478%3d PUSH_NULL 479 LOAD_FAST 0 (b) 480 PRECALL 0 481 CALL 0 482 POP_TOP 483 LOAD_CONST 1 (1) 484 RETURN_VALUE 485 PUSH_EXC_INFO 486 PUSH_NULL 487 LOAD_FAST 0 (b) 488 PRECALL 0 489 CALL 0 490 POP_TOP 491 RERAISE 0 492 >> COPY 3 493 POP_EXCEPT 494 RERAISE 1 495ExceptionTable: 496""" % (_tryfinallyconst.__code__.co_firstlineno, 497 _tryfinallyconst.__code__.co_firstlineno + 1, 498 _tryfinallyconst.__code__.co_firstlineno + 2, 499 _tryfinallyconst.__code__.co_firstlineno + 4, 500 ) 501 502def _g(x): 503 yield x 504 505async def _ag(x): 506 yield x 507 508async def _co(x): 509 async for item in _ag(x): 510 pass 511 512def _h(y): 513 def foo(x): 514 '''funcdoc''' 515 return [x + z for z in y] 516 return foo 517 518dis_nested_0 = """\ 519 MAKE_CELL 0 (y) 520 521%3d RESUME 0 522 523%3d LOAD_CLOSURE 0 (y) 524 BUILD_TUPLE 1 525 LOAD_CONST 1 (<code object foo at 0x..., file "%s", line %d>) 526 MAKE_FUNCTION 8 (closure) 527 STORE_FAST 1 (foo) 528 529%3d LOAD_FAST 1 (foo) 530 RETURN_VALUE 531""" % (_h.__code__.co_firstlineno, 532 _h.__code__.co_firstlineno + 1, 533 __file__, 534 _h.__code__.co_firstlineno + 1, 535 _h.__code__.co_firstlineno + 4, 536) 537 538dis_nested_1 = """%s 539Disassembly of <code object foo at 0x..., file "%s", line %d>: 540 COPY_FREE_VARS 1 541 MAKE_CELL 0 (x) 542 543%3d RESUME 0 544 545%3d LOAD_CLOSURE 0 (x) 546 BUILD_TUPLE 1 547 LOAD_CONST 1 (<code object <listcomp> at 0x..., file "%s", line %d>) 548 MAKE_FUNCTION 8 (closure) 549 LOAD_DEREF 1 (y) 550 GET_ITER 551 PRECALL 0 552 CALL 0 553 RETURN_VALUE 554""" % (dis_nested_0, 555 __file__, 556 _h.__code__.co_firstlineno + 1, 557 _h.__code__.co_firstlineno + 1, 558 _h.__code__.co_firstlineno + 3, 559 __file__, 560 _h.__code__.co_firstlineno + 3, 561) 562 563dis_nested_2 = """%s 564Disassembly of <code object <listcomp> at 0x..., file "%s", line %d>: 565 COPY_FREE_VARS 1 566 567%3d RESUME 0 568 BUILD_LIST 0 569 LOAD_FAST 0 (.0) 570 >> FOR_ITER 7 (to 24) 571 STORE_FAST 1 (z) 572 LOAD_DEREF 2 (x) 573 LOAD_FAST 1 (z) 574 BINARY_OP 0 (+) 575 LIST_APPEND 2 576 JUMP_BACKWARD 8 (to 8) 577 >> RETURN_VALUE 578""" % (dis_nested_1, 579 __file__, 580 _h.__code__.co_firstlineno + 3, 581 _h.__code__.co_firstlineno + 3, 582) 583 584def load_test(x, y=0): 585 a, b = x, y 586 return a, b 587 588dis_load_test_quickened_code = """\ 589%3d 0 RESUME_QUICK 0 590 591%3d 2 LOAD_FAST__LOAD_FAST 0 (x) 592 4 LOAD_FAST 1 (y) 593 6 STORE_FAST__STORE_FAST 3 (b) 594 8 STORE_FAST__LOAD_FAST 2 (a) 595 596%3d 10 LOAD_FAST__LOAD_FAST 2 (a) 597 12 LOAD_FAST 3 (b) 598 14 BUILD_TUPLE 2 599 16 RETURN_VALUE 600""" % (load_test.__code__.co_firstlineno, 601 load_test.__code__.co_firstlineno + 1, 602 load_test.__code__.co_firstlineno + 2) 603 604def loop_test(): 605 for i in [1, 2, 3] * 3: 606 load_test(i) 607 608dis_loop_test_quickened_code = """\ 609%3d 0 RESUME_QUICK 0 610 611%3d 2 BUILD_LIST 0 612 4 LOAD_CONST 1 ((1, 2, 3)) 613 6 LIST_EXTEND 1 614 8 LOAD_CONST 2 (3) 615 10 BINARY_OP_ADAPTIVE 5 (*) 616 14 GET_ITER 617 16 FOR_ITER 17 (to 52) 618 18 STORE_FAST 0 (i) 619 620%3d 20 LOAD_GLOBAL_MODULE 1 (NULL + load_test) 621 32 LOAD_FAST 0 (i) 622 34 PRECALL_PYFUNC 1 623 38 CALL_PY_WITH_DEFAULTS 1 624 48 POP_TOP 625 50 JUMP_BACKWARD_QUICK 18 (to 16) 626 627%3d >> 52 LOAD_CONST 0 (None) 628 54 RETURN_VALUE 629""" % (loop_test.__code__.co_firstlineno, 630 loop_test.__code__.co_firstlineno + 1, 631 loop_test.__code__.co_firstlineno + 2, 632 loop_test.__code__.co_firstlineno + 1,) 633 634def extended_arg_quick(): 635 *_, _ = ... 636 637dis_extended_arg_quick_code = """\ 638%3d 0 RESUME 0 639 640%3d 2 LOAD_CONST 1 (Ellipsis) 641 4 EXTENDED_ARG 1 642 6 UNPACK_EX 256 643 8 STORE_FAST 0 (_) 644 10 STORE_FAST 0 (_) 645 12 LOAD_CONST 0 (None) 646 14 RETURN_VALUE 647"""% (extended_arg_quick.__code__.co_firstlineno, 648 extended_arg_quick.__code__.co_firstlineno + 1,) 649 650QUICKENING_WARMUP_DELAY = 8 651 652class DisTestBase(unittest.TestCase): 653 "Common utilities for DisTests and TestDisTraceback" 654 655 def strip_addresses(self, text): 656 return re.sub(r'\b0x[0-9A-Fa-f]+\b', '0x...', text) 657 658 def find_offset_column(self, lines): 659 for line in lines: 660 if line and not line.startswith("Disassembly"): 661 break 662 else: 663 return 0, 0 664 offset = 5 665 while (line[offset] == " "): 666 offset += 1 667 if (line[offset] == ">"): 668 offset += 2 669 while (line[offset] == " "): 670 offset += 1 671 end = offset 672 while line[end] in "0123456789": 673 end += 1 674 return end-5, end 675 676 def assert_offsets_increasing(self, text, delta): 677 expected_offset = 0 678 lines = text.splitlines() 679 start, end = self.find_offset_column(lines) 680 for line in lines: 681 if not line: 682 continue 683 if line.startswith("Disassembly"): 684 expected_offset = 0 685 continue 686 if line.startswith("Exception"): 687 break 688 offset = int(line[start:end]) 689 self.assertGreaterEqual(offset, expected_offset, line) 690 expected_offset = offset + delta 691 692 def strip_offsets(self, text): 693 lines = text.splitlines(True) 694 start, end = self.find_offset_column(lines) 695 res = [] 696 lines = iter(lines) 697 for line in lines: 698 if line.startswith("Exception"): 699 res.append(line) 700 break 701 if not line or line.startswith("Disassembly"): 702 res.append(line) 703 else: 704 res.append(line[:start] + line[end:]) 705 return "".join(res) 706 707 def do_disassembly_compare(self, got, expected, with_offsets=False): 708 if not with_offsets: 709 self.assert_offsets_increasing(got, 2) 710 got = self.strip_offsets(got) 711 if got != expected: 712 got = self.strip_addresses(got) 713 self.assertEqual(got, expected) 714 715 716class DisTests(DisTestBase): 717 718 maxDiff = None 719 720 def get_disassembly(self, func, lasti=-1, wrapper=True, **kwargs): 721 # We want to test the default printing behaviour, not the file arg 722 output = io.StringIO() 723 with contextlib.redirect_stdout(output): 724 if wrapper: 725 dis.dis(func, **kwargs) 726 else: 727 dis.disassemble(func, lasti, **kwargs) 728 return output.getvalue() 729 730 def get_disassemble_as_string(self, func, lasti=-1): 731 return self.get_disassembly(func, lasti, False) 732 733 def do_disassembly_test(self, func, expected, with_offsets=False): 734 self.maxDiff = None 735 got = self.get_disassembly(func, depth=0) 736 self.do_disassembly_compare(got, expected, with_offsets) 737 738 def test_opmap(self): 739 self.assertEqual(dis.opmap["NOP"], 9) 740 self.assertIn(dis.opmap["LOAD_CONST"], dis.hasconst) 741 self.assertIn(dis.opmap["STORE_NAME"], dis.hasname) 742 743 def test_opname(self): 744 self.assertEqual(dis.opname[dis.opmap["LOAD_FAST"]], "LOAD_FAST") 745 746 def test_boundaries(self): 747 self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG) 748 self.assertEqual(dis.opmap["STORE_NAME"], dis.HAVE_ARGUMENT) 749 750 def test_widths(self): 751 long_opcodes = set(['POP_JUMP_FORWARD_IF_FALSE', 752 'POP_JUMP_FORWARD_IF_TRUE', 753 'POP_JUMP_FORWARD_IF_NOT_NONE', 754 'POP_JUMP_FORWARD_IF_NONE', 755 'POP_JUMP_BACKWARD_IF_FALSE', 756 'POP_JUMP_BACKWARD_IF_TRUE', 757 'POP_JUMP_BACKWARD_IF_NOT_NONE', 758 'POP_JUMP_BACKWARD_IF_NONE', 759 'JUMP_BACKWARD_NO_INTERRUPT', 760 ]) 761 for opcode, opname in enumerate(dis.opname): 762 if opname in long_opcodes: 763 continue 764 with self.subTest(opname=opname): 765 width = dis._OPNAME_WIDTH 766 if opcode < dis.HAVE_ARGUMENT: 767 width += 1 + dis._OPARG_WIDTH 768 self.assertLessEqual(len(opname), width) 769 770 def test_dis(self): 771 self.do_disassembly_test(_f, dis_f) 772 773 def test_bug_708901(self): 774 self.do_disassembly_test(bug708901, dis_bug708901) 775 776 def test_bug_1333982(self): 777 # This one is checking bytecodes generated for an `assert` statement, 778 # so fails if the tests are run with -O. Skip this test then. 779 if not __debug__: 780 self.skipTest('need asserts, run without -O') 781 782 self.do_disassembly_test(bug1333982, dis_bug1333982) 783 784 def test_bug_42562(self): 785 self.do_disassembly_test(bug42562, dis_bug42562) 786 787 def test_bug_45757(self): 788 # Extended arg followed by NOP 789 self.do_disassembly_test(code_bug_45757, dis_bug_45757) 790 791 def test_bug_46724(self): 792 # Test that negative operargs are handled properly 793 self.do_disassembly_test(bug46724, dis_bug46724) 794 795 def test_big_linenos(self): 796 def func(count): 797 namespace = {} 798 func = "def foo():\n " + "".join(["\n "] * count + ["spam\n"]) 799 exec(func, namespace) 800 return namespace['foo'] 801 802 # Test all small ranges 803 for i in range(1, 300): 804 expected = _BIG_LINENO_FORMAT % (i + 2) 805 self.do_disassembly_test(func(i), expected) 806 807 # Test some larger ranges too 808 for i in range(300, 1000, 10): 809 expected = _BIG_LINENO_FORMAT % (i + 2) 810 self.do_disassembly_test(func(i), expected) 811 812 for i in range(1000, 5000, 10): 813 expected = _BIG_LINENO_FORMAT2 % (i + 2) 814 self.do_disassembly_test(func(i), expected) 815 816 from test import dis_module 817 self.do_disassembly_test(dis_module, dis_module_expected_results) 818 819 def test_big_offsets(self): 820 self.maxDiff = None 821 def func(count): 822 namespace = {} 823 func = "def foo(x):\n " + ";".join(["x = x + 1"] * count) + "\n return x" 824 exec(func, namespace) 825 return namespace['foo'] 826 827 def expected(count, w): 828 s = ['''\ 829 1 %*d RESUME 0 830 831''' % (w, 0)] 832 s += ['''\ 833 %*d LOAD_FAST 0 (x) 834 %*d LOAD_CONST 1 (1) 835 %*d BINARY_OP 0 (+) 836 %*d STORE_FAST 0 (x) 837''' % (w, 10*i + 2, w, 10*i + 4, w, 10*i + 6, w, 10*i + 10) 838 for i in range(count)] 839 s += ['''\ 840 841 3 %*d LOAD_FAST 0 (x) 842 %*d RETURN_VALUE 843''' % (w, 10*count + 2, w, 10*count + 4)] 844 s[1] = ' 2' + s[1][3:] 845 return ''.join(s) 846 847 for i in range(1, 5): 848 self.do_disassembly_test(func(i), expected(i, 4), True) 849 self.do_disassembly_test(func(999), expected(999, 4), True) 850 self.do_disassembly_test(func(1000), expected(1000, 5), True) 851 852 def test_disassemble_str(self): 853 self.do_disassembly_test(expr_str, dis_expr_str) 854 self.do_disassembly_test(simple_stmt_str, dis_simple_stmt_str) 855 self.do_disassembly_test(annot_stmt_str, dis_annot_stmt_str) 856 self.do_disassembly_test(compound_stmt_str, dis_compound_stmt_str) 857 858 def test_disassemble_bytes(self): 859 self.do_disassembly_test(_f.__code__.co_code, dis_f_co_code) 860 861 def test_disassemble_class(self): 862 self.do_disassembly_test(_C, dis_c) 863 864 def test_disassemble_instance_method(self): 865 self.do_disassembly_test(_C(1).__init__, dis_c_instance_method) 866 867 def test_disassemble_instance_method_bytes(self): 868 method_bytecode = _C(1).__init__.__code__.co_code 869 self.do_disassembly_test(method_bytecode, dis_c_instance_method_bytes) 870 871 def test_disassemble_static_method(self): 872 self.do_disassembly_test(_C.sm, dis_c_static_method) 873 874 def test_disassemble_class_method(self): 875 self.do_disassembly_test(_C.cm, dis_c_class_method) 876 877 def test_disassemble_generator(self): 878 gen_func_disas = self.get_disassembly(_g) # Generator function 879 gen_disas = self.get_disassembly(_g(1)) # Generator iterator 880 self.assertEqual(gen_disas, gen_func_disas) 881 882 def test_disassemble_async_generator(self): 883 agen_func_disas = self.get_disassembly(_ag) # Async generator function 884 agen_disas = self.get_disassembly(_ag(1)) # Async generator iterator 885 self.assertEqual(agen_disas, agen_func_disas) 886 887 def test_disassemble_coroutine(self): 888 coro_func_disas = self.get_disassembly(_co) # Coroutine function 889 coro = _co(1) # Coroutine object 890 coro.close() # Avoid a RuntimeWarning (never awaited) 891 coro_disas = self.get_disassembly(coro) 892 self.assertEqual(coro_disas, coro_func_disas) 893 894 def test_disassemble_fstring(self): 895 self.do_disassembly_test(_fstring, dis_fstring) 896 897 def test_disassemble_try_finally(self): 898 self.do_disassembly_test(_tryfinally, dis_tryfinally) 899 self.do_disassembly_test(_tryfinallyconst, dis_tryfinallyconst) 900 901 def test_dis_none(self): 902 try: 903 del sys.last_traceback 904 except AttributeError: 905 pass 906 self.assertRaises(RuntimeError, dis.dis, None) 907 908 def test_dis_traceback(self): 909 self.maxDiff = None 910 try: 911 del sys.last_traceback 912 except AttributeError: 913 pass 914 915 try: 916 1/0 917 except Exception as e: 918 tb = e.__traceback__ 919 sys.last_traceback = tb 920 921 tb_dis = self.get_disassemble_as_string(tb.tb_frame.f_code, tb.tb_lasti) 922 self.do_disassembly_test(None, tb_dis, True) 923 924 def test_dis_object(self): 925 self.assertRaises(TypeError, dis.dis, object()) 926 927 def test_disassemble_recursive(self): 928 def check(expected, **kwargs): 929 dis = self.get_disassembly(_h, **kwargs) 930 dis = self.strip_addresses(dis) 931 dis = self.strip_offsets(dis) 932 self.assertEqual(dis, expected) 933 934 check(dis_nested_0, depth=0) 935 check(dis_nested_1, depth=1) 936 check(dis_nested_2, depth=2) 937 check(dis_nested_2, depth=3) 938 check(dis_nested_2, depth=None) 939 check(dis_nested_2) 940 941 @staticmethod 942 def code_quicken(f, times=QUICKENING_WARMUP_DELAY): 943 for _ in range(times): 944 f() 945 946 @cpython_only 947 def test_super_instructions(self): 948 self.code_quicken(lambda: load_test(0, 0)) 949 got = self.get_disassembly(load_test, adaptive=True) 950 self.do_disassembly_compare(got, dis_load_test_quickened_code, True) 951 952 @cpython_only 953 def test_binary_specialize(self): 954 binary_op_quicken = """\ 955 0 0 RESUME_QUICK 0 956 957 1 2 LOAD_NAME 0 (a) 958 4 LOAD_NAME 1 (b) 959 6 %s 960 10 RETURN_VALUE 961""" 962 co_int = compile('a + b', "<int>", "eval") 963 self.code_quicken(lambda: exec(co_int, {}, {'a': 1, 'b': 2})) 964 got = self.get_disassembly(co_int, adaptive=True) 965 self.do_disassembly_compare(got, binary_op_quicken % "BINARY_OP_ADD_INT 0 (+)", True) 966 967 co_unicode = compile('a + b', "<unicode>", "eval") 968 self.code_quicken(lambda: exec(co_unicode, {}, {'a': 'a', 'b': 'b'})) 969 got = self.get_disassembly(co_unicode, adaptive=True) 970 self.do_disassembly_compare(got, binary_op_quicken % "BINARY_OP_ADD_UNICODE 0 (+)", True) 971 972 binary_subscr_quicken = """\ 973 0 0 RESUME_QUICK 0 974 975 1 2 LOAD_NAME 0 (a) 976 4 LOAD_CONST 0 (0) 977 6 %s 978 16 RETURN_VALUE 979""" 980 co_list = compile('a[0]', "<list>", "eval") 981 self.code_quicken(lambda: exec(co_list, {}, {'a': [0]})) 982 got = self.get_disassembly(co_list, adaptive=True) 983 self.do_disassembly_compare(got, binary_subscr_quicken % "BINARY_SUBSCR_LIST_INT", True) 984 985 co_dict = compile('a[0]', "<dict>", "eval") 986 self.code_quicken(lambda: exec(co_dict, {}, {'a': {0: '1'}})) 987 got = self.get_disassembly(co_dict, adaptive=True) 988 self.do_disassembly_compare(got, binary_subscr_quicken % "BINARY_SUBSCR_DICT", True) 989 990 @cpython_only 991 def test_load_attr_specialize(self): 992 load_attr_quicken = """\ 993 0 0 RESUME_QUICK 0 994 995 1 2 LOAD_CONST 0 ('a') 996 4 LOAD_ATTR_SLOT 0 (__class__) 997 14 RETURN_VALUE 998""" 999 co = compile("'a'.__class__", "", "eval") 1000 self.code_quicken(lambda: exec(co, {}, {})) 1001 got = self.get_disassembly(co, adaptive=True) 1002 self.do_disassembly_compare(got, load_attr_quicken, True) 1003 1004 @cpython_only 1005 def test_call_specialize(self): 1006 call_quicken = """\ 1007 0 0 RESUME_QUICK 0 1008 1009 1 2 PUSH_NULL 1010 4 LOAD_NAME 0 (str) 1011 6 LOAD_CONST 0 (1) 1012 8 PRECALL_NO_KW_STR_1 1 1013 12 CALL_ADAPTIVE 1 1014 22 RETURN_VALUE 1015""" 1016 co = compile("str(1)", "", "eval") 1017 self.code_quicken(lambda: exec(co, {}, {})) 1018 got = self.get_disassembly(co, adaptive=True) 1019 self.do_disassembly_compare(got, call_quicken, True) 1020 1021 @cpython_only 1022 def test_loop_quicken(self): 1023 # Loop can trigger a quicken where the loop is located 1024 self.code_quicken(loop_test, 1) 1025 got = self.get_disassembly(loop_test, adaptive=True) 1026 self.do_disassembly_compare(got, dis_loop_test_quickened_code, True) 1027 1028 @cpython_only 1029 def test_extended_arg_quick(self): 1030 got = self.get_disassembly(extended_arg_quick) 1031 self.do_disassembly_compare(got, dis_extended_arg_quick_code, True) 1032 1033 def get_cached_values(self, quickened, adaptive): 1034 def f(): 1035 l = [] 1036 for i in range(42): 1037 l.append(i) 1038 if quickened: 1039 self.code_quicken(f) 1040 else: 1041 # "copy" the code to un-quicken it: 1042 f.__code__ = f.__code__.replace() 1043 for instruction in dis.get_instructions( 1044 f, show_caches=True, adaptive=adaptive 1045 ): 1046 if instruction.opname == "CACHE": 1047 yield instruction.argrepr 1048 1049 @cpython_only 1050 def test_show_caches(self): 1051 for quickened in (False, True): 1052 for adaptive in (False, True): 1053 with self.subTest(f"{quickened=}, {adaptive=}"): 1054 if quickened and adaptive: 1055 pattern = r"^(\w+: \d+)?$" 1056 else: 1057 pattern = r"^(\w+: 0)?$" 1058 caches = list(self.get_cached_values(quickened, adaptive)) 1059 for cache in caches: 1060 self.assertRegex(cache, pattern) 1061 total_caches = 25 1062 empty_caches = 8 if adaptive and quickened else total_caches 1063 self.assertEqual(caches.count(""), empty_caches) 1064 self.assertEqual(len(caches), total_caches) 1065 1066 1067class DisWithFileTests(DisTests): 1068 1069 # Run the tests again, using the file arg instead of print 1070 def get_disassembly(self, func, lasti=-1, wrapper=True, **kwargs): 1071 output = io.StringIO() 1072 if wrapper: 1073 dis.dis(func, file=output, **kwargs) 1074 else: 1075 dis.disassemble(func, lasti, file=output, **kwargs) 1076 return output.getvalue() 1077 1078 1079if dis.code_info.__doc__ is None: 1080 code_info_consts = "0: None" 1081else: 1082 code_info_consts = "0: 'Formatted details of methods, functions, or code.'" 1083 1084code_info_code_info = f"""\ 1085Name: code_info 1086Filename: (.*) 1087Argument count: 1 1088Positional-only arguments: 0 1089Kw-only arguments: 0 1090Number of locals: 1 1091Stack size: \\d+ 1092Flags: OPTIMIZED, NEWLOCALS 1093Constants: 1094 {code_info_consts} 1095Names: 1096 0: _format_code_info 1097 1: _get_code_object 1098Variable names: 1099 0: x""" 1100 1101 1102@staticmethod 1103def tricky(a, b, /, x, y, z=True, *args, c, d, e=[], **kwds): 1104 def f(c=c): 1105 print(a, b, x, y, z, c, d, e, f) 1106 yield a, b, x, y, z, c, d, e, f 1107 1108code_info_tricky = """\ 1109Name: tricky 1110Filename: (.*) 1111Argument count: 5 1112Positional-only arguments: 2 1113Kw-only arguments: 3 1114Number of locals: 10 1115Stack size: \\d+ 1116Flags: OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR 1117Constants: 1118 0: None 1119 1: <code object f at (.*), file "(.*)", line (.*)> 1120Variable names: 1121 0: a 1122 1: b 1123 2: x 1124 3: y 1125 4: z 1126 5: c 1127 6: d 1128 7: e 1129 8: args 1130 9: kwds 1131Cell variables: 1132 0: [abedfxyz] 1133 1: [abedfxyz] 1134 2: [abedfxyz] 1135 3: [abedfxyz] 1136 4: [abedfxyz] 1137 5: [abedfxyz]""" 1138# NOTE: the order of the cell variables above depends on dictionary order! 1139 1140co_tricky_nested_f = tricky.__func__.__code__.co_consts[1] 1141 1142code_info_tricky_nested_f = """\ 1143Filename: (.*) 1144Argument count: 1 1145Positional-only arguments: 0 1146Kw-only arguments: 0 1147Number of locals: 1 1148Stack size: \\d+ 1149Flags: OPTIMIZED, NEWLOCALS, NESTED 1150Constants: 1151 0: None 1152Names: 1153 0: print 1154Variable names: 1155 0: c 1156Free variables: 1157 0: [abedfxyz] 1158 1: [abedfxyz] 1159 2: [abedfxyz] 1160 3: [abedfxyz] 1161 4: [abedfxyz] 1162 5: [abedfxyz]""" 1163 1164code_info_expr_str = """\ 1165Name: <module> 1166Filename: <disassembly> 1167Argument count: 0 1168Positional-only arguments: 0 1169Kw-only arguments: 0 1170Number of locals: 0 1171Stack size: \\d+ 1172Flags: 0x0 1173Constants: 1174 0: 1 1175Names: 1176 0: x""" 1177 1178code_info_simple_stmt_str = """\ 1179Name: <module> 1180Filename: <disassembly> 1181Argument count: 0 1182Positional-only arguments: 0 1183Kw-only arguments: 0 1184Number of locals: 0 1185Stack size: \\d+ 1186Flags: 0x0 1187Constants: 1188 0: 1 1189 1: None 1190Names: 1191 0: x""" 1192 1193code_info_compound_stmt_str = """\ 1194Name: <module> 1195Filename: <disassembly> 1196Argument count: 0 1197Positional-only arguments: 0 1198Kw-only arguments: 0 1199Number of locals: 0 1200Stack size: \\d+ 1201Flags: 0x0 1202Constants: 1203 0: 0 1204 1: 1 1205Names: 1206 0: x""" 1207 1208 1209async def async_def(): 1210 await 1 1211 async for a in b: pass 1212 async with c as d: pass 1213 1214code_info_async_def = """\ 1215Name: async_def 1216Filename: (.*) 1217Argument count: 0 1218Positional-only arguments: 0 1219Kw-only arguments: 0 1220Number of locals: 2 1221Stack size: \\d+ 1222Flags: OPTIMIZED, NEWLOCALS, COROUTINE 1223Constants: 1224 0: None 1225 1: 1 1226Names: 1227 0: b 1228 1: c 1229Variable names: 1230 0: a 1231 1: d""" 1232 1233class CodeInfoTests(unittest.TestCase): 1234 test_pairs = [ 1235 (dis.code_info, code_info_code_info), 1236 (tricky, code_info_tricky), 1237 (co_tricky_nested_f, code_info_tricky_nested_f), 1238 (expr_str, code_info_expr_str), 1239 (simple_stmt_str, code_info_simple_stmt_str), 1240 (compound_stmt_str, code_info_compound_stmt_str), 1241 (async_def, code_info_async_def) 1242 ] 1243 1244 def test_code_info(self): 1245 self.maxDiff = 1000 1246 for x, expected in self.test_pairs: 1247 self.assertRegex(dis.code_info(x), expected) 1248 1249 def test_show_code(self): 1250 self.maxDiff = 1000 1251 for x, expected in self.test_pairs: 1252 with captured_stdout() as output: 1253 dis.show_code(x) 1254 self.assertRegex(output.getvalue(), expected+"\n") 1255 output = io.StringIO() 1256 dis.show_code(x, file=output) 1257 self.assertRegex(output.getvalue(), expected) 1258 1259 def test_code_info_object(self): 1260 self.assertRaises(TypeError, dis.code_info, object()) 1261 1262 def test_pretty_flags_no_flags(self): 1263 self.assertEqual(dis.pretty_flags(0), '0x0') 1264 1265 1266# Fodder for instruction introspection tests 1267# Editing any of these may require recalculating the expected output 1268def outer(a=1, b=2): 1269 def f(c=3, d=4): 1270 def inner(e=5, f=6): 1271 print(a, b, c, d, e, f) 1272 print(a, b, c, d) 1273 return inner 1274 print(a, b, '', 1, [], {}, "Hello world!") 1275 return f 1276 1277def jumpy(): 1278 # This won't actually run (but that's OK, we only disassemble it) 1279 for i in range(10): 1280 print(i) 1281 if i < 4: 1282 continue 1283 if i > 6: 1284 break 1285 else: 1286 print("I can haz else clause?") 1287 while i: 1288 print(i) 1289 i -= 1 1290 if i > 6: 1291 continue 1292 if i < 4: 1293 break 1294 else: 1295 print("Who let lolcatz into this test suite?") 1296 try: 1297 1 / 0 1298 except ZeroDivisionError: 1299 print("Here we go, here we go, here we go...") 1300 else: 1301 with i as dodgy: 1302 print("Never reach this") 1303 finally: 1304 print("OK, now we're done") 1305 1306# End fodder for opinfo generation tests 1307expected_outer_line = 1 1308_line_offset = outer.__code__.co_firstlineno - 1 1309code_object_f = outer.__code__.co_consts[3] 1310expected_f_line = code_object_f.co_firstlineno - _line_offset 1311code_object_inner = code_object_f.co_consts[3] 1312expected_inner_line = code_object_inner.co_firstlineno - _line_offset 1313expected_jumpy_line = 1 1314 1315# The following lines are useful to regenerate the expected results after 1316# either the fodder is modified or the bytecode generation changes 1317# After regeneration, update the references to code_object_f and 1318# code_object_inner before rerunning the tests 1319 1320def _stringify_instruction(instr): 1321 # Since line numbers and other offsets change a lot for these 1322 # test cases, ignore them. 1323 return str(instr._replace(positions=None)) 1324 1325def _prepare_test_cases(): 1326 _instructions = dis.get_instructions(outer, first_line=expected_outer_line) 1327 print('expected_opinfo_outer = [\n ', 1328 ',\n '.join(map(_stringify_instruction, _instructions)), ',\n]', sep='') 1329 _instructions = dis.get_instructions(outer(), first_line=expected_f_line) 1330 print('expected_opinfo_f = [\n ', 1331 ',\n '.join(map(_stringify_instruction, _instructions)), ',\n]', sep='') 1332 _instructions = dis.get_instructions(outer()(), first_line=expected_inner_line) 1333 print('expected_opinfo_inner = [\n ', 1334 ',\n '.join(map(_stringify_instruction, _instructions)), ',\n]', sep='') 1335 _instructions = dis.get_instructions(jumpy, first_line=expected_jumpy_line) 1336 print('expected_opinfo_jumpy = [\n ', 1337 ',\n '.join(map(_stringify_instruction, _instructions)), ',\n]', sep='') 1338 dis.dis(outer) 1339 1340#_prepare_test_cases() 1341 1342Instruction = dis.Instruction 1343expected_opinfo_outer = [ 1344 Instruction(opname='MAKE_CELL', opcode=135, arg=0, argval='a', argrepr='a', offset=0, starts_line=None, is_jump_target=False, positions=None), 1345 Instruction(opname='MAKE_CELL', opcode=135, arg=1, argval='b', argrepr='b', offset=2, starts_line=None, is_jump_target=False, positions=None), 1346 Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=4, starts_line=1, is_jump_target=False, positions=None), 1347 Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=(3, 4), argrepr='(3, 4)', offset=6, starts_line=2, is_jump_target=False, positions=None), 1348 Instruction(opname='LOAD_CLOSURE', opcode=136, arg=0, argval='a', argrepr='a', offset=8, starts_line=None, is_jump_target=False, positions=None), 1349 Instruction(opname='LOAD_CLOSURE', opcode=136, arg=1, argval='b', argrepr='b', offset=10, starts_line=None, is_jump_target=False, positions=None), 1350 Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=12, starts_line=None, is_jump_target=False, positions=None), 1351 Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_f, argrepr=repr(code_object_f), offset=14, starts_line=None, is_jump_target=False, positions=None), 1352 Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=16, starts_line=None, is_jump_target=False, positions=None), 1353 Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=18, starts_line=None, is_jump_target=False, positions=None), 1354 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='NULL + print', offset=20, starts_line=7, is_jump_target=False, positions=None), 1355 Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='a', argrepr='a', offset=32, starts_line=None, is_jump_target=False, positions=None), 1356 Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='b', argrepr='b', offset=34, starts_line=None, is_jump_target=False, positions=None), 1357 Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='', argrepr="''", offset=36, starts_line=None, is_jump_target=False, positions=None), 1358 Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=38, starts_line=None, is_jump_target=False, positions=None), 1359 Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None), 1360 Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=42, starts_line=None, is_jump_target=False, positions=None), 1361 Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Hello world!', argrepr="'Hello world!'", offset=44, starts_line=None, is_jump_target=False, positions=None), 1362 Instruction(opname='PRECALL', opcode=166, arg=7, argval=7, argrepr='', offset=46, starts_line=None, is_jump_target=False, positions=None), 1363 Instruction(opname='CALL', opcode=171, arg=7, argval=7, argrepr='', offset=50, starts_line=None, is_jump_target=False, positions=None), 1364 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=60, starts_line=None, is_jump_target=False, positions=None), 1365 Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=62, starts_line=8, is_jump_target=False, positions=None), 1366 Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=64, starts_line=None, is_jump_target=False, positions=None), 1367] 1368 1369expected_opinfo_f = [ 1370 Instruction(opname='COPY_FREE_VARS', opcode=149, arg=2, argval=2, argrepr='', offset=0, starts_line=None, is_jump_target=False, positions=None), 1371 Instruction(opname='MAKE_CELL', opcode=135, arg=0, argval='c', argrepr='c', offset=2, starts_line=None, is_jump_target=False, positions=None), 1372 Instruction(opname='MAKE_CELL', opcode=135, arg=1, argval='d', argrepr='d', offset=4, starts_line=None, is_jump_target=False, positions=None), 1373 Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=6, starts_line=2, is_jump_target=False, positions=None), 1374 Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval=(5, 6), argrepr='(5, 6)', offset=8, starts_line=3, is_jump_target=False, positions=None), 1375 Instruction(opname='LOAD_CLOSURE', opcode=136, arg=3, argval='a', argrepr='a', offset=10, starts_line=None, is_jump_target=False, positions=None), 1376 Instruction(opname='LOAD_CLOSURE', opcode=136, arg=4, argval='b', argrepr='b', offset=12, starts_line=None, is_jump_target=False, positions=None), 1377 Instruction(opname='LOAD_CLOSURE', opcode=136, arg=0, argval='c', argrepr='c', offset=14, starts_line=None, is_jump_target=False, positions=None), 1378 Instruction(opname='LOAD_CLOSURE', opcode=136, arg=1, argval='d', argrepr='d', offset=16, starts_line=None, is_jump_target=False, positions=None), 1379 Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=18, starts_line=None, is_jump_target=False, positions=None), 1380 Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_inner, argrepr=repr(code_object_inner), offset=20, starts_line=None, is_jump_target=False, positions=None), 1381 Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=22, starts_line=None, is_jump_target=False, positions=None), 1382 Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=24, starts_line=None, is_jump_target=False, positions=None), 1383 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='NULL + print', offset=26, starts_line=5, is_jump_target=False, positions=None), 1384 Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='a', argrepr='a', offset=38, starts_line=None, is_jump_target=False, positions=None), 1385 Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='b', argrepr='b', offset=40, starts_line=None, is_jump_target=False, positions=None), 1386 Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=42, starts_line=None, is_jump_target=False, positions=None), 1387 Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=44, starts_line=None, is_jump_target=False, positions=None), 1388 Instruction(opname='PRECALL', opcode=166, arg=4, argval=4, argrepr='', offset=46, starts_line=None, is_jump_target=False, positions=None), 1389 Instruction(opname='CALL', opcode=171, arg=4, argval=4, argrepr='', offset=50, starts_line=None, is_jump_target=False, positions=None), 1390 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=60, starts_line=None, is_jump_target=False, positions=None), 1391 Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=62, starts_line=6, is_jump_target=False, positions=None), 1392 Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=64, starts_line=None, is_jump_target=False, positions=None), 1393] 1394 1395expected_opinfo_inner = [ 1396 Instruction(opname='COPY_FREE_VARS', opcode=149, arg=4, argval=4, argrepr='', offset=0, starts_line=None, is_jump_target=False, positions=None), 1397 Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=2, starts_line=3, is_jump_target=False, positions=None), 1398 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='NULL + print', offset=4, starts_line=4, is_jump_target=False, positions=None), 1399 Instruction(opname='LOAD_DEREF', opcode=137, arg=2, argval='a', argrepr='a', offset=16, starts_line=None, is_jump_target=False, positions=None), 1400 Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='b', argrepr='b', offset=18, starts_line=None, is_jump_target=False, positions=None), 1401 Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='c', argrepr='c', offset=20, starts_line=None, is_jump_target=False, positions=None), 1402 Instruction(opname='LOAD_DEREF', opcode=137, arg=5, argval='d', argrepr='d', offset=22, starts_line=None, is_jump_target=False, positions=None), 1403 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=24, starts_line=None, is_jump_target=False, positions=None), 1404 Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=26, starts_line=None, is_jump_target=False, positions=None), 1405 Instruction(opname='PRECALL', opcode=166, arg=6, argval=6, argrepr='', offset=28, starts_line=None, is_jump_target=False, positions=None), 1406 Instruction(opname='CALL', opcode=171, arg=6, argval=6, argrepr='', offset=32, starts_line=None, is_jump_target=False, positions=None), 1407 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=42, starts_line=None, is_jump_target=False, positions=None), 1408 Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=44, starts_line=None, is_jump_target=False, positions=None), 1409 Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=46, starts_line=None, is_jump_target=False, positions=None), 1410] 1411 1412expected_opinfo_jumpy = [ 1413 Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=0, starts_line=1, is_jump_target=False, positions=None), 1414 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='range', argrepr='NULL + range', offset=2, starts_line=3, is_jump_target=False, positions=None), 1415 Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=14, starts_line=None, is_jump_target=False, positions=None), 1416 Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=16, starts_line=None, is_jump_target=False, positions=None), 1417 Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=20, starts_line=None, is_jump_target=False, positions=None), 1418 Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=30, starts_line=None, is_jump_target=False, positions=None), 1419 Instruction(opname='FOR_ITER', opcode=93, arg=32, argval=98, argrepr='to 98', offset=32, starts_line=None, is_jump_target=True, positions=None), 1420 Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=34, starts_line=None, is_jump_target=False, positions=None), 1421 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=36, starts_line=4, is_jump_target=False, positions=None), 1422 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=48, starts_line=None, is_jump_target=False, positions=None), 1423 Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=50, starts_line=None, is_jump_target=False, positions=None), 1424 Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=54, starts_line=None, is_jump_target=False, positions=None), 1425 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=64, starts_line=None, is_jump_target=False, positions=None), 1426 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=66, starts_line=5, is_jump_target=False, positions=None), 1427 Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=68, starts_line=None, is_jump_target=False, positions=None), 1428 Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=70, starts_line=None, is_jump_target=False, positions=None), 1429 Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=1, argval=80, argrepr='to 80', offset=76, starts_line=None, is_jump_target=False, positions=None), 1430 Instruction(opname='JUMP_BACKWARD', opcode=140, arg=24, argval=32, argrepr='to 32', offset=78, starts_line=6, is_jump_target=False, positions=None), 1431 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=80, starts_line=7, is_jump_target=True, positions=None), 1432 Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=82, starts_line=None, is_jump_target=False, positions=None), 1433 Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=84, starts_line=None, is_jump_target=False, positions=None), 1434 Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=2, argval=96, argrepr='to 96', offset=90, starts_line=None, is_jump_target=False, positions=None), 1435 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=92, starts_line=8, is_jump_target=False, positions=None), 1436 Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=128, argrepr='to 128', offset=94, starts_line=None, is_jump_target=False, positions=None), 1437 Instruction(opname='JUMP_BACKWARD', opcode=140, arg=33, argval=32, argrepr='to 32', offset=96, starts_line=7, is_jump_target=True, positions=None), 1438 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=98, starts_line=10, is_jump_target=True, positions=None), 1439 Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=110, starts_line=None, is_jump_target=False, positions=None), 1440 Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=112, starts_line=None, is_jump_target=False, positions=None), 1441 Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=116, starts_line=None, is_jump_target=False, positions=None), 1442 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=126, starts_line=None, is_jump_target=False, positions=None), 1443 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=128, starts_line=11, is_jump_target=True, positions=None), 1444 Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=36, argval=204, argrepr='to 204', offset=130, starts_line=None, is_jump_target=False, positions=None), 1445 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=132, starts_line=12, is_jump_target=True, positions=None), 1446 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=144, starts_line=None, is_jump_target=False, positions=None), 1447 Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=146, starts_line=None, is_jump_target=False, positions=None), 1448 Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=150, starts_line=None, is_jump_target=False, positions=None), 1449 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=160, starts_line=None, is_jump_target=False, positions=None), 1450 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=162, starts_line=13, is_jump_target=False, positions=None), 1451 Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=164, starts_line=None, is_jump_target=False, positions=None), 1452 Instruction(opname='BINARY_OP', opcode=122, arg=23, argval=23, argrepr='-=', offset=166, starts_line=None, is_jump_target=False, positions=None), 1453 Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=170, starts_line=None, is_jump_target=False, positions=None), 1454 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=172, starts_line=14, is_jump_target=False, positions=None), 1455 Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=174, starts_line=None, is_jump_target=False, positions=None), 1456 Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=176, starts_line=None, is_jump_target=False, positions=None), 1457 Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=1, argval=186, argrepr='to 186', offset=182, starts_line=None, is_jump_target=False, positions=None), 1458 Instruction(opname='JUMP_BACKWARD', opcode=140, arg=29, argval=128, argrepr='to 128', offset=184, starts_line=15, is_jump_target=False, positions=None), 1459 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=186, starts_line=16, is_jump_target=True, positions=None), 1460 Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=188, starts_line=None, is_jump_target=False, positions=None), 1461 Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=190, starts_line=None, is_jump_target=False, positions=None), 1462 Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=1, argval=200, argrepr='to 200', offset=196, starts_line=None, is_jump_target=False, positions=None), 1463 Instruction(opname='JUMP_FORWARD', opcode=110, arg=17, argval=234, argrepr='to 234', offset=198, starts_line=17, is_jump_target=False, positions=None), 1464 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=200, starts_line=11, is_jump_target=True, positions=None), 1465 Instruction(opname='POP_JUMP_BACKWARD_IF_TRUE', opcode=176, arg=36, argval=132, argrepr='to 132', offset=202, starts_line=None, is_jump_target=False, positions=None), 1466 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=204, starts_line=19, is_jump_target=True, positions=None), 1467 Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=216, starts_line=None, is_jump_target=False, positions=None), 1468 Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=218, starts_line=None, is_jump_target=False, positions=None), 1469 Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=222, starts_line=None, is_jump_target=False, positions=None), 1470 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=232, starts_line=None, is_jump_target=False, positions=None), 1471 Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=234, starts_line=20, is_jump_target=True, positions=None), 1472 Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=236, starts_line=21, is_jump_target=False, positions=None), 1473 Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=238, starts_line=None, is_jump_target=False, positions=None), 1474 Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=240, starts_line=None, is_jump_target=False, positions=None), 1475 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=244, starts_line=None, is_jump_target=False, positions=None), 1476 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=246, starts_line=25, is_jump_target=False, positions=None), 1477 Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=248, starts_line=None, is_jump_target=False, positions=None), 1478 Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=250, starts_line=None, is_jump_target=False, positions=None), 1479 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=252, starts_line=26, is_jump_target=False, positions=None), 1480 Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=264, starts_line=None, is_jump_target=False, positions=None), 1481 Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=266, starts_line=None, is_jump_target=False, positions=None), 1482 Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=270, starts_line=None, is_jump_target=False, positions=None), 1483 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=280, starts_line=None, is_jump_target=False, positions=None), 1484 Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=282, starts_line=25, is_jump_target=False, positions=None), 1485 Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=284, starts_line=None, is_jump_target=False, positions=None), 1486 Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=286, starts_line=None, is_jump_target=False, positions=None), 1487 Instruction(opname='PRECALL', opcode=166, arg=2, argval=2, argrepr='', offset=288, starts_line=None, is_jump_target=False, positions=None), 1488 Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=292, starts_line=None, is_jump_target=False, positions=None), 1489 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=302, starts_line=None, is_jump_target=False, positions=None), 1490 Instruction(opname='JUMP_FORWARD', opcode=110, arg=11, argval=328, argrepr='to 328', offset=304, starts_line=None, is_jump_target=False, positions=None), 1491 Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=306, starts_line=None, is_jump_target=False, positions=None), 1492 Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=308, starts_line=None, is_jump_target=False, positions=None), 1493 Instruction(opname='POP_JUMP_FORWARD_IF_TRUE', opcode=115, arg=4, argval=320, argrepr='to 320', offset=310, starts_line=None, is_jump_target=False, positions=None), 1494 Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=312, starts_line=None, is_jump_target=False, positions=None), 1495 Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=314, starts_line=None, is_jump_target=False, positions=None), 1496 Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=316, starts_line=None, is_jump_target=False, positions=None), 1497 Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=318, starts_line=None, is_jump_target=False, positions=None), 1498 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=320, starts_line=None, is_jump_target=True, positions=None), 1499 Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=322, starts_line=None, is_jump_target=False, positions=None), 1500 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=324, starts_line=None, is_jump_target=False, positions=None), 1501 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=326, starts_line=None, is_jump_target=False, positions=None), 1502 Instruction(opname='JUMP_FORWARD', opcode=110, arg=31, argval=392, argrepr='to 392', offset=328, starts_line=None, is_jump_target=True, positions=None), 1503 Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=330, starts_line=None, is_jump_target=False, positions=None), 1504 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=332, starts_line=22, is_jump_target=False, positions=None), 1505 Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=344, starts_line=None, is_jump_target=False, positions=None), 1506 Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=18, argval=384, argrepr='to 384', offset=346, starts_line=None, is_jump_target=False, positions=None), 1507 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=348, starts_line=None, is_jump_target=False, positions=None), 1508 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=350, starts_line=23, is_jump_target=False, positions=None), 1509 Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=362, starts_line=None, is_jump_target=False, positions=None), 1510 Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=364, starts_line=None, is_jump_target=False, positions=None), 1511 Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=368, starts_line=None, is_jump_target=False, positions=None), 1512 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=378, starts_line=None, is_jump_target=False, positions=None), 1513 Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=380, starts_line=None, is_jump_target=False, positions=None), 1514 Instruction(opname='JUMP_FORWARD', opcode=110, arg=4, argval=392, argrepr='to 392', offset=382, starts_line=None, is_jump_target=False, positions=None), 1515 Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=384, starts_line=22, is_jump_target=True, positions=None), 1516 Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=386, starts_line=None, is_jump_target=False, positions=None), 1517 Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=388, starts_line=None, is_jump_target=False, positions=None), 1518 Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=390, starts_line=None, is_jump_target=False, positions=None), 1519 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=392, starts_line=28, is_jump_target=True, positions=None), 1520 Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=404, starts_line=None, is_jump_target=False, positions=None), 1521 Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=406, starts_line=None, is_jump_target=False, positions=None), 1522 Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=410, starts_line=None, is_jump_target=False, positions=None), 1523 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=420, starts_line=None, is_jump_target=False, positions=None), 1524 Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=422, starts_line=None, is_jump_target=False, positions=None), 1525 Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=424, starts_line=None, is_jump_target=False, positions=None), 1526 Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=426, starts_line=None, is_jump_target=False, positions=None), 1527 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=428, starts_line=None, is_jump_target=False, positions=None), 1528 Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=440, starts_line=None, is_jump_target=False, positions=None), 1529 Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=442, starts_line=None, is_jump_target=False, positions=None), 1530 Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=446, starts_line=None, is_jump_target=False, positions=None), 1531 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=456, starts_line=None, is_jump_target=False, positions=None), 1532 Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=458, starts_line=None, is_jump_target=False, positions=None), 1533 Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=460, starts_line=None, is_jump_target=False, positions=None), 1534 Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=462, starts_line=None, is_jump_target=False, positions=None), 1535 Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=464, starts_line=None, is_jump_target=False, positions=None), 1536] 1537 1538# One last piece of inspect fodder to check the default line number handling 1539def simple(): pass 1540expected_opinfo_simple = [ 1541 Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=0, starts_line=simple.__code__.co_firstlineno, is_jump_target=False, positions=None), 1542 Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=2, starts_line=None, is_jump_target=False), 1543 Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=4, starts_line=None, is_jump_target=False) 1544] 1545 1546 1547class InstructionTestCase(BytecodeTestCase): 1548 1549 def assertInstructionsEqual(self, instrs_1, instrs_2, /): 1550 instrs_1 = [instr_1._replace(positions=None) for instr_1 in instrs_1] 1551 instrs_2 = [instr_2._replace(positions=None) for instr_2 in instrs_2] 1552 self.assertEqual(instrs_1, instrs_2) 1553 1554class InstructionTests(InstructionTestCase): 1555 1556 def __init__(self, *args): 1557 super().__init__(*args) 1558 self.maxDiff = None 1559 1560 def test_default_first_line(self): 1561 actual = dis.get_instructions(simple) 1562 self.assertInstructionsEqual(list(actual), expected_opinfo_simple) 1563 1564 def test_first_line_set_to_None(self): 1565 actual = dis.get_instructions(simple, first_line=None) 1566 self.assertInstructionsEqual(list(actual), expected_opinfo_simple) 1567 1568 def test_outer(self): 1569 actual = dis.get_instructions(outer, first_line=expected_outer_line) 1570 self.assertInstructionsEqual(list(actual), expected_opinfo_outer) 1571 1572 def test_nested(self): 1573 with captured_stdout(): 1574 f = outer() 1575 actual = dis.get_instructions(f, first_line=expected_f_line) 1576 self.assertInstructionsEqual(list(actual), expected_opinfo_f) 1577 1578 def test_doubly_nested(self): 1579 with captured_stdout(): 1580 inner = outer()() 1581 actual = dis.get_instructions(inner, first_line=expected_inner_line) 1582 self.assertInstructionsEqual(list(actual), expected_opinfo_inner) 1583 1584 def test_jumpy(self): 1585 actual = dis.get_instructions(jumpy, first_line=expected_jumpy_line) 1586 self.assertInstructionsEqual(list(actual), expected_opinfo_jumpy) 1587 1588 @requires_debug_ranges() 1589 def test_co_positions(self): 1590 code = compile('f(\n x, y, z\n)', '<test>', 'exec') 1591 positions = [ 1592 instr.positions 1593 for instr in dis.get_instructions(code) 1594 ] 1595 expected = [ 1596 (0, 1, 0, 0), 1597 (1, 1, 0, 1), 1598 (1, 1, 0, 1), 1599 (2, 2, 2, 3), 1600 (2, 2, 5, 6), 1601 (2, 2, 8, 9), 1602 (1, 3, 0, 1), 1603 (1, 3, 0, 1), 1604 (1, 3, 0, 1), 1605 (1, 3, 0, 1), 1606 (1, 3, 0, 1) 1607 ] 1608 self.assertEqual(positions, expected) 1609 1610 named_positions = [ 1611 (pos.lineno, pos.end_lineno, pos.col_offset, pos.end_col_offset) 1612 for pos in positions 1613 ] 1614 self.assertEqual(named_positions, expected) 1615 1616 @requires_debug_ranges() 1617 def test_co_positions_missing_info(self): 1618 code = compile('x, y, z', '<test>', 'exec') 1619 code_without_location_table = code.replace(co_linetable=b'') 1620 actual = dis.get_instructions(code_without_location_table) 1621 for instruction in actual: 1622 with self.subTest(instruction=instruction): 1623 positions = instruction.positions 1624 self.assertEqual(len(positions), 4) 1625 if instruction.opname == "RESUME": 1626 continue 1627 self.assertIsNone(positions.lineno) 1628 self.assertIsNone(positions.end_lineno) 1629 self.assertIsNone(positions.col_offset) 1630 self.assertIsNone(positions.end_col_offset) 1631 1632 @requires_debug_ranges() 1633 def test_co_positions_with_lots_of_caches(self): 1634 def roots(a, b, c): 1635 d = b**2 - 4 * a * c 1636 yield (-b - cmath.sqrt(d)) / (2 * a) 1637 if d: 1638 yield (-b + cmath.sqrt(d)) / (2 * a) 1639 code = roots.__code__ 1640 ops = code.co_code[::2] 1641 cache_opcode = opcode.opmap["CACHE"] 1642 caches = sum(op == cache_opcode for op in ops) 1643 non_caches = len(ops) - caches 1644 # Make sure we have "lots of caches". If not, roots should be changed: 1645 assert 1 / 3 <= caches / non_caches, "this test needs more caches!" 1646 for show_caches in (False, True): 1647 for adaptive in (False, True): 1648 with self.subTest(f"{adaptive=}, {show_caches=}"): 1649 co_positions = [ 1650 positions 1651 for op, positions in zip(ops, code.co_positions(), strict=True) 1652 if show_caches or op != cache_opcode 1653 ] 1654 dis_positions = [ 1655 instruction.positions 1656 for instruction in dis.get_instructions( 1657 code, adaptive=adaptive, show_caches=show_caches 1658 ) 1659 ] 1660 self.assertEqual(co_positions, dis_positions) 1661 1662# get_instructions has its own tests above, so can rely on it to validate 1663# the object oriented API 1664class BytecodeTests(InstructionTestCase, DisTestBase): 1665 1666 def test_instantiation(self): 1667 # Test with function, method, code string and code object 1668 for obj in [_f, _C(1).__init__, "a=1", _f.__code__]: 1669 with self.subTest(obj=obj): 1670 b = dis.Bytecode(obj) 1671 self.assertIsInstance(b.codeobj, types.CodeType) 1672 1673 self.assertRaises(TypeError, dis.Bytecode, object()) 1674 1675 def test_iteration(self): 1676 for obj in [_f, _C(1).__init__, "a=1", _f.__code__]: 1677 with self.subTest(obj=obj): 1678 via_object = list(dis.Bytecode(obj)) 1679 via_generator = list(dis.get_instructions(obj)) 1680 self.assertInstructionsEqual(via_object, via_generator) 1681 1682 def test_explicit_first_line(self): 1683 actual = dis.Bytecode(outer, first_line=expected_outer_line) 1684 self.assertInstructionsEqual(list(actual), expected_opinfo_outer) 1685 1686 def test_source_line_in_disassembly(self): 1687 # Use the line in the source code 1688 actual = dis.Bytecode(simple).dis() 1689 actual = actual.strip().partition(" ")[0] # extract the line no 1690 expected = str(simple.__code__.co_firstlineno) 1691 self.assertEqual(actual, expected) 1692 # Use an explicit first line number 1693 actual = dis.Bytecode(simple, first_line=350).dis() 1694 actual = actual.strip().partition(" ")[0] # extract the line no 1695 self.assertEqual(actual, "350") 1696 1697 def test_info(self): 1698 self.maxDiff = 1000 1699 for x, expected in CodeInfoTests.test_pairs: 1700 b = dis.Bytecode(x) 1701 self.assertRegex(b.info(), expected) 1702 1703 def test_disassembled(self): 1704 actual = dis.Bytecode(_f).dis() 1705 self.do_disassembly_compare(actual, dis_f) 1706 1707 def test_from_traceback(self): 1708 tb = get_tb() 1709 b = dis.Bytecode.from_traceback(tb) 1710 while tb.tb_next: tb = tb.tb_next 1711 1712 self.assertEqual(b.current_offset, tb.tb_lasti) 1713 1714 def test_from_traceback_dis(self): 1715 self.maxDiff = None 1716 tb = get_tb() 1717 b = dis.Bytecode.from_traceback(tb) 1718 self.assertEqual(self.strip_offsets(b.dis()), dis_traceback) 1719 1720 @requires_debug_ranges() 1721 def test_bytecode_co_positions(self): 1722 bytecode = dis.Bytecode("a=1") 1723 for instr, positions in zip(bytecode, bytecode.codeobj.co_positions()): 1724 assert instr.positions == positions 1725 1726class TestBytecodeTestCase(BytecodeTestCase): 1727 def test_assert_not_in_with_op_not_in_bytecode(self): 1728 code = compile("a = 1", "<string>", "exec") 1729 self.assertInBytecode(code, "LOAD_CONST", 1) 1730 self.assertNotInBytecode(code, "LOAD_NAME") 1731 self.assertNotInBytecode(code, "LOAD_NAME", "a") 1732 1733 def test_assert_not_in_with_arg_not_in_bytecode(self): 1734 code = compile("a = 1", "<string>", "exec") 1735 self.assertInBytecode(code, "LOAD_CONST") 1736 self.assertInBytecode(code, "LOAD_CONST", 1) 1737 self.assertNotInBytecode(code, "LOAD_CONST", 2) 1738 1739 def test_assert_not_in_with_arg_in_bytecode(self): 1740 code = compile("a = 1", "<string>", "exec") 1741 with self.assertRaises(AssertionError): 1742 self.assertNotInBytecode(code, "LOAD_CONST", 1) 1743 1744class TestFinderMethods(unittest.TestCase): 1745 def test__find_imports(self): 1746 cases = [ 1747 ("import a.b.c", ('a.b.c', 0, None)), 1748 ("from a.b import c", ('a.b', 0, ('c',))), 1749 ("from a.b import c as d", ('a.b', 0, ('c',))), 1750 ("from a.b import *", ('a.b', 0, ('*',))), 1751 ("from ...a.b import c as d", ('a.b', 3, ('c',))), 1752 ("from ..a.b import c as d, e as f", ('a.b', 2, ('c', 'e'))), 1753 ("from ..a.b import *", ('a.b', 2, ('*',))), 1754 ] 1755 for src, expected in cases: 1756 with self.subTest(src=src): 1757 code = compile(src, "<string>", "exec") 1758 res = tuple(dis._find_imports(code)) 1759 self.assertEqual(len(res), 1) 1760 self.assertEqual(res[0], expected) 1761 1762 def test__find_store_names(self): 1763 cases = [ 1764 ("x+y", ()), 1765 ("x=y=1", ('x', 'y')), 1766 ("x+=y", ('x',)), 1767 ("global x\nx=y=1", ('x', 'y')), 1768 ("global x\nz=x", ('z',)), 1769 ] 1770 for src, expected in cases: 1771 with self.subTest(src=src): 1772 code = compile(src, "<string>", "exec") 1773 res = tuple(dis._find_store_names(code)) 1774 self.assertEqual(res, expected) 1775 1776 def test_findlabels(self): 1777 labels = dis.findlabels(jumpy.__code__.co_code) 1778 jumps = [ 1779 instr.offset 1780 for instr in expected_opinfo_jumpy 1781 if instr.is_jump_target 1782 ] 1783 1784 self.assertEqual(sorted(labels), sorted(jumps)) 1785 1786 1787class TestDisTraceback(DisTestBase): 1788 def setUp(self) -> None: 1789 try: # We need to clean up existing tracebacks 1790 del sys.last_traceback 1791 except AttributeError: 1792 pass 1793 return super().setUp() 1794 1795 def get_disassembly(self, tb): 1796 output = io.StringIO() 1797 with contextlib.redirect_stdout(output): 1798 dis.distb(tb) 1799 return output.getvalue() 1800 1801 def test_distb_empty(self): 1802 with self.assertRaises(RuntimeError): 1803 dis.distb() 1804 1805 def test_distb_last_traceback(self): 1806 self.maxDiff = None 1807 # We need to have an existing last traceback in `sys`: 1808 tb = get_tb() 1809 sys.last_traceback = tb 1810 1811 self.do_disassembly_compare(self.get_disassembly(None), dis_traceback) 1812 1813 def test_distb_explicit_arg(self): 1814 self.maxDiff = None 1815 tb = get_tb() 1816 1817 self.do_disassembly_compare(self.get_disassembly(tb), dis_traceback) 1818 1819 1820class TestDisTracebackWithFile(TestDisTraceback): 1821 # Run the `distb` tests again, using the file arg instead of print 1822 def get_disassembly(self, tb): 1823 output = io.StringIO() 1824 with contextlib.redirect_stdout(output): 1825 dis.distb(tb, file=output) 1826 return output.getvalue() 1827 1828 1829if __name__ == "__main__": 1830 unittest.main() 1831