1# Testing the line trace facility. 2 3from test import support 4import unittest 5from unittest.mock import MagicMock 6import sys 7import difflib 8import gc 9from functools import wraps 10import asyncio 11from test.support import import_helper 12 13support.requires_working_socket(module=True) 14 15class tracecontext: 16 """Context manager that traces its enter and exit.""" 17 def __init__(self, output, value): 18 self.output = output 19 self.value = value 20 21 def __enter__(self): 22 self.output.append(self.value) 23 24 def __exit__(self, *exc_info): 25 self.output.append(-self.value) 26 27class asynctracecontext: 28 """Asynchronous context manager that traces its aenter and aexit.""" 29 def __init__(self, output, value): 30 self.output = output 31 self.value = value 32 33 async def __aenter__(self): 34 self.output.append(self.value) 35 36 async def __aexit__(self, *exc_info): 37 self.output.append(-self.value) 38 39async def asynciter(iterable): 40 """Convert an iterable to an asynchronous iterator.""" 41 for x in iterable: 42 yield x 43 44 45# A very basic example. If this fails, we're in deep trouble. 46def basic(): 47 return 1 48 49basic.events = [(0, 'call'), 50 (1, 'line'), 51 (1, 'return')] 52 53# Many of the tests below are tricky because they involve pass statements. 54# If there is implicit control flow around a pass statement (in an except 55# clause or else clause) under what conditions do you set a line number 56# following that clause? 57 58 59# Some constructs like "while 0:", "if 0:" or "if 1:...else:..." could be optimized 60# away. Make sure that those lines aren't skipped. 61def arigo_example0(): 62 x = 1 63 del x 64 while 0: 65 pass 66 x = 1 67 68arigo_example0.events = [(0, 'call'), 69 (1, 'line'), 70 (2, 'line'), 71 (3, 'line'), 72 (5, 'line'), 73 (5, 'return')] 74 75def arigo_example1(): 76 x = 1 77 del x 78 if 0: 79 pass 80 x = 1 81 82arigo_example1.events = [(0, 'call'), 83 (1, 'line'), 84 (2, 'line'), 85 (3, 'line'), 86 (5, 'line'), 87 (5, 'return')] 88 89def arigo_example2(): 90 x = 1 91 del x 92 if 1: 93 x = 1 94 else: 95 pass 96 return None 97 98arigo_example2.events = [(0, 'call'), 99 (1, 'line'), 100 (2, 'line'), 101 (3, 'line'), 102 (4, 'line'), 103 (7, 'line'), 104 (7, 'return')] 105 106 107# check that lines consisting of just one instruction get traced: 108def one_instr_line(): 109 x = 1 110 del x 111 x = 1 112 113one_instr_line.events = [(0, 'call'), 114 (1, 'line'), 115 (2, 'line'), 116 (3, 'line'), 117 (3, 'return')] 118 119def no_pop_tops(): # 0 120 x = 1 # 1 121 for a in range(2): # 2 122 if a: # 3 123 x = 1 # 4 124 else: # 5 125 x = 1 # 6 126 127no_pop_tops.events = [(0, 'call'), 128 (1, 'line'), 129 (2, 'line'), 130 (3, 'line'), 131 (6, 'line'), 132 (2, 'line'), 133 (3, 'line'), 134 (4, 'line'), 135 (2, 'line'), 136 (2, 'return')] 137 138def no_pop_blocks(): 139 y = 1 140 while not y: 141 bla 142 x = 1 143 144no_pop_blocks.events = [(0, 'call'), 145 (1, 'line'), 146 (2, 'line'), 147 (4, 'line'), 148 (4, 'return')] 149 150def called(): # line -3 151 x = 1 152 153def call(): # line 0 154 called() 155 156call.events = [(0, 'call'), 157 (1, 'line'), 158 (-3, 'call'), 159 (-2, 'line'), 160 (-2, 'return'), 161 (1, 'return')] 162 163def raises(): 164 raise Exception 165 166def test_raise(): 167 try: 168 raises() 169 except Exception: 170 pass 171 172test_raise.events = [(0, 'call'), 173 (1, 'line'), 174 (2, 'line'), 175 (-3, 'call'), 176 (-2, 'line'), 177 (-2, 'exception'), 178 (-2, 'return'), 179 (2, 'exception'), 180 (3, 'line'), 181 (4, 'line'), 182 (4, 'return')] 183 184def _settrace_and_return(tracefunc): 185 sys.settrace(tracefunc) 186 sys._getframe().f_back.f_trace = tracefunc 187def settrace_and_return(tracefunc): 188 _settrace_and_return(tracefunc) 189 190settrace_and_return.events = [(1, 'return')] 191 192def _settrace_and_raise(tracefunc): 193 sys.settrace(tracefunc) 194 sys._getframe().f_back.f_trace = tracefunc 195 raise RuntimeError 196def settrace_and_raise(tracefunc): 197 try: 198 _settrace_and_raise(tracefunc) 199 except RuntimeError: 200 pass 201 202settrace_and_raise.events = [(2, 'exception'), 203 (3, 'line'), 204 (4, 'line'), 205 (4, 'return')] 206 207# implicit return example 208# This test is interesting because of the else: pass 209# part of the code. The code generate for the true 210# part of the if contains a jump past the else branch. 211# The compiler then generates an implicit "return None" 212# Internally, the compiler visits the pass statement 213# and stores its line number for use on the next instruction. 214# The next instruction is the implicit return None. 215def ireturn_example(): 216 a = 5 217 b = 5 218 if a == b: 219 b = a+1 220 else: 221 pass 222 223ireturn_example.events = [(0, 'call'), 224 (1, 'line'), 225 (2, 'line'), 226 (3, 'line'), 227 (4, 'line'), 228 (4, 'return')] 229 230# Tight loop with while(1) example (SF #765624) 231def tightloop_example(): 232 items = range(0, 3) 233 try: 234 i = 0 235 while 1: 236 b = items[i]; i+=1 237 except IndexError: 238 pass 239 240tightloop_example.events = [(0, 'call'), 241 (1, 'line'), 242 (2, 'line'), 243 (3, 'line'), 244 (4, 'line'), 245 (5, 'line'), 246 (4, 'line'), 247 (5, 'line'), 248 (4, 'line'), 249 (5, 'line'), 250 (4, 'line'), 251 (5, 'line'), 252 (5, 'exception'), 253 (6, 'line'), 254 (7, 'line'), 255 (7, 'return')] 256 257def tighterloop_example(): 258 items = range(1, 4) 259 try: 260 i = 0 261 while 1: i = items[i] 262 except IndexError: 263 pass 264 265tighterloop_example.events = [(0, 'call'), 266 (1, 'line'), 267 (2, 'line'), 268 (3, 'line'), 269 (4, 'line'), 270 (4, 'line'), 271 (4, 'line'), 272 (4, 'line'), 273 (4, 'exception'), 274 (5, 'line'), 275 (6, 'line'), 276 (6, 'return')] 277 278def generator_function(): 279 try: 280 yield True 281 "continued" 282 finally: 283 "finally" 284def generator_example(): 285 # any() will leave the generator before its end 286 x = any(generator_function()) 287 288 # the following lines were not traced 289 for x in range(10): 290 y = x 291 292generator_example.events = ([(0, 'call'), 293 (2, 'line'), 294 (-6, 'call'), 295 (-5, 'line'), 296 (-4, 'line'), 297 (-4, 'return'), 298 (-4, 'call'), 299 (-4, 'exception'), 300 (-1, 'line'), 301 (-1, 'return')] + 302 [(5, 'line'), (6, 'line')] * 10 + 303 [(5, 'line'), (5, 'return')]) 304 305 306class Tracer: 307 def __init__(self, trace_line_events=None, trace_opcode_events=None): 308 self.trace_line_events = trace_line_events 309 self.trace_opcode_events = trace_opcode_events 310 self.events = [] 311 312 def _reconfigure_frame(self, frame): 313 if self.trace_line_events is not None: 314 frame.f_trace_lines = self.trace_line_events 315 if self.trace_opcode_events is not None: 316 frame.f_trace_opcodes = self.trace_opcode_events 317 318 def trace(self, frame, event, arg): 319 self._reconfigure_frame(frame) 320 self.events.append((frame.f_lineno, event)) 321 return self.trace 322 323 def traceWithGenexp(self, frame, event, arg): 324 self._reconfigure_frame(frame) 325 (o for o in [1]) 326 self.events.append((frame.f_lineno, event)) 327 return self.trace 328 329 330class TraceTestCase(unittest.TestCase): 331 332 # Disable gc collection when tracing, otherwise the 333 # deallocators may be traced as well. 334 def setUp(self): 335 self.using_gc = gc.isenabled() 336 gc.disable() 337 self.addCleanup(sys.settrace, sys.gettrace()) 338 339 def tearDown(self): 340 if self.using_gc: 341 gc.enable() 342 343 @staticmethod 344 def make_tracer(): 345 """Helper to allow test subclasses to configure tracers differently""" 346 return Tracer() 347 348 def compare_events(self, line_offset, events, expected_events): 349 events = [(l - line_offset, e) for (l, e) in events] 350 if events != expected_events: 351 self.fail( 352 "events did not match expectation:\n" + 353 "\n".join(difflib.ndiff([str(x) for x in expected_events], 354 [str(x) for x in events]))) 355 356 def run_and_compare(self, func, events): 357 tracer = self.make_tracer() 358 sys.settrace(tracer.trace) 359 func() 360 sys.settrace(None) 361 self.compare_events(func.__code__.co_firstlineno, 362 tracer.events, events) 363 364 def run_test(self, func): 365 self.run_and_compare(func, func.events) 366 367 def run_test2(self, func): 368 tracer = self.make_tracer() 369 func(tracer.trace) 370 sys.settrace(None) 371 self.compare_events(func.__code__.co_firstlineno, 372 tracer.events, func.events) 373 374 def test_set_and_retrieve_none(self): 375 sys.settrace(None) 376 assert sys.gettrace() is None 377 378 def test_set_and_retrieve_func(self): 379 def fn(*args): 380 pass 381 382 sys.settrace(fn) 383 try: 384 assert sys.gettrace() is fn 385 finally: 386 sys.settrace(None) 387 388 def test_01_basic(self): 389 self.run_test(basic) 390 def test_02_arigo0(self): 391 self.run_test(arigo_example0) 392 def test_02_arigo1(self): 393 self.run_test(arigo_example1) 394 def test_02_arigo2(self): 395 self.run_test(arigo_example2) 396 def test_03_one_instr(self): 397 self.run_test(one_instr_line) 398 def test_04_no_pop_blocks(self): 399 self.run_test(no_pop_blocks) 400 def test_05_no_pop_tops(self): 401 self.run_test(no_pop_tops) 402 def test_06_call(self): 403 self.run_test(call) 404 def test_07_raise(self): 405 self.run_test(test_raise) 406 407 def test_08_settrace_and_return(self): 408 self.run_test2(settrace_and_return) 409 def test_09_settrace_and_raise(self): 410 self.run_test2(settrace_and_raise) 411 def test_10_ireturn(self): 412 self.run_test(ireturn_example) 413 def test_11_tightloop(self): 414 self.run_test(tightloop_example) 415 def test_12_tighterloop(self): 416 self.run_test(tighterloop_example) 417 418 def test_13_genexp(self): 419 self.run_test(generator_example) 420 # issue1265: if the trace function contains a generator, 421 # and if the traced function contains another generator 422 # that is not completely exhausted, the trace stopped. 423 # Worse: the 'finally' clause was not invoked. 424 tracer = self.make_tracer() 425 sys.settrace(tracer.traceWithGenexp) 426 generator_example() 427 sys.settrace(None) 428 self.compare_events(generator_example.__code__.co_firstlineno, 429 tracer.events, generator_example.events) 430 431 def test_14_onliner_if(self): 432 def onliners(): 433 if True: x=False 434 else: x=True 435 return 0 436 self.run_and_compare( 437 onliners, 438 [(0, 'call'), 439 (1, 'line'), 440 (3, 'line'), 441 (3, 'return')]) 442 443 def test_15_loops(self): 444 # issue1750076: "while" expression is skipped by debugger 445 def for_example(): 446 for x in range(2): 447 pass 448 self.run_and_compare( 449 for_example, 450 [(0, 'call'), 451 (1, 'line'), 452 (2, 'line'), 453 (1, 'line'), 454 (2, 'line'), 455 (1, 'line'), 456 (1, 'return')]) 457 458 def while_example(): 459 # While expression should be traced on every loop 460 x = 2 461 while x > 0: 462 x -= 1 463 self.run_and_compare( 464 while_example, 465 [(0, 'call'), 466 (2, 'line'), 467 (3, 'line'), 468 (4, 'line'), 469 (3, 'line'), 470 (4, 'line'), 471 (3, 'line'), 472 (3, 'return')]) 473 474 def test_16_blank_lines(self): 475 namespace = {} 476 exec("def f():\n" + "\n" * 256 + " pass", namespace) 477 self.run_and_compare( 478 namespace["f"], 479 [(0, 'call'), 480 (257, 'line'), 481 (257, 'return')]) 482 483 def test_17_none_f_trace(self): 484 # Issue 20041: fix TypeError when f_trace is set to None. 485 def func(): 486 sys._getframe().f_trace = None 487 lineno = 2 488 self.run_and_compare(func, 489 [(0, 'call'), 490 (1, 'line')]) 491 492 def test_18_except_with_name(self): 493 def func(): 494 try: 495 try: 496 raise Exception 497 except Exception as e: 498 raise 499 x = "Something" 500 y = "Something" 501 except Exception: 502 pass 503 504 self.run_and_compare(func, 505 [(0, 'call'), 506 (1, 'line'), 507 (2, 'line'), 508 (3, 'line'), 509 (3, 'exception'), 510 (4, 'line'), 511 (5, 'line'), 512 (8, 'line'), 513 (9, 'line'), 514 (9, 'return')]) 515 516 def test_19_except_with_finally(self): 517 def func(): 518 try: 519 try: 520 raise Exception 521 finally: 522 y = "Something" 523 except Exception: 524 b = 23 525 526 self.run_and_compare(func, 527 [(0, 'call'), 528 (1, 'line'), 529 (2, 'line'), 530 (3, 'line'), 531 (3, 'exception'), 532 (5, 'line'), 533 (6, 'line'), 534 (7, 'line'), 535 (7, 'return')]) 536 537 def test_20_async_for_loop(self): 538 class AsyncIteratorWrapper: 539 def __init__(self, obj): 540 self._it = iter(obj) 541 542 def __aiter__(self): 543 return self 544 545 async def __anext__(self): 546 try: 547 return next(self._it) 548 except StopIteration: 549 raise StopAsyncIteration 550 551 async def doit_async(): 552 async for letter in AsyncIteratorWrapper("abc"): 553 x = letter 554 y = 42 555 556 def run(tracer): 557 x = doit_async() 558 try: 559 sys.settrace(tracer) 560 x.send(None) 561 finally: 562 sys.settrace(None) 563 564 tracer = self.make_tracer() 565 events = [ 566 (0, 'call'), 567 (1, 'line'), 568 (-12, 'call'), 569 (-11, 'line'), 570 (-11, 'return'), 571 (-9, 'call'), 572 (-8, 'line'), 573 (-8, 'return'), 574 (-6, 'call'), 575 (-5, 'line'), 576 (-4, 'line'), 577 (-4, 'return'), 578 (1, 'exception'), 579 (2, 'line'), 580 (1, 'line'), 581 (-6, 'call'), 582 (-5, 'line'), 583 (-4, 'line'), 584 (-4, 'return'), 585 (1, 'exception'), 586 (2, 'line'), 587 (1, 'line'), 588 (-6, 'call'), 589 (-5, 'line'), 590 (-4, 'line'), 591 (-4, 'return'), 592 (1, 'exception'), 593 (2, 'line'), 594 (1, 'line'), 595 (-6, 'call'), 596 (-5, 'line'), 597 (-4, 'line'), 598 (-4, 'exception'), 599 (-3, 'line'), 600 (-2, 'line'), 601 (-2, 'exception'), 602 (-2, 'return'), 603 (1, 'exception'), 604 (3, 'line'), 605 (3, 'return')] 606 try: 607 run(tracer.trace) 608 except Exception: 609 pass 610 self.compare_events(doit_async.__code__.co_firstlineno, 611 tracer.events, events) 612 613 def test_async_for_backwards_jump_has_no_line(self): 614 async def arange(n): 615 for i in range(n): 616 yield i 617 async def f(): 618 async for i in arange(3): 619 if i > 100: 620 break # should never be traced 621 622 tracer = self.make_tracer() 623 coro = f() 624 try: 625 sys.settrace(tracer.trace) 626 coro.send(None) 627 except Exception: 628 pass 629 finally: 630 sys.settrace(None) 631 632 events = [ 633 (0, 'call'), 634 (1, 'line'), 635 (-3, 'call'), 636 (-2, 'line'), 637 (-1, 'line'), 638 (-1, 'return'), 639 (1, 'exception'), 640 (2, 'line'), 641 (1, 'line'), 642 (-1, 'call'), 643 (-2, 'line'), 644 (-1, 'line'), 645 (-1, 'return'), 646 (1, 'exception'), 647 (2, 'line'), 648 (1, 'line'), 649 (-1, 'call'), 650 (-2, 'line'), 651 (-1, 'line'), 652 (-1, 'return'), 653 (1, 'exception'), 654 (2, 'line'), 655 (1, 'line'), 656 (-1, 'call'), 657 (-2, 'line'), 658 (-2, 'return'), 659 (1, 'exception'), 660 (1, 'return'), 661 ] 662 self.compare_events(f.__code__.co_firstlineno, 663 tracer.events, events) 664 665 def test_21_repeated_pass(self): 666 def func(): 667 pass 668 pass 669 670 self.run_and_compare(func, 671 [(0, 'call'), 672 (1, 'line'), 673 (2, 'line'), 674 (2, 'return')]) 675 676 def test_loop_in_try_except(self): 677 # https://bugs.python.org/issue41670 678 679 def func(): 680 try: 681 for i in []: pass 682 return 1 683 except: 684 return 2 685 686 self.run_and_compare(func, 687 [(0, 'call'), 688 (1, 'line'), 689 (2, 'line'), 690 (3, 'line'), 691 (3, 'return')]) 692 693 def test_try_except_no_exception(self): 694 695 def func(): 696 try: 697 2 698 except: 699 4 700 else: 701 6 702 if False: 703 8 704 else: 705 10 706 if func.__name__ == 'Fred': 707 12 708 finally: 709 14 710 711 self.run_and_compare(func, 712 [(0, 'call'), 713 (1, 'line'), 714 (2, 'line'), 715 (6, 'line'), 716 (7, 'line'), 717 (10, 'line'), 718 (11, 'line'), 719 (14, 'line'), 720 (14, 'return')]) 721 722 def test_try_exception_in_else(self): 723 724 def func(): 725 try: 726 try: 727 3 728 except: 729 5 730 else: 731 7 732 raise Exception 733 finally: 734 10 735 except: 736 12 737 finally: 738 14 739 740 self.run_and_compare(func, 741 [(0, 'call'), 742 (1, 'line'), 743 (2, 'line'), 744 (3, 'line'), 745 (7, 'line'), 746 (8, 'line'), 747 (8, 'exception'), 748 (10, 'line'), 749 (11, 'line'), 750 (12, 'line'), 751 (14, 'line'), 752 (14, 'return')]) 753 754 def test_nested_loops(self): 755 756 def func(): 757 for i in range(2): 758 for j in range(2): 759 a = i + j 760 return a == 1 761 762 self.run_and_compare(func, 763 [(0, 'call'), 764 (1, 'line'), 765 (2, 'line'), 766 (3, 'line'), 767 (2, 'line'), 768 (3, 'line'), 769 (2, 'line'), 770 (1, 'line'), 771 (2, 'line'), 772 (3, 'line'), 773 (2, 'line'), 774 (3, 'line'), 775 (2, 'line'), 776 (1, 'line'), 777 (4, 'line'), 778 (4, 'return')]) 779 780 def test_if_break(self): 781 782 def func(): 783 seq = [1, 0] 784 while seq: 785 n = seq.pop() 786 if n: 787 break # line 5 788 else: 789 n = 99 790 return n # line 8 791 792 self.run_and_compare(func, 793 [(0, 'call'), 794 (1, 'line'), 795 (2, 'line'), 796 (3, 'line'), 797 (4, 'line'), 798 (2, 'line'), 799 (3, 'line'), 800 (4, 'line'), 801 (5, 'line'), 802 (8, 'line'), 803 (8, 'return')]) 804 805 def test_break_through_finally(self): 806 807 def func(): 808 a, c, d, i = 1, 1, 1, 99 809 try: 810 for i in range(3): 811 try: 812 a = 5 813 if i > 0: 814 break # line 7 815 a = 8 816 finally: 817 c = 10 818 except: 819 d = 12 # line 12 820 assert a == 5 and c == 10 and d == 1 # line 13 821 822 self.run_and_compare(func, 823 [(0, 'call'), 824 (1, 'line'), 825 (2, 'line'), 826 (3, 'line'), 827 (4, 'line'), 828 (5, 'line'), 829 (6, 'line'), 830 (8, 'line'), 831 (10, 'line'), 832 (3, 'line'), 833 (4, 'line'), 834 (5, 'line'), 835 (6, 'line'), 836 (7, 'line'), 837 (10, 'line'), 838 (13, 'line'), 839 (13, 'return')]) 840 841 def test_continue_through_finally(self): 842 843 def func(): 844 a, b, c, d, i = 1, 1, 1, 1, 99 845 try: 846 for i in range(2): 847 try: 848 a = 5 849 if i > 0: 850 continue # line 7 851 b = 8 852 finally: 853 c = 10 854 except: 855 d = 12 # line 12 856 assert (a, b, c, d) == (5, 8, 10, 1) # line 13 857 858 self.run_and_compare(func, 859 [(0, 'call'), 860 (1, 'line'), 861 (2, 'line'), 862 (3, 'line'), 863 (4, 'line'), 864 (5, 'line'), 865 (6, 'line'), 866 (8, 'line'), 867 (10, 'line'), 868 (3, 'line'), 869 (4, 'line'), 870 (5, 'line'), 871 (6, 'line'), 872 (7, 'line'), 873 (10, 'line'), 874 (3, 'line'), 875 (13, 'line'), 876 (13, 'return')]) 877 878 def test_return_through_finally(self): 879 880 def func(): 881 try: 882 return 2 883 finally: 884 4 885 886 self.run_and_compare(func, 887 [(0, 'call'), 888 (1, 'line'), 889 (2, 'line'), 890 (4, 'line'), 891 (4, 'return')]) 892 893 def test_try_except_with_wrong_type(self): 894 895 def func(): 896 try: 897 2/0 898 except IndexError: 899 4 900 finally: 901 return 6 902 903 self.run_and_compare(func, 904 [(0, 'call'), 905 (1, 'line'), 906 (2, 'line'), 907 (2, 'exception'), 908 (3, 'line'), 909 (6, 'line'), 910 (6, 'return')]) 911 912 def test_break_to_continue1(self): 913 914 def func(): 915 TRUE = 1 916 x = [1] 917 while x: 918 x.pop() 919 while TRUE: 920 break 921 continue 922 923 self.run_and_compare(func, 924 [(0, 'call'), 925 (1, 'line'), 926 (2, 'line'), 927 (3, 'line'), 928 (4, 'line'), 929 (5, 'line'), 930 (6, 'line'), 931 (7, 'line'), 932 (3, 'line'), 933 (3, 'return')]) 934 935 def test_break_to_continue2(self): 936 937 def func(): 938 TRUE = 1 939 x = [1] 940 while x: 941 x.pop() 942 while TRUE: 943 break 944 else: 945 continue 946 947 self.run_and_compare(func, 948 [(0, 'call'), 949 (1, 'line'), 950 (2, 'line'), 951 (3, 'line'), 952 (4, 'line'), 953 (5, 'line'), 954 (6, 'line'), 955 (3, 'line'), 956 (3, 'return')]) 957 958 def test_break_to_break(self): 959 960 def func(): 961 TRUE = 1 962 while TRUE: 963 while TRUE: 964 break 965 break 966 967 self.run_and_compare(func, 968 [(0, 'call'), 969 (1, 'line'), 970 (2, 'line'), 971 (3, 'line'), 972 (4, 'line'), 973 (5, 'line'), 974 (5, 'return')]) 975 976 def test_nested_ifs(self): 977 978 def func(): 979 a = b = 1 980 if a == 1: 981 if b == 1: 982 x = 4 983 else: 984 y = 6 985 else: 986 z = 8 987 988 self.run_and_compare(func, 989 [(0, 'call'), 990 (1, 'line'), 991 (2, 'line'), 992 (3, 'line'), 993 (4, 'line'), 994 (4, 'return')]) 995 996 def test_nested_ifs_with_and(self): 997 998 def func(): 999 if A: 1000 if B: 1001 if C: 1002 if D: 1003 return False 1004 else: 1005 return False 1006 elif E and F: 1007 return True 1008 1009 A = B = True 1010 C = False 1011 1012 self.run_and_compare(func, 1013 [(0, 'call'), 1014 (1, 'line'), 1015 (2, 'line'), 1016 (3, 'line'), 1017 (3, 'return')]) 1018 1019 def test_nested_try_if(self): 1020 1021 def func(): 1022 x = "hello" 1023 try: 1024 3/0 1025 except ZeroDivisionError: 1026 if x == 'raise': 1027 raise ValueError() # line 6 1028 f = 7 1029 1030 self.run_and_compare(func, 1031 [(0, 'call'), 1032 (1, 'line'), 1033 (2, 'line'), 1034 (3, 'line'), 1035 (3, 'exception'), 1036 (4, 'line'), 1037 (5, 'line'), 1038 (7, 'line'), 1039 (7, 'return')]) 1040 1041 def test_if_false_in_with(self): 1042 1043 class C: 1044 def __enter__(self): 1045 return self 1046 def __exit__(*args): 1047 pass 1048 1049 def func(): 1050 with C(): 1051 if False: 1052 pass 1053 1054 self.run_and_compare(func, 1055 [(0, 'call'), 1056 (1, 'line'), 1057 (-5, 'call'), 1058 (-4, 'line'), 1059 (-4, 'return'), 1060 (2, 'line'), 1061 (1, 'line'), 1062 (-3, 'call'), 1063 (-2, 'line'), 1064 (-2, 'return'), 1065 (1, 'return')]) 1066 1067 def test_if_false_in_try_except(self): 1068 1069 def func(): 1070 try: 1071 if False: 1072 pass 1073 except Exception: 1074 X 1075 1076 self.run_and_compare(func, 1077 [(0, 'call'), 1078 (1, 'line'), 1079 (2, 'line'), 1080 (2, 'return')]) 1081 1082 def test_implicit_return_in_class(self): 1083 1084 def func(): 1085 class A: 1086 if 3 < 9: 1087 a = 1 1088 else: 1089 a = 2 1090 1091 self.run_and_compare(func, 1092 [(0, 'call'), 1093 (1, 'line'), 1094 (1, 'call'), 1095 (1, 'line'), 1096 (2, 'line'), 1097 (3, 'line'), 1098 (3, 'return'), 1099 (1, 'return')]) 1100 1101 def test_try_in_try(self): 1102 def func(): 1103 try: 1104 try: 1105 pass 1106 except Exception as ex: 1107 pass 1108 except Exception: 1109 pass 1110 1111 self.run_and_compare(func, 1112 [(0, 'call'), 1113 (1, 'line'), 1114 (2, 'line'), 1115 (3, 'line'), 1116 (3, 'return')]) 1117 1118 def test_try_in_try_with_exception(self): 1119 1120 def func(): 1121 try: 1122 try: 1123 raise TypeError 1124 except ValueError as ex: 1125 5 1126 except TypeError: 1127 7 1128 1129 self.run_and_compare(func, 1130 [(0, 'call'), 1131 (1, 'line'), 1132 (2, 'line'), 1133 (3, 'line'), 1134 (3, 'exception'), 1135 (4, 'line'), 1136 (6, 'line'), 1137 (7, 'line'), 1138 (7, 'return')]) 1139 1140 def func(): 1141 try: 1142 try: 1143 raise ValueError 1144 except ValueError as ex: 1145 5 1146 except TypeError: 1147 7 1148 1149 self.run_and_compare(func, 1150 [(0, 'call'), 1151 (1, 'line'), 1152 (2, 'line'), 1153 (3, 'line'), 1154 (3, 'exception'), 1155 (4, 'line'), 1156 (5, 'line'), 1157 (5, 'return')]) 1158 1159 def test_if_in_if_in_if(self): 1160 def func(a=0, p=1, z=1): 1161 if p: 1162 if a: 1163 if z: 1164 pass 1165 else: 1166 pass 1167 else: 1168 pass 1169 1170 self.run_and_compare(func, 1171 [(0, 'call'), 1172 (1, 'line'), 1173 (2, 'line'), 1174 (2, 'return')]) 1175 1176 def test_early_exit_with(self): 1177 1178 class C: 1179 def __enter__(self): 1180 return self 1181 def __exit__(*args): 1182 pass 1183 1184 def func_break(): 1185 for i in (1,2): 1186 with C(): 1187 break 1188 pass 1189 1190 def func_return(): 1191 with C(): 1192 return 1193 1194 self.run_and_compare(func_break, 1195 [(0, 'call'), 1196 (1, 'line'), 1197 (2, 'line'), 1198 (-5, 'call'), 1199 (-4, 'line'), 1200 (-4, 'return'), 1201 (3, 'line'), 1202 (2, 'line'), 1203 (-3, 'call'), 1204 (-2, 'line'), 1205 (-2, 'return'), 1206 (4, 'line'), 1207 (4, 'return')]) 1208 1209 self.run_and_compare(func_return, 1210 [(0, 'call'), 1211 (1, 'line'), 1212 (-11, 'call'), 1213 (-10, 'line'), 1214 (-10, 'return'), 1215 (2, 'line'), 1216 (1, 'line'), 1217 (-9, 'call'), 1218 (-8, 'line'), 1219 (-8, 'return'), 1220 (1, 'return')]) 1221 1222 def test_flow_converges_on_same_line(self): 1223 1224 def foo(x): 1225 if x: 1226 try: 1227 1/(x - 1) 1228 except ZeroDivisionError: 1229 pass 1230 return x 1231 1232 def func(): 1233 for i in range(2): 1234 foo(i) 1235 1236 self.run_and_compare(func, 1237 [(0, 'call'), 1238 (1, 'line'), 1239 (2, 'line'), 1240 (-8, 'call'), 1241 (-7, 'line'), 1242 (-2, 'line'), 1243 (-2, 'return'), 1244 (1, 'line'), 1245 (2, 'line'), 1246 (-8, 'call'), 1247 (-7, 'line'), 1248 (-6, 'line'), 1249 (-5, 'line'), 1250 (-5, 'exception'), 1251 (-4, 'line'), 1252 (-3, 'line'), 1253 (-2, 'line'), 1254 (-2, 'return'), 1255 (1, 'line'), 1256 (1, 'return')]) 1257 1258 def test_no_tracing_of_named_except_cleanup(self): 1259 1260 def func(): 1261 x = 0 1262 try: 1263 1/x 1264 except ZeroDivisionError as error: 1265 if x: 1266 raise 1267 return "done" 1268 1269 self.run_and_compare(func, 1270 [(0, 'call'), 1271 (1, 'line'), 1272 (2, 'line'), 1273 (3, 'line'), 1274 (3, 'exception'), 1275 (4, 'line'), 1276 (5, 'line'), 1277 (7, 'line'), 1278 (7, 'return')]) 1279 1280 def test_tracing_exception_raised_in_with(self): 1281 1282 class NullCtx: 1283 def __enter__(self): 1284 return self 1285 def __exit__(self, *excinfo): 1286 pass 1287 1288 def func(): 1289 try: 1290 with NullCtx(): 1291 1/0 1292 except ZeroDivisionError: 1293 pass 1294 1295 self.run_and_compare(func, 1296 [(0, 'call'), 1297 (1, 'line'), 1298 (2, 'line'), 1299 (-5, 'call'), 1300 (-4, 'line'), 1301 (-4, 'return'), 1302 (3, 'line'), 1303 (3, 'exception'), 1304 (2, 'line'), 1305 (-3, 'call'), 1306 (-2, 'line'), 1307 (-2, 'return'), 1308 (4, 'line'), 1309 (5, 'line'), 1310 (5, 'return')]) 1311 1312 def test_try_except_star_no_exception(self): 1313 1314 def func(): 1315 try: 1316 2 1317 except* Exception: 1318 4 1319 else: 1320 6 1321 if False: 1322 8 1323 else: 1324 10 1325 if func.__name__ == 'Fred': 1326 12 1327 finally: 1328 14 1329 1330 self.run_and_compare(func, 1331 [(0, 'call'), 1332 (1, 'line'), 1333 (2, 'line'), 1334 (6, 'line'), 1335 (7, 'line'), 1336 (10, 'line'), 1337 (11, 'line'), 1338 (14, 'line'), 1339 (14, 'return')]) 1340 1341 def test_try_except_star_named_no_exception(self): 1342 1343 def func(): 1344 try: 1345 2 1346 except* Exception as e: 1347 4 1348 else: 1349 6 1350 finally: 1351 8 1352 1353 self.run_and_compare(func, 1354 [(0, 'call'), 1355 (1, 'line'), 1356 (2, 'line'), 1357 (6, 'line'), 1358 (8, 'line'), 1359 (8, 'return')]) 1360 1361 def test_try_except_star_exception_caught(self): 1362 1363 def func(): 1364 try: 1365 raise ValueError(2) 1366 except* ValueError: 1367 4 1368 else: 1369 6 1370 finally: 1371 8 1372 1373 self.run_and_compare(func, 1374 [(0, 'call'), 1375 (1, 'line'), 1376 (2, 'line'), 1377 (2, 'exception'), 1378 (3, 'line'), 1379 (4, 'line'), 1380 (8, 'line'), 1381 (8, 'return')]) 1382 1383 def test_try_except_star_named_exception_caught(self): 1384 1385 def func(): 1386 try: 1387 raise ValueError(2) 1388 except* ValueError as e: 1389 4 1390 else: 1391 6 1392 finally: 1393 8 1394 1395 self.run_and_compare(func, 1396 [(0, 'call'), 1397 (1, 'line'), 1398 (2, 'line'), 1399 (2, 'exception'), 1400 (3, 'line'), 1401 (4, 'line'), 1402 (8, 'line'), 1403 (8, 'return')]) 1404 1405 def test_try_except_star_exception_not_caught(self): 1406 1407 def func(): 1408 try: 1409 try: 1410 raise ValueError(3) 1411 except* TypeError: 1412 5 1413 except ValueError: 1414 7 1415 1416 self.run_and_compare(func, 1417 [(0, 'call'), 1418 (1, 'line'), 1419 (2, 'line'), 1420 (3, 'line'), 1421 (3, 'exception'), 1422 (4, 'line'), 1423 (6, 'line'), 1424 (7, 'line'), 1425 (7, 'return')]) 1426 1427 def test_try_except_star_named_exception_not_caught(self): 1428 1429 def func(): 1430 try: 1431 try: 1432 raise ValueError(3) 1433 except* TypeError as e: 1434 5 1435 except ValueError: 1436 7 1437 1438 self.run_and_compare(func, 1439 [(0, 'call'), 1440 (1, 'line'), 1441 (2, 'line'), 1442 (3, 'line'), 1443 (3, 'exception'), 1444 (4, 'line'), 1445 (6, 'line'), 1446 (7, 'line'), 1447 (7, 'return')]) 1448 1449 def test_try_except_star_nested(self): 1450 1451 def func(): 1452 try: 1453 try: 1454 raise ExceptionGroup( 1455 'eg', 1456 [ValueError(5), TypeError('bad type')]) 1457 except* TypeError as e: 1458 7 1459 except* OSError: 1460 9 1461 except* ValueError: 1462 raise 1463 except* ValueError: 1464 try: 1465 raise TypeError(14) 1466 except* OSError: 1467 16 1468 except* TypeError as e: 1469 18 1470 return 0 1471 1472 self.run_and_compare(func, 1473 [(0, 'call'), 1474 (1, 'line'), 1475 (2, 'line'), 1476 (3, 'line'), 1477 (4, 'line'), 1478 (5, 'line'), 1479 (3, 'line'), 1480 (3, 'exception'), 1481 (6, 'line'), 1482 (7, 'line'), 1483 (8, 'line'), 1484 (10, 'line'), 1485 (11, 'line'), 1486 (12, 'line'), 1487 (13, 'line'), 1488 (14, 'line'), 1489 (14, 'exception'), 1490 (15, 'line'), 1491 (17, 'line'), 1492 (18, 'line'), 1493 (19, 'line'), 1494 (19, 'return')]) 1495 1496 def test_notrace_lambda(self): 1497 #Regression test for issue 46314 1498 1499 def func(): 1500 1 1501 lambda x: 2 1502 3 1503 1504 self.run_and_compare(func, 1505 [(0, 'call'), 1506 (1, 'line'), 1507 (2, 'line'), 1508 (3, 'line'), 1509 (3, 'return')]) 1510 1511 def test_class_creation_with_docstrings(self): 1512 1513 def func(): 1514 class Class_1: 1515 ''' the docstring. 2''' 1516 def __init__(self): 1517 ''' Another docstring. 4''' 1518 self.a = 5 1519 1520 self.run_and_compare(func, 1521 [(0, 'call'), 1522 (1, 'line'), 1523 (1, 'call'), 1524 (1, 'line'), 1525 (2, 'line'), 1526 (3, 'line'), 1527 (3, 'return'), 1528 (1, 'return')]) 1529 1530 @support.cpython_only 1531 def test_no_line_event_after_creating_generator(self): 1532 # Spurious line events before call events only show up with C tracer 1533 1534 # Skip this test if the _testcapi module isn't available. 1535 _testcapi = import_helper.import_module('_testcapi') 1536 1537 def gen(): 1538 yield 1 1539 1540 def func(): 1541 for _ in ( 1542 gen() 1543 ): 1544 pass 1545 1546 EXPECTED_EVENTS = [ 1547 (0, 'call'), 1548 (2, 'line'), 1549 (1, 'line'), 1550 (-3, 'call'), 1551 (-2, 'line'), 1552 (-2, 'return'), 1553 (4, 'line'), 1554 (1, 'line'), 1555 (-2, 'call'), 1556 (-2, 'return'), 1557 (1, 'return'), 1558 ] 1559 1560 # C level events should be the same as expected and the same as Python level. 1561 1562 events = [] 1563 # Turning on and off tracing must be on same line to avoid unwanted LINE events. 1564 _testcapi.settrace_to_record(events); func(); sys.settrace(None) 1565 start_line = func.__code__.co_firstlineno 1566 events = [ 1567 (line-start_line, EVENT_NAMES[what]) 1568 for (what, line, arg) in events 1569 ] 1570 self.assertEqual(events, EXPECTED_EVENTS) 1571 1572 self.run_and_compare(func, EXPECTED_EVENTS) 1573 1574 def test_settrace_error(self): 1575 1576 raised = False 1577 def error_once(frame, event, arg): 1578 nonlocal raised 1579 if not raised: 1580 raised = True 1581 raise Exception 1582 return error 1583 1584 try: 1585 sys._getframe().f_trace = error_once 1586 sys.settrace(error_once) 1587 len([]) 1588 except Exception as ex: 1589 count = 0 1590 tb = ex.__traceback__ 1591 print(tb) 1592 while tb: 1593 if tb.tb_frame.f_code.co_name == "test_settrace_error": 1594 count += 1 1595 tb = tb.tb_next 1596 if count == 0: 1597 self.fail("Traceback is missing frame") 1598 elif count > 1: 1599 self.fail("Traceback has frame more than once") 1600 else: 1601 self.fail("No exception raised") 1602 finally: 1603 sys.settrace(None) 1604 1605 @support.cpython_only 1606 def test_testcapi_settrace_error(self): 1607 1608 # Skip this test if the _testcapi module isn't available. 1609 _testcapi = import_helper.import_module('_testcapi') 1610 1611 try: 1612 _testcapi.settrace_to_error([]) 1613 len([]) 1614 except Exception as ex: 1615 count = 0 1616 tb = ex.__traceback__ 1617 while tb: 1618 if tb.tb_frame.f_code.co_name == "test_testcapi_settrace_error": 1619 count += 1 1620 tb = tb.tb_next 1621 if count == 0: 1622 self.fail("Traceback is missing frame") 1623 elif count > 1: 1624 self.fail("Traceback has frame more than once") 1625 else: 1626 self.fail("No exception raised") 1627 finally: 1628 sys.settrace(None) 1629 1630 def test_very_large_function(self): 1631 # There is a separate code path when the number of lines > (1 << 15). 1632 d = {} 1633 exec("""def f(): # line 0 1634 x = 0 # line 1 1635 y = 1 # line 2 1636 %s # lines 3 through (1 << 16) 1637 x += 1 # 1638 return""" % ('\n' * (1 << 16),), d) 1639 f = d['f'] 1640 1641 EXPECTED_EVENTS = [ 1642 (0, 'call'), 1643 (1, 'line'), 1644 (2, 'line'), 1645 (65540, 'line'), 1646 (65541, 'line'), 1647 (65541, 'return'), 1648 ] 1649 1650 self.run_and_compare(f, EXPECTED_EVENTS) 1651 1652 1653EVENT_NAMES = [ 1654 'call', 1655 'exception', 1656 'line', 1657 'return' 1658] 1659 1660 1661class SkipLineEventsTraceTestCase(TraceTestCase): 1662 """Repeat the trace tests, but with per-line events skipped""" 1663 1664 def compare_events(self, line_offset, events, expected_events): 1665 skip_line_events = [e for e in expected_events if e[1] != 'line'] 1666 super().compare_events(line_offset, events, skip_line_events) 1667 1668 @staticmethod 1669 def make_tracer(): 1670 return Tracer(trace_line_events=False) 1671 1672 1673@support.cpython_only 1674class TraceOpcodesTestCase(TraceTestCase): 1675 """Repeat the trace tests, but with per-opcodes events enabled""" 1676 1677 def compare_events(self, line_offset, events, expected_events): 1678 skip_opcode_events = [e for e in events if e[1] != 'opcode'] 1679 if len(events) > 1: 1680 self.assertLess(len(skip_opcode_events), len(events), 1681 msg="No 'opcode' events received by the tracer") 1682 super().compare_events(line_offset, skip_opcode_events, expected_events) 1683 1684 @staticmethod 1685 def make_tracer(): 1686 return Tracer(trace_opcode_events=True) 1687 1688 1689class RaisingTraceFuncTestCase(unittest.TestCase): 1690 def setUp(self): 1691 self.addCleanup(sys.settrace, sys.gettrace()) 1692 1693 def trace(self, frame, event, arg): 1694 """A trace function that raises an exception in response to a 1695 specific trace event.""" 1696 if event == self.raiseOnEvent: 1697 raise ValueError # just something that isn't RuntimeError 1698 else: 1699 return self.trace 1700 1701 def f(self): 1702 """The function to trace; raises an exception if that's the case 1703 we're testing, so that the 'exception' trace event fires.""" 1704 if self.raiseOnEvent == 'exception': 1705 x = 0 1706 y = 1/x 1707 else: 1708 return 1 1709 1710 def run_test_for_event(self, event): 1711 """Tests that an exception raised in response to the given event is 1712 handled OK.""" 1713 self.raiseOnEvent = event 1714 try: 1715 for i in range(sys.getrecursionlimit() + 1): 1716 sys.settrace(self.trace) 1717 try: 1718 self.f() 1719 except ValueError: 1720 pass 1721 else: 1722 self.fail("exception not raised!") 1723 except RuntimeError: 1724 self.fail("recursion counter not reset") 1725 1726 # Test the handling of exceptions raised by each kind of trace event. 1727 def test_call(self): 1728 self.run_test_for_event('call') 1729 def test_line(self): 1730 self.run_test_for_event('line') 1731 def test_return(self): 1732 self.run_test_for_event('return') 1733 def test_exception(self): 1734 self.run_test_for_event('exception') 1735 1736 def test_trash_stack(self): 1737 def f(): 1738 for i in range(5): 1739 print(i) # line tracing will raise an exception at this line 1740 1741 def g(frame, why, extra): 1742 if (why == 'line' and 1743 frame.f_lineno == f.__code__.co_firstlineno + 2): 1744 raise RuntimeError("i am crashing") 1745 return g 1746 1747 sys.settrace(g) 1748 try: 1749 f() 1750 except RuntimeError: 1751 # the test is really that this doesn't segfault: 1752 import gc 1753 gc.collect() 1754 else: 1755 self.fail("exception not propagated") 1756 1757 1758 def test_exception_arguments(self): 1759 def f(): 1760 x = 0 1761 # this should raise an error 1762 x.no_such_attr 1763 def g(frame, event, arg): 1764 if (event == 'exception'): 1765 type, exception, trace = arg 1766 self.assertIsInstance(exception, Exception) 1767 return g 1768 1769 existing = sys.gettrace() 1770 try: 1771 sys.settrace(g) 1772 try: 1773 f() 1774 except AttributeError: 1775 # this is expected 1776 pass 1777 finally: 1778 sys.settrace(existing) 1779 1780 def test_line_event_raises_before_opcode_event(self): 1781 exception = ValueError("BOOM!") 1782 def trace(frame, event, arg): 1783 if event == "line": 1784 raise exception 1785 frame.f_trace_opcodes = True 1786 return trace 1787 def f(): 1788 pass 1789 with self.assertRaises(ValueError) as caught: 1790 sys.settrace(trace) 1791 f() 1792 self.assertIs(caught.exception, exception) 1793 1794 1795# 'Jump' tests: assigning to frame.f_lineno within a trace function 1796# moves the execution position - it's how debuggers implement a Jump 1797# command (aka. "Set next statement"). 1798 1799class JumpTracer: 1800 """Defines a trace function that jumps from one place to another.""" 1801 1802 def __init__(self, function, jumpFrom, jumpTo, event='line', 1803 decorated=False): 1804 self.code = function.__code__ 1805 self.jumpFrom = jumpFrom 1806 self.jumpTo = jumpTo 1807 self.event = event 1808 self.firstLine = None if decorated else self.code.co_firstlineno 1809 self.done = False 1810 1811 def trace(self, frame, event, arg): 1812 if self.done: 1813 return 1814 # frame.f_code.co_firstlineno is the first line of the decorator when 1815 # 'function' is decorated and the decorator may be written using 1816 # multiple physical lines when it is too long. Use the first line 1817 # trace event in 'function' to find the first line of 'function'. 1818 if (self.firstLine is None and frame.f_code == self.code and 1819 event == 'line'): 1820 self.firstLine = frame.f_lineno - 1 1821 if (event == self.event and self.firstLine is not None and 1822 frame.f_lineno == self.firstLine + self.jumpFrom): 1823 f = frame 1824 while f is not None and f.f_code != self.code: 1825 f = f.f_back 1826 if f is not None: 1827 # Cope with non-integer self.jumpTo (because of 1828 # no_jump_to_non_integers below). 1829 try: 1830 frame.f_lineno = self.firstLine + self.jumpTo 1831 except TypeError: 1832 frame.f_lineno = self.jumpTo 1833 self.done = True 1834 return self.trace 1835 1836# This verifies the line-numbers-must-be-integers rule. 1837def no_jump_to_non_integers(output): 1838 try: 1839 output.append(2) 1840 except ValueError as e: 1841 output.append('integer' in str(e)) 1842 1843# This verifies that you can't set f_lineno via _getframe or similar 1844# trickery. 1845def no_jump_without_trace_function(): 1846 try: 1847 previous_frame = sys._getframe().f_back 1848 previous_frame.f_lineno = previous_frame.f_lineno 1849 except ValueError as e: 1850 # This is the exception we wanted; make sure the error message 1851 # talks about trace functions. 1852 if 'trace' not in str(e): 1853 raise 1854 else: 1855 # Something's wrong - the expected exception wasn't raised. 1856 raise AssertionError("Trace-function-less jump failed to fail") 1857 1858 1859class JumpTestCase(unittest.TestCase): 1860 def setUp(self): 1861 self.addCleanup(sys.settrace, sys.gettrace()) 1862 sys.settrace(None) 1863 1864 def compare_jump_output(self, expected, received): 1865 if received != expected: 1866 self.fail( "Outputs don't match:\n" + 1867 "Expected: " + repr(expected) + "\n" + 1868 "Received: " + repr(received)) 1869 1870 def run_test(self, func, jumpFrom, jumpTo, expected, error=None, 1871 event='line', decorated=False): 1872 tracer = JumpTracer(func, jumpFrom, jumpTo, event, decorated) 1873 sys.settrace(tracer.trace) 1874 output = [] 1875 if error is None: 1876 func(output) 1877 else: 1878 with self.assertRaisesRegex(*error): 1879 func(output) 1880 sys.settrace(None) 1881 self.compare_jump_output(expected, output) 1882 1883 def run_async_test(self, func, jumpFrom, jumpTo, expected, error=None, 1884 event='line', decorated=False): 1885 tracer = JumpTracer(func, jumpFrom, jumpTo, event, decorated) 1886 sys.settrace(tracer.trace) 1887 output = [] 1888 if error is None: 1889 asyncio.run(func(output)) 1890 else: 1891 with self.assertRaisesRegex(*error): 1892 asyncio.run(func(output)) 1893 sys.settrace(None) 1894 asyncio.set_event_loop_policy(None) 1895 self.compare_jump_output(expected, output) 1896 1897 def jump_test(jumpFrom, jumpTo, expected, error=None, event='line'): 1898 """Decorator that creates a test that makes a jump 1899 from one place to another in the following code. 1900 """ 1901 def decorator(func): 1902 @wraps(func) 1903 def test(self): 1904 self.run_test(func, jumpFrom, jumpTo, expected, 1905 error=error, event=event, decorated=True) 1906 return test 1907 return decorator 1908 1909 def async_jump_test(jumpFrom, jumpTo, expected, error=None, event='line'): 1910 """Decorator that creates a test that makes a jump 1911 from one place to another in the following asynchronous code. 1912 """ 1913 def decorator(func): 1914 @wraps(func) 1915 def test(self): 1916 self.run_async_test(func, jumpFrom, jumpTo, expected, 1917 error=error, event=event, decorated=True) 1918 return test 1919 return decorator 1920 1921 ## The first set of 'jump' tests are for things that are allowed: 1922 1923 @jump_test(1, 3, [3]) 1924 def test_jump_simple_forwards(output): 1925 output.append(1) 1926 output.append(2) 1927 output.append(3) 1928 1929 @jump_test(2, 1, [1, 1, 2]) 1930 def test_jump_simple_backwards(output): 1931 output.append(1) 1932 output.append(2) 1933 1934 @jump_test(3, 5, [2, 5]) 1935 def test_jump_out_of_block_forwards(output): 1936 for i in 1, 2: 1937 output.append(2) 1938 for j in [3]: # Also tests jumping over a block 1939 output.append(4) 1940 output.append(5) 1941 1942 @jump_test(6, 1, [1, 3, 5, 1, 3, 5, 6, 7]) 1943 def test_jump_out_of_block_backwards(output): 1944 output.append(1) 1945 for i in [1]: 1946 output.append(3) 1947 for j in [2]: # Also tests jumping over a block 1948 output.append(5) 1949 output.append(6) 1950 output.append(7) 1951 1952 @async_jump_test(4, 5, [3, 5]) 1953 async def test_jump_out_of_async_for_block_forwards(output): 1954 for i in [1]: 1955 async for i in asynciter([1, 2]): 1956 output.append(3) 1957 output.append(4) 1958 output.append(5) 1959 1960 @async_jump_test(5, 2, [2, 4, 2, 4, 5, 6]) 1961 async def test_jump_out_of_async_for_block_backwards(output): 1962 for i in [1]: 1963 output.append(2) 1964 async for i in asynciter([1]): 1965 output.append(4) 1966 output.append(5) 1967 output.append(6) 1968 1969 @jump_test(1, 2, [3]) 1970 def test_jump_to_codeless_line(output): 1971 output.append(1) 1972 # Jumping to this line should skip to the next one. 1973 output.append(3) 1974 1975 @jump_test(2, 2, [1, 2, 3]) 1976 def test_jump_to_same_line(output): 1977 output.append(1) 1978 output.append(2) 1979 output.append(3) 1980 1981 # Tests jumping within a finally block, and over one. 1982 @jump_test(4, 9, [2, 9]) 1983 def test_jump_in_nested_finally(output): 1984 try: 1985 output.append(2) 1986 finally: 1987 output.append(4) 1988 try: 1989 output.append(6) 1990 finally: 1991 output.append(8) 1992 output.append(9) 1993 1994 @jump_test(6, 7, [2, 7], (ZeroDivisionError, '')) 1995 def test_jump_in_nested_finally_2(output): 1996 try: 1997 output.append(2) 1998 1/0 1999 return 2000 finally: 2001 output.append(6) 2002 output.append(7) 2003 output.append(8) 2004 2005 @jump_test(6, 11, [2, 11], (ZeroDivisionError, '')) 2006 def test_jump_in_nested_finally_3(output): 2007 try: 2008 output.append(2) 2009 1/0 2010 return 2011 finally: 2012 output.append(6) 2013 try: 2014 output.append(8) 2015 finally: 2016 output.append(10) 2017 output.append(11) 2018 output.append(12) 2019 2020 @jump_test(5, 11, [2, 4], (ValueError, 'exception')) 2021 def test_no_jump_over_return_try_finally_in_finally_block(output): 2022 try: 2023 output.append(2) 2024 finally: 2025 output.append(4) 2026 output.append(5) 2027 return 2028 try: 2029 output.append(8) 2030 finally: 2031 output.append(10) 2032 pass 2033 output.append(12) 2034 2035 @jump_test(3, 4, [1], (ValueError, 'after')) 2036 def test_no_jump_infinite_while_loop(output): 2037 output.append(1) 2038 while True: 2039 output.append(3) 2040 output.append(4) 2041 2042 @jump_test(2, 4, [4, 4]) 2043 def test_jump_forwards_into_while_block(output): 2044 i = 1 2045 output.append(2) 2046 while i <= 2: 2047 output.append(4) 2048 i += 1 2049 2050 @jump_test(5, 3, [3, 3, 3, 5]) 2051 def test_jump_backwards_into_while_block(output): 2052 i = 1 2053 while i <= 2: 2054 output.append(3) 2055 i += 1 2056 output.append(5) 2057 2058 @jump_test(2, 3, [1, 3]) 2059 def test_jump_forwards_out_of_with_block(output): 2060 with tracecontext(output, 1): 2061 output.append(2) 2062 output.append(3) 2063 2064 @async_jump_test(2, 3, [1, 3]) 2065 async def test_jump_forwards_out_of_async_with_block(output): 2066 async with asynctracecontext(output, 1): 2067 output.append(2) 2068 output.append(3) 2069 2070 @jump_test(3, 1, [1, 2, 1, 2, 3, -2]) 2071 def test_jump_backwards_out_of_with_block(output): 2072 output.append(1) 2073 with tracecontext(output, 2): 2074 output.append(3) 2075 2076 @async_jump_test(3, 1, [1, 2, 1, 2, 3, -2]) 2077 async def test_jump_backwards_out_of_async_with_block(output): 2078 output.append(1) 2079 async with asynctracecontext(output, 2): 2080 output.append(3) 2081 2082 @jump_test(2, 5, [5]) 2083 def test_jump_forwards_out_of_try_finally_block(output): 2084 try: 2085 output.append(2) 2086 finally: 2087 output.append(4) 2088 output.append(5) 2089 2090 @jump_test(3, 1, [1, 1, 3, 5]) 2091 def test_jump_backwards_out_of_try_finally_block(output): 2092 output.append(1) 2093 try: 2094 output.append(3) 2095 finally: 2096 output.append(5) 2097 2098 @jump_test(2, 6, [6]) 2099 def test_jump_forwards_out_of_try_except_block(output): 2100 try: 2101 output.append(2) 2102 except: 2103 output.append(4) 2104 raise 2105 output.append(6) 2106 2107 @jump_test(3, 1, [1, 1, 3]) 2108 def test_jump_backwards_out_of_try_except_block(output): 2109 output.append(1) 2110 try: 2111 output.append(3) 2112 except: 2113 output.append(5) 2114 raise 2115 2116 @jump_test(5, 7, [4, 7, 8]) 2117 def test_jump_between_except_blocks(output): 2118 try: 2119 1/0 2120 except ZeroDivisionError: 2121 output.append(4) 2122 output.append(5) 2123 except FloatingPointError: 2124 output.append(7) 2125 output.append(8) 2126 2127 @jump_test(5, 7, [4, 7, 8]) 2128 def test_jump_from_except_to_finally(output): 2129 try: 2130 1/0 2131 except ZeroDivisionError: 2132 output.append(4) 2133 output.append(5) 2134 finally: 2135 output.append(7) 2136 output.append(8) 2137 2138 @jump_test(5, 6, [4, 6, 7]) 2139 def test_jump_within_except_block(output): 2140 try: 2141 1/0 2142 except: 2143 output.append(4) 2144 output.append(5) 2145 output.append(6) 2146 output.append(7) 2147 2148 @jump_test(6, 1, [1, 5, 1, 5]) 2149 def test_jump_over_try_except(output): 2150 output.append(1) 2151 try: 2152 1 / 0 2153 except ZeroDivisionError as e: 2154 output.append(5) 2155 x = 42 # has to be a two-instruction block 2156 2157 @jump_test(2, 4, [1, 4, 5, -4]) 2158 def test_jump_across_with(output): 2159 output.append(1) 2160 with tracecontext(output, 2): 2161 output.append(3) 2162 with tracecontext(output, 4): 2163 output.append(5) 2164 2165 @async_jump_test(2, 4, [1, 4, 5, -4]) 2166 async def test_jump_across_async_with(output): 2167 output.append(1) 2168 async with asynctracecontext(output, 2): 2169 output.append(3) 2170 async with asynctracecontext(output, 4): 2171 output.append(5) 2172 2173 @jump_test(4, 5, [1, 3, 5, 6]) 2174 def test_jump_out_of_with_block_within_for_block(output): 2175 output.append(1) 2176 for i in [1]: 2177 with tracecontext(output, 3): 2178 output.append(4) 2179 output.append(5) 2180 output.append(6) 2181 2182 @async_jump_test(4, 5, [1, 3, 5, 6]) 2183 async def test_jump_out_of_async_with_block_within_for_block(output): 2184 output.append(1) 2185 for i in [1]: 2186 async with asynctracecontext(output, 3): 2187 output.append(4) 2188 output.append(5) 2189 output.append(6) 2190 2191 @jump_test(4, 5, [1, 2, 3, 5, -2, 6]) 2192 def test_jump_out_of_with_block_within_with_block(output): 2193 output.append(1) 2194 with tracecontext(output, 2): 2195 with tracecontext(output, 3): 2196 output.append(4) 2197 output.append(5) 2198 output.append(6) 2199 2200 @async_jump_test(4, 5, [1, 2, 3, 5, -2, 6]) 2201 async def test_jump_out_of_async_with_block_within_with_block(output): 2202 output.append(1) 2203 with tracecontext(output, 2): 2204 async with asynctracecontext(output, 3): 2205 output.append(4) 2206 output.append(5) 2207 output.append(6) 2208 2209 @jump_test(5, 6, [2, 4, 6, 7]) 2210 def test_jump_out_of_with_block_within_finally_block(output): 2211 try: 2212 output.append(2) 2213 finally: 2214 with tracecontext(output, 4): 2215 output.append(5) 2216 output.append(6) 2217 output.append(7) 2218 2219 @async_jump_test(5, 6, [2, 4, 6, 7]) 2220 async def test_jump_out_of_async_with_block_within_finally_block(output): 2221 try: 2222 output.append(2) 2223 finally: 2224 async with asynctracecontext(output, 4): 2225 output.append(5) 2226 output.append(6) 2227 output.append(7) 2228 2229 @jump_test(8, 11, [1, 3, 5, 11, 12]) 2230 def test_jump_out_of_complex_nested_blocks(output): 2231 output.append(1) 2232 for i in [1]: 2233 output.append(3) 2234 for j in [1, 2]: 2235 output.append(5) 2236 try: 2237 for k in [1, 2]: 2238 output.append(8) 2239 finally: 2240 output.append(10) 2241 output.append(11) 2242 output.append(12) 2243 2244 @jump_test(3, 5, [1, 2, 5]) 2245 def test_jump_out_of_with_assignment(output): 2246 output.append(1) 2247 with tracecontext(output, 2) \ 2248 as x: 2249 output.append(4) 2250 output.append(5) 2251 2252 @async_jump_test(3, 5, [1, 2, 5]) 2253 async def test_jump_out_of_async_with_assignment(output): 2254 output.append(1) 2255 async with asynctracecontext(output, 2) \ 2256 as x: 2257 output.append(4) 2258 output.append(5) 2259 2260 @jump_test(3, 6, [1, 6, 8, 9]) 2261 def test_jump_over_return_in_try_finally_block(output): 2262 output.append(1) 2263 try: 2264 output.append(3) 2265 if not output: # always false 2266 return 2267 output.append(6) 2268 finally: 2269 output.append(8) 2270 output.append(9) 2271 2272 @jump_test(5, 8, [1, 3, 8, 10, 11, 13]) 2273 def test_jump_over_break_in_try_finally_block(output): 2274 output.append(1) 2275 while True: 2276 output.append(3) 2277 try: 2278 output.append(5) 2279 if not output: # always false 2280 break 2281 output.append(8) 2282 finally: 2283 output.append(10) 2284 output.append(11) 2285 break 2286 output.append(13) 2287 2288 @jump_test(1, 7, [7, 8]) 2289 def test_jump_over_for_block_before_else(output): 2290 output.append(1) 2291 if not output: # always false 2292 for i in [3]: 2293 output.append(4) 2294 else: 2295 output.append(6) 2296 output.append(7) 2297 output.append(8) 2298 2299 @async_jump_test(1, 7, [7, 8]) 2300 async def test_jump_over_async_for_block_before_else(output): 2301 output.append(1) 2302 if not output: # always false 2303 async for i in asynciter([3]): 2304 output.append(4) 2305 else: 2306 output.append(6) 2307 output.append(7) 2308 output.append(8) 2309 2310 # The second set of 'jump' tests are for things that are not allowed: 2311 2312 @jump_test(2, 3, [1], (ValueError, 'after')) 2313 def test_no_jump_too_far_forwards(output): 2314 output.append(1) 2315 output.append(2) 2316 2317 @jump_test(2, -2, [1], (ValueError, 'before')) 2318 def test_no_jump_too_far_backwards(output): 2319 output.append(1) 2320 output.append(2) 2321 2322 # Test each kind of 'except' line. 2323 @jump_test(2, 3, [4], (ValueError, 'except')) 2324 def test_no_jump_to_except_1(output): 2325 try: 2326 output.append(2) 2327 except: 2328 output.append(4) 2329 raise 2330 2331 @jump_test(2, 3, [4], (ValueError, 'except')) 2332 def test_no_jump_to_except_2(output): 2333 try: 2334 output.append(2) 2335 except ValueError: 2336 output.append(4) 2337 raise 2338 2339 @jump_test(2, 3, [4], (ValueError, 'except')) 2340 def test_no_jump_to_except_3(output): 2341 try: 2342 output.append(2) 2343 except ValueError as e: 2344 output.append(4) 2345 raise e 2346 2347 @jump_test(2, 3, [4], (ValueError, 'except')) 2348 def test_no_jump_to_except_4(output): 2349 try: 2350 output.append(2) 2351 except (ValueError, RuntimeError) as e: 2352 output.append(4) 2353 raise e 2354 2355 @jump_test(1, 3, [], (ValueError, 'into')) 2356 def test_no_jump_forwards_into_for_block(output): 2357 output.append(1) 2358 for i in 1, 2: 2359 output.append(3) 2360 2361 @async_jump_test(1, 3, [], (ValueError, 'into')) 2362 async def test_no_jump_forwards_into_async_for_block(output): 2363 output.append(1) 2364 async for i in asynciter([1, 2]): 2365 output.append(3) 2366 pass 2367 2368 @jump_test(3, 2, [2, 2], (ValueError, 'into')) 2369 def test_no_jump_backwards_into_for_block(output): 2370 for i in 1, 2: 2371 output.append(2) 2372 output.append(3) 2373 2374 @async_jump_test(3, 2, [2, 2], (ValueError, "can't jump into the body of a for loop")) 2375 async def test_no_jump_backwards_into_async_for_block(output): 2376 async for i in asynciter([1, 2]): 2377 output.append(2) 2378 output.append(3) 2379 2380 @jump_test(1, 3, [], (ValueError, 'stack')) 2381 def test_no_jump_forwards_into_with_block(output): 2382 output.append(1) 2383 with tracecontext(output, 2): 2384 output.append(3) 2385 2386 @async_jump_test(1, 3, [], (ValueError, 'stack')) 2387 async def test_no_jump_forwards_into_async_with_block(output): 2388 output.append(1) 2389 async with asynctracecontext(output, 2): 2390 output.append(3) 2391 2392 @jump_test(3, 2, [1, 2, -1], (ValueError, 'stack')) 2393 def test_no_jump_backwards_into_with_block(output): 2394 with tracecontext(output, 1): 2395 output.append(2) 2396 output.append(3) 2397 2398 @async_jump_test(3, 2, [1, 2, -1], (ValueError, 'stack')) 2399 async def test_no_jump_backwards_into_async_with_block(output): 2400 async with asynctracecontext(output, 1): 2401 output.append(2) 2402 output.append(3) 2403 2404 @jump_test(1, 3, [3, 5]) 2405 def test_jump_forwards_into_try_finally_block(output): 2406 output.append(1) 2407 try: 2408 output.append(3) 2409 finally: 2410 output.append(5) 2411 2412 @jump_test(5, 2, [2, 4, 2, 4, 5]) 2413 def test_jump_backwards_into_try_finally_block(output): 2414 try: 2415 output.append(2) 2416 finally: 2417 output.append(4) 2418 output.append(5) 2419 2420 @jump_test(1, 3, [3]) 2421 def test_jump_forwards_into_try_except_block(output): 2422 output.append(1) 2423 try: 2424 output.append(3) 2425 except: 2426 output.append(5) 2427 raise 2428 2429 @jump_test(6, 2, [2, 2, 6]) 2430 def test_jump_backwards_into_try_except_block(output): 2431 try: 2432 output.append(2) 2433 except: 2434 output.append(4) 2435 raise 2436 output.append(6) 2437 2438 # 'except' with a variable creates an implicit finally block 2439 @jump_test(5, 7, [4, 7, 8]) 2440 def test_jump_between_except_blocks_2(output): 2441 try: 2442 1/0 2443 except ZeroDivisionError: 2444 output.append(4) 2445 output.append(5) 2446 except FloatingPointError as e: 2447 output.append(7) 2448 output.append(8) 2449 2450 @jump_test(1, 5, [5]) 2451 def test_jump_into_finally_block(output): 2452 output.append(1) 2453 try: 2454 output.append(3) 2455 finally: 2456 output.append(5) 2457 2458 @jump_test(3, 6, [2, 6, 7]) 2459 def test_jump_into_finally_block_from_try_block(output): 2460 try: 2461 output.append(2) 2462 output.append(3) 2463 finally: # still executed if the jump is failed 2464 output.append(5) 2465 output.append(6) 2466 output.append(7) 2467 2468 @jump_test(5, 1, [1, 3, 1, 3, 5]) 2469 def test_jump_out_of_finally_block(output): 2470 output.append(1) 2471 try: 2472 output.append(3) 2473 finally: 2474 output.append(5) 2475 2476 @jump_test(1, 5, [], (ValueError, "can't jump into an 'except' block as there's no exception")) 2477 def test_no_jump_into_bare_except_block(output): 2478 output.append(1) 2479 try: 2480 output.append(3) 2481 except: 2482 output.append(5) 2483 2484 @jump_test(1, 5, [], (ValueError, "can't jump into an 'except' block as there's no exception")) 2485 def test_no_jump_into_qualified_except_block(output): 2486 output.append(1) 2487 try: 2488 output.append(3) 2489 except Exception: 2490 output.append(5) 2491 2492 @jump_test(3, 6, [2, 5, 6], (ValueError, "can't jump into an 'except' block as there's no exception")) 2493 def test_no_jump_into_bare_except_block_from_try_block(output): 2494 try: 2495 output.append(2) 2496 output.append(3) 2497 except: # executed if the jump is failed 2498 output.append(5) 2499 output.append(6) 2500 raise 2501 output.append(8) 2502 2503 @jump_test(3, 6, [2], (ValueError, "can't jump into an 'except' block as there's no exception")) 2504 def test_no_jump_into_qualified_except_block_from_try_block(output): 2505 try: 2506 output.append(2) 2507 output.append(3) 2508 except ZeroDivisionError: 2509 output.append(5) 2510 output.append(6) 2511 raise 2512 output.append(8) 2513 2514 @jump_test(7, 1, [1, 3, 6, 1, 3, 6, 7]) 2515 def test_jump_out_of_bare_except_block(output): 2516 output.append(1) 2517 try: 2518 output.append(3) 2519 1/0 2520 except: 2521 output.append(6) 2522 output.append(7) 2523 2524 @jump_test(7, 1, [1, 3, 6, 1, 3, 6, 7]) 2525 def test_jump_out_of_qualified_except_block(output): 2526 output.append(1) 2527 try: 2528 output.append(3) 2529 1/0 2530 except Exception: 2531 output.append(6) 2532 output.append(7) 2533 2534 @jump_test(3, 5, [1, 2, 5, -2]) 2535 def test_jump_between_with_blocks(output): 2536 output.append(1) 2537 with tracecontext(output, 2): 2538 output.append(3) 2539 with tracecontext(output, 4): 2540 output.append(5) 2541 2542 @async_jump_test(3, 5, [1, 2, 5, -2]) 2543 async def test_jump_between_async_with_blocks(output): 2544 output.append(1) 2545 async with asynctracecontext(output, 2): 2546 output.append(3) 2547 async with asynctracecontext(output, 4): 2548 output.append(5) 2549 2550 @jump_test(5, 7, [2, 4], (ValueError, "after")) 2551 def test_no_jump_over_return_out_of_finally_block(output): 2552 try: 2553 output.append(2) 2554 finally: 2555 output.append(4) 2556 output.append(5) 2557 return 2558 output.append(7) 2559 2560 @jump_test(7, 4, [1, 6], (ValueError, 'into')) 2561 def test_no_jump_into_for_block_before_else(output): 2562 output.append(1) 2563 if not output: # always false 2564 for i in [3]: 2565 output.append(4) 2566 else: 2567 output.append(6) 2568 output.append(7) 2569 output.append(8) 2570 2571 @async_jump_test(7, 4, [1, 6], (ValueError, 'into')) 2572 async def test_no_jump_into_async_for_block_before_else(output): 2573 output.append(1) 2574 if not output: # always false 2575 async for i in asynciter([3]): 2576 output.append(4) 2577 else: 2578 output.append(6) 2579 output.append(7) 2580 output.append(8) 2581 2582 def test_no_jump_to_non_integers(self): 2583 self.run_test(no_jump_to_non_integers, 2, "Spam", [True]) 2584 2585 def test_no_jump_without_trace_function(self): 2586 # Must set sys.settrace(None) in setUp(), else condition is not 2587 # triggered. 2588 no_jump_without_trace_function() 2589 2590 def test_large_function(self): 2591 d = {} 2592 exec("""def f(output): # line 0 2593 x = 0 # line 1 2594 y = 1 # line 2 2595 ''' # line 3 2596 %s # lines 4-1004 2597 ''' # line 1005 2598 x += 1 # line 1006 2599 output.append(x) # line 1007 2600 return""" % ('\n' * 1000,), d) 2601 f = d['f'] 2602 self.run_test(f, 2, 1007, [0]) 2603 2604 def test_jump_to_firstlineno(self): 2605 # This tests that PDB can jump back to the first line in a 2606 # file. See issue #1689458. It can only be triggered in a 2607 # function call if the function is defined on a single line. 2608 code = compile(""" 2609# Comments don't count. 2610output.append(2) # firstlineno is here. 2611output.append(3) 2612output.append(4) 2613""", "<fake module>", "exec") 2614 class fake_function: 2615 __code__ = code 2616 tracer = JumpTracer(fake_function, 4, 1) 2617 sys.settrace(tracer.trace) 2618 namespace = {"output": []} 2619 exec(code, namespace) 2620 sys.settrace(None) 2621 self.compare_jump_output([2, 3, 2, 3, 4], namespace["output"]) 2622 2623 @jump_test(2, 3, [1], event='call', error=(ValueError, "can't jump from" 2624 " the 'call' trace event of a new frame")) 2625 def test_no_jump_from_call(output): 2626 output.append(1) 2627 def nested(): 2628 output.append(3) 2629 nested() 2630 output.append(5) 2631 2632 @jump_test(2, 1, [1], event='return', error=(ValueError, 2633 "can only jump from a 'line' trace event")) 2634 def test_no_jump_from_return_event(output): 2635 output.append(1) 2636 return 2637 2638 @jump_test(2, 1, [1], event='exception', error=(ValueError, 2639 "can only jump from a 'line' trace event")) 2640 def test_no_jump_from_exception_event(output): 2641 output.append(1) 2642 1 / 0 2643 2644 @jump_test(3, 2, [2, 5], event='return') 2645 def test_jump_from_yield(output): 2646 def gen(): 2647 output.append(2) 2648 yield 3 2649 next(gen()) 2650 output.append(5) 2651 2652 @jump_test(2, 3, [1, 3]) 2653 def test_jump_forward_over_listcomp(output): 2654 output.append(1) 2655 x = [i for i in range(10)] 2656 output.append(3) 2657 2658 # checking for segfaults. 2659 # See https://github.com/python/cpython/issues/92311 2660 @jump_test(3, 1, []) 2661 def test_jump_backward_over_listcomp(output): 2662 a = 1 2663 x = [i for i in range(10)] 2664 c = 3 2665 2666 @jump_test(8, 2, [2, 7, 2]) 2667 def test_jump_backward_over_listcomp_v2(output): 2668 flag = False 2669 output.append(2) 2670 if flag: 2671 return 2672 x = [i for i in range(5)] 2673 flag = 6 2674 output.append(7) 2675 output.append(8) 2676 2677 @async_jump_test(2, 3, [1, 3]) 2678 async def test_jump_forward_over_async_listcomp(output): 2679 output.append(1) 2680 x = [i async for i in asynciter(range(10))] 2681 output.append(3) 2682 2683 @async_jump_test(3, 1, []) 2684 async def test_jump_backward_over_async_listcomp(output): 2685 a = 1 2686 x = [i async for i in asynciter(range(10))] 2687 c = 3 2688 2689 @async_jump_test(8, 2, [2, 7, 2]) 2690 async def test_jump_backward_over_async_listcomp_v2(output): 2691 flag = False 2692 output.append(2) 2693 if flag: 2694 return 2695 x = [i async for i in asynciter(range(5))] 2696 flag = 6 2697 output.append(7) 2698 output.append(8) 2699 2700 # checking for segfaults. 2701 @jump_test(3, 7, [], error=(ValueError, "stack")) 2702 def test_jump_with_null_on_stack_load_global(output): 2703 a = 1 2704 print( 2705 output.append(3) 2706 ) 2707 output.append(5) 2708 ( 2709 ( # 7 2710 a 2711 + 2712 10 2713 ) 2714 + 2715 13 2716 ) 2717 output.append(15) 2718 2719 # checking for segfaults. 2720 @jump_test(4, 8, [], error=(ValueError, "stack")) 2721 def test_jump_with_null_on_stack_push_null(output): 2722 a = 1 2723 f = print 2724 f( 2725 output.append(4) 2726 ) 2727 output.append(6) 2728 ( 2729 ( # 8 2730 a 2731 + 2732 11 2733 ) 2734 + 2735 14 2736 ) 2737 output.append(16) 2738 2739 # checking for segfaults. 2740 @jump_test(3, 7, [], error=(ValueError, "stack")) 2741 def test_jump_with_null_on_stack_load_attr(output): 2742 a = 1 2743 list.append( 2744 output, 3 2745 ) 2746 output.append(5) 2747 ( 2748 ( # 7 2749 a 2750 + 2751 10 2752 ) 2753 + 2754 13 2755 ) 2756 output.append(15) 2757 2758 @jump_test(2, 3, [1, 3]) 2759 def test_jump_extended_args_unpack_ex_simple(output): 2760 output.append(1) 2761 _, *_, _ = output.append(2) or "Spam" 2762 output.append(3) 2763 2764 @jump_test(3, 4, [1, 4, 4, 5]) 2765 def test_jump_extended_args_unpack_ex_tricky(output): 2766 output.append(1) 2767 ( 2768 _, *_, _ 2769 ) = output.append(4) or "Spam" 2770 output.append(5) 2771 2772 def test_jump_extended_args_for_iter(self): 2773 # In addition to failing when extended arg handling is broken, this can 2774 # also hang for a *very* long time: 2775 source = [ 2776 "def f(output):", 2777 " output.append(1)", 2778 " for _ in spam:", 2779 *(f" output.append({i})" for i in range(3, 100_000)), 2780 f" output.append(100_000)", 2781 ] 2782 namespace = {} 2783 exec("\n".join(source), namespace) 2784 f = namespace["f"] 2785 self.run_test(f, 2, 100_000, [1, 100_000]) 2786 2787 @jump_test(2, 3, [1, 3]) 2788 def test_jump_or_pop(output): 2789 output.append(1) 2790 _ = output.append(2) and "Spam" 2791 output.append(3) 2792 2793 2794class TestExtendedArgs(unittest.TestCase): 2795 2796 def setUp(self): 2797 self.addCleanup(sys.settrace, sys.gettrace()) 2798 sys.settrace(None) 2799 2800 def count_traces(self, func): 2801 # warmup 2802 for _ in range(20): 2803 func() 2804 2805 counts = {"call": 0, "line": 0, "return": 0} 2806 def trace(frame, event, arg): 2807 counts[event] += 1 2808 return trace 2809 2810 sys.settrace(trace) 2811 func() 2812 sys.settrace(None) 2813 2814 return counts 2815 2816 def test_trace_unpack_long_sequence(self): 2817 ns = {} 2818 code = "def f():\n (" + "y,\n "*300 + ") = range(300)" 2819 exec(code, ns) 2820 counts = self.count_traces(ns["f"]) 2821 self.assertEqual(counts, {'call': 1, 'line': 301, 'return': 1}) 2822 2823 def test_trace_lots_of_globals(self): 2824 code = """if 1: 2825 def f(): 2826 return ( 2827 {} 2828 ) 2829 """.format("\n+\n".join(f"var{i}\n" for i in range(1000))) 2830 ns = {f"var{i}": i for i in range(1000)} 2831 exec(code, ns) 2832 counts = self.count_traces(ns["f"]) 2833 self.assertEqual(counts, {'call': 1, 'line': 2000, 'return': 1}) 2834 2835 2836class TestEdgeCases(unittest.TestCase): 2837 2838 def setUp(self): 2839 self.addCleanup(sys.settrace, sys.gettrace()) 2840 sys.settrace(None) 2841 2842 def test_reentrancy(self): 2843 def foo(*args): 2844 ... 2845 2846 def bar(*args): 2847 ... 2848 2849 class A: 2850 def __call__(self, *args): 2851 pass 2852 2853 def __del__(self): 2854 sys.settrace(bar) 2855 2856 sys.settrace(A()) 2857 with support.catch_unraisable_exception() as cm: 2858 sys.settrace(foo) 2859 self.assertEqual(cm.unraisable.object, A.__del__) 2860 self.assertIsInstance(cm.unraisable.exc_value, RuntimeError) 2861 2862 self.assertEqual(sys.gettrace(), foo) 2863 2864 2865 def test_same_object(self): 2866 def foo(*args): 2867 ... 2868 2869 sys.settrace(foo) 2870 del foo 2871 sys.settrace(sys.gettrace()) 2872 2873 2874if __name__ == "__main__": 2875 unittest.main() 2876