1 # Test various flavors of legal and illegal future statements
2
3 import __future__
4 import ast
5 import unittest
6 from test.support import import_helper
7 from test.support.script_helper import spawn_python, kill_python
8 from textwrap import dedent
9 import os
10 import re
11 import sys
12
13 rx = re.compile(r'\((\S+).py, line (\d+)')
14
15 def get_error_location(msg):
16 mo = rx.search(str(msg))
17 return mo.group(1, 2)
18
19 class ESC[4;38;5;81mFutureTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
20
21 def check_syntax_error(self, err, basename, lineno, offset=1):
22 self.assertIn('%s.py, line %d' % (basename, lineno), str(err))
23 self.assertEqual(os.path.basename(err.filename), basename + '.py')
24 self.assertEqual(err.lineno, lineno)
25 self.assertEqual(err.offset, offset)
26
27 def test_future1(self):
28 with import_helper.CleanImport('future_test1'):
29 from test import future_test1
30 self.assertEqual(future_test1.result, 6)
31
32 def test_future2(self):
33 with import_helper.CleanImport('future_test2'):
34 from test import future_test2
35 self.assertEqual(future_test2.result, 6)
36
37 def test_future3(self):
38 with import_helper.CleanImport('test_future3'):
39 from test import test_future3
40
41 def test_badfuture3(self):
42 with self.assertRaises(SyntaxError) as cm:
43 from test import badsyntax_future3
44 self.check_syntax_error(cm.exception, "badsyntax_future3", 3)
45
46 def test_badfuture4(self):
47 with self.assertRaises(SyntaxError) as cm:
48 from test import badsyntax_future4
49 self.check_syntax_error(cm.exception, "badsyntax_future4", 3)
50
51 def test_badfuture5(self):
52 with self.assertRaises(SyntaxError) as cm:
53 from test import badsyntax_future5
54 self.check_syntax_error(cm.exception, "badsyntax_future5", 4)
55
56 def test_badfuture6(self):
57 with self.assertRaises(SyntaxError) as cm:
58 from test import badsyntax_future6
59 self.check_syntax_error(cm.exception, "badsyntax_future6", 3)
60
61 def test_badfuture7(self):
62 with self.assertRaises(SyntaxError) as cm:
63 from test import badsyntax_future7
64 self.check_syntax_error(cm.exception, "badsyntax_future7", 3, 54)
65
66 def test_badfuture8(self):
67 with self.assertRaises(SyntaxError) as cm:
68 from test import badsyntax_future8
69 self.check_syntax_error(cm.exception, "badsyntax_future8", 3)
70
71 def test_badfuture9(self):
72 with self.assertRaises(SyntaxError) as cm:
73 from test import badsyntax_future9
74 self.check_syntax_error(cm.exception, "badsyntax_future9", 3)
75
76 def test_badfuture10(self):
77 with self.assertRaises(SyntaxError) as cm:
78 from test import badsyntax_future10
79 self.check_syntax_error(cm.exception, "badsyntax_future10", 3)
80
81 def test_ensure_flags_dont_clash(self):
82 # bpo-39562: test that future flags and compiler flags doesn't clash
83
84 # obtain future flags (CO_FUTURE_***) from the __future__ module
85 flags = {
86 f"CO_FUTURE_{future.upper()}": getattr(__future__, future).compiler_flag
87 for future in __future__.all_feature_names
88 }
89 # obtain some of the exported compiler flags (PyCF_***) from the ast module
90 flags |= {
91 flag: getattr(ast, flag)
92 for flag in dir(ast) if flag.startswith("PyCF_")
93 }
94 self.assertCountEqual(set(flags.values()), flags.values())
95
96 def test_parserhack(self):
97 # test that the parser.c::future_hack function works as expected
98 # Note: although this test must pass, it's not testing the original
99 # bug as of 2.6 since the with statement is not optional and
100 # the parser hack disabled. If a new keyword is introduced in
101 # 2.6, change this to refer to the new future import.
102 try:
103 exec("from __future__ import print_function; print 0")
104 except SyntaxError:
105 pass
106 else:
107 self.fail("syntax error didn't occur")
108
109 try:
110 exec("from __future__ import (print_function); print 0")
111 except SyntaxError:
112 pass
113 else:
114 self.fail("syntax error didn't occur")
115
116 def test_multiple_features(self):
117 with import_helper.CleanImport("test.test_future5"):
118 from test import test_future5
119
120 def test_unicode_literals_exec(self):
121 scope = {}
122 exec("from __future__ import unicode_literals; x = ''", {}, scope)
123 self.assertIsInstance(scope["x"], str)
124
125 def test_syntactical_future_repl(self):
126 p = spawn_python('-i')
127 p.stdin.write(b"from __future__ import barry_as_FLUFL\n")
128 p.stdin.write(b"2 <> 3\n")
129 out = kill_python(p)
130 self.assertNotIn(b'SyntaxError: invalid syntax', out)
131
132 class ESC[4;38;5;81mAnnotationsFutureTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
133 template = dedent(
134 """
135 from __future__ import annotations
136 def f() -> {ann}:
137 ...
138 def g(arg: {ann}) -> None:
139 ...
140 async def f2() -> {ann}:
141 ...
142 async def g2(arg: {ann}) -> None:
143 ...
144 class H:
145 var: {ann}
146 object.attr: {ann}
147 var: {ann}
148 var2: {ann} = None
149 object.attr: {ann}
150 """
151 )
152
153 def getActual(self, annotation):
154 scope = {}
155 exec(self.template.format(ann=annotation), {}, scope)
156 func_ret_ann = scope['f'].__annotations__['return']
157 func_arg_ann = scope['g'].__annotations__['arg']
158 async_func_ret_ann = scope['f2'].__annotations__['return']
159 async_func_arg_ann = scope['g2'].__annotations__['arg']
160 var_ann1 = scope['__annotations__']['var']
161 var_ann2 = scope['__annotations__']['var2']
162 self.assertEqual(func_ret_ann, func_arg_ann)
163 self.assertEqual(func_ret_ann, async_func_ret_ann)
164 self.assertEqual(func_ret_ann, async_func_arg_ann)
165 self.assertEqual(func_ret_ann, var_ann1)
166 self.assertEqual(func_ret_ann, var_ann2)
167 return func_ret_ann
168
169 def assertAnnotationEqual(
170 self, annotation, expected=None, drop_parens=False, is_tuple=False,
171 ):
172 actual = self.getActual(annotation)
173 if expected is None:
174 expected = annotation if not is_tuple else annotation[1:-1]
175 if drop_parens:
176 self.assertNotEqual(actual, expected)
177 actual = actual.replace("(", "").replace(")", "")
178
179 self.assertEqual(actual, expected)
180
181 def _exec_future(self, code):
182 scope = {}
183 exec(
184 "from __future__ import annotations\n"
185 + code, scope
186 )
187 return scope
188
189 def test_annotations(self):
190 eq = self.assertAnnotationEqual
191 eq('...')
192 eq("'some_string'")
193 eq("u'some_string'")
194 eq("b'\\xa3'")
195 eq('Name')
196 eq('None')
197 eq('True')
198 eq('False')
199 eq('1')
200 eq('1.0')
201 eq('1j')
202 eq('True or False')
203 eq('True or False or None')
204 eq('True and False')
205 eq('True and False and None')
206 eq('Name1 and Name2 or Name3')
207 eq('Name1 and (Name2 or Name3)')
208 eq('Name1 or Name2 and Name3')
209 eq('(Name1 or Name2) and Name3')
210 eq('Name1 and Name2 or Name3 and Name4')
211 eq('Name1 or Name2 and Name3 or Name4')
212 eq('a + b + (c + d)')
213 eq('a * b * (c * d)')
214 eq('(a ** b) ** c ** d')
215 eq('v1 << 2')
216 eq('1 >> v2')
217 eq('1 % finished')
218 eq('1 + v2 - v3 * 4 ^ 5 ** v6 / 7 // 8')
219 eq('not great')
220 eq('not not great')
221 eq('~great')
222 eq('+value')
223 eq('++value')
224 eq('-1')
225 eq('~int and not v1 ^ 123 + v2 | True')
226 eq('a + (not b)')
227 eq('lambda: None')
228 eq('lambda arg: None')
229 eq('lambda a=True: a')
230 eq('lambda a, b, c=True: a')
231 eq("lambda a, b, c=True, *, d=1 << v2, e='str': a")
232 eq("lambda a, b, c=True, *vararg, d, e='str', **kwargs: a + b")
233 eq("lambda a, /, b, c=True, *vararg, d, e='str', **kwargs: a + b")
234 eq('lambda x, /: x')
235 eq('lambda x=1, /: x')
236 eq('lambda x, /, y: x + y')
237 eq('lambda x=1, /, y=2: x + y')
238 eq('lambda x, /, y=1: x + y')
239 eq('lambda x, /, y=1, *, z=3: x + y + z')
240 eq('lambda x=1, /, y=2, *, z=3: x + y + z')
241 eq('lambda x=1, /, y=2, *, z: x + y + z')
242 eq('lambda x=1, y=2, z=3, /, w=4, *, l, l2: x + y + z + w + l + l2')
243 eq('lambda x=1, y=2, z=3, /, w=4, *, l, l2, **kwargs: x + y + z + w + l + l2')
244 eq('lambda x, /, y=1, *, z: x + y + z')
245 eq('lambda x: lambda y: x + y')
246 eq('1 if True else 2')
247 eq('str or None if int or True else str or bytes or None')
248 eq('str or None if (1 if True else 2) else str or bytes or None')
249 eq("0 if not x else 1 if x > 0 else -1")
250 eq("(1 if x > 0 else -1) if x else 0")
251 eq("{'2.7': dead, '3.7': long_live or die_hard}")
252 eq("{'2.7': dead, '3.7': long_live or die_hard, **{'3.6': verygood}}")
253 eq("{**a, **b, **c}")
254 eq("{'2.7', '3.6', '3.7', '3.8', '3.9', '4.0' if gilectomy else '3.10'}")
255 eq("{*a, *b, *c}")
256 eq("({'a': 'b'}, True or False, +value, 'string', b'bytes') or None")
257 eq("()")
258 eq("(a,)")
259 eq("(a, b)")
260 eq("(a, b, c)")
261 eq("(*a, *b, *c)")
262 eq("[]")
263 eq("[1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or A, 11 or B, 12 or C]")
264 eq("[*a, *b, *c]")
265 eq("{i for i in (1, 2, 3)}")
266 eq("{i ** 2 for i in (1, 2, 3)}")
267 eq("{i ** 2 for i, _ in ((1, 'a'), (2, 'b'), (3, 'c'))}")
268 eq("{i ** 2 + j for i in (1, 2, 3) for j in (1, 2, 3)}")
269 eq("[i for i in (1, 2, 3)]")
270 eq("[i ** 2 for i in (1, 2, 3)]")
271 eq("[i ** 2 for i, _ in ((1, 'a'), (2, 'b'), (3, 'c'))]")
272 eq("[i ** 2 + j for i in (1, 2, 3) for j in (1, 2, 3)]")
273 eq("(i for i in (1, 2, 3))")
274 eq("(i ** 2 for i in (1, 2, 3))")
275 eq("(i ** 2 for i, _ in ((1, 'a'), (2, 'b'), (3, 'c')))")
276 eq("(i ** 2 + j for i in (1, 2, 3) for j in (1, 2, 3))")
277 eq("{i: 0 for i in (1, 2, 3)}")
278 eq("{i: j for i, j in ((1, 'a'), (2, 'b'), (3, 'c'))}")
279 eq("[(x, y) for x, y in (a, b)]")
280 eq("[(x,) for x, in (a,)]")
281 eq("Python3 > Python2 > COBOL")
282 eq("Life is Life")
283 eq("call()")
284 eq("call(arg)")
285 eq("call(kwarg='hey')")
286 eq("call(arg, kwarg='hey')")
287 eq("call(arg, *args, another, kwarg='hey')")
288 eq("call(arg, another, kwarg='hey', **kwargs, kwarg2='ho')")
289 eq("lukasz.langa.pl")
290 eq("call.me(maybe)")
291 eq("1 .real")
292 eq("1.0.real")
293 eq("....__class__")
294 eq("list[str]")
295 eq("dict[str, int]")
296 eq("set[str,]")
297 eq("tuple[()]")
298 eq("tuple[str, ...]")
299 eq("tuple[str, *types]")
300 eq("tuple[str, int, (str, int)]")
301 eq("tuple[*int, str, str, (str, int)]")
302 eq("tuple[str, int, float, dict[str, int]]")
303 eq("slice[0]")
304 eq("slice[0:1]")
305 eq("slice[0:1:2]")
306 eq("slice[:]")
307 eq("slice[:-1]")
308 eq("slice[1:]")
309 eq("slice[::-1]")
310 eq("slice[:,]")
311 eq("slice[1:2,]")
312 eq("slice[1:2:3,]")
313 eq("slice[1:2, 1]")
314 eq("slice[1:2, 2, 3]")
315 eq("slice[()]")
316 # Note that `slice[*Ts]`, `slice[*Ts,]`, and `slice[(*Ts,)]` all have
317 # the same AST, but only `slice[*Ts,]` passes this test, because that's
318 # what the unparser produces.
319 eq("slice[*Ts,]")
320 eq("slice[1, *Ts]")
321 eq("slice[*Ts, 2]")
322 eq("slice[1, *Ts, 2]")
323 eq("slice[*Ts, *Ts]")
324 eq("slice[1, *Ts, *Ts]")
325 eq("slice[*Ts, 1, *Ts]")
326 eq("slice[*Ts, *Ts, 1]")
327 eq("slice[1, *Ts, *Ts, 2]")
328 eq("slice[1:2, *Ts]")
329 eq("slice[*Ts, 1:2]")
330 eq("slice[1:2, *Ts, 3:4]")
331 eq("slice[a, b:c, d:e:f]")
332 eq("slice[(x for x in a)]")
333 eq('str or None if sys.version_info[0] > (3,) else str or bytes or None')
334 eq("f'f-string without formatted values is just a string'")
335 eq("f'{{NOT a formatted value}}'")
336 eq("f'some f-string with {a} {few():.2f} {formatted.values!r}'")
337 eq('''f"{f'{nested} inner'} outer"''')
338 eq("f'space between opening braces: { {a for a in (1, 2, 3)}}'")
339 eq("f'{(lambda x: x)}'")
340 eq("f'{(None if a else lambda x: x)}'")
341 eq("f'{x}'")
342 eq("f'{x!r}'")
343 eq("f'{x!a}'")
344 eq('[x for x in (a if b else c)]')
345 eq('[x for x in a if (b if c else d)]')
346 eq('f(x for x in a)')
347 eq('f(1, (x for x in a))')
348 eq('f((x for x in a), 2)')
349 eq('(((a)))', 'a')
350 eq('(((a, b)))', '(a, b)')
351 eq("1 + 2 + 3")
352
353 def test_fstring_debug_annotations(self):
354 # f-strings with '=' don't round trip very well, so set the expected
355 # result explicitly.
356 self.assertAnnotationEqual("f'{x=!r}'", expected="f'x={x!r}'")
357 self.assertAnnotationEqual("f'{x=:}'", expected="f'x={x:}'")
358 self.assertAnnotationEqual("f'{x=:.2f}'", expected="f'x={x:.2f}'")
359 self.assertAnnotationEqual("f'{x=!r}'", expected="f'x={x!r}'")
360 self.assertAnnotationEqual("f'{x=!a}'", expected="f'x={x!a}'")
361 self.assertAnnotationEqual("f'{x=!s:*^20}'", expected="f'x={x!s:*^20}'")
362
363 def test_infinity_numbers(self):
364 inf = "1e" + repr(sys.float_info.max_10_exp + 1)
365 infj = f"{inf}j"
366 self.assertAnnotationEqual("1e1000", expected=inf)
367 self.assertAnnotationEqual("1e1000j", expected=infj)
368 self.assertAnnotationEqual("-1e1000", expected=f"-{inf}")
369 self.assertAnnotationEqual("3+1e1000j", expected=f"3 + {infj}")
370 self.assertAnnotationEqual("(1e1000, 1e1000j)", expected=f"({inf}, {infj})")
371 self.assertAnnotationEqual("'inf'")
372 self.assertAnnotationEqual("('inf', 1e1000, 'infxxx', 1e1000j)", expected=f"('inf', {inf}, 'infxxx', {infj})")
373 self.assertAnnotationEqual("(1e1000, (1e1000j,))", expected=f"({inf}, ({infj},))")
374
375 def test_annotation_with_complex_target(self):
376 with self.assertRaises(SyntaxError):
377 exec(
378 "from __future__ import annotations\n"
379 "object.__debug__: int"
380 )
381
382 def test_annotations_symbol_table_pass(self):
383 namespace = self._exec_future(dedent("""
384 from __future__ import annotations
385
386 def foo():
387 outer = 1
388 def bar():
389 inner: outer = 1
390 return bar
391 """))
392
393 foo = namespace.pop("foo")
394 self.assertIsNone(foo().__closure__)
395 self.assertEqual(foo.__code__.co_cellvars, ())
396 self.assertEqual(foo().__code__.co_freevars, ())
397
398 def test_annotations_forbidden(self):
399 with self.assertRaises(SyntaxError):
400 self._exec_future("test: (yield)")
401
402 with self.assertRaises(SyntaxError):
403 self._exec_future("test.test: (yield a + b)")
404
405 with self.assertRaises(SyntaxError):
406 self._exec_future("test[something]: (yield from x)")
407
408 with self.assertRaises(SyntaxError):
409 self._exec_future("def func(test: (yield from outside_of_generator)): pass")
410
411 with self.assertRaises(SyntaxError):
412 self._exec_future("def test() -> (await y): pass")
413
414 with self.assertRaises(SyntaxError):
415 self._exec_future("async def test() -> something((a := b)): pass")
416
417 with self.assertRaises(SyntaxError):
418 self._exec_future("test: await some.complicated[0].call(with_args=True or 1 is not 1)")
419
420 with self.assertRaises(SyntaxError):
421 self._exec_future("test: f'{(x := 10):=10}'")
422
423 with self.assertRaises(SyntaxError):
424 self._exec_future(dedent("""\
425 def foo():
426 def bar(arg: (yield)): pass
427 """))
428
429 def test_get_type_hints_on_func_with_variadic_arg(self):
430 # `typing.get_type_hints` might break on a function with a variadic
431 # annotation (e.g. `f(*args: *Ts)`) if `from __future__ import
432 # annotations`, because it could try to evaluate `*Ts` as an expression,
433 # which on its own isn't value syntax.
434 namespace = self._exec_future(dedent("""\
435 class StarredC: pass
436 class C:
437 def __iter__(self):
438 yield StarredC()
439 c = C()
440 def f(*args: *c): pass
441 import typing
442 hints = typing.get_type_hints(f)
443 """))
444
445 hints = namespace.pop('hints')
446 self.assertIsInstance(hints['args'], namespace['StarredC'])
447
448
449 if __name__ == "__main__":
450 unittest.main()