blob: 9b88e3f46425294315e450ae051a17b4b4ce707d [file] [log] [blame]
Jeremy Hylton62e2c7e2001-02-28 17:48:06 +00001# Test various flavors of legal and illegal future statements
2
Neal Norwitz328f3382003-12-13 22:43:34 +00003import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00004from test import support
Guido van Rossum95e4d582018-01-26 08:20:18 -08005from textwrap import dedent
Serhiy Storchaka8b583392016-12-11 14:39:01 +02006import os
Jeremy Hylton62e2c7e2001-02-28 17:48:06 +00007import re
8
R David Murray44b548d2016-09-08 13:59:53 -04009rx = re.compile(r'\((\S+).py, line (\d+)')
Jeremy Hylton62e2c7e2001-02-28 17:48:06 +000010
Neal Norwitz328f3382003-12-13 22:43:34 +000011def get_error_location(msg):
12 mo = rx.search(str(msg))
13 return mo.group(1, 2)
Jeremy Hylton62e2c7e2001-02-28 17:48:06 +000014
Neal Norwitz328f3382003-12-13 22:43:34 +000015class FutureTest(unittest.TestCase):
Jeremy Hylton62e2c7e2001-02-28 17:48:06 +000016
Ammar Askar025eb982018-09-24 17:12:49 -040017 def check_syntax_error(self, err, basename, lineno, offset=1):
Serhiy Storchaka8b583392016-12-11 14:39:01 +020018 self.assertIn('%s.py, line %d' % (basename, lineno), str(err))
19 self.assertEqual(os.path.basename(err.filename), basename + '.py')
20 self.assertEqual(err.lineno, lineno)
21 self.assertEqual(err.offset, offset)
22
Neal Norwitz328f3382003-12-13 22:43:34 +000023 def test_future1(self):
Ezio Melotti1ed6be32013-02-27 10:00:03 +020024 with support.CleanImport('future_test1'):
25 from test import future_test1
26 self.assertEqual(future_test1.result, 6)
Jeremy Hylton62e2c7e2001-02-28 17:48:06 +000027
Neal Norwitz328f3382003-12-13 22:43:34 +000028 def test_future2(self):
Ezio Melotti1ed6be32013-02-27 10:00:03 +020029 with support.CleanImport('future_test2'):
30 from test import future_test2
31 self.assertEqual(future_test2.result, 6)
Jeremy Hylton62e2c7e2001-02-28 17:48:06 +000032
Neal Norwitz328f3382003-12-13 22:43:34 +000033 def test_future3(self):
Ezio Melotti1ed6be32013-02-27 10:00:03 +020034 with support.CleanImport('test_future3'):
35 from test import test_future3
Jeremy Hylton8471a352001-08-20 20:33:42 +000036
Neal Norwitz328f3382003-12-13 22:43:34 +000037 def test_badfuture3(self):
Serhiy Storchaka8b583392016-12-11 14:39:01 +020038 with self.assertRaises(SyntaxError) as cm:
Neal Norwitz328f3382003-12-13 22:43:34 +000039 from test import badsyntax_future3
Serhiy Storchaka8b583392016-12-11 14:39:01 +020040 self.check_syntax_error(cm.exception, "badsyntax_future3", 3)
Jeremy Hylton62e2c7e2001-02-28 17:48:06 +000041
Neal Norwitz328f3382003-12-13 22:43:34 +000042 def test_badfuture4(self):
Serhiy Storchaka8b583392016-12-11 14:39:01 +020043 with self.assertRaises(SyntaxError) as cm:
Neal Norwitz328f3382003-12-13 22:43:34 +000044 from test import badsyntax_future4
Serhiy Storchaka8b583392016-12-11 14:39:01 +020045 self.check_syntax_error(cm.exception, "badsyntax_future4", 3)
Jeremy Hylton62e2c7e2001-02-28 17:48:06 +000046
Neal Norwitz328f3382003-12-13 22:43:34 +000047 def test_badfuture5(self):
Serhiy Storchaka8b583392016-12-11 14:39:01 +020048 with self.assertRaises(SyntaxError) as cm:
Neal Norwitz328f3382003-12-13 22:43:34 +000049 from test import badsyntax_future5
Serhiy Storchaka8b583392016-12-11 14:39:01 +020050 self.check_syntax_error(cm.exception, "badsyntax_future5", 4)
Jeremy Hylton62e2c7e2001-02-28 17:48:06 +000051
Neal Norwitz328f3382003-12-13 22:43:34 +000052 def test_badfuture6(self):
Serhiy Storchaka8b583392016-12-11 14:39:01 +020053 with self.assertRaises(SyntaxError) as cm:
Neal Norwitz328f3382003-12-13 22:43:34 +000054 from test import badsyntax_future6
Serhiy Storchaka8b583392016-12-11 14:39:01 +020055 self.check_syntax_error(cm.exception, "badsyntax_future6", 3)
Jeremy Hylton62e2c7e2001-02-28 17:48:06 +000056
Neal Norwitz328f3382003-12-13 22:43:34 +000057 def test_badfuture7(self):
Serhiy Storchaka8b583392016-12-11 14:39:01 +020058 with self.assertRaises(SyntaxError) as cm:
Neal Norwitz328f3382003-12-13 22:43:34 +000059 from test import badsyntax_future7
Serhiy Storchaka8b583392016-12-11 14:39:01 +020060 self.check_syntax_error(cm.exception, "badsyntax_future7", 3, 53)
Neal Norwitz328f3382003-12-13 22:43:34 +000061
62 def test_badfuture8(self):
Serhiy Storchaka8b583392016-12-11 14:39:01 +020063 with self.assertRaises(SyntaxError) as cm:
Neal Norwitz328f3382003-12-13 22:43:34 +000064 from test import badsyntax_future8
Serhiy Storchaka8b583392016-12-11 14:39:01 +020065 self.check_syntax_error(cm.exception, "badsyntax_future8", 3)
Neal Norwitz328f3382003-12-13 22:43:34 +000066
67 def test_badfuture9(self):
Serhiy Storchaka8b583392016-12-11 14:39:01 +020068 with self.assertRaises(SyntaxError) as cm:
Neal Norwitz328f3382003-12-13 22:43:34 +000069 from test import badsyntax_future9
Ammar Askar025eb982018-09-24 17:12:49 -040070 self.check_syntax_error(cm.exception, "badsyntax_future9", 3)
Neal Norwitz328f3382003-12-13 22:43:34 +000071
Benjamin Peterson2d6acd22013-03-16 09:15:47 -070072 def test_badfuture10(self):
Serhiy Storchaka8b583392016-12-11 14:39:01 +020073 with self.assertRaises(SyntaxError) as cm:
Benjamin Peterson2d6acd22013-03-16 09:15:47 -070074 from test import badsyntax_future10
Ammar Askar025eb982018-09-24 17:12:49 -040075 self.check_syntax_error(cm.exception, "badsyntax_future10", 3)
Benjamin Peterson2d6acd22013-03-16 09:15:47 -070076
Thomas Wouters89f507f2006-12-13 04:49:30 +000077 def test_parserhack(self):
78 # test that the parser.c::future_hack function works as expected
79 # Note: although this test must pass, it's not testing the original
80 # bug as of 2.6 since the with statement is not optional and
81 # the parser hack disabled. If a new keyword is introduced in
82 # 2.6, change this to refer to the new future import.
83 try:
Benjamin Peterson9aebc612008-10-26 20:58:53 +000084 exec("from __future__ import print_function; print 0")
Thomas Wouters89f507f2006-12-13 04:49:30 +000085 except SyntaxError:
86 pass
87 else:
88 self.fail("syntax error didn't occur")
89
90 try:
Benjamin Peterson9aebc612008-10-26 20:58:53 +000091 exec("from __future__ import (print_function); print 0")
Thomas Wouters89f507f2006-12-13 04:49:30 +000092 except SyntaxError:
93 pass
94 else:
95 self.fail("syntax error didn't occur")
96
Benjamin Peterson9aebc612008-10-26 20:58:53 +000097 def test_multiple_features(self):
Ezio Melotti1ed6be32013-02-27 10:00:03 +020098 with support.CleanImport("test.test_future5"):
99 from test import test_future5
Benjamin Peterson9aebc612008-10-26 20:58:53 +0000100
Benjamin Petersonf216c942008-10-31 02:28:05 +0000101 def test_unicode_literals_exec(self):
102 scope = {}
103 exec("from __future__ import unicode_literals; x = ''", {}, scope)
Ezio Melottie9615932010-01-24 19:26:24 +0000104 self.assertIsInstance(scope["x"], str)
Benjamin Petersonf216c942008-10-31 02:28:05 +0000105
Guido van Rossum95e4d582018-01-26 08:20:18 -0800106class AnnotationsFutureTestCase(unittest.TestCase):
107 template = dedent(
108 """
109 from __future__ import annotations
110 def f() -> {ann}:
111 ...
112 def g(arg: {ann}) -> None:
113 ...
Pablo Galindod112c602020-03-18 23:02:09 +0000114 async def f2() -> {ann}:
115 ...
116 async def g2(arg: {ann}) -> None:
117 ...
Guido van Rossum95e4d582018-01-26 08:20:18 -0800118 var: {ann}
119 var2: {ann} = None
120 """
121 )
122
123 def getActual(self, annotation):
124 scope = {}
125 exec(self.template.format(ann=annotation), {}, scope)
126 func_ret_ann = scope['f'].__annotations__['return']
127 func_arg_ann = scope['g'].__annotations__['arg']
Pablo Galindod112c602020-03-18 23:02:09 +0000128 async_func_ret_ann = scope['f2'].__annotations__['return']
129 async_func_arg_ann = scope['g2'].__annotations__['arg']
Guido van Rossum95e4d582018-01-26 08:20:18 -0800130 var_ann1 = scope['__annotations__']['var']
131 var_ann2 = scope['__annotations__']['var2']
132 self.assertEqual(func_ret_ann, func_arg_ann)
Pablo Galindod112c602020-03-18 23:02:09 +0000133 self.assertEqual(func_ret_ann, async_func_ret_ann)
134 self.assertEqual(func_ret_ann, async_func_arg_ann)
Guido van Rossum95e4d582018-01-26 08:20:18 -0800135 self.assertEqual(func_ret_ann, var_ann1)
136 self.assertEqual(func_ret_ann, var_ann2)
137 return func_ret_ann
138
139 def assertAnnotationEqual(
140 self, annotation, expected=None, drop_parens=False, is_tuple=False,
141 ):
142 actual = self.getActual(annotation)
143 if expected is None:
144 expected = annotation if not is_tuple else annotation[1:-1]
145 if drop_parens:
146 self.assertNotEqual(actual, expected)
147 actual = actual.replace("(", "").replace(")", "")
148
149 self.assertEqual(actual, expected)
150
151 def test_annotations(self):
152 eq = self.assertAnnotationEqual
153 eq('...')
154 eq("'some_string'")
155 eq("b'\\xa3'")
156 eq('Name')
157 eq('None')
158 eq('True')
159 eq('False')
160 eq('1')
161 eq('1.0')
162 eq('1j')
163 eq('True or False')
164 eq('True or False or None')
165 eq('True and False')
166 eq('True and False and None')
Serhiy Storchaka64fddc42018-05-17 06:17:48 +0300167 eq('Name1 and Name2 or Name3')
168 eq('Name1 and (Name2 or Name3)')
169 eq('Name1 or Name2 and Name3')
170 eq('(Name1 or Name2) and Name3')
171 eq('Name1 and Name2 or Name3 and Name4')
172 eq('Name1 or Name2 and Name3 or Name4')
173 eq('a + b + (c + d)')
174 eq('a * b * (c * d)')
175 eq('(a ** b) ** c ** d')
Guido van Rossum95e4d582018-01-26 08:20:18 -0800176 eq('v1 << 2')
177 eq('1 >> v2')
Serhiy Storchaka64fddc42018-05-17 06:17:48 +0300178 eq('1 % finished')
179 eq('1 + v2 - v3 * 4 ^ 5 ** v6 / 7 // 8')
Guido van Rossum95e4d582018-01-26 08:20:18 -0800180 eq('not great')
Serhiy Storchaka64fddc42018-05-17 06:17:48 +0300181 eq('not not great')
Guido van Rossum95e4d582018-01-26 08:20:18 -0800182 eq('~great')
183 eq('+value')
Serhiy Storchaka64fddc42018-05-17 06:17:48 +0300184 eq('++value')
Guido van Rossum95e4d582018-01-26 08:20:18 -0800185 eq('-1')
Serhiy Storchaka64fddc42018-05-17 06:17:48 +0300186 eq('~int and not v1 ^ 123 + v2 | True')
187 eq('a + (not b)')
Serhiy Storchaka2a2940e2018-09-30 21:07:05 +0300188 eq('lambda: None')
Guido van Rossum95e4d582018-01-26 08:20:18 -0800189 eq('lambda arg: None')
190 eq('lambda a=True: a')
191 eq('lambda a, b, c=True: a')
Serhiy Storchaka64fddc42018-05-17 06:17:48 +0300192 eq("lambda a, b, c=True, *, d=1 << v2, e='str': a")
Serhiy Storchaka2a2940e2018-09-30 21:07:05 +0300193 eq("lambda a, b, c=True, *vararg, d, e='str', **kwargs: a + b")
Pablo Galindoda6129e2019-05-18 23:40:22 +0100194 eq("lambda a, /, b, c=True, *vararg, d, e='str', **kwargs: a + b")
195 eq('lambda x, /: x')
196 eq('lambda x=1, /: x')
197 eq('lambda x, /, y: x + y')
198 eq('lambda x=1, /, y=2: x + y')
199 eq('lambda x, /, y=1: x + y')
200 eq('lambda x, /, y=1, *, z=3: x + y + z')
201 eq('lambda x=1, /, y=2, *, z=3: x + y + z')
202 eq('lambda x=1, /, y=2, *, z: x + y + z')
203 eq('lambda x=1, y=2, z=3, /, w=4, *, l, l2: x + y + z + w + l + l2')
204 eq('lambda x=1, y=2, z=3, /, w=4, *, l, l2, **kwargs: x + y + z + w + l + l2')
205 eq('lambda x, /, y=1, *, z: x + y + z')
Serhiy Storchaka64fddc42018-05-17 06:17:48 +0300206 eq('lambda x: lambda y: x + y')
Guido van Rossum95e4d582018-01-26 08:20:18 -0800207 eq('1 if True else 2')
Serhiy Storchaka64fddc42018-05-17 06:17:48 +0300208 eq('str or None if int or True else str or bytes or None')
209 eq('str or None if (1 if True else 2) else str or bytes or None')
210 eq("0 if not x else 1 if x > 0 else -1")
211 eq("(1 if x > 0 else -1) if x else 0")
212 eq("{'2.7': dead, '3.7': long_live or die_hard}")
213 eq("{'2.7': dead, '3.7': long_live or die_hard, **{'3.6': verygood}}")
Guido van Rossum95e4d582018-01-26 08:20:18 -0800214 eq("{**a, **b, **c}")
Serhiy Storchaka64fddc42018-05-17 06:17:48 +0300215 eq("{'2.7', '3.6', '3.7', '3.8', '3.9', '4.0' if gilectomy else '3.10'}")
216 eq("{*a, *b, *c}")
217 eq("({'a': 'b'}, True or False, +value, 'string', b'bytes') or None")
Guido van Rossum95e4d582018-01-26 08:20:18 -0800218 eq("()")
Serhiy Storchaka64fddc42018-05-17 06:17:48 +0300219 eq("(a,)")
220 eq("(a, b)")
221 eq("(a, b, c)")
222 eq("(*a, *b, *c)")
Guido van Rossum95e4d582018-01-26 08:20:18 -0800223 eq("[]")
Serhiy Storchaka64fddc42018-05-17 06:17:48 +0300224 eq("[1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or A, 11 or B, 12 or C]")
225 eq("[*a, *b, *c]")
Guido van Rossum95e4d582018-01-26 08:20:18 -0800226 eq("{i for i in (1, 2, 3)}")
Serhiy Storchaka64fddc42018-05-17 06:17:48 +0300227 eq("{i ** 2 for i in (1, 2, 3)}")
228 eq("{i ** 2 for i, _ in ((1, 'a'), (2, 'b'), (3, 'c'))}")
229 eq("{i ** 2 + j for i in (1, 2, 3) for j in (1, 2, 3)}")
Guido van Rossum95e4d582018-01-26 08:20:18 -0800230 eq("[i for i in (1, 2, 3)]")
Serhiy Storchaka64fddc42018-05-17 06:17:48 +0300231 eq("[i ** 2 for i in (1, 2, 3)]")
232 eq("[i ** 2 for i, _ in ((1, 'a'), (2, 'b'), (3, 'c'))]")
233 eq("[i ** 2 + j for i in (1, 2, 3) for j in (1, 2, 3)]")
234 eq("(i for i in (1, 2, 3))")
235 eq("(i ** 2 for i in (1, 2, 3))")
236 eq("(i ** 2 for i, _ in ((1, 'a'), (2, 'b'), (3, 'c')))")
237 eq("(i ** 2 + j for i in (1, 2, 3) for j in (1, 2, 3))")
238 eq("{i: 0 for i in (1, 2, 3)}")
Guido van Rossum95e4d582018-01-26 08:20:18 -0800239 eq("{i: j for i, j in ((1, 'a'), (2, 'b'), (3, 'c'))}")
Serhiy Storchaka64fddc42018-05-17 06:17:48 +0300240 eq("[(x, y) for x, y in (a, b)]")
241 eq("[(x,) for x, in (a,)]")
Guido van Rossum95e4d582018-01-26 08:20:18 -0800242 eq("Python3 > Python2 > COBOL")
243 eq("Life is Life")
244 eq("call()")
245 eq("call(arg)")
246 eq("call(kwarg='hey')")
247 eq("call(arg, kwarg='hey')")
Serhiy Storchaka64fddc42018-05-17 06:17:48 +0300248 eq("call(arg, *args, another, kwarg='hey')")
249 eq("call(arg, another, kwarg='hey', **kwargs, kwarg2='ho')")
Guido van Rossum95e4d582018-01-26 08:20:18 -0800250 eq("lukasz.langa.pl")
251 eq("call.me(maybe)")
252 eq("1 .real")
Serhiy Storchaka3f228112018-09-27 17:42:37 +0300253 eq("1.0.real")
Guido van Rossum95e4d582018-01-26 08:20:18 -0800254 eq("....__class__")
255 eq("list[str]")
256 eq("dict[str, int]")
Serhiy Storchaka64fddc42018-05-17 06:17:48 +0300257 eq("set[str,]")
Guido van Rossum95e4d582018-01-26 08:20:18 -0800258 eq("tuple[str, ...]")
259 eq("tuple[str, int, float, dict[str, int]]")
260 eq("slice[0]")
261 eq("slice[0:1]")
262 eq("slice[0:1:2]")
263 eq("slice[:]")
264 eq("slice[:-1]")
265 eq("slice[1:]")
266 eq("slice[::-1]")
Batuhan Taşkaya185903d2020-03-01 23:07:22 +0300267 eq("slice[:,]")
268 eq("slice[1:2,]")
269 eq("slice[1:2:3,]")
270 eq("slice[1:2, 1]")
271 eq("slice[1:2, 2, 3]")
Serhiy Storchaka64fddc42018-05-17 06:17:48 +0300272 eq("slice[()]")
273 eq("slice[a, b:c, d:e:f]")
274 eq("slice[(x for x in a)]")
275 eq('str or None if sys.version_info[0] > (3,) else str or bytes or None')
Guido van Rossum95e4d582018-01-26 08:20:18 -0800276 eq("f'f-string without formatted values is just a string'")
277 eq("f'{{NOT a formatted value}}'")
278 eq("f'some f-string with {a} {few():.2f} {formatted.values!r}'")
279 eq('''f"{f'{nested} inner'} outer"''')
280 eq("f'space between opening braces: { {a for a in (1, 2, 3)}}'")
Serhiy Storchaka64fddc42018-05-17 06:17:48 +0300281 eq("f'{(lambda x: x)}'")
282 eq("f'{(None if a else lambda x: x)}'")
Eric V. Smith9a4135e2019-05-08 16:28:48 -0400283 eq("f'{x}'")
284 eq("f'{x!r}'")
285 eq("f'{x!a}'")
Guido van Rossum95e4d582018-01-26 08:20:18 -0800286 eq('(yield from outside_of_generator)')
287 eq('(yield)')
Serhiy Storchaka64fddc42018-05-17 06:17:48 +0300288 eq('(yield a + b)')
289 eq('await some.complicated[0].call(with_args=True or 1 is not 1)')
290 eq('[x for x in (a if b else c)]')
291 eq('[x for x in a if (b if c else d)]')
292 eq('f(x for x in a)')
293 eq('f(1, (x for x in a))')
294 eq('f((x for x in a), 2)')
295 eq('(((a)))', 'a')
296 eq('(((a, b)))', '(a, b)')
Batuhan Taşkayafa19a252019-05-19 01:10:20 +0300297 eq("(x:=10)")
298 eq("f'{(x:=10):=10}'")
Pablo Galindod112c602020-03-18 23:02:09 +0000299 eq("1 + 2 + 3")
Thomas Wouters89f507f2006-12-13 04:49:30 +0000300
Eric V. Smithf83d1db2019-05-29 03:55:44 -0400301 def test_fstring_debug_annotations(self):
Eric V. Smith6f6ff8a2019-05-27 15:31:52 -0400302 # f-strings with '=' don't round trip very well, so set the expected
303 # result explicitely.
304 self.assertAnnotationEqual("f'{x=!r}'", expected="f'x={x!r}'")
305 self.assertAnnotationEqual("f'{x=:}'", expected="f'x={x:}'")
306 self.assertAnnotationEqual("f'{x=:.2f}'", expected="f'x={x:.2f}'")
307 self.assertAnnotationEqual("f'{x=!r}'", expected="f'x={x!r}'")
308 self.assertAnnotationEqual("f'{x=!a}'", expected="f'x={x!a}'")
309 self.assertAnnotationEqual("f'{x=!s:*^20}'", expected="f'x={x!s:*^20}'")
310
Neal Norwitz328f3382003-12-13 22:43:34 +0000311if __name__ == "__main__":
Ezio Melotti1ed6be32013-02-27 10:00:03 +0200312 unittest.main()