Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b210342

Browse files
committed
Add tests for SyntaxError with top-level return
1 parent c4bf632 commit b210342

1 file changed

Lines changed: 179 additions & 1 deletion

File tree

IPython/core/tests/test_async_helpers.py

Lines changed: 179 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66

77
import sys
88
import nose.tools as nt
9-
from textwrap import dedent
9+
from textwrap import dedent, indent
1010
from unittest import TestCase
1111

1212
ip = get_ipython()
1313
iprc = lambda x: ip.run_cell(dedent(x))
14+
iprc_err = lambda x: iprc(x).raise_error()
1415

1516
if sys.version_info > (3, 5):
1617
from IPython.core.async_helpers import _should_be_async
@@ -31,6 +32,183 @@ async def awaitable():
3132
)
3233
)
3334

35+
def _get_top_level_cases(self):
36+
# These are test cases that should be valid in a function
37+
# but invalid outside of a function.
38+
test_cases = []
39+
test_cases.append(('basic', "{val}"))
40+
41+
# Note, in all conditional cases, I use True instead of
42+
# False so that the peephole optimizer won't optimize away
43+
# the return, so CPython will see this as a syntax error:
44+
#
45+
# while True:
46+
# break
47+
# return
48+
#
49+
# But not this:
50+
#
51+
# while False:
52+
# return
53+
#
54+
# See https://bugs.python.org/issue1875
55+
56+
test_cases.append(('if', dedent("""
57+
if True:
58+
{val}
59+
""")))
60+
61+
test_cases.append(('while', dedent("""
62+
while True:
63+
{val}
64+
break
65+
""")))
66+
67+
test_cases.append(('try', dedent("""
68+
try:
69+
{val}
70+
except:
71+
pass
72+
""")))
73+
74+
test_cases.append(('except', dedent("""
75+
try:
76+
pass
77+
except:
78+
{val}
79+
""")))
80+
81+
test_cases.append(('finally', dedent("""
82+
try:
83+
pass
84+
except:
85+
pass
86+
finally:
87+
{val}
88+
""")))
89+
90+
test_cases.append(('for', dedent("""
91+
for _ in range(4):
92+
{val}
93+
""")))
94+
95+
96+
test_cases.append(('nested', dedent("""
97+
if True:
98+
while True:
99+
{val}
100+
break
101+
""")))
102+
103+
test_cases.append(('deep-nested', dedent("""
104+
if True:
105+
while True:
106+
break
107+
for x in range(3):
108+
if True:
109+
while True:
110+
for x in range(3):
111+
{val}
112+
""")))
113+
114+
return test_cases
115+
116+
def _get_ry_syntax_errors(self):
117+
# This is a mix of tests that should be a syntax error if
118+
# return or yield whether or not they are in a function
119+
120+
test_cases = []
121+
122+
test_cases.append(('class', dedent("""
123+
class V:
124+
{val}
125+
""")))
126+
127+
test_cases.append(('nested-class', dedent("""
128+
class V:
129+
class C:
130+
{val}
131+
""")))
132+
133+
return test_cases
134+
135+
136+
def test_top_level_return_error(self):
137+
tl_err_test_cases = self._get_top_level_cases()
138+
tl_err_test_cases.extend(self._get_ry_syntax_errors())
139+
140+
vals = ('return', 'yield', 'yield from (_ for _ in range(3))')
141+
142+
for test_name, test_case in tl_err_test_cases:
143+
# This example should work if 'pass' is used as the value
144+
with self.subTest((test_name, 'pass')):
145+
iprc_err(test_case.format(val='pass'))
146+
147+
# It should fail with all the values
148+
for val in vals:
149+
with self.subTest((test_name, val)):
150+
msg = "Syntax error not raised for %s, %s" % (test_name, val)
151+
with self.assertRaises(SyntaxError, msg=msg):
152+
iprc_err(test_case.format(val=val))
153+
154+
def test_in_func_no_error(self):
155+
# Test that the implementation of top-level return/yield
156+
# detection isn't *too* aggressive, and works inside a function
157+
func_contexts = []
158+
159+
func_contexts.append(('func', dedent("""
160+
def f():""")))
161+
162+
func_contexts.append(('method', dedent("""
163+
class MyClass:
164+
def __init__(self):
165+
""")))
166+
167+
func_contexts.append(('async-func', dedent("""
168+
async def f():""")))
169+
170+
func_contexts.append(('closure', dedent("""
171+
def f():
172+
def g():
173+
""")))
174+
175+
def nest_case(context, case):
176+
# Detect indentation
177+
lines = context.strip().splitlines()
178+
prefix_len = 0
179+
for c in lines[-1]:
180+
if c != ' ':
181+
break
182+
prefix_len += 1
183+
184+
indented_case = indent(case, ' ' * (prefix_len + 4))
185+
return context + '\n' + indented_case
186+
187+
# Gather and run the tests
188+
vals = ('return', 'yield')
189+
190+
success_tests = self._get_top_level_cases()
191+
failure_tests = self._get_ry_syntax_errors()
192+
193+
for context_name, context in func_contexts:
194+
# These tests should now successfully run
195+
for test_name, test_case in success_tests:
196+
nested_case = nest_case(context, test_case)
197+
198+
for val in vals:
199+
with self.subTest((test_name, context_name, val)):
200+
iprc_err(nested_case.format(val=val))
201+
202+
# These tests should still raise a SyntaxError
203+
for test_name, test_case in failure_tests:
204+
nested_case = nest_case(context, test_case)
205+
206+
for val in vals:
207+
with self.subTest((test_name, context_name, val)):
208+
with self.assertRaises(SyntaxError):
209+
iprc_err(nested_case.format(val=val))
210+
211+
34212
def test_execute(self):
35213
iprc(
36214
"""

0 commit comments

Comments
 (0)