1# Test various flavors of legal and illegal future statements 2 3import __future__ 4import ast 5import unittest 6from test import support 7from test.support import import_helper 8from textwrap import dedent 9import os 10import re 11import sys 12 13rx = re.compile(r'\((\S+).py, line (\d+)') 14 15def get_error_location(msg): 16 mo = rx.search(str(msg)) 17 return mo.group(1, 2) 18 19class FutureTest(unittest.TestCase): 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, 53) 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 125class AnnotationsFutureTestCase(unittest.TestCase): 126 template = dedent( 127 """ 128 from __future__ import annotations 129 def f() -> {ann}: 130 ... 131 def g(arg: {ann}) -> None: 132 ... 133 async def f2() -> {ann}: 134 ... 135 async def g2(arg: {ann}) -> None: 136 ... 137 class H: 138 var: {ann} 139 object.attr: {ann} 140 var: {ann} 141 var2: {ann} = None 142 object.attr: {ann} 143 """ 144 ) 145 146 def getActual(self, annotation): 147 scope = {} 148 exec(self.template.format(ann=annotation), {}, scope) 149 func_ret_ann = scope['f'].__annotations__['return'] 150 func_arg_ann = scope['g'].__annotations__['arg'] 151 async_func_ret_ann = scope['f2'].__annotations__['return'] 152 async_func_arg_ann = scope['g2'].__annotations__['arg'] 153 var_ann1 = scope['__annotations__']['var'] 154 var_ann2 = scope['__annotations__']['var2'] 155 self.assertEqual(func_ret_ann, func_arg_ann) 156 self.assertEqual(func_ret_ann, async_func_ret_ann) 157 self.assertEqual(func_ret_ann, async_func_arg_ann) 158 self.assertEqual(func_ret_ann, var_ann1) 159 self.assertEqual(func_ret_ann, var_ann2) 160 return func_ret_ann 161 162 def assertAnnotationEqual( 163 self, annotation, expected=None, drop_parens=False, is_tuple=False, 164 ): 165 actual = self.getActual(annotation) 166 if expected is None: 167 expected = annotation if not is_tuple else annotation[1:-1] 168 if drop_parens: 169 self.assertNotEqual(actual, expected) 170 actual = actual.replace("(", "").replace(")", "") 171 172 self.assertEqual(actual, expected) 173 174 def _exec_future(self, code): 175 scope = {} 176 exec( 177 "from __future__ import annotations\n" 178 + code, {}, scope 179 ) 180 return scope 181 182 def test_annotations(self): 183 eq = self.assertAnnotationEqual 184 eq('...') 185 eq("'some_string'") 186 eq("u'some_string'") 187 eq("b'\\xa3'") 188 eq('Name') 189 eq('None') 190 eq('True') 191 eq('False') 192 eq('1') 193 eq('1.0') 194 eq('1j') 195 eq('True or False') 196 eq('True or False or None') 197 eq('True and False') 198 eq('True and False and None') 199 eq('Name1 and Name2 or Name3') 200 eq('Name1 and (Name2 or Name3)') 201 eq('Name1 or Name2 and Name3') 202 eq('(Name1 or Name2) and Name3') 203 eq('Name1 and Name2 or Name3 and Name4') 204 eq('Name1 or Name2 and Name3 or Name4') 205 eq('a + b + (c + d)') 206 eq('a * b * (c * d)') 207 eq('(a ** b) ** c ** d') 208 eq('v1 << 2') 209 eq('1 >> v2') 210 eq('1 % finished') 211 eq('1 + v2 - v3 * 4 ^ 5 ** v6 / 7 // 8') 212 eq('not great') 213 eq('not not great') 214 eq('~great') 215 eq('+value') 216 eq('++value') 217 eq('-1') 218 eq('~int and not v1 ^ 123 + v2 | True') 219 eq('a + (not b)') 220 eq('lambda: None') 221 eq('lambda arg: None') 222 eq('lambda a=True: a') 223 eq('lambda a, b, c=True: a') 224 eq("lambda a, b, c=True, *, d=1 << v2, e='str': a") 225 eq("lambda a, b, c=True, *vararg, d, e='str', **kwargs: a + b") 226 eq("lambda a, /, b, c=True, *vararg, d, e='str', **kwargs: a + b") 227 eq('lambda x, /: x') 228 eq('lambda x=1, /: x') 229 eq('lambda x, /, y: x + y') 230 eq('lambda x=1, /, y=2: x + y') 231 eq('lambda x, /, y=1: x + y') 232 eq('lambda x, /, y=1, *, z=3: x + y + z') 233 eq('lambda x=1, /, y=2, *, z=3: x + y + z') 234 eq('lambda x=1, /, y=2, *, z: x + y + z') 235 eq('lambda x=1, y=2, z=3, /, w=4, *, l, l2: x + y + z + w + l + l2') 236 eq('lambda x=1, y=2, z=3, /, w=4, *, l, l2, **kwargs: x + y + z + w + l + l2') 237 eq('lambda x, /, y=1, *, z: x + y + z') 238 eq('lambda x: lambda y: x + y') 239 eq('1 if True else 2') 240 eq('str or None if int or True else str or bytes or None') 241 eq('str or None if (1 if True else 2) else str or bytes or None') 242 eq("0 if not x else 1 if x > 0 else -1") 243 eq("(1 if x > 0 else -1) if x else 0") 244 eq("{'2.7': dead, '3.7': long_live or die_hard}") 245 eq("{'2.7': dead, '3.7': long_live or die_hard, **{'3.6': verygood}}") 246 eq("{**a, **b, **c}") 247 eq("{'2.7', '3.6', '3.7', '3.8', '3.9', '4.0' if gilectomy else '3.10'}") 248 eq("{*a, *b, *c}") 249 eq("({'a': 'b'}, True or False, +value, 'string', b'bytes') or None") 250 eq("()") 251 eq("(a,)") 252 eq("(a, b)") 253 eq("(a, b, c)") 254 eq("(*a, *b, *c)") 255 eq("[]") 256 eq("[1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or A, 11 or B, 12 or C]") 257 eq("[*a, *b, *c]") 258 eq("{i for i in (1, 2, 3)}") 259 eq("{i ** 2 for i in (1, 2, 3)}") 260 eq("{i ** 2 for i, _ in ((1, 'a'), (2, 'b'), (3, 'c'))}") 261 eq("{i ** 2 + j for i in (1, 2, 3) for j in (1, 2, 3)}") 262 eq("[i for i in (1, 2, 3)]") 263 eq("[i ** 2 for i in (1, 2, 3)]") 264 eq("[i ** 2 for i, _ in ((1, 'a'), (2, 'b'), (3, 'c'))]") 265 eq("[i ** 2 + j for i in (1, 2, 3) for j in (1, 2, 3)]") 266 eq("(i for i in (1, 2, 3))") 267 eq("(i ** 2 for i in (1, 2, 3))") 268 eq("(i ** 2 for i, _ in ((1, 'a'), (2, 'b'), (3, 'c')))") 269 eq("(i ** 2 + j for i in (1, 2, 3) for j in (1, 2, 3))") 270 eq("{i: 0 for i in (1, 2, 3)}") 271 eq("{i: j for i, j in ((1, 'a'), (2, 'b'), (3, 'c'))}") 272 eq("[(x, y) for x, y in (a, b)]") 273 eq("[(x,) for x, in (a,)]") 274 eq("Python3 > Python2 > COBOL") 275 eq("Life is Life") 276 eq("call()") 277 eq("call(arg)") 278 eq("call(kwarg='hey')") 279 eq("call(arg, kwarg='hey')") 280 eq("call(arg, *args, another, kwarg='hey')") 281 eq("call(arg, another, kwarg='hey', **kwargs, kwarg2='ho')") 282 eq("lukasz.langa.pl") 283 eq("call.me(maybe)") 284 eq("1 .real") 285 eq("1.0.real") 286 eq("....__class__") 287 eq("list[str]") 288 eq("dict[str, int]") 289 eq("set[str,]") 290 eq("tuple[str, ...]") 291 eq("tuple[(str, *types)]") 292 eq("tuple[str, int, (str, int)]") 293 eq("tuple[(*int, str, str, (str, int))]") 294 eq("tuple[str, int, float, dict[str, int]]") 295 eq("slice[0]") 296 eq("slice[0:1]") 297 eq("slice[0:1:2]") 298 eq("slice[:]") 299 eq("slice[:-1]") 300 eq("slice[1:]") 301 eq("slice[::-1]") 302 eq("slice[:,]") 303 eq("slice[1:2,]") 304 eq("slice[1:2:3,]") 305 eq("slice[1:2, 1]") 306 eq("slice[1:2, 2, 3]") 307 eq("slice[()]") 308 eq("slice[a, b:c, d:e:f]") 309 eq("slice[(x for x in a)]") 310 eq('str or None if sys.version_info[0] > (3,) else str or bytes or None') 311 eq("f'f-string without formatted values is just a string'") 312 eq("f'{{NOT a formatted value}}'") 313 eq("f'some f-string with {a} {few():.2f} {formatted.values!r}'") 314 eq('''f"{f'{nested} inner'} outer"''') 315 eq("f'space between opening braces: { {a for a in (1, 2, 3)}}'") 316 eq("f'{(lambda x: x)}'") 317 eq("f'{(None if a else lambda x: x)}'") 318 eq("f'{x}'") 319 eq("f'{x!r}'") 320 eq("f'{x!a}'") 321 eq('[x for x in (a if b else c)]') 322 eq('[x for x in a if (b if c else d)]') 323 eq('f(x for x in a)') 324 eq('f(1, (x for x in a))') 325 eq('f((x for x in a), 2)') 326 eq('(((a)))', 'a') 327 eq('(((a, b)))', '(a, b)') 328 eq("1 + 2 + 3") 329 330 def test_fstring_debug_annotations(self): 331 # f-strings with '=' don't round trip very well, so set the expected 332 # result explicitly. 333 self.assertAnnotationEqual("f'{x=!r}'", expected="f'x={x!r}'") 334 self.assertAnnotationEqual("f'{x=:}'", expected="f'x={x:}'") 335 self.assertAnnotationEqual("f'{x=:.2f}'", expected="f'x={x:.2f}'") 336 self.assertAnnotationEqual("f'{x=!r}'", expected="f'x={x!r}'") 337 self.assertAnnotationEqual("f'{x=!a}'", expected="f'x={x!a}'") 338 self.assertAnnotationEqual("f'{x=!s:*^20}'", expected="f'x={x!s:*^20}'") 339 340 def test_infinity_numbers(self): 341 inf = "1e" + repr(sys.float_info.max_10_exp + 1) 342 infj = f"{inf}j" 343 self.assertAnnotationEqual("1e1000", expected=inf) 344 self.assertAnnotationEqual("1e1000j", expected=infj) 345 self.assertAnnotationEqual("-1e1000", expected=f"-{inf}") 346 self.assertAnnotationEqual("3+1e1000j", expected=f"3 + {infj}") 347 self.assertAnnotationEqual("(1e1000, 1e1000j)", expected=f"({inf}, {infj})") 348 self.assertAnnotationEqual("'inf'") 349 self.assertAnnotationEqual("('inf', 1e1000, 'infxxx', 1e1000j)", expected=f"('inf', {inf}, 'infxxx', {infj})") 350 self.assertAnnotationEqual("(1e1000, (1e1000j,))", expected=f"({inf}, ({infj},))") 351 352 def test_annotation_with_complex_target(self): 353 with self.assertRaises(SyntaxError): 354 exec( 355 "from __future__ import annotations\n" 356 "object.__debug__: int" 357 ) 358 359 def test_annotations_symbol_table_pass(self): 360 namespace = self._exec_future(dedent(""" 361 from __future__ import annotations 362 363 def foo(): 364 outer = 1 365 def bar(): 366 inner: outer = 1 367 return bar 368 """)) 369 370 foo = namespace.pop("foo") 371 self.assertIsNone(foo().__closure__) 372 self.assertEqual(foo.__code__.co_cellvars, ()) 373 self.assertEqual(foo().__code__.co_freevars, ()) 374 375 def test_annotations_forbidden(self): 376 with self.assertRaises(SyntaxError): 377 self._exec_future("test: (yield)") 378 379 with self.assertRaises(SyntaxError): 380 self._exec_future("test.test: (yield a + b)") 381 382 with self.assertRaises(SyntaxError): 383 self._exec_future("test[something]: (yield from x)") 384 385 with self.assertRaises(SyntaxError): 386 self._exec_future("def func(test: (yield from outside_of_generator)): pass") 387 388 with self.assertRaises(SyntaxError): 389 self._exec_future("def test() -> (await y): pass") 390 391 with self.assertRaises(SyntaxError): 392 self._exec_future("async def test() -> something((a := b)): pass") 393 394 with self.assertRaises(SyntaxError): 395 self._exec_future("test: await some.complicated[0].call(with_args=True or 1 is not 1)") 396 397 with self.assertRaises(SyntaxError): 398 self._exec_future("test: f'{(x := 10):=10}'") 399 400 with self.assertRaises(SyntaxError): 401 self._exec_future(dedent("""\ 402 def foo(): 403 def bar(arg: (yield)): pass 404 """)) 405 406 407if __name__ == "__main__": 408 unittest.main() 409