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