1# Testing the line trace facility. 2 3from test import test_support 4import unittest 5import sys 6import difflib 7import gc 8from functools import wraps 9 10class tracecontext: 11 """Contex manager that traces its enter and exit.""" 12 def __init__(self, output, value): 13 self.output = output 14 self.value = value 15 16 def __enter__(self): 17 self.output.append(self.value) 18 19 def __exit__(self, *exc_info): 20 self.output.append(-self.value) 21 22# A very basic example. If this fails, we're in deep trouble. 23def basic(): 24 return 1 25 26basic.events = [(0, 'call'), 27 (1, 'line'), 28 (1, 'return')] 29 30# Many of the tests below are tricky because they involve pass statements. 31# If there is implicit control flow around a pass statement (in an except 32# clause or else caluse) under what conditions do you set a line number 33# following that clause? 34 35 36# The entire "while 0:" statement is optimized away. No code 37# exists for it, so the line numbers skip directly from "del x" 38# to "x = 1". 39def arigo_example(): 40 x = 1 41 del x 42 while 0: 43 pass 44 x = 1 45 46arigo_example.events = [(0, 'call'), 47 (1, 'line'), 48 (2, 'line'), 49 (5, 'line'), 50 (5, 'return')] 51 52# check that lines consisting of just one instruction get traced: 53def one_instr_line(): 54 x = 1 55 del x 56 x = 1 57 58one_instr_line.events = [(0, 'call'), 59 (1, 'line'), 60 (2, 'line'), 61 (3, 'line'), 62 (3, 'return')] 63 64def no_pop_tops(): # 0 65 x = 1 # 1 66 for a in range(2): # 2 67 if a: # 3 68 x = 1 # 4 69 else: # 5 70 x = 1 # 6 71 72no_pop_tops.events = [(0, 'call'), 73 (1, 'line'), 74 (2, 'line'), 75 (3, 'line'), 76 (6, 'line'), 77 (2, 'line'), 78 (3, 'line'), 79 (4, 'line'), 80 (2, 'line'), 81 (2, 'return')] 82 83def no_pop_blocks(): 84 y = 1 85 while not y: 86 bla 87 x = 1 88 89no_pop_blocks.events = [(0, 'call'), 90 (1, 'line'), 91 (2, 'line'), 92 (4, 'line'), 93 (4, 'return')] 94 95def called(): # line -3 96 x = 1 97 98def call(): # line 0 99 called() 100 101call.events = [(0, 'call'), 102 (1, 'line'), 103 (-3, 'call'), 104 (-2, 'line'), 105 (-2, 'return'), 106 (1, 'return')] 107 108def raises(): 109 raise Exception 110 111def test_raise(): 112 try: 113 raises() 114 except Exception, exc: 115 x = 1 116 117test_raise.events = [(0, 'call'), 118 (1, 'line'), 119 (2, 'line'), 120 (-3, 'call'), 121 (-2, 'line'), 122 (-2, 'exception'), 123 (-2, 'return'), 124 (2, 'exception'), 125 (3, 'line'), 126 (4, 'line'), 127 (4, 'return')] 128 129def _settrace_and_return(tracefunc): 130 sys.settrace(tracefunc) 131 sys._getframe().f_back.f_trace = tracefunc 132def settrace_and_return(tracefunc): 133 _settrace_and_return(tracefunc) 134 135settrace_and_return.events = [(1, 'return')] 136 137def _settrace_and_raise(tracefunc): 138 sys.settrace(tracefunc) 139 sys._getframe().f_back.f_trace = tracefunc 140 raise RuntimeError 141def settrace_and_raise(tracefunc): 142 try: 143 _settrace_and_raise(tracefunc) 144 except RuntimeError, exc: 145 pass 146 147settrace_and_raise.events = [(2, 'exception'), 148 (3, 'line'), 149 (4, 'line'), 150 (4, 'return')] 151 152# implicit return example 153# This test is interesting because of the else: pass 154# part of the code. The code generate for the true 155# part of the if contains a jump past the else branch. 156# The compiler then generates an implicit "return None" 157# Internally, the compiler visits the pass statement 158# and stores its line number for use on the next instruction. 159# The next instruction is the implicit return None. 160def ireturn_example(): 161 a = 5 162 b = 5 163 if a == b: 164 b = a+1 165 else: 166 pass 167 168ireturn_example.events = [(0, 'call'), 169 (1, 'line'), 170 (2, 'line'), 171 (3, 'line'), 172 (4, 'line'), 173 (6, 'line'), 174 (6, 'return')] 175 176# Tight loop with while(1) example (SF #765624) 177def tightloop_example(): 178 items = range(0, 3) 179 try: 180 i = 0 181 while 1: 182 b = items[i]; i+=1 183 except IndexError: 184 pass 185 186tightloop_example.events = [(0, 'call'), 187 (1, 'line'), 188 (2, 'line'), 189 (3, 'line'), 190 (4, 'line'), 191 (5, 'line'), 192 (5, 'line'), 193 (5, 'line'), 194 (5, 'line'), 195 (5, 'exception'), 196 (6, 'line'), 197 (7, 'line'), 198 (7, 'return')] 199 200def tighterloop_example(): 201 items = range(1, 4) 202 try: 203 i = 0 204 while 1: i = items[i] 205 except IndexError: 206 pass 207 208tighterloop_example.events = [(0, 'call'), 209 (1, 'line'), 210 (2, 'line'), 211 (3, 'line'), 212 (4, 'line'), 213 (4, 'line'), 214 (4, 'line'), 215 (4, 'line'), 216 (4, 'exception'), 217 (5, 'line'), 218 (6, 'line'), 219 (6, 'return')] 220 221def generator_function(): 222 try: 223 yield True 224 "continued" 225 finally: 226 "finally" 227def generator_example(): 228 # any() will leave the generator before its end 229 x = any(generator_function()) 230 231 # the following lines were not traced 232 for x in range(10): 233 y = x 234 235generator_example.events = ([(0, 'call'), 236 (2, 'line'), 237 (-6, 'call'), 238 (-5, 'line'), 239 (-4, 'line'), 240 (-4, 'return'), 241 (-4, 'call'), 242 (-4, 'exception'), 243 (-1, 'line'), 244 (-1, 'return')] + 245 [(5, 'line'), (6, 'line')] * 10 + 246 [(5, 'line'), (5, 'return')]) 247 248 249class Tracer: 250 def __init__(self): 251 self.events = [] 252 def trace(self, frame, event, arg): 253 self.events.append((frame.f_lineno, event)) 254 return self.trace 255 def traceWithGenexp(self, frame, event, arg): 256 (o for o in [1]) 257 self.events.append((frame.f_lineno, event)) 258 return self.trace 259 260class TraceTestCase(unittest.TestCase): 261 262 # Disable gc collection when tracing, otherwise the 263 # deallocators may be traced as well. 264 def setUp(self): 265 self.using_gc = gc.isenabled() 266 gc.disable() 267 268 def tearDown(self): 269 if self.using_gc: 270 gc.enable() 271 272 def compare_events(self, line_offset, events, expected_events): 273 events = [(l - line_offset, e) for (l, e) in events] 274 if events != expected_events: 275 self.fail( 276 "events did not match expectation:\n" + 277 "\n".join(difflib.ndiff([str(x) for x in expected_events], 278 [str(x) for x in events]))) 279 280 def run_and_compare(self, func, events): 281 tracer = Tracer() 282 sys.settrace(tracer.trace) 283 func() 284 sys.settrace(None) 285 self.compare_events(func.func_code.co_firstlineno, 286 tracer.events, events) 287 288 def run_test(self, func): 289 self.run_and_compare(func, func.events) 290 291 def run_test2(self, func): 292 tracer = Tracer() 293 func(tracer.trace) 294 sys.settrace(None) 295 self.compare_events(func.func_code.co_firstlineno, 296 tracer.events, func.events) 297 298 def test_set_and_retrieve_none(self): 299 sys.settrace(None) 300 assert sys.gettrace() is None 301 302 def test_set_and_retrieve_func(self): 303 def fn(*args): 304 pass 305 306 sys.settrace(fn) 307 try: 308 assert sys.gettrace() is fn 309 finally: 310 sys.settrace(None) 311 312 def test_01_basic(self): 313 self.run_test(basic) 314 def test_02_arigo(self): 315 self.run_test(arigo_example) 316 def test_03_one_instr(self): 317 self.run_test(one_instr_line) 318 def test_04_no_pop_blocks(self): 319 self.run_test(no_pop_blocks) 320 def test_05_no_pop_tops(self): 321 self.run_test(no_pop_tops) 322 def test_06_call(self): 323 self.run_test(call) 324 def test_07_raise(self): 325 self.run_test(test_raise) 326 327 def test_08_settrace_and_return(self): 328 self.run_test2(settrace_and_return) 329 def test_09_settrace_and_raise(self): 330 self.run_test2(settrace_and_raise) 331 def test_10_ireturn(self): 332 self.run_test(ireturn_example) 333 def test_11_tightloop(self): 334 self.run_test(tightloop_example) 335 def test_12_tighterloop(self): 336 self.run_test(tighterloop_example) 337 338 def test_13_genexp(self): 339 self.run_test(generator_example) 340 # issue1265: if the trace function contains a generator, 341 # and if the traced function contains another generator 342 # that is not completely exhausted, the trace stopped. 343 # Worse: the 'finally' clause was not invoked. 344 tracer = Tracer() 345 sys.settrace(tracer.traceWithGenexp) 346 generator_example() 347 sys.settrace(None) 348 self.compare_events(generator_example.__code__.co_firstlineno, 349 tracer.events, generator_example.events) 350 351 def test_14_onliner_if(self): 352 def onliners(): 353 if True: False 354 else: True 355 return 0 356 self.run_and_compare( 357 onliners, 358 [(0, 'call'), 359 (1, 'line'), 360 (3, 'line'), 361 (3, 'return')]) 362 363 def test_15_loops(self): 364 # issue1750076: "while" expression is skipped by debugger 365 def for_example(): 366 for x in range(2): 367 pass 368 self.run_and_compare( 369 for_example, 370 [(0, 'call'), 371 (1, 'line'), 372 (2, 'line'), 373 (1, 'line'), 374 (2, 'line'), 375 (1, 'line'), 376 (1, 'return')]) 377 378 def while_example(): 379 # While expression should be traced on every loop 380 x = 2 381 while x > 0: 382 x -= 1 383 self.run_and_compare( 384 while_example, 385 [(0, 'call'), 386 (2, 'line'), 387 (3, 'line'), 388 (4, 'line'), 389 (3, 'line'), 390 (4, 'line'), 391 (3, 'line'), 392 (3, 'return')]) 393 394 def test_16_blank_lines(self): 395 exec("def f():\n" + "\n" * 256 + " pass") 396 self.run_and_compare( 397 f, 398 [(0, 'call'), 399 (257, 'line'), 400 (257, 'return')]) 401 402 def test_17_none_f_trace(self): 403 # Issue 20041: fix TypeError when f_trace is set to None. 404 def func(): 405 sys._getframe().f_trace = None 406 lineno = 2 407 self.run_and_compare(func, 408 [(0, 'call'), 409 (1, 'line')]) 410 411 412class RaisingTraceFuncTestCase(unittest.TestCase): 413 def trace(self, frame, event, arg): 414 """A trace function that raises an exception in response to a 415 specific trace event.""" 416 if event == self.raiseOnEvent: 417 raise ValueError # just something that isn't RuntimeError 418 else: 419 return self.trace 420 421 def f(self): 422 """The function to trace; raises an exception if that's the case 423 we're testing, so that the 'exception' trace event fires.""" 424 if self.raiseOnEvent == 'exception': 425 x = 0 426 y = 1 // x 427 else: 428 return 1 429 430 def run_test_for_event(self, event): 431 """Tests that an exception raised in response to the given event is 432 handled OK.""" 433 self.raiseOnEvent = event 434 try: 435 for i in xrange(sys.getrecursionlimit() + 1): 436 sys.settrace(self.trace) 437 try: 438 self.f() 439 except ValueError: 440 pass 441 else: 442 self.fail("exception not raised!") 443 except RuntimeError: 444 self.fail("recursion counter not reset") 445 446 # Test the handling of exceptions raised by each kind of trace event. 447 def test_call(self): 448 self.run_test_for_event('call') 449 def test_line(self): 450 self.run_test_for_event('line') 451 def test_return(self): 452 self.run_test_for_event('return') 453 def test_exception(self): 454 self.run_test_for_event('exception') 455 456 def test_trash_stack(self): 457 def f(): 458 for i in range(5): 459 print i # line tracing will raise an exception at this line 460 461 def g(frame, why, extra): 462 if (why == 'line' and 463 frame.f_lineno == f.func_code.co_firstlineno + 2): 464 raise RuntimeError, "i am crashing" 465 return g 466 467 sys.settrace(g) 468 try: 469 f() 470 except RuntimeError: 471 # the test is really that this doesn't segfault: 472 import gc 473 gc.collect() 474 else: 475 self.fail("exception not propagated") 476 477 478# 'Jump' tests: assigning to frame.f_lineno within a trace function 479# moves the execution position - it's how debuggers implement a Jump 480# command (aka. "Set next statement"). 481 482class JumpTracer: 483 """Defines a trace function that jumps from one place to another.""" 484 485 def __init__(self, function, jumpFrom, jumpTo, event='line', 486 decorated=False): 487 self.code = function.func_code 488 self.jumpFrom = jumpFrom 489 self.jumpTo = jumpTo 490 self.event = event 491 self.firstLine = None if decorated else self.code.co_firstlineno 492 self.done = False 493 494 def trace(self, frame, event, arg): 495 if self.done: 496 return 497 # frame.f_code.co_firstlineno is the first line of the decorator when 498 # 'function' is decorated and the decorator may be written using 499 # multiple physical lines when it is too long. Use the first line 500 # trace event in 'function' to find the first line of 'function'. 501 if (self.firstLine is None and frame.f_code == self.code and 502 event == 'line'): 503 self.firstLine = frame.f_lineno - 1 504 if (event == self.event and self.firstLine and 505 frame.f_lineno == self.firstLine + self.jumpFrom): 506 f = frame 507 while f is not None and f.f_code != self.code: 508 f = f.f_back 509 if f is not None: 510 # Cope with non-integer self.jumpTo (because of 511 # no_jump_to_non_integers below). 512 try: 513 frame.f_lineno = self.firstLine + self.jumpTo 514 except TypeError: 515 frame.f_lineno = self.jumpTo 516 self.done = True 517 return self.trace 518 519# This verifies the line-numbers-must-be-integers rule. 520def no_jump_to_non_integers(output): 521 try: 522 output.append(2) 523 except ValueError as e: 524 output.append('integer' in str(e)) 525 526# This verifies that you can't set f_lineno via _getframe or similar 527# trickery. 528def no_jump_without_trace_function(): 529 try: 530 previous_frame = sys._getframe().f_back 531 previous_frame.f_lineno = previous_frame.f_lineno 532 except ValueError as e: 533 # This is the exception we wanted; make sure the error message 534 # talks about trace functions. 535 if 'trace' not in str(e): 536 raise 537 else: 538 # Something's wrong - the expected exception wasn't raised. 539 raise AssertionError("Trace-function-less jump failed to fail") 540 541 542class JumpTestCase(unittest.TestCase): 543 def setUp(self): 544 self.addCleanup(sys.settrace, sys.gettrace()) 545 sys.settrace(None) 546 547 def compare_jump_output(self, expected, received): 548 if received != expected: 549 self.fail( "Outputs don't match:\n" + 550 "Expected: " + repr(expected) + "\n" + 551 "Received: " + repr(received)) 552 553 def run_test(self, func, jumpFrom, jumpTo, expected, error=None, 554 event='line', decorated=False): 555 tracer = JumpTracer(func, jumpFrom, jumpTo, event, decorated) 556 sys.settrace(tracer.trace) 557 output = [] 558 if error is None: 559 func(output) 560 else: 561 with self.assertRaisesRegexp(*error): 562 func(output) 563 sys.settrace(None) 564 self.compare_jump_output(expected, output) 565 566 def jump_test(jumpFrom, jumpTo, expected, error=None, event='line'): 567 """Decorator that creates a test that makes a jump 568 from one place to another in the following code. 569 """ 570 def decorator(func): 571 @wraps(func) 572 def test(self): 573 self.run_test(func, jumpFrom, jumpTo, expected, 574 error=error, event=event, decorated=True) 575 return test 576 return decorator 577 578 ## The first set of 'jump' tests are for things that are allowed: 579 580 @jump_test(1, 3, [3]) 581 def test_jump_simple_forwards(output): 582 output.append(1) 583 output.append(2) 584 output.append(3) 585 586 @jump_test(2, 1, [1, 1, 2]) 587 def test_jump_simple_backwards(output): 588 output.append(1) 589 output.append(2) 590 591 @jump_test(3, 5, [2, 5]) 592 def test_jump_out_of_block_forwards(output): 593 for i in 1, 2: 594 output.append(2) 595 for j in [3]: # Also tests jumping over a block 596 output.append(4) 597 output.append(5) 598 599 @jump_test(6, 1, [1, 3, 5, 1, 3, 5, 6, 7]) 600 def test_jump_out_of_block_backwards(output): 601 output.append(1) 602 for i in [1]: 603 output.append(3) 604 for j in [2]: # Also tests jumping over a block 605 output.append(5) 606 output.append(6) 607 output.append(7) 608 609 @jump_test(1, 2, [3]) 610 def test_jump_to_codeless_line(output): 611 output.append(1) 612 # Jumping to this line should skip to the next one. 613 output.append(3) 614 615 @jump_test(2, 2, [1, 2, 3]) 616 def test_jump_to_same_line(output): 617 output.append(1) 618 output.append(2) 619 output.append(3) 620 621 # Tests jumping within a finally block, and over one. 622 @jump_test(4, 9, [2, 9]) 623 def test_jump_in_nested_finally(output): 624 try: 625 output.append(2) 626 finally: 627 output.append(4) 628 try: 629 output.append(6) 630 finally: 631 output.append(8) 632 output.append(9) 633 634 @jump_test(6, 7, [2, 7], (ZeroDivisionError, '')) 635 def test_jump_in_nested_finally_2(output): 636 try: 637 output.append(2) 638 1.0/0.0 639 return 640 finally: 641 output.append(6) 642 output.append(7) 643 output.append(8) 644 645 @jump_test(6, 11, [2, 11], (ZeroDivisionError, '')) 646 def test_jump_in_nested_finally_3(output): 647 try: 648 output.append(2) 649 1.0/0.0 650 return 651 finally: 652 output.append(6) 653 try: 654 output.append(8) 655 finally: 656 output.append(10) 657 output.append(11) 658 output.append(12) 659 660 @jump_test(3, 4, [1, 4]) 661 def test_jump_infinite_while_loop(output): 662 output.append(1) 663 while True: 664 output.append(3) 665 output.append(4) 666 667 @jump_test(2, 3, [1, 3]) 668 def test_jump_forwards_out_of_with_block(output): 669 with tracecontext(output, 1): 670 output.append(2) 671 output.append(3) 672 673 @jump_test(3, 1, [1, 2, 1, 2, 3, -2]) 674 def test_jump_backwards_out_of_with_block(output): 675 output.append(1) 676 with tracecontext(output, 2): 677 output.append(3) 678 679 @jump_test(2, 5, [5]) 680 def test_jump_forwards_out_of_try_finally_block(output): 681 try: 682 output.append(2) 683 finally: 684 output.append(4) 685 output.append(5) 686 687 @jump_test(3, 1, [1, 1, 3, 5]) 688 def test_jump_backwards_out_of_try_finally_block(output): 689 output.append(1) 690 try: 691 output.append(3) 692 finally: 693 output.append(5) 694 695 @jump_test(2, 6, [6]) 696 def test_jump_forwards_out_of_try_except_block(output): 697 try: 698 output.append(2) 699 except: 700 output.append(4) 701 raise 702 output.append(6) 703 704 @jump_test(3, 1, [1, 1, 3]) 705 def test_jump_backwards_out_of_try_except_block(output): 706 output.append(1) 707 try: 708 output.append(3) 709 except: 710 output.append(5) 711 raise 712 713 @jump_test(5, 7, [4, 7, 8]) 714 def test_jump_between_except_blocks(output): 715 try: 716 1.0/0.0 717 except ZeroDivisionError: 718 output.append(4) 719 output.append(5) 720 except FloatingPointError: 721 output.append(7) 722 output.append(8) 723 724 @jump_test(5, 6, [4, 6, 7]) 725 def test_jump_within_except_block(output): 726 try: 727 1.0/0.0 728 except: 729 output.append(4) 730 output.append(5) 731 output.append(6) 732 output.append(7) 733 734 @jump_test(2, 4, [1, 4, 5, -4]) 735 def test_jump_across_with(output): 736 output.append(1) 737 with tracecontext(output, 2): 738 output.append(3) 739 with tracecontext(output, 4): 740 output.append(5) 741 742 @jump_test(4, 5, [1, 3, 5, 6]) 743 def test_jump_out_of_with_block_within_for_block(output): 744 output.append(1) 745 for i in [1]: 746 with tracecontext(output, 3): 747 output.append(4) 748 output.append(5) 749 output.append(6) 750 751 @jump_test(4, 5, [1, 2, 3, 5, -2, 6]) 752 def test_jump_out_of_with_block_within_with_block(output): 753 output.append(1) 754 with tracecontext(output, 2): 755 with tracecontext(output, 3): 756 output.append(4) 757 output.append(5) 758 output.append(6) 759 760 @jump_test(5, 6, [2, 4, 6, 7]) 761 def test_jump_out_of_with_block_within_finally_block(output): 762 try: 763 output.append(2) 764 finally: 765 with tracecontext(output, 4): 766 output.append(5) 767 output.append(6) 768 output.append(7) 769 770 @jump_test(8, 11, [1, 3, 5, 11, 12]) 771 def test_jump_out_of_complex_nested_blocks(output): 772 output.append(1) 773 for i in [1]: 774 output.append(3) 775 for j in [1, 2]: 776 output.append(5) 777 try: 778 for k in [1, 2]: 779 output.append(8) 780 finally: 781 output.append(10) 782 output.append(11) 783 output.append(12) 784 785 @jump_test(3, 5, [1, 2, 5]) 786 def test_jump_out_of_with_assignment(output): 787 output.append(1) 788 with tracecontext(output, 2) \ 789 as x: 790 output.append(4) 791 output.append(5) 792 793 @jump_test(3, 6, [1, 6, 8, 9]) 794 def test_jump_over_return_in_try_finally_block(output): 795 output.append(1) 796 try: 797 output.append(3) 798 if not output: # always false 799 return 800 output.append(6) 801 finally: 802 output.append(8) 803 output.append(9) 804 805 @jump_test(5, 8, [1, 3, 8, 10, 11, 13]) 806 def test_jump_over_break_in_try_finally_block(output): 807 output.append(1) 808 while True: 809 output.append(3) 810 try: 811 output.append(5) 812 if not output: # always false 813 break 814 output.append(8) 815 finally: 816 output.append(10) 817 output.append(11) 818 break 819 output.append(13) 820 821 @jump_test(1, 7, [7, 8]) 822 def test_jump_over_for_block_before_else(output): 823 output.append(1) 824 if not output: # always false 825 for i in [3]: 826 output.append(4) 827 else: 828 output.append(6) 829 output.append(7) 830 output.append(8) 831 832 # The second set of 'jump' tests are for things that are not allowed: 833 834 @jump_test(2, 3, [1], (ValueError, 'after')) 835 def test_no_jump_too_far_forwards(output): 836 output.append(1) 837 output.append(2) 838 839 @jump_test(2, -2, [1], (ValueError, 'before')) 840 def test_no_jump_too_far_backwards(output): 841 output.append(1) 842 output.append(2) 843 844 # Test each kind of 'except' line. 845 @jump_test(2, 3, [4], (ValueError, 'except')) 846 def test_no_jump_to_except_1(output): 847 try: 848 output.append(2) 849 except: 850 output.append(4) 851 raise 852 853 @jump_test(2, 3, [4], (ValueError, 'except')) 854 def test_no_jump_to_except_2(output): 855 try: 856 output.append(2) 857 except ValueError: 858 output.append(4) 859 raise 860 861 @jump_test(2, 3, [4], (ValueError, 'except')) 862 def test_no_jump_to_except_3(output): 863 try: 864 output.append(2) 865 except ValueError as e: 866 output.append(4) 867 raise e 868 869 @jump_test(2, 3, [4], (ValueError, 'except')) 870 def test_no_jump_to_except_4(output): 871 try: 872 output.append(2) 873 except (ValueError, RuntimeError) as e: 874 output.append(4) 875 raise e 876 877 @jump_test(1, 3, [], (ValueError, 'into')) 878 def test_no_jump_forwards_into_for_block(output): 879 output.append(1) 880 for i in 1, 2: 881 output.append(3) 882 883 @jump_test(3, 2, [2, 2], (ValueError, 'into')) 884 def test_no_jump_backwards_into_for_block(output): 885 for i in 1, 2: 886 output.append(2) 887 output.append(3) 888 889 @jump_test(2, 4, [], (ValueError, 'into')) 890 def test_no_jump_forwards_into_while_block(output): 891 i = 1 892 output.append(2) 893 while i <= 2: 894 output.append(4) 895 i += 1 896 897 @jump_test(5, 3, [3, 3], (ValueError, 'into')) 898 def test_no_jump_backwards_into_while_block(output): 899 i = 1 900 while i <= 2: 901 output.append(3) 902 i += 1 903 output.append(5) 904 905 @jump_test(1, 3, [], (ValueError, 'into')) 906 def test_no_jump_forwards_into_with_block(output): 907 output.append(1) 908 with tracecontext(output, 2): 909 output.append(3) 910 911 @jump_test(3, 2, [1, 2, -1], (ValueError, 'into')) 912 def test_no_jump_backwards_into_with_block(output): 913 with tracecontext(output, 1): 914 output.append(2) 915 output.append(3) 916 917 @jump_test(1, 3, [], (ValueError, 'into')) 918 def test_no_jump_forwards_into_try_finally_block(output): 919 output.append(1) 920 try: 921 output.append(3) 922 finally: 923 output.append(5) 924 925 @jump_test(5, 2, [2, 4], (ValueError, 'into')) 926 def test_no_jump_backwards_into_try_finally_block(output): 927 try: 928 output.append(2) 929 finally: 930 output.append(4) 931 output.append(5) 932 933 @jump_test(1, 3, [], (ValueError, 'into')) 934 def test_no_jump_forwards_into_try_except_block(output): 935 output.append(1) 936 try: 937 output.append(3) 938 except: 939 output.append(5) 940 raise 941 942 @jump_test(6, 2, [2], (ValueError, 'into')) 943 def test_no_jump_backwards_into_try_except_block(output): 944 try: 945 output.append(2) 946 except: 947 output.append(4) 948 raise 949 output.append(6) 950 951 @jump_test(3, 6, [2, 5, 6], (ValueError, 'finally')) 952 def test_no_jump_into_finally_block(output): 953 try: 954 output.append(2) 955 output.append(3) 956 finally: # still executed if the jump is failed 957 output.append(5) 958 output.append(6) 959 output.append(7) 960 961 @jump_test(1, 5, [], (ValueError, 'finally')) 962 def test_no_jump_into_finally_block_2(output): 963 output.append(1) 964 try: 965 output.append(3) 966 finally: 967 output.append(5) 968 969 @jump_test(5, 1, [1, 3], (ValueError, 'finally')) 970 def test_no_jump_out_of_finally_block(output): 971 output.append(1) 972 try: 973 output.append(3) 974 finally: 975 output.append(5) 976 977 @jump_test(3, 5, [1, 2, -2], (ValueError, 'into')) 978 def test_no_jump_between_with_blocks(output): 979 output.append(1) 980 with tracecontext(output, 2): 981 output.append(3) 982 with tracecontext(output, 4): 983 output.append(5) 984 985 @jump_test(7, 4, [1, 6], (ValueError, 'into')) 986 def test_no_jump_into_for_block_before_else(output): 987 output.append(1) 988 if not output: # always false 989 for i in [3]: 990 output.append(4) 991 else: 992 output.append(6) 993 output.append(7) 994 output.append(8) 995 996 def test_no_jump_to_non_integers(self): 997 self.run_test(no_jump_to_non_integers, 2, "Spam", [True]) 998 999 def test_no_jump_without_trace_function(self): 1000 # Must set sys.settrace(None) in setUp(), else condition is not 1001 # triggered. 1002 no_jump_without_trace_function() 1003 1004 def test_large_function(self): 1005 d = {} 1006 exec("""def f(output): # line 0 1007 x = 0 # line 1 1008 y = 1 # line 2 1009 ''' # line 3 1010 %s # lines 4-1004 1011 ''' # line 1005 1012 x += 1 # line 1006 1013 output.append(x) # line 1007 1014 return""" % ('\n' * 1000,), d) 1015 f = d['f'] 1016 self.run_test(f, 2, 1007, [0]) 1017 1018 def test_jump_to_firstlineno(self): 1019 # This tests that PDB can jump back to the first line in a 1020 # file. See issue #1689458. It can only be triggered in a 1021 # function call if the function is defined on a single line. 1022 code = compile(""" 1023# Comments don't count. 1024output.append(2) # firstlineno is here. 1025output.append(3) 1026output.append(4) 1027""", "<fake module>", "exec") 1028 class fake_function: 1029 func_code = code 1030 tracer = JumpTracer(fake_function, 2, 0) 1031 sys.settrace(tracer.trace) 1032 namespace = {"output": []} 1033 exec code in namespace 1034 sys.settrace(None) 1035 self.compare_jump_output([2, 3, 2, 3, 4], namespace["output"]) 1036 1037 @jump_test(2, 3, [1], event='call', error=(ValueError, "can't jump from" 1038 " the 'call' trace event of a new frame")) 1039 def test_no_jump_from_call(output): 1040 output.append(1) 1041 def nested(): 1042 output.append(3) 1043 nested() 1044 output.append(5) 1045 1046 @jump_test(2, 1, [1], event='return', error=(ValueError, 1047 "can only jump from a 'line' trace event")) 1048 def test_no_jump_from_return_event(output): 1049 output.append(1) 1050 return 1051 1052 @jump_test(2, 1, [1], event='exception', error=(ValueError, 1053 "can only jump from a 'line' trace event")) 1054 def test_no_jump_from_exception_event(output): 1055 output.append(1) 1056 1 / 0 1057 1058 @jump_test(3, 2, [2], event='return', error=(ValueError, 1059 "can't jump from a yield statement")) 1060 def test_no_jump_from_yield(output): 1061 def gen(): 1062 output.append(2) 1063 yield 3 1064 next(gen()) 1065 output.append(5) 1066 1067 1068def test_main(): 1069 test_support.run_unittest( 1070 TraceTestCase, 1071 RaisingTraceFuncTestCase, 1072 JumpTestCase 1073 ) 1074 1075if __name__ == "__main__": 1076 test_main() 1077