bpo-33041: Add tests for jumps in/out of 'async with' blocks. (#6110) · python/cpython@bc300ce (original) (raw)
`@@ -6,6 +6,8 @@
`
6
6
`import difflib
`
7
7
`import gc
`
8
8
`from functools import wraps
`
``
9
`+
import asyncio
`
``
10
+
9
11
``
10
12
`class tracecontext:
`
11
13
`"""Context manager that traces its enter and exit."""
`
`@@ -19,6 +21,20 @@ def enter(self):
`
19
21
`def exit(self, *exc_info):
`
20
22
`self.output.append(-self.value)
`
21
23
``
``
24
`+
class asynctracecontext:
`
``
25
`+
"""Asynchronous context manager that traces its aenter and aexit."""
`
``
26
`+
def init(self, output, value):
`
``
27
`+
self.output = output
`
``
28
`+
self.value = value
`
``
29
+
``
30
`+
async def aenter(self):
`
``
31
`+
self.output.append(self.value)
`
``
32
+
``
33
`+
async def aexit(self, *exc_info):
`
``
34
`+
self.output.append(-self.value)
`
``
35
+
``
36
+
``
37
+
22
38
`# A very basic example. If this fails, we're in deep trouble.
`
23
39
`def basic():
`
24
40
`return 1
`
`@@ -636,6 +652,19 @@ def run_test(self, func, jumpFrom, jumpTo, expected, error=None,
`
636
652
`sys.settrace(None)
`
637
653
`self.compare_jump_output(expected, output)
`
638
654
``
``
655
`+
def run_async_test(self, func, jumpFrom, jumpTo, expected, error=None,
`
``
656
`+
event='line', decorated=False):
`
``
657
`+
tracer = JumpTracer(func, jumpFrom, jumpTo, event, decorated)
`
``
658
`+
sys.settrace(tracer.trace)
`
``
659
`+
output = []
`
``
660
`+
if error is None:
`
``
661
`+
asyncio.run(func(output))
`
``
662
`+
else:
`
``
663
`+
with self.assertRaisesRegex(*error):
`
``
664
`+
asyncio.run(func(output))
`
``
665
`+
sys.settrace(None)
`
``
666
`+
self.compare_jump_output(expected, output)
`
``
667
+
639
668
`def jump_test(jumpFrom, jumpTo, expected, error=None, event='line'):
`
640
669
`"""Decorator that creates a test that makes a jump
`
641
670
` from one place to another in the following code.
`
`@@ -648,6 +677,18 @@ def test(self):
`
648
677
`return test
`
649
678
`return decorator
`
650
679
``
``
680
`+
def async_jump_test(jumpFrom, jumpTo, expected, error=None, event='line'):
`
``
681
`+
"""Decorator that creates a test that makes a jump
`
``
682
`+
from one place to another in the following asynchronous code.
`
``
683
`+
"""
`
``
684
`+
def decorator(func):
`
``
685
`+
@wraps(func)
`
``
686
`+
def test(self):
`
``
687
`+
self.run_async_test(func, jumpFrom, jumpTo, expected,
`
``
688
`+
error=error, event=event, decorated=True)
`
``
689
`+
return test
`
``
690
`+
return decorator
`
``
691
+
651
692
`## The first set of 'jump' tests are for things that are allowed:
`
652
693
``
653
694
`@jump_test(1, 3, [3])
`
`@@ -774,12 +815,24 @@ def test_jump_forwards_out_of_with_block(output):
`
774
815
`output.append(2)
`
775
816
`output.append(3)
`
776
817
``
``
818
`+
@async_jump_test(2, 3, [1, 3])
`
``
819
`+
async def test_jump_forwards_out_of_async_with_block(output):
`
``
820
`+
async with asynctracecontext(output, 1):
`
``
821
`+
output.append(2)
`
``
822
`+
output.append(3)
`
``
823
+
777
824
`@jump_test(3, 1, [1, 2, 1, 2, 3, -2])
`
778
825
`def test_jump_backwards_out_of_with_block(output):
`
779
826
`output.append(1)
`
780
827
`with tracecontext(output, 2):
`
781
828
`output.append(3)
`
782
829
``
``
830
`+
@async_jump_test(3, 1, [1, 2, 1, 2, 3, -2])
`
``
831
`+
async def test_jump_backwards_out_of_async_with_block(output):
`
``
832
`+
output.append(1)
`
``
833
`+
async with asynctracecontext(output, 2):
`
``
834
`+
output.append(3)
`
``
835
+
783
836
`@jump_test(2, 5, [5])
`
784
837
`def test_jump_forwards_out_of_try_finally_block(output):
`
785
838
`try:
`
`@@ -843,6 +896,14 @@ def test_jump_across_with(output):
`
843
896
`with tracecontext(output, 4):
`
844
897
`output.append(5)
`
845
898
``
``
899
`+
@async_jump_test(2, 4, [1, 4, 5, -4])
`
``
900
`+
async def test_jump_across_async_with(output):
`
``
901
`+
output.append(1)
`
``
902
`+
async with asynctracecontext(output, 2):
`
``
903
`+
output.append(3)
`
``
904
`+
async with asynctracecontext(output, 4):
`
``
905
`+
output.append(5)
`
``
906
+
846
907
`@jump_test(4, 5, [1, 3, 5, 6])
`
847
908
`def test_jump_out_of_with_block_within_for_block(output):
`
848
909
`output.append(1)
`
`@@ -852,6 +913,15 @@ def test_jump_out_of_with_block_within_for_block(output):
`
852
913
`output.append(5)
`
853
914
`output.append(6)
`
854
915
``
``
916
`+
@async_jump_test(4, 5, [1, 3, 5, 6])
`
``
917
`+
async def test_jump_out_of_async_with_block_within_for_block(output):
`
``
918
`+
output.append(1)
`
``
919
`+
for i in [1]:
`
``
920
`+
async with asynctracecontext(output, 3):
`
``
921
`+
output.append(4)
`
``
922
`+
output.append(5)
`
``
923
`+
output.append(6)
`
``
924
+
855
925
`@jump_test(4, 5, [1, 2, 3, 5, -2, 6])
`
856
926
`def test_jump_out_of_with_block_within_with_block(output):
`
857
927
`output.append(1)
`
`@@ -861,6 +931,15 @@ def test_jump_out_of_with_block_within_with_block(output):
`
861
931
`output.append(5)
`
862
932
`output.append(6)
`
863
933
``
``
934
`+
@async_jump_test(4, 5, [1, 2, 3, 5, -2, 6])
`
``
935
`+
async def test_jump_out_of_async_with_block_within_with_block(output):
`
``
936
`+
output.append(1)
`
``
937
`+
with tracecontext(output, 2):
`
``
938
`+
async with asynctracecontext(output, 3):
`
``
939
`+
output.append(4)
`
``
940
`+
output.append(5)
`
``
941
`+
output.append(6)
`
``
942
+
864
943
`@jump_test(5, 6, [2, 4, 6, 7])
`
865
944
`def test_jump_out_of_with_block_within_finally_block(output):
`
866
945
`try:
`
`@@ -871,6 +950,16 @@ def test_jump_out_of_with_block_within_finally_block(output):
`
871
950
`output.append(6)
`
872
951
`output.append(7)
`
873
952
``
``
953
`+
@async_jump_test(5, 6, [2, 4, 6, 7])
`
``
954
`+
async def test_jump_out_of_async_with_block_within_finally_block(output):
`
``
955
`+
try:
`
``
956
`+
output.append(2)
`
``
957
`+
finally:
`
``
958
`+
async with asynctracecontext(output, 4):
`
``
959
`+
output.append(5)
`
``
960
`+
output.append(6)
`
``
961
`+
output.append(7)
`
``
962
+
874
963
`@jump_test(8, 11, [1, 3, 5, 11, 12])
`
875
964
`def test_jump_out_of_complex_nested_blocks(output):
`
876
965
`output.append(1)
`
`@@ -894,6 +983,14 @@ def test_jump_out_of_with_assignment(output):
`
894
983
`output.append(4)
`
895
984
`output.append(5)
`
896
985
``
``
986
`+
@async_jump_test(3, 5, [1, 2, 5])
`
``
987
`+
async def test_jump_out_of_async_with_assignment(output):
`
``
988
`+
output.append(1)
`
``
989
`+
async with asynctracecontext(output, 2) \
`
``
990
`+
as x:
`
``
991
`+
output.append(4)
`
``
992
`+
output.append(5)
`
``
993
+
897
994
`@jump_test(3, 6, [1, 6, 8, 9])
`
898
995
`def test_jump_over_return_in_try_finally_block(output):
`
899
996
`output.append(1)
`
`@@ -996,12 +1093,24 @@ def test_no_jump_forwards_into_with_block(output):
`
996
1093
`with tracecontext(output, 2):
`
997
1094
`output.append(3)
`
998
1095
``
``
1096
`+
@async_jump_test(1, 3, [], (ValueError, 'into'))
`
``
1097
`+
async def test_no_jump_forwards_into_async_with_block(output):
`
``
1098
`+
output.append(1)
`
``
1099
`+
async with asynctracecontext(output, 2):
`
``
1100
`+
output.append(3)
`
``
1101
+
999
1102
`@jump_test(3, 2, [1, 2, -1], (ValueError, 'into'))
`
1000
1103
`def test_no_jump_backwards_into_with_block(output):
`
1001
1104
`with tracecontext(output, 1):
`
1002
1105
`output.append(2)
`
1003
1106
`output.append(3)
`
1004
1107
``
``
1108
`+
@async_jump_test(3, 2, [1, 2, -1], (ValueError, 'into'))
`
``
1109
`+
async def test_no_jump_backwards_into_async_with_block(output):
`
``
1110
`+
async with asynctracecontext(output, 1):
`
``
1111
`+
output.append(2)
`
``
1112
`+
output.append(3)
`
``
1113
+
1005
1114
`@jump_test(1, 3, [], (ValueError, 'into'))
`
1006
1115
`def test_no_jump_forwards_into_try_finally_block(output):
`
1007
1116
`output.append(1)
`
`@@ -1082,6 +1191,14 @@ def test_no_jump_between_with_blocks(output):
`
1082
1191
`with tracecontext(output, 4):
`
1083
1192
`output.append(5)
`
1084
1193
``
``
1194
`+
@async_jump_test(3, 5, [1, 2, -2], (ValueError, 'into'))
`
``
1195
`+
async def test_no_jump_between_async_with_blocks(output):
`
``
1196
`+
output.append(1)
`
``
1197
`+
async with asynctracecontext(output, 2):
`
``
1198
`+
output.append(3)
`
``
1199
`+
async with asynctracecontext(output, 4):
`
``
1200
`+
output.append(5)
`
``
1201
+
1085
1202
`@jump_test(5, 7, [2, 4], (ValueError, 'finally'))
`
1086
1203
`def test_no_jump_over_return_out_of_finally_block(output):
`
1087
1204
`try:
`