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