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