1# Minimal tests for dis module 2 3from test.support import captured_stdout 4from test.bytecode_helper import BytecodeTestCase 5import unittest 6import sys 7import dis 8import io 9import re 10import types 11import contextlib 12 13def get_tb(): 14 def _error(): 15 try: 16 1 / 0 17 except Exception as e: 18 tb = e.__traceback__ 19 return tb 20 21 tb = _error() 22 while tb.tb_next: 23 tb = tb.tb_next 24 return tb 25 26TRACEBACK_CODE = get_tb().tb_frame.f_code 27 28class _C: 29 def __init__(self, x): 30 self.x = x == 1 31 32 @staticmethod 33 def sm(x): 34 x = x == 1 35 36 @classmethod 37 def cm(cls, x): 38 cls.x = x == 1 39 40dis_c_instance_method = """\ 41%3d 0 LOAD_FAST 1 (x) 42 2 LOAD_CONST 1 (1) 43 4 COMPARE_OP 2 (==) 44 6 LOAD_FAST 0 (self) 45 8 STORE_ATTR 0 (x) 46 10 LOAD_CONST 0 (None) 47 12 RETURN_VALUE 48""" % (_C.__init__.__code__.co_firstlineno + 1,) 49 50dis_c_instance_method_bytes = """\ 51 0 LOAD_FAST 1 (1) 52 2 LOAD_CONST 1 (1) 53 4 COMPARE_OP 2 (==) 54 6 LOAD_FAST 0 (0) 55 8 STORE_ATTR 0 (0) 56 10 LOAD_CONST 0 (0) 57 12 RETURN_VALUE 58""" 59 60dis_c_class_method = """\ 61%3d 0 LOAD_FAST 1 (x) 62 2 LOAD_CONST 1 (1) 63 4 COMPARE_OP 2 (==) 64 6 LOAD_FAST 0 (cls) 65 8 STORE_ATTR 0 (x) 66 10 LOAD_CONST 0 (None) 67 12 RETURN_VALUE 68""" % (_C.cm.__code__.co_firstlineno + 2,) 69 70dis_c_static_method = """\ 71%3d 0 LOAD_FAST 0 (x) 72 2 LOAD_CONST 1 (1) 73 4 COMPARE_OP 2 (==) 74 6 STORE_FAST 0 (x) 75 8 LOAD_CONST 0 (None) 76 10 RETURN_VALUE 77""" % (_C.sm.__code__.co_firstlineno + 2,) 78 79# Class disassembling info has an extra newline at end. 80dis_c = """\ 81Disassembly of %s: 82%s 83Disassembly of %s: 84%s 85Disassembly of %s: 86%s 87""" % (_C.__init__.__name__, dis_c_instance_method, 88 _C.cm.__name__, dis_c_class_method, 89 _C.sm.__name__, dis_c_static_method) 90 91def _f(a): 92 print(a) 93 return 1 94 95dis_f = """\ 96%3d 0 LOAD_GLOBAL 0 (print) 97 2 LOAD_FAST 0 (a) 98 4 CALL_FUNCTION 1 99 6 POP_TOP 100 101%3d 8 LOAD_CONST 1 (1) 102 10 RETURN_VALUE 103""" % (_f.__code__.co_firstlineno + 1, 104 _f.__code__.co_firstlineno + 2) 105 106 107dis_f_co_code = """\ 108 0 LOAD_GLOBAL 0 (0) 109 2 LOAD_FAST 0 (0) 110 4 CALL_FUNCTION 1 111 6 POP_TOP 112 8 LOAD_CONST 1 (1) 113 10 RETURN_VALUE 114""" 115 116 117def bug708901(): 118 for res in range(1, 119 10): 120 pass 121 122dis_bug708901 = """\ 123%3d 0 SETUP_LOOP 18 (to 20) 124 2 LOAD_GLOBAL 0 (range) 125 4 LOAD_CONST 1 (1) 126 127%3d 6 LOAD_CONST 2 (10) 128 8 CALL_FUNCTION 2 129 10 GET_ITER 130 >> 12 FOR_ITER 4 (to 18) 131 14 STORE_FAST 0 (res) 132 133%3d 16 JUMP_ABSOLUTE 12 134 >> 18 POP_BLOCK 135 >> 20 LOAD_CONST 0 (None) 136 22 RETURN_VALUE 137""" % (bug708901.__code__.co_firstlineno + 1, 138 bug708901.__code__.co_firstlineno + 2, 139 bug708901.__code__.co_firstlineno + 3) 140 141 142def bug1333982(x=[]): 143 assert 0, ([s for s in x] + 144 1) 145 pass 146 147dis_bug1333982 = """\ 148%3d 0 LOAD_CONST 1 (0) 149 2 POP_JUMP_IF_TRUE 26 150 4 LOAD_GLOBAL 0 (AssertionError) 151 6 LOAD_CONST 2 (<code object <listcomp> at 0x..., file "%s", line %d>) 152 8 LOAD_CONST 3 ('bug1333982.<locals>.<listcomp>') 153 10 MAKE_FUNCTION 0 154 12 LOAD_FAST 0 (x) 155 14 GET_ITER 156 16 CALL_FUNCTION 1 157 158%3d 18 LOAD_CONST 4 (1) 159 20 BINARY_ADD 160 22 CALL_FUNCTION 1 161 24 RAISE_VARARGS 1 162 163%3d >> 26 LOAD_CONST 0 (None) 164 28 RETURN_VALUE 165""" % (bug1333982.__code__.co_firstlineno + 1, 166 __file__, 167 bug1333982.__code__.co_firstlineno + 1, 168 bug1333982.__code__.co_firstlineno + 2, 169 bug1333982.__code__.co_firstlineno + 3) 170 171_BIG_LINENO_FORMAT = """\ 172%3d 0 LOAD_GLOBAL 0 (spam) 173 2 POP_TOP 174 4 LOAD_CONST 0 (None) 175 6 RETURN_VALUE 176""" 177 178_BIG_LINENO_FORMAT2 = """\ 179%4d 0 LOAD_GLOBAL 0 (spam) 180 2 POP_TOP 181 4 LOAD_CONST 0 (None) 182 6 RETURN_VALUE 183""" 184 185dis_module_expected_results = """\ 186Disassembly of f: 187 4 0 LOAD_CONST 0 (None) 188 2 RETURN_VALUE 189 190Disassembly of g: 191 5 0 LOAD_CONST 0 (None) 192 2 RETURN_VALUE 193 194""" 195 196expr_str = "x + 1" 197 198dis_expr_str = """\ 199 1 0 LOAD_NAME 0 (x) 200 2 LOAD_CONST 0 (1) 201 4 BINARY_ADD 202 6 RETURN_VALUE 203""" 204 205simple_stmt_str = "x = x + 1" 206 207dis_simple_stmt_str = """\ 208 1 0 LOAD_NAME 0 (x) 209 2 LOAD_CONST 0 (1) 210 4 BINARY_ADD 211 6 STORE_NAME 0 (x) 212 8 LOAD_CONST 1 (None) 213 10 RETURN_VALUE 214""" 215 216annot_stmt_str = """\ 217 218x: int = 1 219y: fun(1) 220lst[fun(0)]: int = 1 221""" 222# leading newline is for a reason (tests lineno) 223 224dis_annot_stmt_str = """\ 225 2 0 SETUP_ANNOTATIONS 226 2 LOAD_CONST 0 (1) 227 4 STORE_NAME 0 (x) 228 6 LOAD_NAME 1 (int) 229 8 LOAD_NAME 2 (__annotations__) 230 10 LOAD_CONST 1 ('x') 231 12 STORE_SUBSCR 232 233 3 14 LOAD_NAME 3 (fun) 234 16 LOAD_CONST 0 (1) 235 18 CALL_FUNCTION 1 236 20 LOAD_NAME 2 (__annotations__) 237 22 LOAD_CONST 2 ('y') 238 24 STORE_SUBSCR 239 240 4 26 LOAD_CONST 0 (1) 241 28 LOAD_NAME 4 (lst) 242 30 LOAD_NAME 3 (fun) 243 32 LOAD_CONST 3 (0) 244 34 CALL_FUNCTION 1 245 36 STORE_SUBSCR 246 38 LOAD_NAME 1 (int) 247 40 POP_TOP 248 42 LOAD_CONST 4 (None) 249 44 RETURN_VALUE 250""" 251 252compound_stmt_str = """\ 253x = 0 254while 1: 255 x += 1""" 256# Trailing newline has been deliberately omitted 257 258dis_compound_stmt_str = """\ 259 1 0 LOAD_CONST 0 (0) 260 2 STORE_NAME 0 (x) 261 262 2 4 SETUP_LOOP 12 (to 18) 263 264 3 >> 6 LOAD_NAME 0 (x) 265 8 LOAD_CONST 1 (1) 266 10 INPLACE_ADD 267 12 STORE_NAME 0 (x) 268 14 JUMP_ABSOLUTE 6 269 16 POP_BLOCK 270 >> 18 LOAD_CONST 2 (None) 271 20 RETURN_VALUE 272""" 273 274dis_traceback = """\ 275%3d 0 SETUP_EXCEPT 12 (to 14) 276 277%3d 2 LOAD_CONST 1 (1) 278 4 LOAD_CONST 2 (0) 279 --> 6 BINARY_TRUE_DIVIDE 280 8 POP_TOP 281 10 POP_BLOCK 282 12 JUMP_FORWARD 40 (to 54) 283 284%3d >> 14 DUP_TOP 285 16 LOAD_GLOBAL 0 (Exception) 286 18 COMPARE_OP 10 (exception match) 287 20 POP_JUMP_IF_FALSE 52 288 22 POP_TOP 289 24 STORE_FAST 0 (e) 290 26 POP_TOP 291 28 SETUP_FINALLY 10 (to 40) 292 293%3d 30 LOAD_FAST 0 (e) 294 32 LOAD_ATTR 1 (__traceback__) 295 34 STORE_FAST 1 (tb) 296 36 POP_BLOCK 297 38 LOAD_CONST 0 (None) 298 >> 40 LOAD_CONST 0 (None) 299 42 STORE_FAST 0 (e) 300 44 DELETE_FAST 0 (e) 301 46 END_FINALLY 302 48 POP_EXCEPT 303 50 JUMP_FORWARD 2 (to 54) 304 >> 52 END_FINALLY 305 306%3d >> 54 LOAD_FAST 1 (tb) 307 56 RETURN_VALUE 308""" % (TRACEBACK_CODE.co_firstlineno + 1, 309 TRACEBACK_CODE.co_firstlineno + 2, 310 TRACEBACK_CODE.co_firstlineno + 3, 311 TRACEBACK_CODE.co_firstlineno + 4, 312 TRACEBACK_CODE.co_firstlineno + 5) 313 314def _fstring(a, b, c, d): 315 return f'{a} {b:4} {c!r} {d!r:4}' 316 317dis_fstring = """\ 318%3d 0 LOAD_FAST 0 (a) 319 2 FORMAT_VALUE 0 320 4 LOAD_CONST 1 (' ') 321 6 LOAD_FAST 1 (b) 322 8 LOAD_CONST 2 ('4') 323 10 FORMAT_VALUE 4 (with format) 324 12 LOAD_CONST 1 (' ') 325 14 LOAD_FAST 2 (c) 326 16 FORMAT_VALUE 2 (repr) 327 18 LOAD_CONST 1 (' ') 328 20 LOAD_FAST 3 (d) 329 22 LOAD_CONST 2 ('4') 330 24 FORMAT_VALUE 6 (repr, with format) 331 26 BUILD_STRING 7 332 28 RETURN_VALUE 333""" % (_fstring.__code__.co_firstlineno + 1,) 334 335def _g(x): 336 yield x 337 338async def _ag(x): 339 yield x 340 341async def _co(x): 342 async for item in _ag(x): 343 pass 344 345def _h(y): 346 def foo(x): 347 '''funcdoc''' 348 return [x + z for z in y] 349 return foo 350 351dis_nested_0 = """\ 352%3d 0 LOAD_CLOSURE 0 (y) 353 2 BUILD_TUPLE 1 354 4 LOAD_CONST 1 (<code object foo at 0x..., file "%s", line %d>) 355 6 LOAD_CONST 2 ('_h.<locals>.foo') 356 8 MAKE_FUNCTION 8 357 10 STORE_FAST 1 (foo) 358 359%3d 12 LOAD_FAST 1 (foo) 360 14 RETURN_VALUE 361""" % (_h.__code__.co_firstlineno + 1, 362 __file__, 363 _h.__code__.co_firstlineno + 1, 364 _h.__code__.co_firstlineno + 4, 365) 366 367dis_nested_1 = """%s 368Disassembly of <code object foo at 0x..., file "%s", line %d>: 369%3d 0 LOAD_CLOSURE 0 (x) 370 2 BUILD_TUPLE 1 371 4 LOAD_CONST 1 (<code object <listcomp> at 0x..., file "%s", line %d>) 372 6 LOAD_CONST 2 ('_h.<locals>.foo.<locals>.<listcomp>') 373 8 MAKE_FUNCTION 8 374 10 LOAD_DEREF 1 (y) 375 12 GET_ITER 376 14 CALL_FUNCTION 1 377 16 RETURN_VALUE 378""" % (dis_nested_0, 379 __file__, 380 _h.__code__.co_firstlineno + 1, 381 _h.__code__.co_firstlineno + 3, 382 __file__, 383 _h.__code__.co_firstlineno + 3, 384) 385 386dis_nested_2 = """%s 387Disassembly of <code object <listcomp> at 0x..., file "%s", line %d>: 388%3d 0 BUILD_LIST 0 389 2 LOAD_FAST 0 (.0) 390 >> 4 FOR_ITER 12 (to 18) 391 6 STORE_FAST 1 (z) 392 8 LOAD_DEREF 0 (x) 393 10 LOAD_FAST 1 (z) 394 12 BINARY_ADD 395 14 LIST_APPEND 2 396 16 JUMP_ABSOLUTE 4 397 >> 18 RETURN_VALUE 398""" % (dis_nested_1, 399 __file__, 400 _h.__code__.co_firstlineno + 3, 401 _h.__code__.co_firstlineno + 3, 402) 403 404 405class DisTests(unittest.TestCase): 406 407 maxDiff = None 408 409 def get_disassembly(self, func, lasti=-1, wrapper=True, **kwargs): 410 # We want to test the default printing behaviour, not the file arg 411 output = io.StringIO() 412 with contextlib.redirect_stdout(output): 413 if wrapper: 414 dis.dis(func, **kwargs) 415 else: 416 dis.disassemble(func, lasti, **kwargs) 417 return output.getvalue() 418 419 def get_disassemble_as_string(self, func, lasti=-1): 420 return self.get_disassembly(func, lasti, False) 421 422 def strip_addresses(self, text): 423 return re.sub(r'\b0x[0-9A-Fa-f]+\b', '0x...', text) 424 425 def do_disassembly_test(self, func, expected): 426 got = self.get_disassembly(func, depth=0) 427 if got != expected: 428 got = self.strip_addresses(got) 429 self.assertEqual(got, expected) 430 431 def test_opmap(self): 432 self.assertEqual(dis.opmap["NOP"], 9) 433 self.assertIn(dis.opmap["LOAD_CONST"], dis.hasconst) 434 self.assertIn(dis.opmap["STORE_NAME"], dis.hasname) 435 436 def test_opname(self): 437 self.assertEqual(dis.opname[dis.opmap["LOAD_FAST"]], "LOAD_FAST") 438 439 def test_boundaries(self): 440 self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG) 441 self.assertEqual(dis.opmap["STORE_NAME"], dis.HAVE_ARGUMENT) 442 443 def test_widths(self): 444 for opcode, opname in enumerate(dis.opname): 445 if opname in ('BUILD_MAP_UNPACK_WITH_CALL', 446 'BUILD_TUPLE_UNPACK_WITH_CALL'): 447 continue 448 with self.subTest(opname=opname): 449 width = dis._OPNAME_WIDTH 450 if opcode < dis.HAVE_ARGUMENT: 451 width += 1 + dis._OPARG_WIDTH 452 self.assertLessEqual(len(opname), width) 453 454 def test_dis(self): 455 self.do_disassembly_test(_f, dis_f) 456 457 def test_bug_708901(self): 458 self.do_disassembly_test(bug708901, dis_bug708901) 459 460 def test_bug_1333982(self): 461 # This one is checking bytecodes generated for an `assert` statement, 462 # so fails if the tests are run with -O. Skip this test then. 463 if not __debug__: 464 self.skipTest('need asserts, run without -O') 465 466 self.do_disassembly_test(bug1333982, dis_bug1333982) 467 468 def test_big_linenos(self): 469 def func(count): 470 namespace = {} 471 func = "def foo():\n " + "".join(["\n "] * count + ["spam\n"]) 472 exec(func, namespace) 473 return namespace['foo'] 474 475 # Test all small ranges 476 for i in range(1, 300): 477 expected = _BIG_LINENO_FORMAT % (i + 2) 478 self.do_disassembly_test(func(i), expected) 479 480 # Test some larger ranges too 481 for i in range(300, 1000, 10): 482 expected = _BIG_LINENO_FORMAT % (i + 2) 483 self.do_disassembly_test(func(i), expected) 484 485 for i in range(1000, 5000, 10): 486 expected = _BIG_LINENO_FORMAT2 % (i + 2) 487 self.do_disassembly_test(func(i), expected) 488 489 from test import dis_module 490 self.do_disassembly_test(dis_module, dis_module_expected_results) 491 492 def test_big_offsets(self): 493 def func(count): 494 namespace = {} 495 func = "def foo(x):\n " + ";".join(["x = x + 1"] * count) + "\n return x" 496 exec(func, namespace) 497 return namespace['foo'] 498 499 def expected(count, w): 500 s = ['''\ 501 %*d LOAD_FAST 0 (x) 502 %*d LOAD_CONST 1 (1) 503 %*d BINARY_ADD 504 %*d STORE_FAST 0 (x) 505''' % (w, 8*i, w, 8*i + 2, w, 8*i + 4, w, 8*i + 6) 506 for i in range(count)] 507 s += ['''\ 508 509 3 %*d LOAD_FAST 0 (x) 510 %*d RETURN_VALUE 511''' % (w, 8*count, w, 8*count + 2)] 512 s[0] = ' 2' + s[0][3:] 513 return ''.join(s) 514 515 for i in range(1, 5): 516 self.do_disassembly_test(func(i), expected(i, 4)) 517 self.do_disassembly_test(func(1249), expected(1249, 4)) 518 self.do_disassembly_test(func(1250), expected(1250, 5)) 519 520 def test_disassemble_str(self): 521 self.do_disassembly_test(expr_str, dis_expr_str) 522 self.do_disassembly_test(simple_stmt_str, dis_simple_stmt_str) 523 self.do_disassembly_test(annot_stmt_str, dis_annot_stmt_str) 524 self.do_disassembly_test(compound_stmt_str, dis_compound_stmt_str) 525 526 def test_disassemble_bytes(self): 527 self.do_disassembly_test(_f.__code__.co_code, dis_f_co_code) 528 529 def test_disassemble_class(self): 530 self.do_disassembly_test(_C, dis_c) 531 532 def test_disassemble_instance_method(self): 533 self.do_disassembly_test(_C(1).__init__, dis_c_instance_method) 534 535 def test_disassemble_instance_method_bytes(self): 536 method_bytecode = _C(1).__init__.__code__.co_code 537 self.do_disassembly_test(method_bytecode, dis_c_instance_method_bytes) 538 539 def test_disassemble_static_method(self): 540 self.do_disassembly_test(_C.sm, dis_c_static_method) 541 542 def test_disassemble_class_method(self): 543 self.do_disassembly_test(_C.cm, dis_c_class_method) 544 545 def test_disassemble_generator(self): 546 gen_func_disas = self.get_disassembly(_g) # Generator function 547 gen_disas = self.get_disassembly(_g(1)) # Generator iterator 548 self.assertEqual(gen_disas, gen_func_disas) 549 550 def test_disassemble_async_generator(self): 551 agen_func_disas = self.get_disassembly(_ag) # Async generator function 552 agen_disas = self.get_disassembly(_ag(1)) # Async generator iterator 553 self.assertEqual(agen_disas, agen_func_disas) 554 555 def test_disassemble_coroutine(self): 556 coro_func_disas = self.get_disassembly(_co) # Coroutine function 557 coro = _co(1) # Coroutine object 558 coro.close() # Avoid a RuntimeWarning (never awaited) 559 coro_disas = self.get_disassembly(coro) 560 self.assertEqual(coro_disas, coro_func_disas) 561 562 def test_disassemble_fstring(self): 563 self.do_disassembly_test(_fstring, dis_fstring) 564 565 def test_dis_none(self): 566 try: 567 del sys.last_traceback 568 except AttributeError: 569 pass 570 self.assertRaises(RuntimeError, dis.dis, None) 571 572 def test_dis_traceback(self): 573 try: 574 del sys.last_traceback 575 except AttributeError: 576 pass 577 578 try: 579 1/0 580 except Exception as e: 581 tb = e.__traceback__ 582 sys.last_traceback = tb 583 584 tb_dis = self.get_disassemble_as_string(tb.tb_frame.f_code, tb.tb_lasti) 585 self.do_disassembly_test(None, tb_dis) 586 587 def test_dis_object(self): 588 self.assertRaises(TypeError, dis.dis, object()) 589 590 def test_disassemble_recursive(self): 591 def check(expected, **kwargs): 592 dis = self.get_disassembly(_h, **kwargs) 593 dis = self.strip_addresses(dis) 594 self.assertEqual(dis, expected) 595 596 check(dis_nested_0, depth=0) 597 check(dis_nested_1, depth=1) 598 check(dis_nested_2, depth=2) 599 check(dis_nested_2, depth=3) 600 check(dis_nested_2, depth=None) 601 check(dis_nested_2) 602 603 604class DisWithFileTests(DisTests): 605 606 # Run the tests again, using the file arg instead of print 607 def get_disassembly(self, func, lasti=-1, wrapper=True, **kwargs): 608 output = io.StringIO() 609 if wrapper: 610 dis.dis(func, file=output, **kwargs) 611 else: 612 dis.disassemble(func, lasti, file=output, **kwargs) 613 return output.getvalue() 614 615 616 617code_info_code_info = """\ 618Name: code_info 619Filename: (.*) 620Argument count: 1 621Kw-only arguments: 0 622Number of locals: 1 623Stack size: 3 624Flags: OPTIMIZED, NEWLOCALS, NOFREE 625Constants: 626 0: %r 627Names: 628 0: _format_code_info 629 1: _get_code_object 630Variable names: 631 0: x""" % (('Formatted details of methods, functions, or code.',) 632 if sys.flags.optimize < 2 else (None,)) 633 634@staticmethod 635def tricky(x, y, z=True, *args, c, d, e=[], **kwds): 636 def f(c=c): 637 print(x, y, z, c, d, e, f) 638 yield x, y, z, c, d, e, f 639 640code_info_tricky = """\ 641Name: tricky 642Filename: (.*) 643Argument count: 3 644Kw-only arguments: 3 645Number of locals: 8 646Stack size: 7 647Flags: OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR 648Constants: 649 0: None 650 1: <code object f at (.*), file "(.*)", line (.*)> 651 2: 'tricky.<locals>.f' 652Variable names: 653 0: x 654 1: y 655 2: z 656 3: c 657 4: d 658 5: e 659 6: args 660 7: kwds 661Cell variables: 662 0: [edfxyz] 663 1: [edfxyz] 664 2: [edfxyz] 665 3: [edfxyz] 666 4: [edfxyz] 667 5: [edfxyz]""" 668# NOTE: the order of the cell variables above depends on dictionary order! 669 670co_tricky_nested_f = tricky.__func__.__code__.co_consts[1] 671 672code_info_tricky_nested_f = """\ 673Name: f 674Filename: (.*) 675Argument count: 1 676Kw-only arguments: 0 677Number of locals: 1 678Stack size: 8 679Flags: OPTIMIZED, NEWLOCALS, NESTED 680Constants: 681 0: None 682Names: 683 0: print 684Variable names: 685 0: c 686Free variables: 687 0: [edfxyz] 688 1: [edfxyz] 689 2: [edfxyz] 690 3: [edfxyz] 691 4: [edfxyz] 692 5: [edfxyz]""" 693 694code_info_expr_str = """\ 695Name: <module> 696Filename: <disassembly> 697Argument count: 0 698Kw-only arguments: 0 699Number of locals: 0 700Stack size: 2 701Flags: NOFREE 702Constants: 703 0: 1 704Names: 705 0: x""" 706 707code_info_simple_stmt_str = """\ 708Name: <module> 709Filename: <disassembly> 710Argument count: 0 711Kw-only arguments: 0 712Number of locals: 0 713Stack size: 2 714Flags: NOFREE 715Constants: 716 0: 1 717 1: None 718Names: 719 0: x""" 720 721code_info_compound_stmt_str = """\ 722Name: <module> 723Filename: <disassembly> 724Argument count: 0 725Kw-only arguments: 0 726Number of locals: 0 727Stack size: 2 728Flags: NOFREE 729Constants: 730 0: 0 731 1: 1 732 2: None 733Names: 734 0: x""" 735 736 737async def async_def(): 738 await 1 739 async for a in b: pass 740 async with c as d: pass 741 742code_info_async_def = """\ 743Name: async_def 744Filename: (.*) 745Argument count: 0 746Kw-only arguments: 0 747Number of locals: 2 748Stack size: 10 749Flags: OPTIMIZED, NEWLOCALS, NOFREE, COROUTINE 750Constants: 751 0: None 752 1: 1""" 753 754class CodeInfoTests(unittest.TestCase): 755 test_pairs = [ 756 (dis.code_info, code_info_code_info), 757 (tricky, code_info_tricky), 758 (co_tricky_nested_f, code_info_tricky_nested_f), 759 (expr_str, code_info_expr_str), 760 (simple_stmt_str, code_info_simple_stmt_str), 761 (compound_stmt_str, code_info_compound_stmt_str), 762 (async_def, code_info_async_def) 763 ] 764 765 def test_code_info(self): 766 self.maxDiff = 1000 767 for x, expected in self.test_pairs: 768 self.assertRegex(dis.code_info(x), expected) 769 770 def test_show_code(self): 771 self.maxDiff = 1000 772 for x, expected in self.test_pairs: 773 with captured_stdout() as output: 774 dis.show_code(x) 775 self.assertRegex(output.getvalue(), expected+"\n") 776 output = io.StringIO() 777 dis.show_code(x, file=output) 778 self.assertRegex(output.getvalue(), expected) 779 780 def test_code_info_object(self): 781 self.assertRaises(TypeError, dis.code_info, object()) 782 783 def test_pretty_flags_no_flags(self): 784 self.assertEqual(dis.pretty_flags(0), '0x0') 785 786 787# Fodder for instruction introspection tests 788# Editing any of these may require recalculating the expected output 789def outer(a=1, b=2): 790 def f(c=3, d=4): 791 def inner(e=5, f=6): 792 print(a, b, c, d, e, f) 793 print(a, b, c, d) 794 return inner 795 print(a, b, '', 1, [], {}, "Hello world!") 796 return f 797 798def jumpy(): 799 # This won't actually run (but that's OK, we only disassemble it) 800 for i in range(10): 801 print(i) 802 if i < 4: 803 continue 804 if i > 6: 805 break 806 else: 807 print("I can haz else clause?") 808 while i: 809 print(i) 810 i -= 1 811 if i > 6: 812 continue 813 if i < 4: 814 break 815 else: 816 print("Who let lolcatz into this test suite?") 817 try: 818 1 / 0 819 except ZeroDivisionError: 820 print("Here we go, here we go, here we go...") 821 else: 822 with i as dodgy: 823 print("Never reach this") 824 finally: 825 print("OK, now we're done") 826 827# End fodder for opinfo generation tests 828expected_outer_line = 1 829_line_offset = outer.__code__.co_firstlineno - 1 830code_object_f = outer.__code__.co_consts[3] 831expected_f_line = code_object_f.co_firstlineno - _line_offset 832code_object_inner = code_object_f.co_consts[3] 833expected_inner_line = code_object_inner.co_firstlineno - _line_offset 834expected_jumpy_line = 1 835 836# The following lines are useful to regenerate the expected results after 837# either the fodder is modified or the bytecode generation changes 838# After regeneration, update the references to code_object_f and 839# code_object_inner before rerunning the tests 840 841#_instructions = dis.get_instructions(outer, first_line=expected_outer_line) 842#print('expected_opinfo_outer = [\n ', 843 #',\n '.join(map(str, _instructions)), ',\n]', sep='') 844#_instructions = dis.get_instructions(outer(), first_line=expected_f_line) 845#print('expected_opinfo_f = [\n ', 846 #',\n '.join(map(str, _instructions)), ',\n]', sep='') 847#_instructions = dis.get_instructions(outer()(), first_line=expected_inner_line) 848#print('expected_opinfo_inner = [\n ', 849 #',\n '.join(map(str, _instructions)), ',\n]', sep='') 850#_instructions = dis.get_instructions(jumpy, first_line=expected_jumpy_line) 851#print('expected_opinfo_jumpy = [\n ', 852 #',\n '.join(map(str, _instructions)), ',\n]', sep='') 853 854 855Instruction = dis.Instruction 856expected_opinfo_outer = [ 857 Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval=(3, 4), argrepr='(3, 4)', offset=0, starts_line=2, is_jump_target=False), 858 Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False), 859 Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False), 860 Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=6, starts_line=None, is_jump_target=False), 861 Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_f, argrepr=repr(code_object_f), offset=8, starts_line=None, is_jump_target=False), 862 Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f', argrepr="'outer.<locals>.f'", offset=10, starts_line=None, is_jump_target=False), 863 Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='', offset=12, starts_line=None, is_jump_target=False), 864 Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=14, starts_line=None, is_jump_target=False), 865 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=16, starts_line=7, is_jump_target=False), 866 Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='a', argrepr='a', offset=18, starts_line=None, is_jump_target=False), 867 Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='b', argrepr='b', offset=20, starts_line=None, is_jump_target=False), 868 Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval='', argrepr="''", offset=22, starts_line=None, is_jump_target=False), 869 Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval=1, argrepr='1', offset=24, starts_line=None, is_jump_target=False), 870 Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=26, starts_line=None, is_jump_target=False), 871 Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=28, starts_line=None, is_jump_target=False), 872 Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval='Hello world!', argrepr="'Hello world!'", offset=30, starts_line=None, is_jump_target=False), 873 Instruction(opname='CALL_FUNCTION', opcode=131, arg=7, argval=7, argrepr='', offset=32, starts_line=None, is_jump_target=False), 874 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=34, starts_line=None, is_jump_target=False), 875 Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=36, starts_line=8, is_jump_target=False), 876 Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=38, starts_line=None, is_jump_target=False), 877] 878 879expected_opinfo_f = [ 880 Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=(5, 6), argrepr='(5, 6)', offset=0, starts_line=3, is_jump_target=False), 881 Instruction(opname='LOAD_CLOSURE', opcode=135, arg=2, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False), 882 Instruction(opname='LOAD_CLOSURE', opcode=135, arg=3, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False), 883 Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='c', argrepr='c', offset=6, starts_line=None, is_jump_target=False), 884 Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='d', argrepr='d', offset=8, starts_line=None, is_jump_target=False), 885 Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=10, starts_line=None, is_jump_target=False), 886 Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_inner, argrepr=repr(code_object_inner), offset=12, starts_line=None, is_jump_target=False), 887 Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f.<locals>.inner', argrepr="'outer.<locals>.f.<locals>.inner'", offset=14, starts_line=None, is_jump_target=False), 888 Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='', offset=16, starts_line=None, is_jump_target=False), 889 Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=18, starts_line=None, is_jump_target=False), 890 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=20, starts_line=5, is_jump_target=False), 891 Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='a', argrepr='a', offset=22, starts_line=None, is_jump_target=False), 892 Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='b', argrepr='b', offset=24, starts_line=None, is_jump_target=False), 893 Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='c', argrepr='c', offset=26, starts_line=None, is_jump_target=False), 894 Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='d', argrepr='d', offset=28, starts_line=None, is_jump_target=False), 895 Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='', offset=30, starts_line=None, is_jump_target=False), 896 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=32, starts_line=None, is_jump_target=False), 897 Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=34, starts_line=6, is_jump_target=False), 898 Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=36, starts_line=None, is_jump_target=False), 899] 900 901expected_opinfo_inner = [ 902 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=0, starts_line=4, is_jump_target=False), 903 Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False), 904 Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False), 905 Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='c', argrepr='c', offset=6, starts_line=None, is_jump_target=False), 906 Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='d', argrepr='d', offset=8, starts_line=None, is_jump_target=False), 907 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=10, starts_line=None, is_jump_target=False), 908 Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=12, starts_line=None, is_jump_target=False), 909 Instruction(opname='CALL_FUNCTION', opcode=131, arg=6, argval=6, argrepr='', offset=14, starts_line=None, is_jump_target=False), 910 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=16, starts_line=None, is_jump_target=False), 911 Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=18, starts_line=None, is_jump_target=False), 912 Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=20, starts_line=None, is_jump_target=False), 913] 914 915expected_opinfo_jumpy = [ 916 Instruction(opname='SETUP_LOOP', opcode=120, arg=52, argval=54, argrepr='to 54', offset=0, starts_line=3, is_jump_target=False), 917 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='range', argrepr='range', offset=2, starts_line=None, is_jump_target=False), 918 Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=4, starts_line=None, is_jump_target=False), 919 Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=6, starts_line=None, is_jump_target=False), 920 Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=8, starts_line=None, is_jump_target=False), 921 Instruction(opname='FOR_ITER', opcode=93, arg=32, argval=44, argrepr='to 44', offset=10, starts_line=None, is_jump_target=True), 922 Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=12, starts_line=None, is_jump_target=False), 923 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=14, starts_line=4, is_jump_target=False), 924 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=16, starts_line=None, is_jump_target=False), 925 Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=18, starts_line=None, is_jump_target=False), 926 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=20, starts_line=None, is_jump_target=False), 927 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=22, starts_line=5, is_jump_target=False), 928 Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=24, starts_line=None, is_jump_target=False), 929 Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=26, starts_line=None, is_jump_target=False), 930 Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=32, argval=32, argrepr='', offset=28, starts_line=None, is_jump_target=False), 931 Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=10, argval=10, argrepr='', offset=30, starts_line=6, is_jump_target=False), 932 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=32, starts_line=7, is_jump_target=True), 933 Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=34, starts_line=None, is_jump_target=False), 934 Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=36, starts_line=None, is_jump_target=False), 935 Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=10, argval=10, argrepr='', offset=38, starts_line=None, is_jump_target=False), 936 Instruction(opname='BREAK_LOOP', opcode=80, arg=None, argval=None, argrepr='', offset=40, starts_line=8, is_jump_target=False), 937 Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=10, argval=10, argrepr='', offset=42, starts_line=None, is_jump_target=False), 938 Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=44, starts_line=None, is_jump_target=True), 939 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=46, starts_line=10, is_jump_target=False), 940 Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=48, starts_line=None, is_jump_target=False), 941 Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=50, starts_line=None, is_jump_target=False), 942 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=52, starts_line=None, is_jump_target=False), 943 Instruction(opname='SETUP_LOOP', opcode=120, arg=52, argval=108, argrepr='to 108', offset=54, starts_line=11, is_jump_target=True), 944 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=56, starts_line=None, is_jump_target=True), 945 Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=98, argval=98, argrepr='', offset=58, starts_line=None, is_jump_target=False), 946 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=60, starts_line=12, is_jump_target=False), 947 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=62, starts_line=None, is_jump_target=False), 948 Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=64, starts_line=None, is_jump_target=False), 949 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=66, starts_line=None, is_jump_target=False), 950 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=68, starts_line=13, is_jump_target=False), 951 Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=70, starts_line=None, is_jump_target=False), 952 Instruction(opname='INPLACE_SUBTRACT', opcode=56, arg=None, argval=None, argrepr='', offset=72, starts_line=None, is_jump_target=False), 953 Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=74, starts_line=None, is_jump_target=False), 954 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=76, starts_line=14, is_jump_target=False), 955 Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=78, starts_line=None, is_jump_target=False), 956 Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=80, starts_line=None, is_jump_target=False), 957 Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=86, argval=86, argrepr='', offset=82, starts_line=None, is_jump_target=False), 958 Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=56, argval=56, argrepr='', offset=84, starts_line=15, is_jump_target=False), 959 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=86, starts_line=16, is_jump_target=True), 960 Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=88, starts_line=None, is_jump_target=False), 961 Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=90, starts_line=None, is_jump_target=False), 962 Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=56, argval=56, argrepr='', offset=92, starts_line=None, is_jump_target=False), 963 Instruction(opname='BREAK_LOOP', opcode=80, arg=None, argval=None, argrepr='', offset=94, starts_line=17, is_jump_target=False), 964 Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=56, argval=56, argrepr='', offset=96, starts_line=None, is_jump_target=False), 965 Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=98, starts_line=None, is_jump_target=True), 966 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=100, starts_line=19, is_jump_target=False), 967 Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=102, starts_line=None, is_jump_target=False), 968 Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=104, starts_line=None, is_jump_target=False), 969 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=106, starts_line=None, is_jump_target=False), 970 Instruction(opname='SETUP_FINALLY', opcode=122, arg=70, argval=180, argrepr='to 180', offset=108, starts_line=20, is_jump_target=True), 971 Instruction(opname='SETUP_EXCEPT', opcode=121, arg=12, argval=124, argrepr='to 124', offset=110, starts_line=None, is_jump_target=False), 972 Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=112, starts_line=21, is_jump_target=False), 973 Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=114, starts_line=None, is_jump_target=False), 974 Instruction(opname='BINARY_TRUE_DIVIDE', opcode=27, arg=None, argval=None, argrepr='', offset=116, starts_line=None, is_jump_target=False), 975 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=118, starts_line=None, is_jump_target=False), 976 Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=120, starts_line=None, is_jump_target=False), 977 Instruction(opname='JUMP_FORWARD', opcode=110, arg=28, argval=152, argrepr='to 152', offset=122, starts_line=None, is_jump_target=False), 978 Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=124, starts_line=22, is_jump_target=True), 979 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=2, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=126, starts_line=None, is_jump_target=False), 980 Instruction(opname='COMPARE_OP', opcode=107, arg=10, argval='exception match', argrepr='exception match', offset=128, starts_line=None, is_jump_target=False), 981 Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=150, argval=150, argrepr='', offset=130, starts_line=None, is_jump_target=False), 982 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=132, starts_line=None, is_jump_target=False), 983 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=134, starts_line=None, is_jump_target=False), 984 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=136, starts_line=None, is_jump_target=False), 985 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=138, starts_line=23, is_jump_target=False), 986 Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=140, starts_line=None, is_jump_target=False), 987 Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=142, starts_line=None, is_jump_target=False), 988 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=144, starts_line=None, is_jump_target=False), 989 Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=146, starts_line=None, is_jump_target=False), 990 Instruction(opname='JUMP_FORWARD', opcode=110, arg=26, argval=176, argrepr='to 176', offset=148, starts_line=None, is_jump_target=False), 991 Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=150, starts_line=None, is_jump_target=True), 992 Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=152, starts_line=25, is_jump_target=True), 993 Instruction(opname='SETUP_WITH', opcode=143, arg=14, argval=170, argrepr='to 170', offset=154, starts_line=None, is_jump_target=False), 994 Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=156, starts_line=None, is_jump_target=False), 995 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=158, starts_line=26, is_jump_target=False), 996 Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=160, starts_line=None, is_jump_target=False), 997 Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=162, starts_line=None, is_jump_target=False), 998 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=164, starts_line=None, is_jump_target=False), 999 Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=166, starts_line=None, is_jump_target=False), 1000 Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=168, starts_line=None, is_jump_target=False), 1001 Instruction(opname='WITH_CLEANUP_START', opcode=81, arg=None, argval=None, argrepr='', offset=170, starts_line=None, is_jump_target=True), 1002 Instruction(opname='WITH_CLEANUP_FINISH', opcode=82, arg=None, argval=None, argrepr='', offset=172, starts_line=None, is_jump_target=False), 1003 Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=174, starts_line=None, is_jump_target=False), 1004 Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=176, starts_line=None, is_jump_target=True), 1005 Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=178, starts_line=None, is_jump_target=False), 1006 Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=180, starts_line=28, is_jump_target=True), 1007 Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=182, starts_line=None, is_jump_target=False), 1008 Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=184, starts_line=None, is_jump_target=False), 1009 Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=186, starts_line=None, is_jump_target=False), 1010 Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=188, starts_line=None, is_jump_target=False), 1011 Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=190, starts_line=None, is_jump_target=False), 1012 Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=192, starts_line=None, is_jump_target=False), 1013] 1014 1015# One last piece of inspect fodder to check the default line number handling 1016def simple(): pass 1017expected_opinfo_simple = [ 1018 Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=0, starts_line=simple.__code__.co_firstlineno, is_jump_target=False), 1019 Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=2, starts_line=None, is_jump_target=False) 1020] 1021 1022 1023class InstructionTests(BytecodeTestCase): 1024 1025 def test_default_first_line(self): 1026 actual = dis.get_instructions(simple) 1027 self.assertEqual(list(actual), expected_opinfo_simple) 1028 1029 def test_first_line_set_to_None(self): 1030 actual = dis.get_instructions(simple, first_line=None) 1031 self.assertEqual(list(actual), expected_opinfo_simple) 1032 1033 def test_outer(self): 1034 actual = dis.get_instructions(outer, first_line=expected_outer_line) 1035 self.assertEqual(list(actual), expected_opinfo_outer) 1036 1037 def test_nested(self): 1038 with captured_stdout(): 1039 f = outer() 1040 actual = dis.get_instructions(f, first_line=expected_f_line) 1041 self.assertEqual(list(actual), expected_opinfo_f) 1042 1043 def test_doubly_nested(self): 1044 with captured_stdout(): 1045 inner = outer()() 1046 actual = dis.get_instructions(inner, first_line=expected_inner_line) 1047 self.assertEqual(list(actual), expected_opinfo_inner) 1048 1049 def test_jumpy(self): 1050 actual = dis.get_instructions(jumpy, first_line=expected_jumpy_line) 1051 self.assertEqual(list(actual), expected_opinfo_jumpy) 1052 1053# get_instructions has its own tests above, so can rely on it to validate 1054# the object oriented API 1055class BytecodeTests(unittest.TestCase): 1056 def test_instantiation(self): 1057 # Test with function, method, code string and code object 1058 for obj in [_f, _C(1).__init__, "a=1", _f.__code__]: 1059 with self.subTest(obj=obj): 1060 b = dis.Bytecode(obj) 1061 self.assertIsInstance(b.codeobj, types.CodeType) 1062 1063 self.assertRaises(TypeError, dis.Bytecode, object()) 1064 1065 def test_iteration(self): 1066 for obj in [_f, _C(1).__init__, "a=1", _f.__code__]: 1067 with self.subTest(obj=obj): 1068 via_object = list(dis.Bytecode(obj)) 1069 via_generator = list(dis.get_instructions(obj)) 1070 self.assertEqual(via_object, via_generator) 1071 1072 def test_explicit_first_line(self): 1073 actual = dis.Bytecode(outer, first_line=expected_outer_line) 1074 self.assertEqual(list(actual), expected_opinfo_outer) 1075 1076 def test_source_line_in_disassembly(self): 1077 # Use the line in the source code 1078 actual = dis.Bytecode(simple).dis() 1079 actual = actual.strip().partition(" ")[0] # extract the line no 1080 expected = str(simple.__code__.co_firstlineno) 1081 self.assertEqual(actual, expected) 1082 # Use an explicit first line number 1083 actual = dis.Bytecode(simple, first_line=350).dis() 1084 actual = actual.strip().partition(" ")[0] # extract the line no 1085 self.assertEqual(actual, "350") 1086 1087 def test_info(self): 1088 self.maxDiff = 1000 1089 for x, expected in CodeInfoTests.test_pairs: 1090 b = dis.Bytecode(x) 1091 self.assertRegex(b.info(), expected) 1092 1093 def test_disassembled(self): 1094 actual = dis.Bytecode(_f).dis() 1095 self.assertEqual(actual, dis_f) 1096 1097 def test_from_traceback(self): 1098 tb = get_tb() 1099 b = dis.Bytecode.from_traceback(tb) 1100 while tb.tb_next: tb = tb.tb_next 1101 1102 self.assertEqual(b.current_offset, tb.tb_lasti) 1103 1104 def test_from_traceback_dis(self): 1105 tb = get_tb() 1106 b = dis.Bytecode.from_traceback(tb) 1107 self.assertEqual(b.dis(), dis_traceback) 1108 1109if __name__ == "__main__": 1110 unittest.main() 1111