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