1# Testing the line trace facility. 2 3from test import support 4import unittest 5import sys 6import difflib 7import gc 8from functools import wraps 9import asyncio 10 11 12class tracecontext: 13 """Context manager that traces its enter and exit.""" 14 def __init__(self, output, value): 15 self.output = output 16 self.value = value 17 18 def __enter__(self): 19 self.output.append(self.value) 20 21 def __exit__(self, *exc_info): 22 self.output.append(-self.value) 23 24class asynctracecontext: 25 """Asynchronous context manager that traces its aenter and aexit.""" 26 def __init__(self, output, value): 27 self.output = output 28 self.value = value 29 30 async def __aenter__(self): 31 self.output.append(self.value) 32 33 async def __aexit__(self, *exc_info): 34 self.output.append(-self.value) 35 36async def asynciter(iterable): 37 """Convert an iterable to an asynchronous iterator.""" 38 for x in iterable: 39 yield x 40 41 42# A very basic example. If this fails, we're in deep trouble. 43def basic(): 44 return 1 45 46basic.events = [(0, 'call'), 47 (1, 'line'), 48 (1, 'return')] 49 50# Many of the tests below are tricky because they involve pass statements. 51# If there is implicit control flow around a pass statement (in an except 52# clause or else clause) under what conditions do you set a line number 53# following that clause? 54 55 56# Some constructs like "while 0:", "if 0:" or "if 1:...else:..." could be optimized 57# away. Make sure that those lines aren't skipped. 58def arigo_example0(): 59 x = 1 60 del x 61 while 0: 62 pass 63 x = 1 64 65arigo_example0.events = [(0, 'call'), 66 (1, 'line'), 67 (2, 'line'), 68 (3, 'line'), 69 (5, 'line'), 70 (5, 'return')] 71 72def arigo_example1(): 73 x = 1 74 del x 75 if 0: 76 pass 77 x = 1 78 79arigo_example1.events = [(0, 'call'), 80 (1, 'line'), 81 (2, 'line'), 82 (3, 'line'), 83 (5, 'line'), 84 (5, 'return')] 85 86def arigo_example2(): 87 x = 1 88 del x 89 if 1: 90 x = 1 91 else: 92 pass 93 return None 94 95arigo_example2.events = [(0, 'call'), 96 (1, 'line'), 97 (2, 'line'), 98 (3, 'line'), 99 (4, 'line'), 100 (7, 'line'), 101 (7, 'return')] 102 103 104# check that lines consisting of just one instruction get traced: 105def one_instr_line(): 106 x = 1 107 del x 108 x = 1 109 110one_instr_line.events = [(0, 'call'), 111 (1, 'line'), 112 (2, 'line'), 113 (3, 'line'), 114 (3, 'return')] 115 116def no_pop_tops(): # 0 117 x = 1 # 1 118 for a in range(2): # 2 119 if a: # 3 120 x = 1 # 4 121 else: # 5 122 x = 1 # 6 123 124no_pop_tops.events = [(0, 'call'), 125 (1, 'line'), 126 (2, 'line'), 127 (3, 'line'), 128 (6, 'line'), 129 (2, 'line'), 130 (3, 'line'), 131 (4, 'line'), 132 (2, 'line'), 133 (2, 'return')] 134 135def no_pop_blocks(): 136 y = 1 137 while not y: 138 bla 139 x = 1 140 141no_pop_blocks.events = [(0, 'call'), 142 (1, 'line'), 143 (2, 'line'), 144 (4, 'line'), 145 (4, 'return')] 146 147def called(): # line -3 148 x = 1 149 150def call(): # line 0 151 called() 152 153call.events = [(0, 'call'), 154 (1, 'line'), 155 (-3, 'call'), 156 (-2, 'line'), 157 (-2, 'return'), 158 (1, 'return')] 159 160def raises(): 161 raise Exception 162 163def test_raise(): 164 try: 165 raises() 166 except Exception: 167 pass 168 169test_raise.events = [(0, 'call'), 170 (1, 'line'), 171 (2, 'line'), 172 (-3, 'call'), 173 (-2, 'line'), 174 (-2, 'exception'), 175 (-2, 'return'), 176 (2, 'exception'), 177 (3, 'line'), 178 (4, 'line'), 179 (4, 'return')] 180 181def _settrace_and_return(tracefunc): 182 sys.settrace(tracefunc) 183 sys._getframe().f_back.f_trace = tracefunc 184def settrace_and_return(tracefunc): 185 _settrace_and_return(tracefunc) 186 187settrace_and_return.events = [(1, 'return')] 188 189def _settrace_and_raise(tracefunc): 190 sys.settrace(tracefunc) 191 sys._getframe().f_back.f_trace = tracefunc 192 raise RuntimeError 193def settrace_and_raise(tracefunc): 194 try: 195 _settrace_and_raise(tracefunc) 196 except RuntimeError: 197 pass 198 199settrace_and_raise.events = [(2, 'exception'), 200 (3, 'line'), 201 (4, 'line'), 202 (4, 'return')] 203 204# implicit return example 205# This test is interesting because of the else: pass 206# part of the code. The code generate for the true 207# part of the if contains a jump past the else branch. 208# The compiler then generates an implicit "return None" 209# Internally, the compiler visits the pass statement 210# and stores its line number for use on the next instruction. 211# The next instruction is the implicit return None. 212def ireturn_example(): 213 a = 5 214 b = 5 215 if a == b: 216 b = a+1 217 else: 218 pass 219 220ireturn_example.events = [(0, 'call'), 221 (1, 'line'), 222 (2, 'line'), 223 (3, 'line'), 224 (4, 'line'), 225 (4, 'return')] 226 227# Tight loop with while(1) example (SF #765624) 228def tightloop_example(): 229 items = range(0, 3) 230 try: 231 i = 0 232 while 1: 233 b = items[i]; i+=1 234 except IndexError: 235 pass 236 237tightloop_example.events = [(0, 'call'), 238 (1, 'line'), 239 (2, 'line'), 240 (3, 'line'), 241 (4, 'line'), 242 (5, 'line'), 243 (4, 'line'), 244 (5, 'line'), 245 (4, 'line'), 246 (5, 'line'), 247 (4, 'line'), 248 (5, 'line'), 249 (5, 'exception'), 250 (6, 'line'), 251 (7, 'line'), 252 (7, 'return')] 253 254def tighterloop_example(): 255 items = range(1, 4) 256 try: 257 i = 0 258 while 1: i = items[i] 259 except IndexError: 260 pass 261 262tighterloop_example.events = [(0, 'call'), 263 (1, 'line'), 264 (2, 'line'), 265 (3, 'line'), 266 (4, 'line'), 267 (4, 'line'), 268 (4, 'line'), 269 (4, 'line'), 270 (4, 'exception'), 271 (5, 'line'), 272 (6, 'line'), 273 (6, 'return')] 274 275def generator_function(): 276 try: 277 yield True 278 "continued" 279 finally: 280 "finally" 281def generator_example(): 282 # any() will leave the generator before its end 283 x = any(generator_function()) 284 285 # the following lines were not traced 286 for x in range(10): 287 y = x 288 289generator_example.events = ([(0, 'call'), 290 (2, 'line'), 291 (-6, 'call'), 292 (-5, 'line'), 293 (-4, 'line'), 294 (-4, 'return'), 295 (-4, 'call'), 296 (-4, 'exception'), 297 (-1, 'line'), 298 (-1, 'return')] + 299 [(5, 'line'), (6, 'line')] * 10 + 300 [(5, 'line'), (5, 'return')]) 301 302 303class Tracer: 304 def __init__(self, trace_line_events=None, trace_opcode_events=None): 305 self.trace_line_events = trace_line_events 306 self.trace_opcode_events = trace_opcode_events 307 self.events = [] 308 309 def _reconfigure_frame(self, frame): 310 if self.trace_line_events is not None: 311 frame.f_trace_lines = self.trace_line_events 312 if self.trace_opcode_events is not None: 313 frame.f_trace_opcodes = self.trace_opcode_events 314 315 def trace(self, frame, event, arg): 316 self._reconfigure_frame(frame) 317 self.events.append((frame.f_lineno, event)) 318 return self.trace 319 320 def traceWithGenexp(self, frame, event, arg): 321 self._reconfigure_frame(frame) 322 (o for o in [1]) 323 self.events.append((frame.f_lineno, event)) 324 return self.trace 325 326 327class TraceTestCase(unittest.TestCase): 328 329 # Disable gc collection when tracing, otherwise the 330 # deallocators may be traced as well. 331 def setUp(self): 332 self.using_gc = gc.isenabled() 333 gc.disable() 334 self.addCleanup(sys.settrace, sys.gettrace()) 335 336 def tearDown(self): 337 if self.using_gc: 338 gc.enable() 339 340 @staticmethod 341 def make_tracer(): 342 """Helper to allow test subclasses to configure tracers differently""" 343 return Tracer() 344 345 def compare_events(self, line_offset, events, expected_events): 346 events = [(l - line_offset, e) for (l, e) in events] 347 if events != expected_events: 348 self.fail( 349 "events did not match expectation:\n" + 350 "\n".join(difflib.ndiff([str(x) for x in expected_events], 351 [str(x) for x in events]))) 352 353 def run_and_compare(self, func, events): 354 tracer = self.make_tracer() 355 sys.settrace(tracer.trace) 356 func() 357 sys.settrace(None) 358 self.compare_events(func.__code__.co_firstlineno, 359 tracer.events, events) 360 361 def run_test(self, func): 362 self.run_and_compare(func, func.events) 363 364 def run_test2(self, func): 365 tracer = self.make_tracer() 366 func(tracer.trace) 367 sys.settrace(None) 368 self.compare_events(func.__code__.co_firstlineno, 369 tracer.events, func.events) 370 371 def test_set_and_retrieve_none(self): 372 sys.settrace(None) 373 assert sys.gettrace() is None 374 375 def test_set_and_retrieve_func(self): 376 def fn(*args): 377 pass 378 379 sys.settrace(fn) 380 try: 381 assert sys.gettrace() is fn 382 finally: 383 sys.settrace(None) 384 385 def test_01_basic(self): 386 self.run_test(basic) 387 def test_02_arigo0(self): 388 self.run_test(arigo_example0) 389 def test_02_arigo1(self): 390 self.run_test(arigo_example1) 391 def test_02_arigo2(self): 392 self.run_test(arigo_example2) 393 def test_03_one_instr(self): 394 self.run_test(one_instr_line) 395 def test_04_no_pop_blocks(self): 396 self.run_test(no_pop_blocks) 397 def test_05_no_pop_tops(self): 398 self.run_test(no_pop_tops) 399 def test_06_call(self): 400 self.run_test(call) 401 def test_07_raise(self): 402 self.run_test(test_raise) 403 404 def test_08_settrace_and_return(self): 405 self.run_test2(settrace_and_return) 406 def test_09_settrace_and_raise(self): 407 self.run_test2(settrace_and_raise) 408 def test_10_ireturn(self): 409 self.run_test(ireturn_example) 410 def test_11_tightloop(self): 411 self.run_test(tightloop_example) 412 def test_12_tighterloop(self): 413 self.run_test(tighterloop_example) 414 415 def test_13_genexp(self): 416 self.run_test(generator_example) 417 # issue1265: if the trace function contains a generator, 418 # and if the traced function contains another generator 419 # that is not completely exhausted, the trace stopped. 420 # Worse: the 'finally' clause was not invoked. 421 tracer = self.make_tracer() 422 sys.settrace(tracer.traceWithGenexp) 423 generator_example() 424 sys.settrace(None) 425 self.compare_events(generator_example.__code__.co_firstlineno, 426 tracer.events, generator_example.events) 427 428 def test_14_onliner_if(self): 429 def onliners(): 430 if True: x=False 431 else: x=True 432 return 0 433 self.run_and_compare( 434 onliners, 435 [(0, 'call'), 436 (1, 'line'), 437 (3, 'line'), 438 (3, 'return')]) 439 440 def test_15_loops(self): 441 # issue1750076: "while" expression is skipped by debugger 442 def for_example(): 443 for x in range(2): 444 pass 445 self.run_and_compare( 446 for_example, 447 [(0, 'call'), 448 (1, 'line'), 449 (2, 'line'), 450 (1, 'line'), 451 (2, 'line'), 452 (1, 'line'), 453 (1, 'return')]) 454 455 def while_example(): 456 # While expression should be traced on every loop 457 x = 2 458 while x > 0: 459 x -= 1 460 self.run_and_compare( 461 while_example, 462 [(0, 'call'), 463 (2, 'line'), 464 (3, 'line'), 465 (4, 'line'), 466 (3, 'line'), 467 (4, 'line'), 468 (3, 'line'), 469 (3, 'return')]) 470 471 def test_16_blank_lines(self): 472 namespace = {} 473 exec("def f():\n" + "\n" * 256 + " pass", namespace) 474 self.run_and_compare( 475 namespace["f"], 476 [(0, 'call'), 477 (257, 'line'), 478 (257, 'return')]) 479 480 def test_17_none_f_trace(self): 481 # Issue 20041: fix TypeError when f_trace is set to None. 482 def func(): 483 sys._getframe().f_trace = None 484 lineno = 2 485 self.run_and_compare(func, 486 [(0, 'call'), 487 (1, 'line')]) 488 489 def test_18_except_with_name(self): 490 def func(): 491 try: 492 try: 493 raise Exception 494 except Exception as e: 495 raise 496 x = "Something" 497 y = "Something" 498 except Exception: 499 pass 500 501 self.run_and_compare(func, 502 [(0, 'call'), 503 (1, 'line'), 504 (2, 'line'), 505 (3, 'line'), 506 (3, 'exception'), 507 (4, 'line'), 508 (5, 'line'), 509 (8, 'line'), 510 (9, 'line'), 511 (9, 'return')]) 512 513 def test_19_except_with_finally(self): 514 def func(): 515 try: 516 try: 517 raise Exception 518 finally: 519 y = "Something" 520 except Exception: 521 b = 23 522 523 self.run_and_compare(func, 524 [(0, 'call'), 525 (1, 'line'), 526 (2, 'line'), 527 (3, 'line'), 528 (3, 'exception'), 529 (5, 'line'), 530 (6, 'line'), 531 (7, 'line'), 532 (7, 'return')]) 533 534 def test_20_async_for_loop(self): 535 class AsyncIteratorWrapper: 536 def __init__(self, obj): 537 self._it = iter(obj) 538 539 def __aiter__(self): 540 return self 541 542 async def __anext__(self): 543 try: 544 return next(self._it) 545 except StopIteration: 546 raise StopAsyncIteration 547 548 async def doit_async(): 549 async for letter in AsyncIteratorWrapper("abc"): 550 x = letter 551 y = 42 552 553 def run(tracer): 554 x = doit_async() 555 try: 556 sys.settrace(tracer) 557 x.send(None) 558 finally: 559 sys.settrace(None) 560 561 tracer = self.make_tracer() 562 events = [ 563 (0, 'call'), 564 (1, 'line'), 565 (-12, 'call'), 566 (-11, 'line'), 567 (-11, 'return'), 568 (-9, 'call'), 569 (-8, 'line'), 570 (-8, 'return'), 571 (-6, 'call'), 572 (-5, 'line'), 573 (-4, 'line'), 574 (-4, 'return'), 575 (1, 'exception'), 576 (2, 'line'), 577 (1, 'line'), 578 (-6, 'call'), 579 (-5, 'line'), 580 (-4, 'line'), 581 (-4, 'return'), 582 (1, 'exception'), 583 (2, 'line'), 584 (1, 'line'), 585 (-6, 'call'), 586 (-5, 'line'), 587 (-4, 'line'), 588 (-4, 'return'), 589 (1, 'exception'), 590 (2, 'line'), 591 (1, 'line'), 592 (-6, 'call'), 593 (-5, 'line'), 594 (-4, 'line'), 595 (-4, 'exception'), 596 (-3, 'line'), 597 (-2, 'line'), 598 (-2, 'exception'), 599 (-2, 'return'), 600 (1, 'exception'), 601 (3, 'line'), 602 (3, 'return')] 603 try: 604 run(tracer.trace) 605 except Exception: 606 pass 607 self.compare_events(doit_async.__code__.co_firstlineno, 608 tracer.events, events) 609 610 def test_21_repeated_pass(self): 611 def func(): 612 pass 613 pass 614 615 self.run_and_compare(func, 616 [(0, 'call'), 617 (1, 'line'), 618 (2, 'line'), 619 (2, 'return')]) 620 621 def test_loop_in_try_except(self): 622 # https://bugs.python.org/issue41670 623 624 def func(): 625 try: 626 for i in []: pass 627 return 1 628 except: 629 return 2 630 631 self.run_and_compare(func, 632 [(0, 'call'), 633 (1, 'line'), 634 (2, 'line'), 635 (3, 'line'), 636 (3, 'return')]) 637 638 def test_try_except_no_exception(self): 639 640 def func(): 641 try: 642 2 643 except: 644 4 645 finally: 646 6 647 648 self.run_and_compare(func, 649 [(0, 'call'), 650 (1, 'line'), 651 (2, 'line'), 652 (6, 'line'), 653 (6, 'return')]) 654 655 def test_nested_loops(self): 656 657 def func(): 658 for i in range(2): 659 for j in range(2): 660 a = i + j 661 return a == 1 662 663 self.run_and_compare(func, 664 [(0, 'call'), 665 (1, 'line'), 666 (2, 'line'), 667 (3, 'line'), 668 (2, 'line'), 669 (3, 'line'), 670 (2, 'line'), 671 (1, 'line'), 672 (2, 'line'), 673 (3, 'line'), 674 (2, 'line'), 675 (3, 'line'), 676 (2, 'line'), 677 (1, 'line'), 678 (4, 'line'), 679 (4, 'return')]) 680 681 def test_if_break(self): 682 683 def func(): 684 seq = [1, 0] 685 while seq: 686 n = seq.pop() 687 if n: 688 break # line 5 689 else: 690 n = 99 691 return n # line 8 692 693 self.run_and_compare(func, 694 [(0, 'call'), 695 (1, 'line'), 696 (2, 'line'), 697 (3, 'line'), 698 (4, 'line'), 699 (2, 'line'), 700 (3, 'line'), 701 (4, 'line'), 702 (5, 'line'), 703 (8, 'line'), 704 (8, 'return')]) 705 706 def test_break_through_finally(self): 707 708 def func(): 709 a, c, d, i = 1, 1, 1, 99 710 try: 711 for i in range(3): 712 try: 713 a = 5 714 if i > 0: 715 break # line 7 716 a = 8 717 finally: 718 c = 10 719 except: 720 d = 12 # line 12 721 assert a == 5 and c == 10 and d == 1 # line 13 722 723 self.run_and_compare(func, 724 [(0, 'call'), 725 (1, 'line'), 726 (2, 'line'), 727 (3, 'line'), 728 (4, 'line'), 729 (5, 'line'), 730 (6, 'line'), 731 (8, 'line'), 732 (10, 'line'), 733 (3, 'line'), 734 (4, 'line'), 735 (5, 'line'), 736 (6, 'line'), 737 (7, 'line'), 738 (10, 'line'), 739 (13, 'line'), 740 (13, 'return')]) 741 742 def test_continue_through_finally(self): 743 744 def func(): 745 a, b, c, d, i = 1, 1, 1, 1, 99 746 try: 747 for i in range(2): 748 try: 749 a = 5 750 if i > 0: 751 continue # line 7 752 b = 8 753 finally: 754 c = 10 755 except: 756 d = 12 # line 12 757 assert (a, b, c, d) == (5, 8, 10, 1) # line 13 758 759 self.run_and_compare(func, 760 [(0, 'call'), 761 (1, 'line'), 762 (2, 'line'), 763 (3, 'line'), 764 (4, 'line'), 765 (5, 'line'), 766 (6, 'line'), 767 (8, 'line'), 768 (10, 'line'), 769 (3, 'line'), 770 (4, 'line'), 771 (5, 'line'), 772 (6, 'line'), 773 (7, 'line'), 774 (10, 'line'), 775 (3, 'line'), 776 (13, 'line'), 777 (13, 'return')]) 778 779 def test_return_through_finally(self): 780 781 def func(): 782 try: 783 return 2 784 finally: 785 4 786 787 self.run_and_compare(func, 788 [(0, 'call'), 789 (1, 'line'), 790 (2, 'line'), 791 (4, 'line'), 792 (4, 'return')]) 793 794 def test_try_except_with_wrong_type(self): 795 796 def func(): 797 try: 798 2/0 799 except IndexError: 800 4 801 finally: 802 return 6 803 804 self.run_and_compare(func, 805 [(0, 'call'), 806 (1, 'line'), 807 (2, 'line'), 808 (2, 'exception'), 809 (3, 'line'), 810 (6, 'line'), 811 (6, 'return')]) 812 813 def test_break_to_continue1(self): 814 815 def func(): 816 TRUE = 1 817 x = [1] 818 while x: 819 x.pop() 820 while TRUE: 821 break 822 continue 823 824 self.run_and_compare(func, 825 [(0, 'call'), 826 (1, 'line'), 827 (2, 'line'), 828 (3, 'line'), 829 (4, 'line'), 830 (5, 'line'), 831 (6, 'line'), 832 (7, 'line'), 833 (3, 'line'), 834 (3, 'return')]) 835 836 def test_break_to_continue2(self): 837 838 def func(): 839 TRUE = 1 840 x = [1] 841 while x: 842 x.pop() 843 while TRUE: 844 break 845 else: 846 continue 847 848 self.run_and_compare(func, 849 [(0, 'call'), 850 (1, 'line'), 851 (2, 'line'), 852 (3, 'line'), 853 (4, 'line'), 854 (5, 'line'), 855 (6, 'line'), 856 (3, 'line'), 857 (3, 'return')]) 858 859 def test_break_to_break(self): 860 861 def func(): 862 TRUE = 1 863 while TRUE: 864 while TRUE: 865 break 866 break 867 868 self.run_and_compare(func, 869 [(0, 'call'), 870 (1, 'line'), 871 (2, 'line'), 872 (3, 'line'), 873 (4, 'line'), 874 (5, 'line'), 875 (5, 'return')]) 876 877 def test_nested_ifs(self): 878 879 def func(): 880 a = b = 1 881 if a == 1: 882 if b == 1: 883 x = 4 884 else: 885 y = 6 886 else: 887 z = 8 888 889 self.run_and_compare(func, 890 [(0, 'call'), 891 (1, 'line'), 892 (2, 'line'), 893 (3, 'line'), 894 (4, 'line'), 895 (4, 'return')]) 896 897 def test_nested_ifs_with_and(self): 898 899 def func(): 900 if A: 901 if B: 902 if C: 903 if D: 904 return False 905 else: 906 return False 907 elif E and F: 908 return True 909 910 A = B = True 911 C = False 912 913 self.run_and_compare(func, 914 [(0, 'call'), 915 (1, 'line'), 916 (2, 'line'), 917 (3, 'line'), 918 (3, 'return')]) 919 920 def test_nested_try_if(self): 921 922 def func(): 923 x = "hello" 924 try: 925 3/0 926 except ZeroDivisionError: 927 if x == 'raise': 928 raise ValueError() # line 6 929 f = 7 930 931 self.run_and_compare(func, 932 [(0, 'call'), 933 (1, 'line'), 934 (2, 'line'), 935 (3, 'line'), 936 (3, 'exception'), 937 (4, 'line'), 938 (5, 'line'), 939 (7, 'line'), 940 (7, 'return')]) 941 942 def test_if_false_in_with(self): 943 944 class C: 945 def __enter__(self): 946 return self 947 def __exit__(*args): 948 pass 949 950 def func(): 951 with C(): 952 if False: 953 pass 954 955 self.run_and_compare(func, 956 [(0, 'call'), 957 (1, 'line'), 958 (-5, 'call'), 959 (-4, 'line'), 960 (-4, 'return'), 961 (2, 'line'), 962 (1, 'line'), 963 (-3, 'call'), 964 (-2, 'line'), 965 (-2, 'return'), 966 (1, 'return')]) 967 968 def test_if_false_in_try_except(self): 969 970 def func(): 971 try: 972 if False: 973 pass 974 except Exception: 975 X 976 977 self.run_and_compare(func, 978 [(0, 'call'), 979 (1, 'line'), 980 (2, 'line'), 981 (2, 'return')]) 982 983 def test_implicit_return_in_class(self): 984 985 def func(): 986 class A: 987 if 3 < 9: 988 a = 1 989 else: 990 a = 2 991 992 self.run_and_compare(func, 993 [(0, 'call'), 994 (1, 'line'), 995 (1, 'call'), 996 (1, 'line'), 997 (2, 'line'), 998 (3, 'line'), 999 (3, 'return'), 1000 (1, 'return')]) 1001 1002 def test_try_in_try(self): 1003 def func(): 1004 try: 1005 try: 1006 pass 1007 except Exception as ex: 1008 pass 1009 except Exception: 1010 pass 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_if_in_if_in_if(self): 1020 def func(a=0, p=1, z=1): 1021 if p: 1022 if a: 1023 if z: 1024 pass 1025 else: 1026 pass 1027 else: 1028 pass 1029 1030 self.run_and_compare(func, 1031 [(0, 'call'), 1032 (1, 'line'), 1033 (2, 'line'), 1034 (2, 'return')]) 1035 1036 def test_early_exit_with(self): 1037 1038 class C: 1039 def __enter__(self): 1040 return self 1041 def __exit__(*args): 1042 pass 1043 1044 def func_break(): 1045 for i in (1,2): 1046 with C(): 1047 break 1048 pass 1049 1050 def func_return(): 1051 with C(): 1052 return 1053 1054 self.run_and_compare(func_break, 1055 [(0, 'call'), 1056 (1, 'line'), 1057 (2, 'line'), 1058 (-5, 'call'), 1059 (-4, 'line'), 1060 (-4, 'return'), 1061 (3, 'line'), 1062 (2, 'line'), 1063 (-3, 'call'), 1064 (-2, 'line'), 1065 (-2, 'return'), 1066 (4, 'line'), 1067 (4, 'return')]) 1068 1069 self.run_and_compare(func_return, 1070 [(0, 'call'), 1071 (1, 'line'), 1072 (-11, 'call'), 1073 (-10, 'line'), 1074 (-10, 'return'), 1075 (2, 'line'), 1076 (1, 'line'), 1077 (-9, 'call'), 1078 (-8, 'line'), 1079 (-8, 'return'), 1080 (1, 'return')]) 1081 1082 def test_flow_converges_on_same_line(self): 1083 1084 def foo(x): 1085 if x: 1086 try: 1087 1/(x - 1) 1088 except ZeroDivisionError: 1089 pass 1090 return x 1091 1092 def func(): 1093 for i in range(2): 1094 foo(i) 1095 1096 self.run_and_compare(func, 1097 [(0, 'call'), 1098 (1, 'line'), 1099 (2, 'line'), 1100 (-8, 'call'), 1101 (-7, 'line'), 1102 (-2, 'line'), 1103 (-2, 'return'), 1104 (1, 'line'), 1105 (2, 'line'), 1106 (-8, 'call'), 1107 (-7, 'line'), 1108 (-6, 'line'), 1109 (-5, 'line'), 1110 (-5, 'exception'), 1111 (-4, 'line'), 1112 (-3, 'line'), 1113 (-2, 'line'), 1114 (-2, 'return'), 1115 (1, 'line'), 1116 (1, 'return')]) 1117 1118 def test_no_tracing_of_named_except_cleanup(self): 1119 1120 def func(): 1121 x = 0 1122 try: 1123 1/x 1124 except ZeroDivisionError as error: 1125 if x: 1126 raise 1127 return "done" 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 (5, 'line'), 1137 (7, 'line'), 1138 (7, 'return')]) 1139 1140 1141class SkipLineEventsTraceTestCase(TraceTestCase): 1142 """Repeat the trace tests, but with per-line events skipped""" 1143 1144 def compare_events(self, line_offset, events, expected_events): 1145 skip_line_events = [e for e in expected_events if e[1] != 'line'] 1146 super().compare_events(line_offset, events, skip_line_events) 1147 1148 @staticmethod 1149 def make_tracer(): 1150 return Tracer(trace_line_events=False) 1151 1152 1153@support.cpython_only 1154class TraceOpcodesTestCase(TraceTestCase): 1155 """Repeat the trace tests, but with per-opcodes events enabled""" 1156 1157 def compare_events(self, line_offset, events, expected_events): 1158 skip_opcode_events = [e for e in events if e[1] != 'opcode'] 1159 if len(events) > 1: 1160 self.assertLess(len(skip_opcode_events), len(events), 1161 msg="No 'opcode' events received by the tracer") 1162 super().compare_events(line_offset, skip_opcode_events, expected_events) 1163 1164 @staticmethod 1165 def make_tracer(): 1166 return Tracer(trace_opcode_events=True) 1167 1168 1169class RaisingTraceFuncTestCase(unittest.TestCase): 1170 def setUp(self): 1171 self.addCleanup(sys.settrace, sys.gettrace()) 1172 1173 def trace(self, frame, event, arg): 1174 """A trace function that raises an exception in response to a 1175 specific trace event.""" 1176 if event == self.raiseOnEvent: 1177 raise ValueError # just something that isn't RuntimeError 1178 else: 1179 return self.trace 1180 1181 def f(self): 1182 """The function to trace; raises an exception if that's the case 1183 we're testing, so that the 'exception' trace event fires.""" 1184 if self.raiseOnEvent == 'exception': 1185 x = 0 1186 y = 1/x 1187 else: 1188 return 1 1189 1190 def run_test_for_event(self, event): 1191 """Tests that an exception raised in response to the given event is 1192 handled OK.""" 1193 self.raiseOnEvent = event 1194 try: 1195 for i in range(sys.getrecursionlimit() + 1): 1196 sys.settrace(self.trace) 1197 try: 1198 self.f() 1199 except ValueError: 1200 pass 1201 else: 1202 self.fail("exception not raised!") 1203 except RuntimeError: 1204 self.fail("recursion counter not reset") 1205 1206 # Test the handling of exceptions raised by each kind of trace event. 1207 def test_call(self): 1208 self.run_test_for_event('call') 1209 def test_line(self): 1210 self.run_test_for_event('line') 1211 def test_return(self): 1212 self.run_test_for_event('return') 1213 def test_exception(self): 1214 self.run_test_for_event('exception') 1215 1216 def test_trash_stack(self): 1217 def f(): 1218 for i in range(5): 1219 print(i) # line tracing will raise an exception at this line 1220 1221 def g(frame, why, extra): 1222 if (why == 'line' and 1223 frame.f_lineno == f.__code__.co_firstlineno + 2): 1224 raise RuntimeError("i am crashing") 1225 return g 1226 1227 sys.settrace(g) 1228 try: 1229 f() 1230 except RuntimeError: 1231 # the test is really that this doesn't segfault: 1232 import gc 1233 gc.collect() 1234 else: 1235 self.fail("exception not propagated") 1236 1237 1238 def test_exception_arguments(self): 1239 def f(): 1240 x = 0 1241 # this should raise an error 1242 x.no_such_attr 1243 def g(frame, event, arg): 1244 if (event == 'exception'): 1245 type, exception, trace = arg 1246 self.assertIsInstance(exception, Exception) 1247 return g 1248 1249 existing = sys.gettrace() 1250 try: 1251 sys.settrace(g) 1252 try: 1253 f() 1254 except AttributeError: 1255 # this is expected 1256 pass 1257 finally: 1258 sys.settrace(existing) 1259 1260 1261# 'Jump' tests: assigning to frame.f_lineno within a trace function 1262# moves the execution position - it's how debuggers implement a Jump 1263# command (aka. "Set next statement"). 1264 1265class JumpTracer: 1266 """Defines a trace function that jumps from one place to another.""" 1267 1268 def __init__(self, function, jumpFrom, jumpTo, event='line', 1269 decorated=False): 1270 self.code = function.__code__ 1271 self.jumpFrom = jumpFrom 1272 self.jumpTo = jumpTo 1273 self.event = event 1274 self.firstLine = None if decorated else self.code.co_firstlineno 1275 self.done = False 1276 1277 def trace(self, frame, event, arg): 1278 if self.done: 1279 return 1280 # frame.f_code.co_firstlineno is the first line of the decorator when 1281 # 'function' is decorated and the decorator may be written using 1282 # multiple physical lines when it is too long. Use the first line 1283 # trace event in 'function' to find the first line of 'function'. 1284 if (self.firstLine is None and frame.f_code == self.code and 1285 event == 'line'): 1286 self.firstLine = frame.f_lineno - 1 1287 if (event == self.event and self.firstLine is not None and 1288 frame.f_lineno == self.firstLine + self.jumpFrom): 1289 f = frame 1290 while f is not None and f.f_code != self.code: 1291 f = f.f_back 1292 if f is not None: 1293 # Cope with non-integer self.jumpTo (because of 1294 # no_jump_to_non_integers below). 1295 try: 1296 frame.f_lineno = self.firstLine + self.jumpTo 1297 except TypeError: 1298 frame.f_lineno = self.jumpTo 1299 self.done = True 1300 return self.trace 1301 1302# This verifies the line-numbers-must-be-integers rule. 1303def no_jump_to_non_integers(output): 1304 try: 1305 output.append(2) 1306 except ValueError as e: 1307 output.append('integer' in str(e)) 1308 1309# This verifies that you can't set f_lineno via _getframe or similar 1310# trickery. 1311def no_jump_without_trace_function(): 1312 try: 1313 previous_frame = sys._getframe().f_back 1314 previous_frame.f_lineno = previous_frame.f_lineno 1315 except ValueError as e: 1316 # This is the exception we wanted; make sure the error message 1317 # talks about trace functions. 1318 if 'trace' not in str(e): 1319 raise 1320 else: 1321 # Something's wrong - the expected exception wasn't raised. 1322 raise AssertionError("Trace-function-less jump failed to fail") 1323 1324 1325class JumpTestCase(unittest.TestCase): 1326 def setUp(self): 1327 self.addCleanup(sys.settrace, sys.gettrace()) 1328 sys.settrace(None) 1329 1330 def compare_jump_output(self, expected, received): 1331 if received != expected: 1332 self.fail( "Outputs don't match:\n" + 1333 "Expected: " + repr(expected) + "\n" + 1334 "Received: " + repr(received)) 1335 1336 def run_test(self, func, jumpFrom, jumpTo, expected, error=None, 1337 event='line', decorated=False): 1338 tracer = JumpTracer(func, jumpFrom, jumpTo, event, decorated) 1339 sys.settrace(tracer.trace) 1340 output = [] 1341 if error is None: 1342 func(output) 1343 else: 1344 with self.assertRaisesRegex(*error): 1345 func(output) 1346 sys.settrace(None) 1347 self.compare_jump_output(expected, output) 1348 1349 def run_async_test(self, func, jumpFrom, jumpTo, expected, error=None, 1350 event='line', decorated=False): 1351 tracer = JumpTracer(func, jumpFrom, jumpTo, event, decorated) 1352 sys.settrace(tracer.trace) 1353 output = [] 1354 if error is None: 1355 asyncio.run(func(output)) 1356 else: 1357 with self.assertRaisesRegex(*error): 1358 asyncio.run(func(output)) 1359 sys.settrace(None) 1360 asyncio.set_event_loop_policy(None) 1361 self.compare_jump_output(expected, output) 1362 1363 def jump_test(jumpFrom, jumpTo, expected, error=None, event='line'): 1364 """Decorator that creates a test that makes a jump 1365 from one place to another in the following code. 1366 """ 1367 def decorator(func): 1368 @wraps(func) 1369 def test(self): 1370 self.run_test(func, jumpFrom, jumpTo, expected, 1371 error=error, event=event, decorated=True) 1372 return test 1373 return decorator 1374 1375 def async_jump_test(jumpFrom, jumpTo, expected, error=None, event='line'): 1376 """Decorator that creates a test that makes a jump 1377 from one place to another in the following asynchronous code. 1378 """ 1379 def decorator(func): 1380 @wraps(func) 1381 def test(self): 1382 self.run_async_test(func, jumpFrom, jumpTo, expected, 1383 error=error, event=event, decorated=True) 1384 return test 1385 return decorator 1386 1387 ## The first set of 'jump' tests are for things that are allowed: 1388 1389 @jump_test(1, 3, [3]) 1390 def test_jump_simple_forwards(output): 1391 output.append(1) 1392 output.append(2) 1393 output.append(3) 1394 1395 @jump_test(2, 1, [1, 1, 2]) 1396 def test_jump_simple_backwards(output): 1397 output.append(1) 1398 output.append(2) 1399 1400 @jump_test(3, 5, [2, 5]) 1401 def test_jump_out_of_block_forwards(output): 1402 for i in 1, 2: 1403 output.append(2) 1404 for j in [3]: # Also tests jumping over a block 1405 output.append(4) 1406 output.append(5) 1407 1408 @jump_test(6, 1, [1, 3, 5, 1, 3, 5, 6, 7]) 1409 def test_jump_out_of_block_backwards(output): 1410 output.append(1) 1411 for i in [1]: 1412 output.append(3) 1413 for j in [2]: # Also tests jumping over a block 1414 output.append(5) 1415 output.append(6) 1416 output.append(7) 1417 1418 @async_jump_test(4, 5, [3, 5]) 1419 async def test_jump_out_of_async_for_block_forwards(output): 1420 for i in [1]: 1421 async for i in asynciter([1, 2]): 1422 output.append(3) 1423 output.append(4) 1424 output.append(5) 1425 1426 @async_jump_test(5, 2, [2, 4, 2, 4, 5, 6]) 1427 async def test_jump_out_of_async_for_block_backwards(output): 1428 for i in [1]: 1429 output.append(2) 1430 async for i in asynciter([1]): 1431 output.append(4) 1432 output.append(5) 1433 output.append(6) 1434 1435 @jump_test(1, 2, [3]) 1436 def test_jump_to_codeless_line(output): 1437 output.append(1) 1438 # Jumping to this line should skip to the next one. 1439 output.append(3) 1440 1441 @jump_test(2, 2, [1, 2, 3]) 1442 def test_jump_to_same_line(output): 1443 output.append(1) 1444 output.append(2) 1445 output.append(3) 1446 1447 # Tests jumping within a finally block, and over one. 1448 @jump_test(4, 9, [2, 9]) 1449 def test_jump_in_nested_finally(output): 1450 try: 1451 output.append(2) 1452 finally: 1453 output.append(4) 1454 try: 1455 output.append(6) 1456 finally: 1457 output.append(8) 1458 output.append(9) 1459 1460 @jump_test(6, 7, [2, 7], (ZeroDivisionError, '')) 1461 def test_jump_in_nested_finally_2(output): 1462 try: 1463 output.append(2) 1464 1/0 1465 return 1466 finally: 1467 output.append(6) 1468 output.append(7) 1469 output.append(8) 1470 1471 @jump_test(6, 11, [2, 11], (ZeroDivisionError, '')) 1472 def test_jump_in_nested_finally_3(output): 1473 try: 1474 output.append(2) 1475 1/0 1476 return 1477 finally: 1478 output.append(6) 1479 try: 1480 output.append(8) 1481 finally: 1482 output.append(10) 1483 output.append(11) 1484 output.append(12) 1485 1486 @jump_test(5, 11, [2, 4], (ValueError, 'after')) 1487 def test_no_jump_over_return_try_finally_in_finally_block(output): 1488 try: 1489 output.append(2) 1490 finally: 1491 output.append(4) 1492 output.append(5) 1493 return 1494 try: 1495 output.append(8) 1496 finally: 1497 output.append(10) 1498 pass 1499 output.append(12) 1500 1501 @jump_test(3, 4, [1], (ValueError, 'after')) 1502 def test_no_jump_infinite_while_loop(output): 1503 output.append(1) 1504 while True: 1505 output.append(3) 1506 output.append(4) 1507 1508 @jump_test(2, 4, [4, 4]) 1509 def test_jump_forwards_into_while_block(output): 1510 i = 1 1511 output.append(2) 1512 while i <= 2: 1513 output.append(4) 1514 i += 1 1515 1516 @jump_test(5, 3, [3, 3, 3, 5]) 1517 def test_jump_backwards_into_while_block(output): 1518 i = 1 1519 while i <= 2: 1520 output.append(3) 1521 i += 1 1522 output.append(5) 1523 1524 @jump_test(2, 3, [1, 3]) 1525 def test_jump_forwards_out_of_with_block(output): 1526 with tracecontext(output, 1): 1527 output.append(2) 1528 output.append(3) 1529 1530 @async_jump_test(2, 3, [1, 3]) 1531 async def test_jump_forwards_out_of_async_with_block(output): 1532 async with asynctracecontext(output, 1): 1533 output.append(2) 1534 output.append(3) 1535 1536 @jump_test(3, 1, [1, 2, 1, 2, 3, -2]) 1537 def test_jump_backwards_out_of_with_block(output): 1538 output.append(1) 1539 with tracecontext(output, 2): 1540 output.append(3) 1541 1542 @async_jump_test(3, 1, [1, 2, 1, 2, 3, -2]) 1543 async def test_jump_backwards_out_of_async_with_block(output): 1544 output.append(1) 1545 async with asynctracecontext(output, 2): 1546 output.append(3) 1547 1548 @jump_test(2, 5, [5]) 1549 def test_jump_forwards_out_of_try_finally_block(output): 1550 try: 1551 output.append(2) 1552 finally: 1553 output.append(4) 1554 output.append(5) 1555 1556 @jump_test(3, 1, [1, 1, 3, 5]) 1557 def test_jump_backwards_out_of_try_finally_block(output): 1558 output.append(1) 1559 try: 1560 output.append(3) 1561 finally: 1562 output.append(5) 1563 1564 @jump_test(2, 6, [6]) 1565 def test_jump_forwards_out_of_try_except_block(output): 1566 try: 1567 output.append(2) 1568 except: 1569 output.append(4) 1570 raise 1571 output.append(6) 1572 1573 @jump_test(3, 1, [1, 1, 3]) 1574 def test_jump_backwards_out_of_try_except_block(output): 1575 output.append(1) 1576 try: 1577 output.append(3) 1578 except: 1579 output.append(5) 1580 raise 1581 1582 @jump_test(5, 7, [4, 7, 8]) 1583 def test_jump_between_except_blocks(output): 1584 try: 1585 1/0 1586 except ZeroDivisionError: 1587 output.append(4) 1588 output.append(5) 1589 except FloatingPointError: 1590 output.append(7) 1591 output.append(8) 1592 1593 @jump_test(5, 6, [4, 6, 7]) 1594 def test_jump_within_except_block(output): 1595 try: 1596 1/0 1597 except: 1598 output.append(4) 1599 output.append(5) 1600 output.append(6) 1601 output.append(7) 1602 1603 @jump_test(2, 4, [1, 4, 5, -4]) 1604 def test_jump_across_with(output): 1605 output.append(1) 1606 with tracecontext(output, 2): 1607 output.append(3) 1608 with tracecontext(output, 4): 1609 output.append(5) 1610 1611 @async_jump_test(2, 4, [1, 4, 5, -4]) 1612 async def test_jump_across_async_with(output): 1613 output.append(1) 1614 async with asynctracecontext(output, 2): 1615 output.append(3) 1616 async with asynctracecontext(output, 4): 1617 output.append(5) 1618 1619 @jump_test(4, 5, [1, 3, 5, 6]) 1620 def test_jump_out_of_with_block_within_for_block(output): 1621 output.append(1) 1622 for i in [1]: 1623 with tracecontext(output, 3): 1624 output.append(4) 1625 output.append(5) 1626 output.append(6) 1627 1628 @async_jump_test(4, 5, [1, 3, 5, 6]) 1629 async def test_jump_out_of_async_with_block_within_for_block(output): 1630 output.append(1) 1631 for i in [1]: 1632 async with asynctracecontext(output, 3): 1633 output.append(4) 1634 output.append(5) 1635 output.append(6) 1636 1637 @jump_test(4, 5, [1, 2, 3, 5, -2, 6]) 1638 def test_jump_out_of_with_block_within_with_block(output): 1639 output.append(1) 1640 with tracecontext(output, 2): 1641 with tracecontext(output, 3): 1642 output.append(4) 1643 output.append(5) 1644 output.append(6) 1645 1646 @async_jump_test(4, 5, [1, 2, 3, 5, -2, 6]) 1647 async def test_jump_out_of_async_with_block_within_with_block(output): 1648 output.append(1) 1649 with tracecontext(output, 2): 1650 async with asynctracecontext(output, 3): 1651 output.append(4) 1652 output.append(5) 1653 output.append(6) 1654 1655 @jump_test(5, 6, [2, 4, 6, 7]) 1656 def test_jump_out_of_with_block_within_finally_block(output): 1657 try: 1658 output.append(2) 1659 finally: 1660 with tracecontext(output, 4): 1661 output.append(5) 1662 output.append(6) 1663 output.append(7) 1664 1665 @async_jump_test(5, 6, [2, 4, 6, 7]) 1666 async def test_jump_out_of_async_with_block_within_finally_block(output): 1667 try: 1668 output.append(2) 1669 finally: 1670 async with asynctracecontext(output, 4): 1671 output.append(5) 1672 output.append(6) 1673 output.append(7) 1674 1675 @jump_test(8, 11, [1, 3, 5, 11, 12]) 1676 def test_jump_out_of_complex_nested_blocks(output): 1677 output.append(1) 1678 for i in [1]: 1679 output.append(3) 1680 for j in [1, 2]: 1681 output.append(5) 1682 try: 1683 for k in [1, 2]: 1684 output.append(8) 1685 finally: 1686 output.append(10) 1687 output.append(11) 1688 output.append(12) 1689 1690 @jump_test(3, 5, [1, 2, 5]) 1691 def test_jump_out_of_with_assignment(output): 1692 output.append(1) 1693 with tracecontext(output, 2) \ 1694 as x: 1695 output.append(4) 1696 output.append(5) 1697 1698 @async_jump_test(3, 5, [1, 2, 5]) 1699 async def test_jump_out_of_async_with_assignment(output): 1700 output.append(1) 1701 async with asynctracecontext(output, 2) \ 1702 as x: 1703 output.append(4) 1704 output.append(5) 1705 1706 @jump_test(3, 6, [1, 6, 8, 9]) 1707 def test_jump_over_return_in_try_finally_block(output): 1708 output.append(1) 1709 try: 1710 output.append(3) 1711 if not output: # always false 1712 return 1713 output.append(6) 1714 finally: 1715 output.append(8) 1716 output.append(9) 1717 1718 @jump_test(5, 8, [1, 3, 8, 10, 11, 13]) 1719 def test_jump_over_break_in_try_finally_block(output): 1720 output.append(1) 1721 while True: 1722 output.append(3) 1723 try: 1724 output.append(5) 1725 if not output: # always false 1726 break 1727 output.append(8) 1728 finally: 1729 output.append(10) 1730 output.append(11) 1731 break 1732 output.append(13) 1733 1734 @jump_test(1, 7, [7, 8]) 1735 def test_jump_over_for_block_before_else(output): 1736 output.append(1) 1737 if not output: # always false 1738 for i in [3]: 1739 output.append(4) 1740 else: 1741 output.append(6) 1742 output.append(7) 1743 output.append(8) 1744 1745 @async_jump_test(1, 7, [7, 8]) 1746 async def test_jump_over_async_for_block_before_else(output): 1747 output.append(1) 1748 if not output: # always false 1749 async for i in asynciter([3]): 1750 output.append(4) 1751 else: 1752 output.append(6) 1753 output.append(7) 1754 output.append(8) 1755 1756 # The second set of 'jump' tests are for things that are not allowed: 1757 1758 @jump_test(2, 3, [1], (ValueError, 'after')) 1759 def test_no_jump_too_far_forwards(output): 1760 output.append(1) 1761 output.append(2) 1762 1763 @jump_test(2, -2, [1], (ValueError, 'before')) 1764 def test_no_jump_too_far_backwards(output): 1765 output.append(1) 1766 output.append(2) 1767 1768 # Test each kind of 'except' line. 1769 @jump_test(2, 3, [4], (ValueError, 'except')) 1770 def test_no_jump_to_except_1(output): 1771 try: 1772 output.append(2) 1773 except: 1774 output.append(4) 1775 raise 1776 1777 @jump_test(2, 3, [4], (ValueError, 'except')) 1778 def test_no_jump_to_except_2(output): 1779 try: 1780 output.append(2) 1781 except ValueError: 1782 output.append(4) 1783 raise 1784 1785 @jump_test(2, 3, [4], (ValueError, 'except')) 1786 def test_no_jump_to_except_3(output): 1787 try: 1788 output.append(2) 1789 except ValueError as e: 1790 output.append(4) 1791 raise e 1792 1793 @jump_test(2, 3, [4], (ValueError, 'except')) 1794 def test_no_jump_to_except_4(output): 1795 try: 1796 output.append(2) 1797 except (ValueError, RuntimeError) as e: 1798 output.append(4) 1799 raise e 1800 1801 @jump_test(1, 3, [], (ValueError, 'into')) 1802 def test_no_jump_forwards_into_for_block(output): 1803 output.append(1) 1804 for i in 1, 2: 1805 output.append(3) 1806 1807 @async_jump_test(1, 3, [], (ValueError, 'into')) 1808 async def test_no_jump_forwards_into_async_for_block(output): 1809 output.append(1) 1810 async for i in asynciter([1, 2]): 1811 output.append(3) 1812 pass 1813 1814 @jump_test(3, 2, [2, 2], (ValueError, 'into')) 1815 def test_no_jump_backwards_into_for_block(output): 1816 for i in 1, 2: 1817 output.append(2) 1818 output.append(3) 1819 1820 @async_jump_test(3, 2, [2, 2], (ValueError, 'into')) 1821 async def test_no_jump_backwards_into_async_for_block(output): 1822 async for i in asynciter([1, 2]): 1823 output.append(2) 1824 output.append(3) 1825 1826 @jump_test(1, 3, [], (ValueError, 'into')) 1827 def test_no_jump_forwards_into_with_block(output): 1828 output.append(1) 1829 with tracecontext(output, 2): 1830 output.append(3) 1831 1832 @async_jump_test(1, 3, [], (ValueError, 'into')) 1833 async def test_no_jump_forwards_into_async_with_block(output): 1834 output.append(1) 1835 async with asynctracecontext(output, 2): 1836 output.append(3) 1837 1838 @jump_test(3, 2, [1, 2, -1], (ValueError, 'into')) 1839 def test_no_jump_backwards_into_with_block(output): 1840 with tracecontext(output, 1): 1841 output.append(2) 1842 output.append(3) 1843 1844 @async_jump_test(3, 2, [1, 2, -1], (ValueError, 'into')) 1845 async def test_no_jump_backwards_into_async_with_block(output): 1846 async with asynctracecontext(output, 1): 1847 output.append(2) 1848 output.append(3) 1849 1850 @jump_test(1, 3, [], (ValueError, 'into')) 1851 def test_no_jump_forwards_into_try_finally_block(output): 1852 output.append(1) 1853 try: 1854 output.append(3) 1855 finally: 1856 output.append(5) 1857 1858 @jump_test(5, 2, [2, 4], (ValueError, 'into')) 1859 def test_no_jump_backwards_into_try_finally_block(output): 1860 try: 1861 output.append(2) 1862 finally: 1863 output.append(4) 1864 output.append(5) 1865 1866 @jump_test(1, 3, [], (ValueError, 'into')) 1867 def test_no_jump_forwards_into_try_except_block(output): 1868 output.append(1) 1869 try: 1870 output.append(3) 1871 except: 1872 output.append(5) 1873 raise 1874 1875 @jump_test(6, 2, [2], (ValueError, 'into')) 1876 def test_no_jump_backwards_into_try_except_block(output): 1877 try: 1878 output.append(2) 1879 except: 1880 output.append(4) 1881 raise 1882 output.append(6) 1883 1884 # 'except' with a variable creates an implicit finally block 1885 @jump_test(5, 7, [4], (ValueError, 'into')) 1886 def test_no_jump_between_except_blocks_2(output): 1887 try: 1888 1/0 1889 except ZeroDivisionError: 1890 output.append(4) 1891 output.append(5) 1892 except FloatingPointError as e: 1893 output.append(7) 1894 output.append(8) 1895 1896 @jump_test(1, 5, [5]) 1897 def test_jump_into_finally_block(output): 1898 output.append(1) 1899 try: 1900 output.append(3) 1901 finally: 1902 output.append(5) 1903 1904 @jump_test(3, 6, [2, 6, 7]) 1905 def test_jump_into_finally_block_from_try_block(output): 1906 try: 1907 output.append(2) 1908 output.append(3) 1909 finally: # still executed if the jump is failed 1910 output.append(5) 1911 output.append(6) 1912 output.append(7) 1913 1914 @jump_test(5, 1, [1, 3, 1, 3, 5]) 1915 def test_jump_out_of_finally_block(output): 1916 output.append(1) 1917 try: 1918 output.append(3) 1919 finally: 1920 output.append(5) 1921 1922 @jump_test(1, 5, [], (ValueError, "into an 'except'")) 1923 def test_no_jump_into_bare_except_block(output): 1924 output.append(1) 1925 try: 1926 output.append(3) 1927 except: 1928 output.append(5) 1929 1930 @jump_test(1, 5, [], (ValueError, "into an 'except'")) 1931 def test_no_jump_into_qualified_except_block(output): 1932 output.append(1) 1933 try: 1934 output.append(3) 1935 except Exception: 1936 output.append(5) 1937 1938 @jump_test(3, 6, [2, 5, 6], (ValueError, "into an 'except'")) 1939 def test_no_jump_into_bare_except_block_from_try_block(output): 1940 try: 1941 output.append(2) 1942 output.append(3) 1943 except: # executed if the jump is failed 1944 output.append(5) 1945 output.append(6) 1946 raise 1947 output.append(8) 1948 1949 @jump_test(3, 6, [2], (ValueError, "into an 'except'")) 1950 def test_no_jump_into_qualified_except_block_from_try_block(output): 1951 try: 1952 output.append(2) 1953 output.append(3) 1954 except ZeroDivisionError: 1955 output.append(5) 1956 output.append(6) 1957 raise 1958 output.append(8) 1959 1960 @jump_test(7, 1, [1, 3, 6], (ValueError, "out of an 'except'")) 1961 def test_no_jump_out_of_bare_except_block(output): 1962 output.append(1) 1963 try: 1964 output.append(3) 1965 1/0 1966 except: 1967 output.append(6) 1968 output.append(7) 1969 1970 @jump_test(7, 1, [1, 3, 6], (ValueError, "out of an 'except'")) 1971 def test_no_jump_out_of_qualified_except_block(output): 1972 output.append(1) 1973 try: 1974 output.append(3) 1975 1/0 1976 except Exception: 1977 output.append(6) 1978 output.append(7) 1979 1980 @jump_test(3, 5, [1, 2, 5, -2]) 1981 def test_jump_between_with_blocks(output): 1982 output.append(1) 1983 with tracecontext(output, 2): 1984 output.append(3) 1985 with tracecontext(output, 4): 1986 output.append(5) 1987 1988 @async_jump_test(3, 5, [1, 2, 5, -2]) 1989 async def test_jump_between_async_with_blocks(output): 1990 output.append(1) 1991 async with asynctracecontext(output, 2): 1992 output.append(3) 1993 async with asynctracecontext(output, 4): 1994 output.append(5) 1995 1996 @jump_test(5, 7, [2, 4], (ValueError, "after")) 1997 def test_no_jump_over_return_out_of_finally_block(output): 1998 try: 1999 output.append(2) 2000 finally: 2001 output.append(4) 2002 output.append(5) 2003 return 2004 output.append(7) 2005 2006 @jump_test(7, 4, [1, 6], (ValueError, 'into')) 2007 def test_no_jump_into_for_block_before_else(output): 2008 output.append(1) 2009 if not output: # always false 2010 for i in [3]: 2011 output.append(4) 2012 else: 2013 output.append(6) 2014 output.append(7) 2015 output.append(8) 2016 2017 @async_jump_test(7, 4, [1, 6], (ValueError, 'into')) 2018 async def test_no_jump_into_async_for_block_before_else(output): 2019 output.append(1) 2020 if not output: # always false 2021 async for i in asynciter([3]): 2022 output.append(4) 2023 else: 2024 output.append(6) 2025 output.append(7) 2026 output.append(8) 2027 2028 def test_no_jump_to_non_integers(self): 2029 self.run_test(no_jump_to_non_integers, 2, "Spam", [True]) 2030 2031 def test_no_jump_without_trace_function(self): 2032 # Must set sys.settrace(None) in setUp(), else condition is not 2033 # triggered. 2034 no_jump_without_trace_function() 2035 2036 def test_large_function(self): 2037 d = {} 2038 exec("""def f(output): # line 0 2039 x = 0 # line 1 2040 y = 1 # line 2 2041 ''' # line 3 2042 %s # lines 4-1004 2043 ''' # line 1005 2044 x += 1 # line 1006 2045 output.append(x) # line 1007 2046 return""" % ('\n' * 1000,), d) 2047 f = d['f'] 2048 self.run_test(f, 2, 1007, [0]) 2049 2050 def test_jump_to_firstlineno(self): 2051 # This tests that PDB can jump back to the first line in a 2052 # file. See issue #1689458. It can only be triggered in a 2053 # function call if the function is defined on a single line. 2054 code = compile(""" 2055# Comments don't count. 2056output.append(2) # firstlineno is here. 2057output.append(3) 2058output.append(4) 2059""", "<fake module>", "exec") 2060 class fake_function: 2061 __code__ = code 2062 tracer = JumpTracer(fake_function, 4, 1) 2063 sys.settrace(tracer.trace) 2064 namespace = {"output": []} 2065 exec(code, namespace) 2066 sys.settrace(None) 2067 self.compare_jump_output([2, 3, 2, 3, 4], namespace["output"]) 2068 2069 @jump_test(2, 3, [1], event='call', error=(ValueError, "can't jump from" 2070 " the 'call' trace event of a new frame")) 2071 def test_no_jump_from_call(output): 2072 output.append(1) 2073 def nested(): 2074 output.append(3) 2075 nested() 2076 output.append(5) 2077 2078 @jump_test(2, 1, [1], event='return', error=(ValueError, 2079 "can only jump from a 'line' trace event")) 2080 def test_no_jump_from_return_event(output): 2081 output.append(1) 2082 return 2083 2084 @jump_test(2, 1, [1], event='exception', error=(ValueError, 2085 "can only jump from a 'line' trace event")) 2086 def test_no_jump_from_exception_event(output): 2087 output.append(1) 2088 1 / 0 2089 2090 @jump_test(3, 2, [2, 5], event='return') 2091 def test_jump_from_yield(output): 2092 def gen(): 2093 output.append(2) 2094 yield 3 2095 next(gen()) 2096 output.append(5) 2097 2098 2099if __name__ == "__main__": 2100 unittest.main() 2101