1# Minimal tests for dis module 2 3import contextlib 4import dis 5import functools 6import io 7import re 8import sys 9import types 10import unittest 11from test.support import (captured_stdout, requires_debug_ranges, 12 requires_specialization, cpython_only) 13from test.support.bytecode_helper import BytecodeTestCase 14 15import opcode 16 17CACHE = dis.opmap["CACHE"] 18 19def get_tb(): 20 def _error(): 21 try: 22 1 / 0 23 except Exception as e: 24 tb = e.__traceback__ 25 return tb 26 27 tb = _error() 28 while tb.tb_next: 29 tb = tb.tb_next 30 return tb 31 32TRACEBACK_CODE = get_tb().tb_frame.f_code 33 34class _C: 35 def __init__(self, x): 36 self.x = x == 1 37 38 @staticmethod 39 def sm(x): 40 x = x == 1 41 42 @classmethod 43 def cm(cls, x): 44 cls.x = x == 1 45 46dis_c_instance_method = """\ 47%3d RESUME 0 48 49%3d LOAD_FAST 1 (x) 50 LOAD_CONST 1 (1) 51 COMPARE_OP 72 (==) 52 LOAD_FAST 0 (self) 53 STORE_ATTR 0 (x) 54 RETURN_CONST 0 (None) 55""" % (_C.__init__.__code__.co_firstlineno, _C.__init__.__code__.co_firstlineno + 1,) 56 57dis_c_instance_method_bytes = """\ 58 RESUME 0 59 LOAD_FAST 1 60 LOAD_CONST 1 61 COMPARE_OP 72 (==) 62 LOAD_FAST 0 63 STORE_ATTR 0 64 RETURN_CONST 0 65""" 66 67dis_c_class_method = """\ 68%3d RESUME 0 69 70%3d LOAD_FAST 1 (x) 71 LOAD_CONST 1 (1) 72 COMPARE_OP 72 (==) 73 LOAD_FAST 0 (cls) 74 STORE_ATTR 0 (x) 75 RETURN_CONST 0 (None) 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 72 (==) 84 STORE_FAST 0 (x) 85 RETURN_CONST 0 (None) 86""" % (_C.sm.__code__.co_firstlineno, _C.sm.__code__.co_firstlineno + 2,) 87 88# Class disassembling info has an extra newline at end. 89dis_c = """\ 90Disassembly of %s: 91%s 92Disassembly of %s: 93%s 94Disassembly of %s: 95%s 96""" % (_C.__init__.__name__, dis_c_instance_method, 97 _C.cm.__name__, dis_c_class_method, 98 _C.sm.__name__, dis_c_static_method) 99 100def _f(a): 101 print(a) 102 return 1 103 104dis_f = """\ 105%3d RESUME 0 106 107%3d LOAD_GLOBAL 1 (print + NULL) 108 LOAD_FAST 0 (a) 109 CALL 1 110 POP_TOP 111 112%3d RETURN_CONST 1 (1) 113""" % (_f.__code__.co_firstlineno, 114 _f.__code__.co_firstlineno + 1, 115 _f.__code__.co_firstlineno + 2) 116 117dis_f_with_offsets = """\ 118%3d 0 RESUME 0 119 120%3d 2 LOAD_GLOBAL 1 (print + NULL) 121 12 LOAD_FAST 0 (a) 122 14 CALL 1 123 22 POP_TOP 124 125%3d 24 RETURN_CONST 1 (1) 126""" % (_f.__code__.co_firstlineno, 127 _f.__code__.co_firstlineno + 1, 128 _f.__code__.co_firstlineno + 2) 129 130 131dis_f_co_code = """\ 132 RESUME 0 133 LOAD_GLOBAL 1 134 LOAD_FAST 0 135 CALL 1 136 POP_TOP 137 RETURN_CONST 1 138""" 139 140def bug708901(): 141 for res in range(1, 142 10): 143 pass 144 145dis_bug708901 = """\ 146%3d RESUME 0 147 148%3d LOAD_GLOBAL 1 (range + NULL) 149 LOAD_CONST 1 (1) 150 151%3d LOAD_CONST 2 (10) 152 153%3d CALL 2 154 GET_ITER 155 L1: FOR_ITER 3 (to L2) 156 STORE_FAST 0 (res) 157 158%3d JUMP_BACKWARD 5 (to L1) 159 160%3d L2: END_FOR 161 POP_TOP 162 RETURN_CONST 0 (None) 163""" % (bug708901.__code__.co_firstlineno, 164 bug708901.__code__.co_firstlineno + 1, 165 bug708901.__code__.co_firstlineno + 2, 166 bug708901.__code__.co_firstlineno + 1, 167 bug708901.__code__.co_firstlineno + 3, 168 bug708901.__code__.co_firstlineno + 1) 169 170 171def bug1333982(x=[]): 172 assert 0, ((s for s in x) + 173 1) 174 pass 175 176dis_bug1333982 = """\ 177%3d RESUME 0 178 179%3d LOAD_ASSERTION_ERROR 180 LOAD_CONST 1 (<code object <genexpr> at 0x..., file "%s", line %d>) 181 MAKE_FUNCTION 182 LOAD_FAST 0 (x) 183 GET_ITER 184 CALL 0 185 186%3d LOAD_CONST 2 (1) 187 188%3d BINARY_OP 0 (+) 189 CALL 0 190 RAISE_VARARGS 1 191""" % (bug1333982.__code__.co_firstlineno, 192 bug1333982.__code__.co_firstlineno + 1, 193 __file__, 194 bug1333982.__code__.co_firstlineno + 1, 195 bug1333982.__code__.co_firstlineno + 2, 196 bug1333982.__code__.co_firstlineno + 1) 197 198 199def bug42562(): 200 pass 201 202 203# Set line number for 'pass' to None 204bug42562.__code__ = bug42562.__code__.replace(co_linetable=b'\xf8') 205 206 207dis_bug42562 = """\ 208 RESUME 0 209 RETURN_CONST 0 (None) 210""" 211 212# Extended arg followed by NOP 213code_bug_45757 = bytes([ 214 opcode.opmap['EXTENDED_ARG'], 0x01, # EXTENDED_ARG 0x01 215 opcode.opmap['NOP'], 0xFF, # NOP 0xFF 216 opcode.opmap['EXTENDED_ARG'], 0x01, # EXTENDED_ARG 0x01 217 opcode.opmap['LOAD_CONST'], 0x29, # LOAD_CONST 0x29 218 opcode.opmap['RETURN_VALUE'], 0x00, # RETURN_VALUE 0x00 219 ]) 220 221dis_bug_45757 = """\ 222 EXTENDED_ARG 1 223 NOP 224 EXTENDED_ARG 1 225 LOAD_CONST 297 226 RETURN_VALUE 227""" 228 229# [255, 255, 255, 252] is -4 in a 4 byte signed integer 230bug46724 = bytes([ 231 opcode.EXTENDED_ARG, 255, 232 opcode.EXTENDED_ARG, 255, 233 opcode.EXTENDED_ARG, 255, 234 opcode.opmap['JUMP_FORWARD'], 252, 235]) 236 237 238dis_bug46724 = """\ 239 L1: EXTENDED_ARG 255 240 EXTENDED_ARG 65535 241 EXTENDED_ARG 16777215 242 JUMP_FORWARD -4 (to L1) 243""" 244 245def func_w_kwargs(a, b, **c): 246 pass 247 248def wrap_func_w_kwargs(): 249 func_w_kwargs(1, 2, c=5) 250 251dis_kw_names = """\ 252%3d RESUME 0 253 254%3d LOAD_GLOBAL 1 (func_w_kwargs + NULL) 255 LOAD_CONST 1 (1) 256 LOAD_CONST 2 (2) 257 LOAD_CONST 3 (5) 258 LOAD_CONST 4 (('c',)) 259 CALL_KW 3 260 POP_TOP 261 RETURN_CONST 0 (None) 262""" % (wrap_func_w_kwargs.__code__.co_firstlineno, 263 wrap_func_w_kwargs.__code__.co_firstlineno + 1) 264 265dis_intrinsic_1_2 = """\ 266 0 RESUME 0 267 268 1 LOAD_CONST 0 (0) 269 LOAD_CONST 1 (('*',)) 270 IMPORT_NAME 0 (math) 271 CALL_INTRINSIC_1 2 (INTRINSIC_IMPORT_STAR) 272 POP_TOP 273 RETURN_CONST 2 (None) 274""" 275 276dis_intrinsic_1_5 = """\ 277 0 RESUME 0 278 279 1 LOAD_NAME 0 (a) 280 CALL_INTRINSIC_1 5 (INTRINSIC_UNARY_POSITIVE) 281 RETURN_VALUE 282""" 283 284dis_intrinsic_1_6 = """\ 285 0 RESUME 0 286 287 1 BUILD_LIST 0 288 LOAD_NAME 0 (a) 289 LIST_EXTEND 1 290 CALL_INTRINSIC_1 6 (INTRINSIC_LIST_TO_TUPLE) 291 RETURN_VALUE 292""" 293 294_BIG_LINENO_FORMAT = """\ 295 1 RESUME 0 296 297%3d LOAD_GLOBAL 0 (spam) 298 POP_TOP 299 RETURN_CONST 0 (None) 300""" 301 302_BIG_LINENO_FORMAT2 = """\ 303 1 RESUME 0 304 305%4d LOAD_GLOBAL 0 (spam) 306 POP_TOP 307 RETURN_CONST 0 (None) 308""" 309 310dis_module_expected_results = """\ 311Disassembly of f: 312 4 RESUME 0 313 RETURN_CONST 0 (None) 314 315Disassembly of g: 316 5 RESUME 0 317 RETURN_CONST 0 (None) 318 319""" 320 321expr_str = "x + 1" 322 323dis_expr_str = """\ 324 0 RESUME 0 325 326 1 LOAD_NAME 0 (x) 327 LOAD_CONST 0 (1) 328 BINARY_OP 0 (+) 329 RETURN_VALUE 330""" 331 332simple_stmt_str = "x = x + 1" 333 334dis_simple_stmt_str = """\ 335 0 RESUME 0 336 337 1 LOAD_NAME 0 (x) 338 LOAD_CONST 0 (1) 339 BINARY_OP 0 (+) 340 STORE_NAME 0 (x) 341 RETURN_CONST 1 (None) 342""" 343 344annot_stmt_str = """\ 345 346x: int = 1 347y: fun(1) 348lst[fun(0)]: int = 1 349""" 350# leading newline is for a reason (tests lineno) 351 352dis_annot_stmt_str = """\ 353 0 RESUME 0 354 355 2 SETUP_ANNOTATIONS 356 LOAD_CONST 0 (1) 357 STORE_NAME 0 (x) 358 LOAD_NAME 1 (int) 359 LOAD_NAME 2 (__annotations__) 360 LOAD_CONST 1 ('x') 361 STORE_SUBSCR 362 363 3 LOAD_NAME 3 (fun) 364 PUSH_NULL 365 LOAD_CONST 0 (1) 366 CALL 1 367 LOAD_NAME 2 (__annotations__) 368 LOAD_CONST 2 ('y') 369 STORE_SUBSCR 370 371 4 LOAD_CONST 0 (1) 372 LOAD_NAME 4 (lst) 373 LOAD_NAME 3 (fun) 374 PUSH_NULL 375 LOAD_CONST 3 (0) 376 CALL 1 377 STORE_SUBSCR 378 LOAD_NAME 1 (int) 379 POP_TOP 380 RETURN_CONST 4 (None) 381""" 382 383compound_stmt_str = """\ 384x = 0 385while 1: 386 x += 1""" 387# Trailing newline has been deliberately omitted 388 389dis_compound_stmt_str = """\ 390 0 RESUME 0 391 392 1 LOAD_CONST 0 (0) 393 STORE_NAME 0 (x) 394 395 2 NOP 396 397 3 L1: LOAD_NAME 0 (x) 398 LOAD_CONST 1 (1) 399 BINARY_OP 13 (+=) 400 STORE_NAME 0 (x) 401 402 2 JUMP_BACKWARD 7 (to L1) 403""" 404 405dis_traceback = """\ 406%4d RESUME 0 407 408%4d NOP 409 410%4d L1: LOAD_CONST 1 (1) 411 LOAD_CONST 2 (0) 412 --> BINARY_OP 11 (/) 413 POP_TOP 414 415%4d L2: LOAD_FAST_CHECK 1 (tb) 416 RETURN_VALUE 417 418 -- L3: PUSH_EXC_INFO 419 420%4d LOAD_GLOBAL 0 (Exception) 421 CHECK_EXC_MATCH 422 POP_JUMP_IF_FALSE 23 (to L7) 423 STORE_FAST 0 (e) 424 425%4d L4: LOAD_FAST 0 (e) 426 LOAD_ATTR 2 (__traceback__) 427 STORE_FAST 1 (tb) 428 L5: POP_EXCEPT 429 LOAD_CONST 0 (None) 430 STORE_FAST 0 (e) 431 DELETE_FAST 0 (e) 432 433%4d LOAD_FAST 1 (tb) 434 RETURN_VALUE 435 436 -- L6: LOAD_CONST 0 (None) 437 STORE_FAST 0 (e) 438 DELETE_FAST 0 (e) 439 RERAISE 1 440 441%4d L7: RERAISE 0 442 443 -- L8: COPY 3 444 POP_EXCEPT 445 RERAISE 1 446ExceptionTable: 447 L1 to L2 -> L3 [0] 448 L3 to L4 -> L8 [1] lasti 449 L4 to L5 -> L6 [1] lasti 450 L6 to L8 -> L8 [1] lasti 451""" % (TRACEBACK_CODE.co_firstlineno, 452 TRACEBACK_CODE.co_firstlineno + 1, 453 TRACEBACK_CODE.co_firstlineno + 2, 454 TRACEBACK_CODE.co_firstlineno + 5, 455 TRACEBACK_CODE.co_firstlineno + 3, 456 TRACEBACK_CODE.co_firstlineno + 4, 457 TRACEBACK_CODE.co_firstlineno + 5, 458 TRACEBACK_CODE.co_firstlineno + 3) 459 460def _fstring(a, b, c, d): 461 return f'{a} {b:4} {c!r} {d!r:4}' 462 463dis_fstring = """\ 464%3d RESUME 0 465 466%3d LOAD_FAST 0 (a) 467 FORMAT_SIMPLE 468 LOAD_CONST 1 (' ') 469 LOAD_FAST 1 (b) 470 LOAD_CONST 2 ('4') 471 FORMAT_WITH_SPEC 472 LOAD_CONST 1 (' ') 473 LOAD_FAST 2 (c) 474 CONVERT_VALUE 2 (repr) 475 FORMAT_SIMPLE 476 LOAD_CONST 1 (' ') 477 LOAD_FAST 3 (d) 478 CONVERT_VALUE 2 (repr) 479 LOAD_CONST 2 ('4') 480 FORMAT_WITH_SPEC 481 BUILD_STRING 7 482 RETURN_VALUE 483""" % (_fstring.__code__.co_firstlineno, _fstring.__code__.co_firstlineno + 1) 484 485def _with(c): 486 with c: 487 x = 1 488 y = 2 489 490dis_with = """\ 491%4d RESUME 0 492 493%4d LOAD_FAST 0 (c) 494 BEFORE_WITH 495 L1: POP_TOP 496 497%4d LOAD_CONST 1 (1) 498 STORE_FAST 1 (x) 499 500%4d L2: LOAD_CONST 0 (None) 501 LOAD_CONST 0 (None) 502 LOAD_CONST 0 (None) 503 CALL 2 504 POP_TOP 505 506%4d LOAD_CONST 2 (2) 507 STORE_FAST 2 (y) 508 RETURN_CONST 0 (None) 509 510%4d L3: PUSH_EXC_INFO 511 WITH_EXCEPT_START 512 TO_BOOL 513 POP_JUMP_IF_TRUE 1 (to L4) 514 RERAISE 2 515 L4: POP_TOP 516 L5: POP_EXCEPT 517 POP_TOP 518 POP_TOP 519 520%4d LOAD_CONST 2 (2) 521 STORE_FAST 2 (y) 522 RETURN_CONST 0 (None) 523 524 -- L6: COPY 3 525 POP_EXCEPT 526 RERAISE 1 527ExceptionTable: 528 L1 to L2 -> L3 [1] lasti 529 L3 to L5 -> L6 [3] lasti 530""" % (_with.__code__.co_firstlineno, 531 _with.__code__.co_firstlineno + 1, 532 _with.__code__.co_firstlineno + 2, 533 _with.__code__.co_firstlineno + 1, 534 _with.__code__.co_firstlineno + 3, 535 _with.__code__.co_firstlineno + 1, 536 _with.__code__.co_firstlineno + 3, 537 ) 538 539async def _asyncwith(c): 540 async with c: 541 x = 1 542 y = 2 543 544dis_asyncwith = """\ 545%4d RETURN_GENERATOR 546 POP_TOP 547 L1: RESUME 0 548 549%4d LOAD_FAST 0 (c) 550 BEFORE_ASYNC_WITH 551 GET_AWAITABLE 1 552 LOAD_CONST 0 (None) 553 L2: SEND 3 (to L5) 554 L3: YIELD_VALUE 1 555 L4: RESUME 3 556 JUMP_BACKWARD_NO_INTERRUPT 5 (to L2) 557 L5: END_SEND 558 L6: POP_TOP 559 560%4d LOAD_CONST 1 (1) 561 STORE_FAST 1 (x) 562 563%4d L7: LOAD_CONST 0 (None) 564 LOAD_CONST 0 (None) 565 LOAD_CONST 0 (None) 566 CALL 2 567 GET_AWAITABLE 2 568 LOAD_CONST 0 (None) 569 L8: SEND 3 (to L11) 570 L9: YIELD_VALUE 1 571 L10: RESUME 3 572 JUMP_BACKWARD_NO_INTERRUPT 5 (to L8) 573 L11: END_SEND 574 POP_TOP 575 576%4d LOAD_CONST 2 (2) 577 STORE_FAST 2 (y) 578 RETURN_CONST 0 (None) 579 580%4d L12: CLEANUP_THROW 581 L13: JUMP_BACKWARD_NO_INTERRUPT 25 (to L5) 582 L14: CLEANUP_THROW 583 L15: JUMP_BACKWARD_NO_INTERRUPT 9 (to L11) 584 L16: PUSH_EXC_INFO 585 WITH_EXCEPT_START 586 GET_AWAITABLE 2 587 LOAD_CONST 0 (None) 588 L17: SEND 4 (to L21) 589 L18: YIELD_VALUE 1 590 L19: RESUME 3 591 JUMP_BACKWARD_NO_INTERRUPT 5 (to L17) 592 L20: CLEANUP_THROW 593 L21: END_SEND 594 TO_BOOL 595 POP_JUMP_IF_TRUE 1 (to L22) 596 RERAISE 2 597 L22: POP_TOP 598 L23: POP_EXCEPT 599 POP_TOP 600 POP_TOP 601 602%4d LOAD_CONST 2 (2) 603 STORE_FAST 2 (y) 604 RETURN_CONST 0 (None) 605 606 -- L24: COPY 3 607 POP_EXCEPT 608 RERAISE 1 609 L25: CALL_INTRINSIC_1 3 (INTRINSIC_STOPITERATION_ERROR) 610 RERAISE 1 611ExceptionTable: 612 L1 to L3 -> L25 [0] lasti 613 L3 to L4 -> L12 [3] 614 L4 to L6 -> L25 [0] lasti 615 L6 to L7 -> L16 [1] lasti 616 L7 to L9 -> L25 [0] lasti 617 L9 to L10 -> L14 [2] 618 L10 to L13 -> L25 [0] lasti 619 L14 to L15 -> L25 [0] lasti 620 L16 to L18 -> L24 [3] lasti 621 L18 to L19 -> L20 [6] 622 L19 to L23 -> L24 [3] lasti 623 L23 to L25 -> L25 [0] lasti 624""" % (_asyncwith.__code__.co_firstlineno, 625 _asyncwith.__code__.co_firstlineno + 1, 626 _asyncwith.__code__.co_firstlineno + 2, 627 _asyncwith.__code__.co_firstlineno + 1, 628 _asyncwith.__code__.co_firstlineno + 3, 629 _asyncwith.__code__.co_firstlineno + 1, 630 _asyncwith.__code__.co_firstlineno + 3, 631 ) 632 633 634def _tryfinally(a, b): 635 try: 636 return a 637 finally: 638 b() 639 640def _tryfinallyconst(b): 641 try: 642 return 1 643 finally: 644 b() 645 646dis_tryfinally = """\ 647%4d RESUME 0 648 649%4d NOP 650 651%4d L1: LOAD_FAST 0 (a) 652 653%4d L2: LOAD_FAST 1 (b) 654 PUSH_NULL 655 CALL 0 656 POP_TOP 657 RETURN_VALUE 658 659 -- L3: PUSH_EXC_INFO 660 661%4d LOAD_FAST 1 (b) 662 PUSH_NULL 663 CALL 0 664 POP_TOP 665 RERAISE 0 666 667 -- L4: COPY 3 668 POP_EXCEPT 669 RERAISE 1 670ExceptionTable: 671 L1 to L2 -> L3 [0] 672 L3 to L4 -> L4 [1] lasti 673""" % (_tryfinally.__code__.co_firstlineno, 674 _tryfinally.__code__.co_firstlineno + 1, 675 _tryfinally.__code__.co_firstlineno + 2, 676 _tryfinally.__code__.co_firstlineno + 4, 677 _tryfinally.__code__.co_firstlineno + 4, 678 ) 679 680dis_tryfinallyconst = """\ 681%4d RESUME 0 682 683%4d NOP 684 685%4d NOP 686 687%4d LOAD_FAST 0 (b) 688 PUSH_NULL 689 CALL 0 690 POP_TOP 691 RETURN_CONST 1 (1) 692 693 -- L1: PUSH_EXC_INFO 694 695%4d LOAD_FAST 0 (b) 696 PUSH_NULL 697 CALL 0 698 POP_TOP 699 RERAISE 0 700 701 -- L2: COPY 3 702 POP_EXCEPT 703 RERAISE 1 704ExceptionTable: 705 L1 to L2 -> L2 [1] lasti 706""" % (_tryfinallyconst.__code__.co_firstlineno, 707 _tryfinallyconst.__code__.co_firstlineno + 1, 708 _tryfinallyconst.__code__.co_firstlineno + 2, 709 _tryfinallyconst.__code__.co_firstlineno + 4, 710 _tryfinallyconst.__code__.co_firstlineno + 4, 711 ) 712 713def _g(x): 714 yield x 715 716async def _ag(x): 717 yield x 718 719async def _co(x): 720 async for item in _ag(x): 721 pass 722 723def _h(y): 724 def foo(x): 725 '''funcdoc''' 726 return list(x + z for z in y) 727 return foo 728 729dis_nested_0 = """\ 730 -- MAKE_CELL 0 (y) 731 732%4d RESUME 0 733 734%4d LOAD_FAST 0 (y) 735 BUILD_TUPLE 1 736 LOAD_CONST 1 (<code object foo at 0x..., file "%s", line %d>) 737 MAKE_FUNCTION 738 SET_FUNCTION_ATTRIBUTE 8 (closure) 739 STORE_FAST 1 (foo) 740 741%4d LOAD_FAST 1 (foo) 742 RETURN_VALUE 743""" % (_h.__code__.co_firstlineno, 744 _h.__code__.co_firstlineno + 1, 745 __file__, 746 _h.__code__.co_firstlineno + 1, 747 _h.__code__.co_firstlineno + 4, 748) 749 750dis_nested_1 = """%s 751Disassembly of <code object foo at 0x..., file "%s", line %d>: 752 -- COPY_FREE_VARS 1 753 MAKE_CELL 0 (x) 754 755%4d RESUME 0 756 757%4d LOAD_GLOBAL 1 (list + NULL) 758 LOAD_FAST 0 (x) 759 BUILD_TUPLE 1 760 LOAD_CONST 1 (<code object <genexpr> at 0x..., file "%s", line %d>) 761 MAKE_FUNCTION 762 SET_FUNCTION_ATTRIBUTE 8 (closure) 763 LOAD_DEREF 1 (y) 764 GET_ITER 765 CALL 0 766 CALL 1 767 RETURN_VALUE 768""" % (dis_nested_0, 769 __file__, 770 _h.__code__.co_firstlineno + 1, 771 _h.__code__.co_firstlineno + 1, 772 _h.__code__.co_firstlineno + 3, 773 __file__, 774 _h.__code__.co_firstlineno + 3, 775) 776 777dis_nested_2 = """%s 778Disassembly of <code object <genexpr> at 0x..., file "%s", line %d>: 779 -- COPY_FREE_VARS 1 780 781%4d RETURN_GENERATOR 782 POP_TOP 783 L1: RESUME 0 784 LOAD_FAST 0 (.0) 785 GET_ITER 786 L2: FOR_ITER 10 (to L3) 787 STORE_FAST 1 (z) 788 LOAD_DEREF 2 (x) 789 LOAD_FAST 1 (z) 790 BINARY_OP 0 (+) 791 YIELD_VALUE 0 792 RESUME 5 793 POP_TOP 794 JUMP_BACKWARD 12 (to L2) 795 L3: END_FOR 796 POP_TOP 797 RETURN_CONST 0 (None) 798 799 -- L4: CALL_INTRINSIC_1 3 (INTRINSIC_STOPITERATION_ERROR) 800 RERAISE 1 801ExceptionTable: 802 L1 to L4 -> L4 [0] lasti 803""" % (dis_nested_1, 804 __file__, 805 _h.__code__.co_firstlineno + 3, 806 _h.__code__.co_firstlineno + 3, 807) 808 809def load_test(x, y=0): 810 a, b = x, y 811 return a, b 812 813dis_load_test_quickened_code = """\ 814%3d RESUME_CHECK 0 815 816%3d LOAD_FAST_LOAD_FAST 1 (x, y) 817 STORE_FAST_STORE_FAST 50 (b, a) 818 819%3d LOAD_FAST_LOAD_FAST 35 (a, b) 820 BUILD_TUPLE 2 821 RETURN_VALUE 822""" % (load_test.__code__.co_firstlineno, 823 load_test.__code__.co_firstlineno + 1, 824 load_test.__code__.co_firstlineno + 2) 825 826def loop_test(): 827 for i in [1, 2, 3] * 3: 828 load_test(i) 829 830dis_loop_test_quickened_code = """\ 831%3d RESUME_CHECK 0 832 833%3d BUILD_LIST 0 834 LOAD_CONST 1 ((1, 2, 3)) 835 LIST_EXTEND 1 836 LOAD_CONST 2 (3) 837 BINARY_OP 5 (*) 838 GET_ITER 839 L1: FOR_ITER_LIST 14 (to L2) 840 STORE_FAST 0 (i) 841 842%3d LOAD_GLOBAL_MODULE 1 (load_test + NULL) 843 LOAD_FAST 0 (i) 844 CALL_PY_GENERAL 1 845 POP_TOP 846 JUMP_BACKWARD 16 (to L1) 847 848%3d L2: END_FOR 849 POP_TOP 850 RETURN_CONST 0 (None) 851""" % (loop_test.__code__.co_firstlineno, 852 loop_test.__code__.co_firstlineno + 1, 853 loop_test.__code__.co_firstlineno + 2, 854 loop_test.__code__.co_firstlineno + 1,) 855 856def extended_arg_quick(): 857 *_, _ = ... 858 859dis_extended_arg_quick_code = """\ 860%3d RESUME 0 861 862%3d LOAD_CONST 1 (Ellipsis) 863 EXTENDED_ARG 1 864 UNPACK_EX 256 865 POP_TOP 866 STORE_FAST 0 (_) 867 RETURN_CONST 0 (None) 868"""% (extended_arg_quick.__code__.co_firstlineno, 869 extended_arg_quick.__code__.co_firstlineno + 1,) 870 871ADAPTIVE_WARMUP_DELAY = 2 872 873class DisTestBase(unittest.TestCase): 874 "Common utilities for DisTests and TestDisTraceback" 875 876 def strip_addresses(self, text): 877 return re.sub(r'\b0x[0-9A-Fa-f]+\b', '0x...', text) 878 879 def assert_exception_table_increasing(self, lines): 880 prev_start, prev_end = -1, -1 881 count = 0 882 for line in lines: 883 m = re.match(r' L(\d+) to L(\d+) -> L\d+ \[\d+\]', line) 884 start, end = [int(g) for g in m.groups()] 885 self.assertGreaterEqual(end, start) 886 self.assertGreaterEqual(start, prev_end) 887 prev_start, prev_end = start, end 888 count += 1 889 return count 890 891 def do_disassembly_compare(self, got, expected): 892 if got != expected: 893 got = self.strip_addresses(got) 894 self.assertEqual(got, expected) 895 896 897class DisTests(DisTestBase): 898 899 maxDiff = None 900 901 def get_disassembly(self, func, lasti=-1, wrapper=True, **kwargs): 902 # We want to test the default printing behaviour, not the file arg 903 output = io.StringIO() 904 with contextlib.redirect_stdout(output): 905 if wrapper: 906 dis.dis(func, **kwargs) 907 else: 908 dis.disassemble(func, lasti, **kwargs) 909 return output.getvalue() 910 911 def get_disassemble_as_string(self, func, lasti=-1): 912 return self.get_disassembly(func, lasti, False) 913 914 def do_disassembly_test(self, func, expected, **kwargs): 915 self.maxDiff = None 916 got = self.get_disassembly(func, depth=0, **kwargs) 917 self.do_disassembly_compare(got, expected) 918 # Add checks for dis.disco 919 if hasattr(func, '__code__'): 920 got_disco = io.StringIO() 921 with contextlib.redirect_stdout(got_disco): 922 dis.disco(func.__code__, **kwargs) 923 self.do_disassembly_compare(got_disco.getvalue(), expected) 924 925 def test_opmap(self): 926 self.assertEqual(dis.opmap["CACHE"], 0) 927 self.assertIn(dis.opmap["LOAD_CONST"], dis.hasconst) 928 self.assertIn(dis.opmap["STORE_NAME"], dis.hasname) 929 930 def test_opname(self): 931 self.assertEqual(dis.opname[dis.opmap["LOAD_FAST"]], "LOAD_FAST") 932 933 def test_boundaries(self): 934 self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG) 935 936 def test_widths(self): 937 long_opcodes = set(['JUMP_BACKWARD_NO_INTERRUPT', 938 'INSTRUMENTED_CALL_FUNCTION_EX']) 939 for opcode, opname in enumerate(dis.opname): 940 if opname in long_opcodes or opname.startswith("INSTRUMENTED"): 941 continue 942 with self.subTest(opname=opname): 943 width = dis._OPNAME_WIDTH 944 if opcode in dis.hasarg: 945 width += 1 + dis._OPARG_WIDTH 946 self.assertLessEqual(len(opname), width) 947 948 def test_dis(self): 949 self.do_disassembly_test(_f, dis_f) 950 951 def test_dis_with_offsets(self): 952 self.do_disassembly_test(_f, dis_f_with_offsets, show_offsets=True) 953 954 def test_bug_708901(self): 955 self.do_disassembly_test(bug708901, dis_bug708901) 956 957 def test_bug_1333982(self): 958 # This one is checking bytecodes generated for an `assert` statement, 959 # so fails if the tests are run with -O. Skip this test then. 960 if not __debug__: 961 self.skipTest('need asserts, run without -O') 962 963 self.do_disassembly_test(bug1333982, dis_bug1333982) 964 965 def test_bug_42562(self): 966 self.do_disassembly_test(bug42562, dis_bug42562) 967 968 def test_bug_45757(self): 969 # Extended arg followed by NOP 970 self.do_disassembly_test(code_bug_45757, dis_bug_45757) 971 972 def test_bug_46724(self): 973 # Test that negative operargs are handled properly 974 self.do_disassembly_test(bug46724, dis_bug46724) 975 976 def test_kw_names(self): 977 # Test that value is displayed for keyword argument names: 978 self.do_disassembly_test(wrap_func_w_kwargs, dis_kw_names) 979 980 def test_intrinsic_1(self): 981 # Test that argrepr is displayed for CALL_INTRINSIC_1 982 self.do_disassembly_test("from math import *", dis_intrinsic_1_2) 983 self.do_disassembly_test("+a", dis_intrinsic_1_5) 984 self.do_disassembly_test("(*a,)", dis_intrinsic_1_6) 985 986 def test_intrinsic_2(self): 987 self.assertIn("CALL_INTRINSIC_2 1 (INTRINSIC_PREP_RERAISE_STAR)", 988 self.get_disassembly("try: pass\nexcept* Exception: x")) 989 990 def test_big_linenos(self): 991 def func(count): 992 namespace = {} 993 func = "def foo():\n " + "".join(["\n "] * count + ["spam\n"]) 994 exec(func, namespace) 995 return namespace['foo'] 996 997 # Test all small ranges 998 for i in range(1, 300): 999 expected = _BIG_LINENO_FORMAT % (i + 2) 1000 self.do_disassembly_test(func(i), expected) 1001 1002 # Test some larger ranges too 1003 for i in range(300, 1000, 10): 1004 expected = _BIG_LINENO_FORMAT % (i + 2) 1005 self.do_disassembly_test(func(i), expected) 1006 1007 for i in range(1000, 5000, 10): 1008 expected = _BIG_LINENO_FORMAT2 % (i + 2) 1009 self.do_disassembly_test(func(i), expected) 1010 1011 from test import dis_module 1012 self.do_disassembly_test(dis_module, dis_module_expected_results) 1013 1014 def test_disassemble_str(self): 1015 self.do_disassembly_test(expr_str, dis_expr_str) 1016 self.do_disassembly_test(simple_stmt_str, dis_simple_stmt_str) 1017 self.do_disassembly_test(annot_stmt_str, dis_annot_stmt_str) 1018 self.do_disassembly_test(compound_stmt_str, dis_compound_stmt_str) 1019 1020 def test_disassemble_bytes(self): 1021 self.do_disassembly_test(_f.__code__.co_code, dis_f_co_code) 1022 1023 def test_disassemble_class(self): 1024 self.do_disassembly_test(_C, dis_c) 1025 1026 def test_disassemble_instance_method(self): 1027 self.do_disassembly_test(_C(1).__init__, dis_c_instance_method) 1028 1029 def test_disassemble_instance_method_bytes(self): 1030 method_bytecode = _C(1).__init__.__code__.co_code 1031 self.do_disassembly_test(method_bytecode, dis_c_instance_method_bytes) 1032 1033 def test_disassemble_static_method(self): 1034 self.do_disassembly_test(_C.sm, dis_c_static_method) 1035 1036 def test_disassemble_class_method(self): 1037 self.do_disassembly_test(_C.cm, dis_c_class_method) 1038 1039 def test_disassemble_generator(self): 1040 gen_func_disas = self.get_disassembly(_g) # Generator function 1041 gen_disas = self.get_disassembly(_g(1)) # Generator iterator 1042 self.assertEqual(gen_disas, gen_func_disas) 1043 1044 def test_disassemble_async_generator(self): 1045 agen_func_disas = self.get_disassembly(_ag) # Async generator function 1046 agen_disas = self.get_disassembly(_ag(1)) # Async generator iterator 1047 self.assertEqual(agen_disas, agen_func_disas) 1048 1049 def test_disassemble_coroutine(self): 1050 coro_func_disas = self.get_disassembly(_co) # Coroutine function 1051 coro = _co(1) # Coroutine object 1052 coro.close() # Avoid a RuntimeWarning (never awaited) 1053 coro_disas = self.get_disassembly(coro) 1054 self.assertEqual(coro_disas, coro_func_disas) 1055 1056 def test_disassemble_fstring(self): 1057 self.do_disassembly_test(_fstring, dis_fstring) 1058 1059 def test_disassemble_with(self): 1060 self.do_disassembly_test(_with, dis_with) 1061 1062 def test_disassemble_asyncwith(self): 1063 self.do_disassembly_test(_asyncwith, dis_asyncwith) 1064 1065 def test_disassemble_try_finally(self): 1066 self.do_disassembly_test(_tryfinally, dis_tryfinally) 1067 self.do_disassembly_test(_tryfinallyconst, dis_tryfinallyconst) 1068 1069 def test_dis_none(self): 1070 try: 1071 del sys.last_exc 1072 except AttributeError: 1073 pass 1074 try: 1075 del sys.last_traceback 1076 except AttributeError: 1077 pass 1078 self.assertRaises(RuntimeError, dis.dis, None) 1079 1080 def test_dis_traceback(self): 1081 self.maxDiff = None 1082 try: 1083 del sys.last_traceback 1084 except AttributeError: 1085 pass 1086 1087 try: 1088 1/0 1089 except Exception as e: 1090 tb = e.__traceback__ 1091 sys.last_exc = e 1092 1093 tb_dis = self.get_disassemble_as_string(tb.tb_frame.f_code, tb.tb_lasti) 1094 self.do_disassembly_test(None, tb_dis) 1095 1096 def test_dis_object(self): 1097 self.assertRaises(TypeError, dis.dis, object()) 1098 1099 def test_disassemble_recursive(self): 1100 def check(expected, **kwargs): 1101 dis = self.get_disassembly(_h, **kwargs) 1102 dis = self.strip_addresses(dis) 1103 self.assertEqual(dis, expected) 1104 1105 check(dis_nested_0, depth=0) 1106 check(dis_nested_1, depth=1) 1107 check(dis_nested_2, depth=2) 1108 check(dis_nested_2, depth=3) 1109 check(dis_nested_2, depth=None) 1110 check(dis_nested_2) 1111 1112 def test__try_compile_no_context_exc_on_error(self): 1113 # see gh-102114 1114 try: 1115 dis._try_compile(")", "") 1116 except Exception as e: 1117 self.assertIsNone(e.__context__) 1118 1119 @staticmethod 1120 def code_quicken(f, times=ADAPTIVE_WARMUP_DELAY): 1121 for _ in range(times): 1122 f() 1123 1124 @cpython_only 1125 @requires_specialization 1126 def test_super_instructions(self): 1127 self.code_quicken(lambda: load_test(0, 0)) 1128 got = self.get_disassembly(load_test, adaptive=True) 1129 self.do_disassembly_compare(got, dis_load_test_quickened_code) 1130 1131 @cpython_only 1132 @requires_specialization 1133 def test_binary_specialize(self): 1134 binary_op_quicken = """\ 1135 0 RESUME_CHECK 0 1136 1137 1 LOAD_NAME 0 (a) 1138 LOAD_NAME 1 (b) 1139 %s 1140 RETURN_VALUE 1141""" 1142 co_int = compile('a + b', "<int>", "eval") 1143 self.code_quicken(lambda: exec(co_int, {}, {'a': 1, 'b': 2})) 1144 got = self.get_disassembly(co_int, adaptive=True) 1145 self.do_disassembly_compare(got, binary_op_quicken % "BINARY_OP_ADD_INT 0 (+)") 1146 1147 co_unicode = compile('a + b', "<unicode>", "eval") 1148 self.code_quicken(lambda: exec(co_unicode, {}, {'a': 'a', 'b': 'b'})) 1149 got = self.get_disassembly(co_unicode, adaptive=True) 1150 self.do_disassembly_compare(got, binary_op_quicken % "BINARY_OP_ADD_UNICODE 0 (+)") 1151 1152 binary_subscr_quicken = """\ 1153 0 RESUME_CHECK 0 1154 1155 1 LOAD_NAME 0 (a) 1156 LOAD_CONST 0 (0) 1157 %s 1158 RETURN_VALUE 1159""" 1160 co_list = compile('a[0]', "<list>", "eval") 1161 self.code_quicken(lambda: exec(co_list, {}, {'a': [0]})) 1162 got = self.get_disassembly(co_list, adaptive=True) 1163 self.do_disassembly_compare(got, binary_subscr_quicken % "BINARY_SUBSCR_LIST_INT") 1164 1165 co_dict = compile('a[0]', "<dict>", "eval") 1166 self.code_quicken(lambda: exec(co_dict, {}, {'a': {0: '1'}})) 1167 got = self.get_disassembly(co_dict, adaptive=True) 1168 self.do_disassembly_compare(got, binary_subscr_quicken % "BINARY_SUBSCR_DICT") 1169 1170 @cpython_only 1171 @requires_specialization 1172 def test_load_attr_specialize(self): 1173 load_attr_quicken = """\ 1174 0 RESUME_CHECK 0 1175 1176 1 LOAD_CONST 0 ('a') 1177 LOAD_ATTR_SLOT 0 (__class__) 1178 RETURN_VALUE 1179""" 1180 co = compile("'a'.__class__", "", "eval") 1181 self.code_quicken(lambda: exec(co, {}, {})) 1182 got = self.get_disassembly(co, adaptive=True) 1183 self.do_disassembly_compare(got, load_attr_quicken) 1184 1185 @cpython_only 1186 @requires_specialization 1187 def test_call_specialize(self): 1188 call_quicken = """\ 1189 0 RESUME_CHECK 0 1190 1191 1 LOAD_NAME 0 (str) 1192 PUSH_NULL 1193 LOAD_CONST 0 (1) 1194 CALL_STR_1 1 1195 RETURN_VALUE 1196""" 1197 co = compile("str(1)", "", "eval") 1198 self.code_quicken(lambda: exec(co, {}, {})) 1199 got = self.get_disassembly(co, adaptive=True) 1200 self.do_disassembly_compare(got, call_quicken) 1201 1202 @cpython_only 1203 @requires_specialization 1204 def test_loop_quicken(self): 1205 # Loop can trigger a quicken where the loop is located 1206 self.code_quicken(loop_test, 4) 1207 got = self.get_disassembly(loop_test, adaptive=True) 1208 expected = dis_loop_test_quickened_code 1209 self.do_disassembly_compare(got, expected) 1210 1211 @cpython_only 1212 def test_extended_arg_quick(self): 1213 got = self.get_disassembly(extended_arg_quick) 1214 self.do_disassembly_compare(got, dis_extended_arg_quick_code) 1215 1216 def get_cached_values(self, quickened, adaptive): 1217 def f(): 1218 l = [] 1219 for i in range(42): 1220 l.append(i) 1221 if quickened: 1222 self.code_quicken(f) 1223 else: 1224 # "copy" the code to un-quicken it: 1225 f.__code__ = f.__code__.replace() 1226 for instruction in _unroll_caches_as_Instructions(dis.get_instructions( 1227 f, show_caches=True, adaptive=adaptive 1228 ), show_caches=True): 1229 if instruction.opname == "CACHE": 1230 yield instruction.argrepr 1231 1232 @cpython_only 1233 def test_show_caches(self): 1234 for quickened in (False, True): 1235 for adaptive in (False, True): 1236 with self.subTest(f"{quickened=}, {adaptive=}"): 1237 if adaptive: 1238 pattern = r"^(\w+: \d+)?$" 1239 else: 1240 pattern = r"^(\w+: 0)?$" 1241 caches = list(self.get_cached_values(quickened, adaptive)) 1242 for cache in caches: 1243 self.assertRegex(cache, pattern) 1244 total_caches = 21 1245 empty_caches = 7 1246 self.assertEqual(caches.count(""), empty_caches) 1247 self.assertEqual(len(caches), total_caches) 1248 1249 @cpython_only 1250 def test_show_currinstr_with_cache(self): 1251 """ 1252 Make sure that with lasti pointing to CACHE, it still shows the current 1253 line correctly 1254 """ 1255 def f(): 1256 print(a) 1257 # The code above should generate a LOAD_GLOBAL which has CACHE instr after 1258 # However, this might change in the future. So we explicitly try to find 1259 # a CACHE entry in the instructions. If we can't do that, fail the test 1260 1261 for inst in _unroll_caches_as_Instructions( 1262 dis.get_instructions(f, show_caches=True), show_caches=True): 1263 if inst.opname == "CACHE": 1264 op_offset = inst.offset - 2 1265 cache_offset = inst.offset 1266 break 1267 else: 1268 opname = inst.opname 1269 else: 1270 self.fail("Can't find a CACHE entry in the function provided to do the test") 1271 1272 assem_op = self.get_disassembly(f.__code__, lasti=op_offset, wrapper=False) 1273 assem_cache = self.get_disassembly(f.__code__, lasti=cache_offset, wrapper=False) 1274 1275 # Make sure --> exists and points to the correct op 1276 self.assertRegex(assem_op, fr"--> {opname}") 1277 # Make sure when lasti points to cache, it shows the same disassembly 1278 self.assertEqual(assem_op, assem_cache) 1279 1280 1281class DisWithFileTests(DisTests): 1282 1283 # Run the tests again, using the file arg instead of print 1284 def get_disassembly(self, func, lasti=-1, wrapper=True, **kwargs): 1285 output = io.StringIO() 1286 if wrapper: 1287 dis.dis(func, file=output, **kwargs) 1288 else: 1289 dis.disassemble(func, lasti, file=output, **kwargs) 1290 return output.getvalue() 1291 1292 1293if dis.code_info.__doc__ is None: 1294 code_info_consts = "0: None" 1295else: 1296 code_info_consts = "0: 'Formatted details of methods, functions, or code.'" 1297 1298code_info_code_info = f"""\ 1299Name: code_info 1300Filename: (.*) 1301Argument count: 1 1302Positional-only arguments: 0 1303Kw-only arguments: 0 1304Number of locals: 1 1305Stack size: \\d+ 1306Flags: OPTIMIZED, NEWLOCALS 1307Constants: 1308 {code_info_consts} 1309Names: 1310 0: _format_code_info 1311 1: _get_code_object 1312Variable names: 1313 0: x""" 1314 1315 1316@staticmethod 1317def tricky(a, b, /, x, y, z=True, *args, c, d, e=[], **kwds): 1318 def f(c=c): 1319 print(a, b, x, y, z, c, d, e, f) 1320 yield a, b, x, y, z, c, d, e, f 1321 1322code_info_tricky = """\ 1323Name: tricky 1324Filename: (.*) 1325Argument count: 5 1326Positional-only arguments: 2 1327Kw-only arguments: 3 1328Number of locals: 10 1329Stack size: \\d+ 1330Flags: OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR 1331Constants: 1332 0: None 1333 1: <code object f at (.*), file "(.*)", line (.*)> 1334Variable names: 1335 0: a 1336 1: b 1337 2: x 1338 3: y 1339 4: z 1340 5: c 1341 6: d 1342 7: e 1343 8: args 1344 9: kwds 1345Cell variables: 1346 0: [abedfxyz] 1347 1: [abedfxyz] 1348 2: [abedfxyz] 1349 3: [abedfxyz] 1350 4: [abedfxyz] 1351 5: [abedfxyz]""" 1352# NOTE: the order of the cell variables above depends on dictionary order! 1353 1354co_tricky_nested_f = tricky.__func__.__code__.co_consts[1] 1355 1356code_info_tricky_nested_f = """\ 1357Filename: (.*) 1358Argument count: 1 1359Positional-only arguments: 0 1360Kw-only arguments: 0 1361Number of locals: 1 1362Stack size: \\d+ 1363Flags: OPTIMIZED, NEWLOCALS, NESTED 1364Constants: 1365 0: None 1366Names: 1367 0: print 1368Variable names: 1369 0: c 1370Free variables: 1371 0: [abedfxyz] 1372 1: [abedfxyz] 1373 2: [abedfxyz] 1374 3: [abedfxyz] 1375 4: [abedfxyz] 1376 5: [abedfxyz]""" 1377 1378code_info_expr_str = """\ 1379Name: <module> 1380Filename: <disassembly> 1381Argument count: 0 1382Positional-only arguments: 0 1383Kw-only arguments: 0 1384Number of locals: 0 1385Stack size: \\d+ 1386Flags: 0x0 1387Constants: 1388 0: 1 1389Names: 1390 0: x""" 1391 1392code_info_simple_stmt_str = """\ 1393Name: <module> 1394Filename: <disassembly> 1395Argument count: 0 1396Positional-only arguments: 0 1397Kw-only arguments: 0 1398Number of locals: 0 1399Stack size: \\d+ 1400Flags: 0x0 1401Constants: 1402 0: 1 1403 1: None 1404Names: 1405 0: x""" 1406 1407code_info_compound_stmt_str = """\ 1408Name: <module> 1409Filename: <disassembly> 1410Argument count: 0 1411Positional-only arguments: 0 1412Kw-only arguments: 0 1413Number of locals: 0 1414Stack size: \\d+ 1415Flags: 0x0 1416Constants: 1417 0: 0 1418 1: 1 1419Names: 1420 0: x""" 1421 1422 1423async def async_def(): 1424 await 1 1425 async for a in b: pass 1426 async with c as d: pass 1427 1428code_info_async_def = """\ 1429Name: async_def 1430Filename: (.*) 1431Argument count: 0 1432Positional-only arguments: 0 1433Kw-only arguments: 0 1434Number of locals: 2 1435Stack size: \\d+ 1436Flags: OPTIMIZED, NEWLOCALS, COROUTINE 1437Constants: 1438 0: None 1439 1: 1 1440Names: 1441 0: b 1442 1: c 1443Variable names: 1444 0: a 1445 1: d""" 1446 1447class CodeInfoTests(unittest.TestCase): 1448 test_pairs = [ 1449 (dis.code_info, code_info_code_info), 1450 (tricky, code_info_tricky), 1451 (co_tricky_nested_f, code_info_tricky_nested_f), 1452 (expr_str, code_info_expr_str), 1453 (simple_stmt_str, code_info_simple_stmt_str), 1454 (compound_stmt_str, code_info_compound_stmt_str), 1455 (async_def, code_info_async_def) 1456 ] 1457 1458 def test_code_info(self): 1459 self.maxDiff = 1000 1460 for x, expected in self.test_pairs: 1461 self.assertRegex(dis.code_info(x), expected) 1462 1463 def test_show_code(self): 1464 self.maxDiff = 1000 1465 for x, expected in self.test_pairs: 1466 with captured_stdout() as output: 1467 dis.show_code(x) 1468 self.assertRegex(output.getvalue(), expected+"\n") 1469 output = io.StringIO() 1470 dis.show_code(x, file=output) 1471 self.assertRegex(output.getvalue(), expected) 1472 1473 def test_code_info_object(self): 1474 self.assertRaises(TypeError, dis.code_info, object()) 1475 1476 def test_pretty_flags_no_flags(self): 1477 self.assertEqual(dis.pretty_flags(0), '0x0') 1478 1479 1480# Fodder for instruction introspection tests 1481# Editing any of these may require recalculating the expected output 1482def outer(a=1, b=2): 1483 def f(c=3, d=4): 1484 def inner(e=5, f=6): 1485 print(a, b, c, d, e, f) 1486 print(a, b, c, d) 1487 return inner 1488 print(a, b, '', 1, [], {}, "Hello world!") 1489 return f 1490 1491def jumpy(): 1492 # This won't actually run (but that's OK, we only disassemble it) 1493 for i in range(10): 1494 print(i) 1495 if i < 4: 1496 continue 1497 if i > 6: 1498 break 1499 else: 1500 print("I can haz else clause?") 1501 while i: 1502 print(i) 1503 i -= 1 1504 if i > 6: 1505 continue 1506 if i < 4: 1507 break 1508 else: 1509 print("Who let lolcatz into this test suite?") 1510 try: 1511 1 / 0 1512 except ZeroDivisionError: 1513 print("Here we go, here we go, here we go...") 1514 else: 1515 with i as dodgy: 1516 print("Never reach this") 1517 finally: 1518 print("OK, now we're done") 1519 1520# End fodder for opinfo generation tests 1521expected_outer_line = 1 1522_line_offset = outer.__code__.co_firstlineno - 1 1523code_object_f = outer.__code__.co_consts[1] 1524expected_f_line = code_object_f.co_firstlineno - _line_offset 1525code_object_inner = code_object_f.co_consts[1] 1526expected_inner_line = code_object_inner.co_firstlineno - _line_offset 1527expected_jumpy_line = 1 1528 1529# The following lines are useful to regenerate the expected results after 1530# either the fodder is modified or the bytecode generation changes 1531# After regeneration, update the references to code_object_f and 1532# code_object_inner before rerunning the tests 1533 1534def _stringify_instruction(instr): 1535 # Since line numbers and other offsets change a lot for these 1536 # test cases, ignore them. 1537 return f" {instr._replace(positions=None)!r}," 1538 1539def _prepare_test_cases(): 1540 ignore = io.StringIO() 1541 with contextlib.redirect_stdout(ignore): 1542 f = outer() 1543 inner = f() 1544 _instructions_outer = dis.get_instructions(outer, first_line=expected_outer_line) 1545 _instructions_f = dis.get_instructions(f, first_line=expected_f_line) 1546 _instructions_inner = dis.get_instructions(inner, first_line=expected_inner_line) 1547 _instructions_jumpy = dis.get_instructions(jumpy, first_line=expected_jumpy_line) 1548 result = "\n".join( 1549 [ 1550 "expected_opinfo_outer = [", 1551 *map(_stringify_instruction, _instructions_outer), 1552 "]", 1553 "", 1554 "expected_opinfo_f = [", 1555 *map(_stringify_instruction, _instructions_f), 1556 "]", 1557 "", 1558 "expected_opinfo_inner = [", 1559 *map(_stringify_instruction, _instructions_inner), 1560 "]", 1561 "", 1562 "expected_opinfo_jumpy = [", 1563 *map(_stringify_instruction, _instructions_jumpy), 1564 "]", 1565 ] 1566 ) 1567 result = result.replace(repr(repr(code_object_f)), "repr(code_object_f)") 1568 result = result.replace(repr(code_object_f), "code_object_f") 1569 result = result.replace(repr(repr(code_object_inner)), "repr(code_object_inner)") 1570 result = result.replace(repr(code_object_inner), "code_object_inner") 1571 print(result) 1572 1573# from test.test_dis import _prepare_test_cases; _prepare_test_cases() 1574 1575Instruction = dis.Instruction 1576 1577expected_opinfo_outer = [ 1578 Instruction(opname='MAKE_CELL', opcode=94, arg=0, argval='a', argrepr='a', offset=0, start_offset=0, starts_line=True, line_number=None, label=None, positions=None), 1579 Instruction(opname='MAKE_CELL', opcode=94, arg=1, argval='b', argrepr='b', offset=2, start_offset=2, starts_line=False, line_number=None, label=None, positions=None), 1580 Instruction(opname='RESUME', opcode=149, arg=0, argval=0, argrepr='', offset=4, start_offset=4, starts_line=True, line_number=1, label=None, positions=None), 1581 Instruction(opname='LOAD_CONST', opcode=83, arg=5, argval=(3, 4), argrepr='(3, 4)', offset=6, start_offset=6, starts_line=True, line_number=2, label=None, positions=None), 1582 Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='a', argrepr='a', offset=8, start_offset=8, starts_line=False, line_number=2, label=None, positions=None), 1583 Instruction(opname='LOAD_FAST', opcode=85, arg=1, argval='b', argrepr='b', offset=10, start_offset=10, starts_line=False, line_number=2, label=None, positions=None), 1584 Instruction(opname='BUILD_TUPLE', opcode=52, arg=2, argval=2, argrepr='', offset=12, start_offset=12, starts_line=False, line_number=2, label=None, positions=None), 1585 Instruction(opname='LOAD_CONST', opcode=83, arg=1, argval=code_object_f, argrepr=repr(code_object_f), offset=14, start_offset=14, starts_line=False, line_number=2, label=None, positions=None), 1586 Instruction(opname='MAKE_FUNCTION', opcode=26, arg=None, argval=None, argrepr='', offset=16, start_offset=16, starts_line=False, line_number=2, label=None, positions=None), 1587 Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=106, arg=8, argval=8, argrepr='closure', offset=18, start_offset=18, starts_line=False, line_number=2, label=None, positions=None), 1588 Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=106, arg=1, argval=1, argrepr='defaults', offset=20, start_offset=20, starts_line=False, line_number=2, label=None, positions=None), 1589 Instruction(opname='STORE_FAST', opcode=110, arg=2, argval='f', argrepr='f', offset=22, start_offset=22, starts_line=False, line_number=2, label=None, positions=None), 1590 Instruction(opname='LOAD_GLOBAL', opcode=91, arg=1, argval='print', argrepr='print + NULL', offset=24, start_offset=24, starts_line=True, line_number=7, label=None, positions=None), 1591 Instruction(opname='LOAD_DEREF', opcode=84, arg=0, argval='a', argrepr='a', offset=34, start_offset=34, starts_line=False, line_number=7, label=None, positions=None), 1592 Instruction(opname='LOAD_DEREF', opcode=84, arg=1, argval='b', argrepr='b', offset=36, start_offset=36, starts_line=False, line_number=7, label=None, positions=None), 1593 Instruction(opname='LOAD_CONST', opcode=83, arg=2, argval='', argrepr="''", offset=38, start_offset=38, starts_line=False, line_number=7, label=None, positions=None), 1594 Instruction(opname='LOAD_CONST', opcode=83, arg=3, argval=1, argrepr='1', offset=40, start_offset=40, starts_line=False, line_number=7, label=None, positions=None), 1595 Instruction(opname='BUILD_LIST', opcode=47, arg=0, argval=0, argrepr='', offset=42, start_offset=42, starts_line=False, line_number=7, label=None, positions=None), 1596 Instruction(opname='BUILD_MAP', opcode=48, arg=0, argval=0, argrepr='', offset=44, start_offset=44, starts_line=False, line_number=7, label=None, positions=None), 1597 Instruction(opname='LOAD_CONST', opcode=83, arg=4, argval='Hello world!', argrepr="'Hello world!'", offset=46, start_offset=46, starts_line=False, line_number=7, label=None, positions=None), 1598 Instruction(opname='CALL', opcode=53, arg=7, argval=7, argrepr='', offset=48, start_offset=48, starts_line=False, line_number=7, label=None, positions=None), 1599 Instruction(opname='POP_TOP', opcode=32, arg=None, argval=None, argrepr='', offset=56, start_offset=56, starts_line=False, line_number=7, label=None, positions=None), 1600 Instruction(opname='LOAD_FAST', opcode=85, arg=2, argval='f', argrepr='f', offset=58, start_offset=58, starts_line=True, line_number=8, label=None, positions=None), 1601 Instruction(opname='RETURN_VALUE', opcode=36, arg=None, argval=None, argrepr='', offset=60, start_offset=60, starts_line=False, line_number=8, label=None, positions=None), 1602] 1603 1604expected_opinfo_f = [ 1605 Instruction(opname='COPY_FREE_VARS', opcode=62, arg=2, argval=2, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=None, label=None, positions=None), 1606 Instruction(opname='MAKE_CELL', opcode=94, arg=0, argval='c', argrepr='c', offset=2, start_offset=2, starts_line=False, line_number=None, label=None, positions=None), 1607 Instruction(opname='MAKE_CELL', opcode=94, arg=1, argval='d', argrepr='d', offset=4, start_offset=4, starts_line=False, line_number=None, label=None, positions=None), 1608 Instruction(opname='RESUME', opcode=149, arg=0, argval=0, argrepr='', offset=6, start_offset=6, starts_line=True, line_number=2, label=None, positions=None), 1609 Instruction(opname='LOAD_CONST', opcode=83, arg=2, argval=(5, 6), argrepr='(5, 6)', offset=8, start_offset=8, starts_line=True, line_number=3, label=None, positions=None), 1610 Instruction(opname='LOAD_FAST', opcode=85, arg=3, argval='a', argrepr='a', offset=10, start_offset=10, starts_line=False, line_number=3, label=None, positions=None), 1611 Instruction(opname='LOAD_FAST', opcode=85, arg=4, argval='b', argrepr='b', offset=12, start_offset=12, starts_line=False, line_number=3, label=None, positions=None), 1612 Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='c', argrepr='c', offset=14, start_offset=14, starts_line=False, line_number=3, label=None, positions=None), 1613 Instruction(opname='LOAD_FAST', opcode=85, arg=1, argval='d', argrepr='d', offset=16, start_offset=16, starts_line=False, line_number=3, label=None, positions=None), 1614 Instruction(opname='BUILD_TUPLE', opcode=52, arg=4, argval=4, argrepr='', offset=18, start_offset=18, starts_line=False, line_number=3, label=None, positions=None), 1615 Instruction(opname='LOAD_CONST', opcode=83, arg=1, argval=code_object_inner, argrepr=repr(code_object_inner), offset=20, start_offset=20, starts_line=False, line_number=3, label=None, positions=None), 1616 Instruction(opname='MAKE_FUNCTION', opcode=26, arg=None, argval=None, argrepr='', offset=22, start_offset=22, starts_line=False, line_number=3, label=None, positions=None), 1617 Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=106, arg=8, argval=8, argrepr='closure', offset=24, start_offset=24, starts_line=False, line_number=3, label=None, positions=None), 1618 Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=106, arg=1, argval=1, argrepr='defaults', offset=26, start_offset=26, starts_line=False, line_number=3, label=None, positions=None), 1619 Instruction(opname='STORE_FAST', opcode=110, arg=2, argval='inner', argrepr='inner', offset=28, start_offset=28, starts_line=False, line_number=3, label=None, positions=None), 1620 Instruction(opname='LOAD_GLOBAL', opcode=91, arg=1, argval='print', argrepr='print + NULL', offset=30, start_offset=30, starts_line=True, line_number=5, label=None, positions=None), 1621 Instruction(opname='LOAD_DEREF', opcode=84, arg=3, argval='a', argrepr='a', offset=40, start_offset=40, starts_line=False, line_number=5, label=None, positions=None), 1622 Instruction(opname='LOAD_DEREF', opcode=84, arg=4, argval='b', argrepr='b', offset=42, start_offset=42, starts_line=False, line_number=5, label=None, positions=None), 1623 Instruction(opname='LOAD_DEREF', opcode=84, arg=0, argval='c', argrepr='c', offset=44, start_offset=44, starts_line=False, line_number=5, label=None, positions=None), 1624 Instruction(opname='LOAD_DEREF', opcode=84, arg=1, argval='d', argrepr='d', offset=46, start_offset=46, starts_line=False, line_number=5, label=None, positions=None), 1625 Instruction(opname='CALL', opcode=53, arg=4, argval=4, argrepr='', offset=48, start_offset=48, starts_line=False, line_number=5, label=None, positions=None), 1626 Instruction(opname='POP_TOP', opcode=32, arg=None, argval=None, argrepr='', offset=56, start_offset=56, starts_line=False, line_number=5, label=None, positions=None), 1627 Instruction(opname='LOAD_FAST', opcode=85, arg=2, argval='inner', argrepr='inner', offset=58, start_offset=58, starts_line=True, line_number=6, label=None, positions=None), 1628 Instruction(opname='RETURN_VALUE', opcode=36, arg=None, argval=None, argrepr='', offset=60, start_offset=60, starts_line=False, line_number=6, label=None, positions=None), 1629] 1630 1631expected_opinfo_inner = [ 1632 Instruction(opname='COPY_FREE_VARS', opcode=62, arg=4, argval=4, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=None, label=None, positions=None), 1633 Instruction(opname='RESUME', opcode=149, arg=0, argval=0, argrepr='', offset=2, start_offset=2, starts_line=True, line_number=3, label=None, positions=None), 1634 Instruction(opname='LOAD_GLOBAL', opcode=91, arg=1, argval='print', argrepr='print + NULL', offset=4, start_offset=4, starts_line=True, line_number=4, label=None, positions=None), 1635 Instruction(opname='LOAD_DEREF', opcode=84, arg=2, argval='a', argrepr='a', offset=14, start_offset=14, starts_line=False, line_number=4, label=None, positions=None), 1636 Instruction(opname='LOAD_DEREF', opcode=84, arg=3, argval='b', argrepr='b', offset=16, start_offset=16, starts_line=False, line_number=4, label=None, positions=None), 1637 Instruction(opname='LOAD_DEREF', opcode=84, arg=4, argval='c', argrepr='c', offset=18, start_offset=18, starts_line=False, line_number=4, label=None, positions=None), 1638 Instruction(opname='LOAD_DEREF', opcode=84, arg=5, argval='d', argrepr='d', offset=20, start_offset=20, starts_line=False, line_number=4, label=None, positions=None), 1639 Instruction(opname='LOAD_FAST_LOAD_FAST', opcode=88, arg=1, argval=('e', 'f'), argrepr='e, f', offset=22, start_offset=22, starts_line=False, line_number=4, label=None, positions=None), 1640 Instruction(opname='CALL', opcode=53, arg=6, argval=6, argrepr='', offset=24, start_offset=24, starts_line=False, line_number=4, label=None, positions=None), 1641 Instruction(opname='POP_TOP', opcode=32, arg=None, argval=None, argrepr='', offset=32, start_offset=32, starts_line=False, line_number=4, label=None, positions=None), 1642 Instruction(opname='RETURN_CONST', opcode=103, arg=0, argval=None, argrepr='None', offset=34, start_offset=34, starts_line=False, line_number=4, label=None, positions=None), 1643] 1644 1645expected_opinfo_jumpy = [ 1646 Instruction(opname='RESUME', opcode=149, arg=0, argval=0, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=1, label=None, positions=None, cache_info=None), 1647 Instruction(opname='LOAD_GLOBAL', opcode=91, arg=1, argval='range', argrepr='range + NULL', offset=2, start_offset=2, starts_line=True, line_number=3, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), 1648 Instruction(opname='LOAD_CONST', opcode=83, arg=1, argval=10, argrepr='10', offset=12, start_offset=12, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), 1649 Instruction(opname='CALL', opcode=53, arg=1, argval=1, argrepr='', offset=14, start_offset=14, starts_line=False, line_number=3, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), 1650 Instruction(opname='GET_ITER', opcode=19, arg=None, argval=None, argrepr='', offset=22, start_offset=22, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), 1651 Instruction(opname='FOR_ITER', opcode=72, arg=30, argval=88, argrepr='to L4', offset=24, start_offset=24, starts_line=False, line_number=3, label=1, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), 1652 Instruction(opname='STORE_FAST', opcode=110, arg=0, argval='i', argrepr='i', offset=28, start_offset=28, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), 1653 Instruction(opname='LOAD_GLOBAL', opcode=91, arg=3, argval='print', argrepr='print + NULL', offset=30, start_offset=30, starts_line=True, line_number=4, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), 1654 Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='i', argrepr='i', offset=40, start_offset=40, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), 1655 Instruction(opname='CALL', opcode=53, arg=1, argval=1, argrepr='', offset=42, start_offset=42, starts_line=False, line_number=4, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), 1656 Instruction(opname='POP_TOP', opcode=32, arg=None, argval=None, argrepr='', offset=50, start_offset=50, starts_line=False, line_number=4, label=None, positions=None, cache_info=None), 1657 Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='i', argrepr='i', offset=52, start_offset=52, starts_line=True, line_number=5, label=None, positions=None, cache_info=None), 1658 Instruction(opname='LOAD_CONST', opcode=83, arg=2, argval=4, argrepr='4', offset=54, start_offset=54, starts_line=False, line_number=5, label=None, positions=None, cache_info=None), 1659 Instruction(opname='COMPARE_OP', opcode=58, arg=18, argval='<', argrepr='bool(<)', offset=56, start_offset=56, starts_line=False, line_number=5, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), 1660 Instruction(opname='POP_JUMP_IF_FALSE', opcode=97, arg=2, argval=68, argrepr='to L2', offset=60, start_offset=60, starts_line=False, line_number=5, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), 1661 Instruction(opname='JUMP_BACKWARD', opcode=77, arg=22, argval=24, argrepr='to L1', offset=64, start_offset=64, starts_line=True, line_number=6, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), 1662 Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='i', argrepr='i', offset=68, start_offset=68, starts_line=True, line_number=7, label=2, positions=None, cache_info=None), 1663 Instruction(opname='LOAD_CONST', opcode=83, arg=3, argval=6, argrepr='6', offset=70, start_offset=70, starts_line=False, line_number=7, label=None, positions=None, cache_info=None), 1664 Instruction(opname='COMPARE_OP', opcode=58, arg=148, argval='>', argrepr='bool(>)', offset=72, start_offset=72, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), 1665 Instruction(opname='POP_JUMP_IF_TRUE', opcode=100, arg=2, argval=84, argrepr='to L3', offset=76, start_offset=76, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), 1666 Instruction(opname='JUMP_BACKWARD', opcode=77, arg=30, argval=24, argrepr='to L1', offset=80, start_offset=80, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), 1667 Instruction(opname='POP_TOP', opcode=32, arg=None, argval=None, argrepr='', offset=84, start_offset=84, starts_line=True, line_number=8, label=3, positions=None, cache_info=None), 1668 Instruction(opname='JUMP_FORWARD', opcode=79, arg=13, argval=114, argrepr='to L5', offset=86, start_offset=86, starts_line=False, line_number=8, label=None, positions=None, cache_info=None), 1669 Instruction(opname='END_FOR', opcode=11, arg=None, argval=None, argrepr='', offset=88, start_offset=88, starts_line=True, line_number=3, label=4, positions=None, cache_info=None), 1670 Instruction(opname='POP_TOP', opcode=32, arg=None, argval=None, argrepr='', offset=90, start_offset=90, starts_line=False, line_number=3, label=None, positions=None, cache_info=None), 1671 Instruction(opname='LOAD_GLOBAL', opcode=91, arg=3, argval='print', argrepr='print + NULL', offset=92, start_offset=92, starts_line=True, line_number=10, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), 1672 Instruction(opname='LOAD_CONST', opcode=83, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=102, start_offset=102, starts_line=False, line_number=10, label=None, positions=None, cache_info=None), 1673 Instruction(opname='CALL', opcode=53, arg=1, argval=1, argrepr='', offset=104, start_offset=104, starts_line=False, line_number=10, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), 1674 Instruction(opname='POP_TOP', opcode=32, arg=None, argval=None, argrepr='', offset=112, start_offset=112, starts_line=False, line_number=10, label=None, positions=None, cache_info=None), 1675 Instruction(opname='LOAD_FAST_CHECK', opcode=87, arg=0, argval='i', argrepr='i', offset=114, start_offset=114, starts_line=True, line_number=11, label=5, positions=None, cache_info=None), 1676 Instruction(opname='TO_BOOL', opcode=40, arg=None, argval=None, argrepr='', offset=116, start_offset=116, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), 1677 Instruction(opname='POP_JUMP_IF_FALSE', opcode=97, arg=40, argval=208, argrepr='to L9', offset=124, start_offset=124, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), 1678 Instruction(opname='LOAD_GLOBAL', opcode=91, arg=3, argval='print', argrepr='print + NULL', offset=128, start_offset=128, starts_line=True, line_number=12, label=6, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), 1679 Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='i', argrepr='i', offset=138, start_offset=138, starts_line=False, line_number=12, label=None, positions=None, cache_info=None), 1680 Instruction(opname='CALL', opcode=53, arg=1, argval=1, argrepr='', offset=140, start_offset=140, starts_line=False, line_number=12, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), 1681 Instruction(opname='POP_TOP', opcode=32, arg=None, argval=None, argrepr='', offset=148, start_offset=148, starts_line=False, line_number=12, label=None, positions=None, cache_info=None), 1682 Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='i', argrepr='i', offset=150, start_offset=150, starts_line=True, line_number=13, label=None, positions=None, cache_info=None), 1683 Instruction(opname='LOAD_CONST', opcode=83, arg=5, argval=1, argrepr='1', offset=152, start_offset=152, starts_line=False, line_number=13, label=None, positions=None, cache_info=None), 1684 Instruction(opname='BINARY_OP', opcode=45, arg=23, argval=23, argrepr='-=', offset=154, start_offset=154, starts_line=False, line_number=13, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), 1685 Instruction(opname='STORE_FAST', opcode=110, arg=0, argval='i', argrepr='i', offset=158, start_offset=158, starts_line=False, line_number=13, label=None, positions=None, cache_info=None), 1686 Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='i', argrepr='i', offset=160, start_offset=160, starts_line=True, line_number=14, label=None, positions=None, cache_info=None), 1687 Instruction(opname='LOAD_CONST', opcode=83, arg=3, argval=6, argrepr='6', offset=162, start_offset=162, starts_line=False, line_number=14, label=None, positions=None, cache_info=None), 1688 Instruction(opname='COMPARE_OP', opcode=58, arg=148, argval='>', argrepr='bool(>)', offset=164, start_offset=164, starts_line=False, line_number=14, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), 1689 Instruction(opname='POP_JUMP_IF_FALSE', opcode=97, arg=2, argval=176, argrepr='to L7', offset=168, start_offset=168, starts_line=False, line_number=14, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), 1690 Instruction(opname='JUMP_BACKWARD', opcode=77, arg=31, argval=114, argrepr='to L5', offset=172, start_offset=172, starts_line=True, line_number=15, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), 1691 Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='i', argrepr='i', offset=176, start_offset=176, starts_line=True, line_number=16, label=7, positions=None, cache_info=None), 1692 Instruction(opname='LOAD_CONST', opcode=83, arg=2, argval=4, argrepr='4', offset=178, start_offset=178, starts_line=False, line_number=16, label=None, positions=None, cache_info=None), 1693 Instruction(opname='COMPARE_OP', opcode=58, arg=18, argval='<', argrepr='bool(<)', offset=180, start_offset=180, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), 1694 Instruction(opname='POP_JUMP_IF_FALSE', opcode=97, arg=1, argval=190, argrepr='to L8', offset=184, start_offset=184, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), 1695 Instruction(opname='JUMP_FORWARD', opcode=79, arg=20, argval=230, argrepr='to L10', offset=188, start_offset=188, starts_line=True, line_number=17, label=None, positions=None, cache_info=None), 1696 Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='i', argrepr='i', offset=190, start_offset=190, starts_line=True, line_number=11, label=8, positions=None, cache_info=None), 1697 Instruction(opname='TO_BOOL', opcode=40, arg=None, argval=None, argrepr='', offset=192, start_offset=192, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), 1698 Instruction(opname='POP_JUMP_IF_FALSE', opcode=97, arg=2, argval=208, argrepr='to L9', offset=200, start_offset=200, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), 1699 Instruction(opname='JUMP_BACKWARD', opcode=77, arg=40, argval=128, argrepr='to L6', offset=204, start_offset=204, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), 1700 Instruction(opname='LOAD_GLOBAL', opcode=91, arg=3, argval='print', argrepr='print + NULL', offset=208, start_offset=208, starts_line=True, line_number=19, label=9, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), 1701 Instruction(opname='LOAD_CONST', opcode=83, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=218, start_offset=218, starts_line=False, line_number=19, label=None, positions=None, cache_info=None), 1702 Instruction(opname='CALL', opcode=53, arg=1, argval=1, argrepr='', offset=220, start_offset=220, starts_line=False, line_number=19, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), 1703 Instruction(opname='POP_TOP', opcode=32, arg=None, argval=None, argrepr='', offset=228, start_offset=228, starts_line=False, line_number=19, label=None, positions=None, cache_info=None), 1704 Instruction(opname='NOP', opcode=30, arg=None, argval=None, argrepr='', offset=230, start_offset=230, starts_line=True, line_number=20, label=10, positions=None, cache_info=None), 1705 Instruction(opname='LOAD_CONST', opcode=83, arg=5, argval=1, argrepr='1', offset=232, start_offset=232, starts_line=True, line_number=21, label=None, positions=None, cache_info=None), 1706 Instruction(opname='LOAD_CONST', opcode=83, arg=7, argval=0, argrepr='0', offset=234, start_offset=234, starts_line=False, line_number=21, label=None, positions=None, cache_info=None), 1707 Instruction(opname='BINARY_OP', opcode=45, arg=11, argval=11, argrepr='/', offset=236, start_offset=236, starts_line=False, line_number=21, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), 1708 Instruction(opname='POP_TOP', opcode=32, arg=None, argval=None, argrepr='', offset=240, start_offset=240, starts_line=False, line_number=21, label=None, positions=None, cache_info=None), 1709 Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='i', argrepr='i', offset=242, start_offset=242, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), 1710 Instruction(opname='BEFORE_WITH', opcode=2, arg=None, argval=None, argrepr='', offset=244, start_offset=244, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), 1711 Instruction(opname='STORE_FAST', opcode=110, arg=1, argval='dodgy', argrepr='dodgy', offset=246, start_offset=246, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), 1712 Instruction(opname='LOAD_GLOBAL', opcode=91, arg=3, argval='print', argrepr='print + NULL', offset=248, start_offset=248, starts_line=True, line_number=26, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), 1713 Instruction(opname='LOAD_CONST', opcode=83, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=258, start_offset=258, starts_line=False, line_number=26, label=None, positions=None, cache_info=None), 1714 Instruction(opname='CALL', opcode=53, arg=1, argval=1, argrepr='', offset=260, start_offset=260, starts_line=False, line_number=26, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), 1715 Instruction(opname='POP_TOP', opcode=32, arg=None, argval=None, argrepr='', offset=268, start_offset=268, starts_line=False, line_number=26, label=None, positions=None, cache_info=None), 1716 Instruction(opname='LOAD_CONST', opcode=83, arg=0, argval=None, argrepr='None', offset=270, start_offset=270, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), 1717 Instruction(opname='LOAD_CONST', opcode=83, arg=0, argval=None, argrepr='None', offset=272, start_offset=272, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), 1718 Instruction(opname='LOAD_CONST', opcode=83, arg=0, argval=None, argrepr='None', offset=274, start_offset=274, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), 1719 Instruction(opname='CALL', opcode=53, arg=2, argval=2, argrepr='', offset=276, start_offset=276, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), 1720 Instruction(opname='POP_TOP', opcode=32, arg=None, argval=None, argrepr='', offset=284, start_offset=284, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), 1721 Instruction(opname='LOAD_GLOBAL', opcode=91, arg=3, argval='print', argrepr='print + NULL', offset=286, start_offset=286, starts_line=True, line_number=28, label=11, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), 1722 Instruction(opname='LOAD_CONST', opcode=83, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=296, start_offset=296, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), 1723 Instruction(opname='CALL', opcode=53, arg=1, argval=1, argrepr='', offset=298, start_offset=298, starts_line=False, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), 1724 Instruction(opname='POP_TOP', opcode=32, arg=None, argval=None, argrepr='', offset=306, start_offset=306, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), 1725 Instruction(opname='RETURN_CONST', opcode=103, arg=0, argval=None, argrepr='None', offset=308, start_offset=308, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), 1726 Instruction(opname='PUSH_EXC_INFO', opcode=33, arg=None, argval=None, argrepr='', offset=310, start_offset=310, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), 1727 Instruction(opname='WITH_EXCEPT_START', opcode=44, arg=None, argval=None, argrepr='', offset=312, start_offset=312, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), 1728 Instruction(opname='TO_BOOL', opcode=40, arg=None, argval=None, argrepr='', offset=314, start_offset=314, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), 1729 Instruction(opname='POP_JUMP_IF_TRUE', opcode=100, arg=1, argval=328, argrepr='to L12', offset=322, start_offset=322, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), 1730 Instruction(opname='RERAISE', opcode=102, arg=2, argval=2, argrepr='', offset=326, start_offset=326, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), 1731 Instruction(opname='POP_TOP', opcode=32, arg=None, argval=None, argrepr='', offset=328, start_offset=328, starts_line=False, line_number=25, label=12, positions=None, cache_info=None), 1732 Instruction(opname='POP_EXCEPT', opcode=31, arg=None, argval=None, argrepr='', offset=330, start_offset=330, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), 1733 Instruction(opname='POP_TOP', opcode=32, arg=None, argval=None, argrepr='', offset=332, start_offset=332, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), 1734 Instruction(opname='POP_TOP', opcode=32, arg=None, argval=None, argrepr='', offset=334, start_offset=334, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), 1735 Instruction(opname='JUMP_BACKWARD_NO_INTERRUPT', opcode=78, arg=26, argval=286, argrepr='to L11', offset=336, start_offset=336, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), 1736 Instruction(opname='COPY', opcode=61, arg=3, argval=3, argrepr='', offset=338, start_offset=338, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), 1737 Instruction(opname='POP_EXCEPT', opcode=31, arg=None, argval=None, argrepr='', offset=340, start_offset=340, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), 1738 Instruction(opname='RERAISE', opcode=102, arg=1, argval=1, argrepr='', offset=342, start_offset=342, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), 1739 Instruction(opname='PUSH_EXC_INFO', opcode=33, arg=None, argval=None, argrepr='', offset=344, start_offset=344, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), 1740 Instruction(opname='LOAD_GLOBAL', opcode=91, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=346, start_offset=346, starts_line=True, line_number=22, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), 1741 Instruction(opname='CHECK_EXC_MATCH', opcode=7, arg=None, argval=None, argrepr='', offset=356, start_offset=356, starts_line=False, line_number=22, label=None, positions=None, cache_info=None), 1742 Instruction(opname='POP_JUMP_IF_FALSE', opcode=97, arg=14, argval=390, argrepr='to L13', offset=358, start_offset=358, starts_line=False, line_number=22, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), 1743 Instruction(opname='POP_TOP', opcode=32, arg=None, argval=None, argrepr='', offset=362, start_offset=362, starts_line=False, line_number=22, label=None, positions=None, cache_info=None), 1744 Instruction(opname='LOAD_GLOBAL', opcode=91, arg=3, argval='print', argrepr='print + NULL', offset=364, start_offset=364, starts_line=True, line_number=23, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), 1745 Instruction(opname='LOAD_CONST', opcode=83, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=374, start_offset=374, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), 1746 Instruction(opname='CALL', opcode=53, arg=1, argval=1, argrepr='', offset=376, start_offset=376, starts_line=False, line_number=23, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), 1747 Instruction(opname='POP_TOP', opcode=32, arg=None, argval=None, argrepr='', offset=384, start_offset=384, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), 1748 Instruction(opname='POP_EXCEPT', opcode=31, arg=None, argval=None, argrepr='', offset=386, start_offset=386, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), 1749 Instruction(opname='JUMP_BACKWARD_NO_INTERRUPT', opcode=78, arg=52, argval=286, argrepr='to L11', offset=388, start_offset=388, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), 1750 Instruction(opname='RERAISE', opcode=102, arg=0, argval=0, argrepr='', offset=390, start_offset=390, starts_line=True, line_number=22, label=13, positions=None, cache_info=None), 1751 Instruction(opname='COPY', opcode=61, arg=3, argval=3, argrepr='', offset=392, start_offset=392, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), 1752 Instruction(opname='POP_EXCEPT', opcode=31, arg=None, argval=None, argrepr='', offset=394, start_offset=394, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), 1753 Instruction(opname='RERAISE', opcode=102, arg=1, argval=1, argrepr='', offset=396, start_offset=396, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), 1754 Instruction(opname='PUSH_EXC_INFO', opcode=33, arg=None, argval=None, argrepr='', offset=398, start_offset=398, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), 1755 Instruction(opname='LOAD_GLOBAL', opcode=91, arg=3, argval='print', argrepr='print + NULL', offset=400, start_offset=400, starts_line=True, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), 1756 Instruction(opname='LOAD_CONST', opcode=83, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=410, start_offset=410, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), 1757 Instruction(opname='CALL', opcode=53, arg=1, argval=1, argrepr='', offset=412, start_offset=412, starts_line=False, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), 1758 Instruction(opname='POP_TOP', opcode=32, arg=None, argval=None, argrepr='', offset=420, start_offset=420, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), 1759 Instruction(opname='RERAISE', opcode=102, arg=0, argval=0, argrepr='', offset=422, start_offset=422, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), 1760 Instruction(opname='COPY', opcode=61, arg=3, argval=3, argrepr='', offset=424, start_offset=424, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), 1761 Instruction(opname='POP_EXCEPT', opcode=31, arg=None, argval=None, argrepr='', offset=426, start_offset=426, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), 1762 Instruction(opname='RERAISE', opcode=102, arg=1, argval=1, argrepr='', offset=428, start_offset=428, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), 1763] 1764 1765# One last piece of inspect fodder to check the default line number handling 1766def simple(): pass 1767expected_opinfo_simple = [ 1768 Instruction(opname='RESUME', opcode=149, arg=0, argval=0, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=simple.__code__.co_firstlineno, label=None, positions=None), 1769 Instruction(opname='RETURN_CONST', opcode=103, arg=0, argval=None, argrepr='None', offset=2, start_offset=2, starts_line=False, line_number=simple.__code__.co_firstlineno, label=None), 1770] 1771 1772 1773class InstructionTestCase(BytecodeTestCase): 1774 1775 def assertInstructionsEqual(self, instrs_1, instrs_2, /): 1776 instrs_1 = [instr_1._replace(positions=None, cache_info=None) for instr_1 in instrs_1] 1777 instrs_2 = [instr_2._replace(positions=None, cache_info=None) for instr_2 in instrs_2] 1778 self.assertEqual(instrs_1, instrs_2) 1779 1780class InstructionTests(InstructionTestCase): 1781 1782 def __init__(self, *args): 1783 super().__init__(*args) 1784 self.maxDiff = None 1785 1786 def test_instruction_str(self): 1787 # smoke test for __str__ 1788 instrs = dis.get_instructions(simple) 1789 for instr in instrs: 1790 str(instr) 1791 1792 def test_default_first_line(self): 1793 actual = dis.get_instructions(simple) 1794 self.assertInstructionsEqual(list(actual), expected_opinfo_simple) 1795 1796 def test_first_line_set_to_None(self): 1797 actual = dis.get_instructions(simple, first_line=None) 1798 self.assertInstructionsEqual(list(actual), expected_opinfo_simple) 1799 1800 def test_outer(self): 1801 actual = dis.get_instructions(outer, first_line=expected_outer_line) 1802 self.assertInstructionsEqual(list(actual), expected_opinfo_outer) 1803 1804 def test_nested(self): 1805 with captured_stdout(): 1806 f = outer() 1807 actual = dis.get_instructions(f, first_line=expected_f_line) 1808 self.assertInstructionsEqual(list(actual), expected_opinfo_f) 1809 1810 def test_doubly_nested(self): 1811 with captured_stdout(): 1812 inner = outer()() 1813 actual = dis.get_instructions(inner, first_line=expected_inner_line) 1814 self.assertInstructionsEqual(list(actual), expected_opinfo_inner) 1815 1816 def test_jumpy(self): 1817 actual = dis.get_instructions(jumpy, first_line=expected_jumpy_line) 1818 self.assertInstructionsEqual(list(actual), expected_opinfo_jumpy) 1819 1820 @requires_debug_ranges() 1821 def test_co_positions(self): 1822 code = compile('f(\n x, y, z\n)', '<test>', 'exec') 1823 positions = [ 1824 instr.positions 1825 for instr in dis.get_instructions(code) 1826 ] 1827 expected = [ 1828 (0, 1, 0, 0), 1829 (1, 1, 0, 1), 1830 (1, 1, 0, 1), 1831 (2, 2, 2, 3), 1832 (2, 2, 5, 6), 1833 (2, 2, 8, 9), 1834 (1, 3, 0, 1), 1835 (1, 3, 0, 1), 1836 (1, 3, 0, 1) 1837 ] 1838 self.assertEqual(positions, expected) 1839 1840 named_positions = [ 1841 (pos.lineno, pos.end_lineno, pos.col_offset, pos.end_col_offset) 1842 for pos in positions 1843 ] 1844 self.assertEqual(named_positions, expected) 1845 1846 @requires_debug_ranges() 1847 def test_co_positions_missing_info(self): 1848 code = compile('x, y, z', '<test>', 'exec') 1849 code_without_location_table = code.replace(co_linetable=b'') 1850 actual = dis.get_instructions(code_without_location_table) 1851 for instruction in actual: 1852 with self.subTest(instruction=instruction): 1853 positions = instruction.positions 1854 self.assertEqual(len(positions), 4) 1855 if instruction.opname == "RESUME": 1856 continue 1857 self.assertIsNone(positions.lineno) 1858 self.assertIsNone(positions.end_lineno) 1859 self.assertIsNone(positions.col_offset) 1860 self.assertIsNone(positions.end_col_offset) 1861 1862 @requires_debug_ranges() 1863 def test_co_positions_with_lots_of_caches(self): 1864 def roots(a, b, c): 1865 d = b**2 - 4 * a * c 1866 yield (-b - cmath.sqrt(d)) / (2 * a) 1867 if d: 1868 yield (-b + cmath.sqrt(d)) / (2 * a) 1869 code = roots.__code__ 1870 ops = code.co_code[::2] 1871 cache_opcode = opcode.opmap["CACHE"] 1872 caches = sum(op == cache_opcode for op in ops) 1873 non_caches = len(ops) - caches 1874 # Make sure we have "lots of caches". If not, roots should be changed: 1875 assert 1 / 3 <= caches / non_caches, "this test needs more caches!" 1876 for show_caches in (False, True): 1877 for adaptive in (False, True): 1878 with self.subTest(f"{adaptive=}, {show_caches=}"): 1879 co_positions = [ 1880 positions 1881 for op, positions in zip(ops, code.co_positions(), strict=True) 1882 if show_caches or op != cache_opcode 1883 ] 1884 dis_positions = [ 1885 None if instruction.positions is None else ( 1886 instruction.positions.lineno, 1887 instruction.positions.end_lineno, 1888 instruction.positions.col_offset, 1889 instruction.positions.end_col_offset, 1890 ) 1891 for instruction in _unroll_caches_as_Instructions(dis.get_instructions( 1892 code, adaptive=adaptive, show_caches=show_caches 1893 ), show_caches=show_caches) 1894 ] 1895 self.assertEqual(co_positions, dis_positions) 1896 1897 def test_oparg_alias(self): 1898 instruction = Instruction(opname="NOP", opcode=dis.opmap["NOP"], arg=None, argval=None, 1899 argrepr='', offset=10, start_offset=10, starts_line=True, line_number=1, label=None, 1900 positions=None) 1901 self.assertEqual(instruction.arg, instruction.oparg) 1902 1903 def test_show_caches_with_label(self): 1904 def f(x, y, z): 1905 if x: 1906 res = y 1907 else: 1908 res = z 1909 return res 1910 1911 output = io.StringIO() 1912 dis.dis(f.__code__, file=output, show_caches=True) 1913 self.assertIn("L1:", output.getvalue()) 1914 1915 def test_baseopname_and_baseopcode(self): 1916 # Standard instructions 1917 for name, code in dis.opmap.items(): 1918 instruction = Instruction(opname=name, opcode=code, arg=None, argval=None, argrepr='', offset=0, 1919 start_offset=0, starts_line=True, line_number=1, label=None, positions=None) 1920 baseopname = instruction.baseopname 1921 baseopcode = instruction.baseopcode 1922 self.assertIsNotNone(baseopname) 1923 self.assertIsNotNone(baseopcode) 1924 self.assertEqual(name, baseopname) 1925 self.assertEqual(code, baseopcode) 1926 1927 # Specialized instructions 1928 for name in opcode._specialized_opmap: 1929 instruction = Instruction(opname=name, opcode=dis._all_opmap[name], arg=None, argval=None, argrepr='', 1930 offset=0, start_offset=0, starts_line=True, line_number=1, label=None, positions=None) 1931 baseopname = instruction.baseopname 1932 baseopcode = instruction.baseopcode 1933 self.assertIn(name, opcode._specializations[baseopname]) 1934 self.assertEqual(opcode.opmap[baseopname], baseopcode) 1935 1936 def test_jump_target(self): 1937 # Non-jump instructions should return None 1938 instruction = Instruction(opname="NOP", opcode=dis.opmap["NOP"], arg=None, argval=None, 1939 argrepr='', offset=10, start_offset=10, starts_line=True, line_number=1, label=None, 1940 positions=None) 1941 self.assertIsNone(instruction.jump_target) 1942 1943 delta = 100 1944 instruction = Instruction(opname="JUMP_FORWARD", opcode=dis.opmap["JUMP_FORWARD"], arg=delta, argval=delta, 1945 argrepr='', offset=10, start_offset=10, starts_line=True, line_number=1, label=None, 1946 positions=None) 1947 self.assertEqual(10 + 2 + 100*2, instruction.jump_target) 1948 1949 # Test negative deltas 1950 instruction = Instruction(opname="JUMP_BACKWARD", opcode=dis.opmap["JUMP_BACKWARD"], arg=delta, argval=delta, 1951 argrepr='', offset=200, start_offset=200, starts_line=True, line_number=1, label=None, 1952 positions=None) 1953 self.assertEqual(200 + 2 - 100*2 + 2*1, instruction.jump_target) 1954 1955 # Make sure cache entries are handled 1956 instruction = Instruction(opname="SEND", opcode=dis.opmap["SEND"], arg=delta, argval=delta, 1957 argrepr='', offset=10, start_offset=10, starts_line=True, line_number=1, label=None, 1958 positions=None) 1959 self.assertEqual(10 + 2 + 1*2 + 100*2, instruction.jump_target) 1960 1961 def test_argval_argrepr(self): 1962 def f(opcode, oparg, offset, *init_args): 1963 arg_resolver = dis.ArgResolver(*init_args) 1964 return arg_resolver.get_argval_argrepr(opcode, oparg, offset) 1965 1966 offset = 42 1967 co_consts = (0, 1, 2, 3) 1968 names = {1: 'a', 2: 'b'} 1969 varname_from_oparg = lambda i : names[i] 1970 labels_map = {24: 1} 1971 args = (offset, co_consts, names, varname_from_oparg, labels_map) 1972 self.assertEqual(f(opcode.opmap["POP_TOP"], None, *args), (None, '')) 1973 self.assertEqual(f(opcode.opmap["LOAD_CONST"], 1, *args), (1, '1')) 1974 self.assertEqual(f(opcode.opmap["LOAD_GLOBAL"], 2, *args), ('a', 'a')) 1975 self.assertEqual(f(opcode.opmap["JUMP_BACKWARD"], 11, *args), (24, 'to L1')) 1976 self.assertEqual(f(opcode.opmap["COMPARE_OP"], 3, *args), ('<', '<')) 1977 self.assertEqual(f(opcode.opmap["SET_FUNCTION_ATTRIBUTE"], 2, *args), (2, 'kwdefaults')) 1978 self.assertEqual(f(opcode.opmap["BINARY_OP"], 3, *args), (3, '<<')) 1979 self.assertEqual(f(opcode.opmap["CALL_INTRINSIC_1"], 2, *args), (2, 'INTRINSIC_IMPORT_STAR')) 1980 1981 def test_custom_arg_resolver(self): 1982 class MyArgResolver(dis.ArgResolver): 1983 def offset_from_jump_arg(self, op, arg, offset): 1984 return arg + 1 1985 1986 def get_label_for_offset(self, offset): 1987 return 2 * offset 1988 1989 def f(opcode, oparg, offset, *init_args): 1990 arg_resolver = MyArgResolver(*init_args) 1991 return arg_resolver.get_argval_argrepr(opcode, oparg, offset) 1992 offset = 42 1993 self.assertEqual(f(opcode.opmap["JUMP_BACKWARD"], 1, offset), (2, 'to L4')) 1994 self.assertEqual(f(opcode.opmap["SETUP_FINALLY"], 2, offset), (3, 'to L6')) 1995 1996 1997 def get_instructions(self, code): 1998 return dis._get_instructions_bytes(code) 1999 2000 def test_start_offset(self): 2001 # When no extended args are present, 2002 # start_offset should be equal to offset 2003 2004 instructions = list(dis.Bytecode(_f)) 2005 for instruction in instructions: 2006 self.assertEqual(instruction.offset, instruction.start_offset) 2007 2008 def last_item(iterable): 2009 return functools.reduce(lambda a, b : b, iterable) 2010 2011 code = bytes([ 2012 opcode.opmap["LOAD_FAST"], 0x00, 2013 opcode.opmap["EXTENDED_ARG"], 0x01, 2014 opcode.opmap["POP_JUMP_IF_TRUE"], 0xFF, 2015 ]) 2016 labels_map = dis._make_labels_map(code) 2017 jump = last_item(self.get_instructions(code)) 2018 self.assertEqual(4, jump.offset) 2019 self.assertEqual(2, jump.start_offset) 2020 2021 code = bytes([ 2022 opcode.opmap["LOAD_FAST"], 0x00, 2023 opcode.opmap["EXTENDED_ARG"], 0x01, 2024 opcode.opmap["EXTENDED_ARG"], 0x01, 2025 opcode.opmap["EXTENDED_ARG"], 0x01, 2026 opcode.opmap["POP_JUMP_IF_TRUE"], 0xFF, 2027 opcode.opmap["CACHE"], 0x00, 2028 ]) 2029 jump = last_item(self.get_instructions(code)) 2030 self.assertEqual(8, jump.offset) 2031 self.assertEqual(2, jump.start_offset) 2032 2033 code = bytes([ 2034 opcode.opmap["LOAD_FAST"], 0x00, 2035 opcode.opmap["EXTENDED_ARG"], 0x01, 2036 opcode.opmap["POP_JUMP_IF_TRUE"], 0xFF, 2037 opcode.opmap["CACHE"], 0x00, 2038 opcode.opmap["EXTENDED_ARG"], 0x01, 2039 opcode.opmap["EXTENDED_ARG"], 0x01, 2040 opcode.opmap["EXTENDED_ARG"], 0x01, 2041 opcode.opmap["POP_JUMP_IF_TRUE"], 0xFF, 2042 opcode.opmap["CACHE"], 0x00, 2043 ]) 2044 instructions = list(self.get_instructions(code)) 2045 # 1st jump 2046 self.assertEqual(4, instructions[2].offset) 2047 self.assertEqual(2, instructions[2].start_offset) 2048 # 2nd jump 2049 self.assertEqual(14, instructions[6].offset) 2050 self.assertEqual(8, instructions[6].start_offset) 2051 2052 def test_cache_offset_and_end_offset(self): 2053 code = bytes([ 2054 opcode.opmap["LOAD_GLOBAL"], 0x01, 2055 opcode.opmap["CACHE"], 0x00, 2056 opcode.opmap["CACHE"], 0x00, 2057 opcode.opmap["CACHE"], 0x00, 2058 opcode.opmap["CACHE"], 0x00, 2059 opcode.opmap["LOAD_FAST"], 0x00, 2060 opcode.opmap["CALL"], 0x01, 2061 opcode.opmap["CACHE"], 0x00, 2062 opcode.opmap["CACHE"], 0x00, 2063 opcode.opmap["CACHE"], 0x00 2064 ]) 2065 instructions = list(self.get_instructions(code)) 2066 self.assertEqual(2, instructions[0].cache_offset) 2067 self.assertEqual(10, instructions[0].end_offset) 2068 self.assertEqual(12, instructions[1].cache_offset) 2069 self.assertEqual(12, instructions[1].end_offset) 2070 self.assertEqual(14, instructions[2].cache_offset) 2071 self.assertEqual(20, instructions[2].end_offset) 2072 2073 # end_offset of the previous instruction should be equal to the 2074 # start_offset of the following instruction 2075 instructions = list(dis.Bytecode(self.test_cache_offset_and_end_offset)) 2076 for prev, curr in zip(instructions, instructions[1:]): 2077 self.assertEqual(prev.end_offset, curr.start_offset) 2078 2079 2080# get_instructions has its own tests above, so can rely on it to validate 2081# the object oriented API 2082class BytecodeTests(InstructionTestCase, DisTestBase): 2083 2084 def test_instantiation(self): 2085 # Test with function, method, code string and code object 2086 for obj in [_f, _C(1).__init__, "a=1", _f.__code__]: 2087 with self.subTest(obj=obj): 2088 b = dis.Bytecode(obj) 2089 self.assertIsInstance(b.codeobj, types.CodeType) 2090 2091 self.assertRaises(TypeError, dis.Bytecode, object()) 2092 2093 def test_iteration(self): 2094 for obj in [_f, _C(1).__init__, "a=1", _f.__code__]: 2095 with self.subTest(obj=obj): 2096 via_object = list(dis.Bytecode(obj)) 2097 via_generator = list(dis.get_instructions(obj)) 2098 self.assertInstructionsEqual(via_object, via_generator) 2099 2100 def test_explicit_first_line(self): 2101 actual = dis.Bytecode(outer, first_line=expected_outer_line) 2102 self.assertInstructionsEqual(list(actual), expected_opinfo_outer) 2103 2104 def test_source_line_in_disassembly(self): 2105 # Use the line in the source code 2106 actual = dis.Bytecode(simple).dis() 2107 actual = actual.strip().partition(" ")[0] # extract the line no 2108 expected = str(simple.__code__.co_firstlineno) 2109 self.assertEqual(actual, expected) 2110 # Use an explicit first line number 2111 actual = dis.Bytecode(simple, first_line=350).dis() 2112 actual = actual.strip().partition(" ")[0] # extract the line no 2113 self.assertEqual(actual, "350") 2114 2115 def test_info(self): 2116 self.maxDiff = 1000 2117 for x, expected in CodeInfoTests.test_pairs: 2118 b = dis.Bytecode(x) 2119 self.assertRegex(b.info(), expected) 2120 2121 def test_disassembled(self): 2122 actual = dis.Bytecode(_f).dis() 2123 self.do_disassembly_compare(actual, dis_f) 2124 2125 def test_from_traceback(self): 2126 tb = get_tb() 2127 b = dis.Bytecode.from_traceback(tb) 2128 while tb.tb_next: tb = tb.tb_next 2129 2130 self.assertEqual(b.current_offset, tb.tb_lasti) 2131 2132 def test_from_traceback_dis(self): 2133 self.maxDiff = None 2134 tb = get_tb() 2135 b = dis.Bytecode.from_traceback(tb) 2136 self.assertEqual(b.dis(), dis_traceback) 2137 2138 @requires_debug_ranges() 2139 def test_bytecode_co_positions(self): 2140 bytecode = dis.Bytecode("a=1") 2141 for instr, positions in zip(bytecode, bytecode.codeobj.co_positions()): 2142 assert instr.positions == positions 2143 2144class TestBytecodeTestCase(BytecodeTestCase): 2145 def test_assert_not_in_with_op_not_in_bytecode(self): 2146 code = compile("a = 1", "<string>", "exec") 2147 self.assertInBytecode(code, "LOAD_CONST", 1) 2148 self.assertNotInBytecode(code, "LOAD_NAME") 2149 self.assertNotInBytecode(code, "LOAD_NAME", "a") 2150 2151 def test_assert_not_in_with_arg_not_in_bytecode(self): 2152 code = compile("a = 1", "<string>", "exec") 2153 self.assertInBytecode(code, "LOAD_CONST") 2154 self.assertInBytecode(code, "LOAD_CONST", 1) 2155 self.assertNotInBytecode(code, "LOAD_CONST", 2) 2156 2157 def test_assert_not_in_with_arg_in_bytecode(self): 2158 code = compile("a = 1", "<string>", "exec") 2159 with self.assertRaises(AssertionError): 2160 self.assertNotInBytecode(code, "LOAD_CONST", 1) 2161 2162class TestFinderMethods(unittest.TestCase): 2163 def test__find_imports(self): 2164 cases = [ 2165 ("import a.b.c", ('a.b.c', 0, None)), 2166 ("from a.b import c", ('a.b', 0, ('c',))), 2167 ("from a.b import c as d", ('a.b', 0, ('c',))), 2168 ("from a.b import *", ('a.b', 0, ('*',))), 2169 ("from ...a.b import c as d", ('a.b', 3, ('c',))), 2170 ("from ..a.b import c as d, e as f", ('a.b', 2, ('c', 'e'))), 2171 ("from ..a.b import *", ('a.b', 2, ('*',))), 2172 ] 2173 for src, expected in cases: 2174 with self.subTest(src=src): 2175 code = compile(src, "<string>", "exec") 2176 res = tuple(dis._find_imports(code)) 2177 self.assertEqual(len(res), 1) 2178 self.assertEqual(res[0], expected) 2179 2180 def test__find_store_names(self): 2181 cases = [ 2182 ("x+y", ()), 2183 ("x=y=1", ('x', 'y')), 2184 ("x+=y", ('x',)), 2185 ("global x\nx=y=1", ('x', 'y')), 2186 ("global x\nz=x", ('z',)), 2187 ] 2188 for src, expected in cases: 2189 with self.subTest(src=src): 2190 code = compile(src, "<string>", "exec") 2191 res = tuple(dis._find_store_names(code)) 2192 self.assertEqual(res, expected) 2193 2194 def test_findlabels(self): 2195 labels = dis.findlabels(jumpy.__code__.co_code) 2196 jumps = [ 2197 instr.offset 2198 for instr in expected_opinfo_jumpy 2199 if instr.is_jump_target 2200 ] 2201 2202 self.assertEqual(sorted(labels), sorted(jumps)) 2203 2204 def test_findlinestarts(self): 2205 def func(): 2206 pass 2207 2208 code = func.__code__ 2209 offsets = [linestart[0] for linestart in dis.findlinestarts(code)] 2210 self.assertEqual(offsets, [0, 2]) 2211 2212 2213class TestDisTraceback(DisTestBase): 2214 def setUp(self) -> None: 2215 try: # We need to clean up existing tracebacks 2216 del sys.last_exc 2217 except AttributeError: 2218 pass 2219 try: # We need to clean up existing tracebacks 2220 del sys.last_traceback 2221 except AttributeError: 2222 pass 2223 return super().setUp() 2224 2225 def get_disassembly(self, tb): 2226 output = io.StringIO() 2227 with contextlib.redirect_stdout(output): 2228 dis.distb(tb) 2229 return output.getvalue() 2230 2231 def test_distb_empty(self): 2232 with self.assertRaises(RuntimeError): 2233 dis.distb() 2234 2235 def test_distb_last_traceback(self): 2236 self.maxDiff = None 2237 # We need to have an existing last traceback in `sys`: 2238 tb = get_tb() 2239 sys.last_traceback = tb 2240 2241 self.do_disassembly_compare(self.get_disassembly(None), dis_traceback) 2242 2243 def test_distb_explicit_arg(self): 2244 self.maxDiff = None 2245 tb = get_tb() 2246 2247 self.do_disassembly_compare(self.get_disassembly(tb), dis_traceback) 2248 2249 2250class TestDisTracebackWithFile(TestDisTraceback): 2251 # Run the `distb` tests again, using the file arg instead of print 2252 def get_disassembly(self, tb): 2253 output = io.StringIO() 2254 with contextlib.redirect_stdout(output): 2255 dis.distb(tb, file=output) 2256 return output.getvalue() 2257 2258def _unroll_caches_as_Instructions(instrs, show_caches=False): 2259 # Cache entries are no longer reported by dis as fake instructions, 2260 # but some tests assume that do. We should rewrite the tests to assume 2261 # the new API, but it will be clearer to keep the tests working as 2262 # before and do that in a separate PR. 2263 2264 for instr in instrs: 2265 yield instr 2266 if not show_caches: 2267 continue 2268 2269 offset = instr.offset 2270 for name, size, data in (instr.cache_info or ()): 2271 for i in range(size): 2272 offset += 2 2273 # Only show the fancy argrepr for a CACHE instruction when it's 2274 # the first entry for a particular cache value: 2275 if i == 0: 2276 argrepr = f"{name}: {int.from_bytes(data, sys.byteorder)}" 2277 else: 2278 argrepr = "" 2279 2280 yield Instruction("CACHE", CACHE, 0, None, argrepr, offset, offset, 2281 False, None, None, instr.positions) 2282 2283 2284if __name__ == "__main__": 2285 unittest.main() 2286