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