1# Test various flavors of legal and illegal future statements
2
3import __future__
4import ast
5import unittest
6from test import support
7from textwrap import dedent
8import os
9import re
10
11rx = re.compile(r'\((\S+).py, line (\d+)')
12
13def get_error_location(msg):
14    mo = rx.search(str(msg))
15    return mo.group(1, 2)
16
17class FutureTest(unittest.TestCase):
18
19    def check_syntax_error(self, err, basename, lineno, offset=1):
20        self.assertIn('%s.py, line %d' % (basename, lineno), str(err))
21        self.assertEqual(os.path.basename(err.filename), basename + '.py')
22        self.assertEqual(err.lineno, lineno)
23        self.assertEqual(err.offset, offset)
24
25    def test_future1(self):
26        with support.CleanImport('future_test1'):
27            from test import future_test1
28            self.assertEqual(future_test1.result, 6)
29
30    def test_future2(self):
31        with support.CleanImport('future_test2'):
32            from test import future_test2
33            self.assertEqual(future_test2.result, 6)
34
35    def test_future3(self):
36        with support.CleanImport('test_future3'):
37            from test import test_future3
38
39    def test_badfuture3(self):
40        with self.assertRaises(SyntaxError) as cm:
41            from test import badsyntax_future3
42        self.check_syntax_error(cm.exception, "badsyntax_future3", 3)
43
44    def test_badfuture4(self):
45        with self.assertRaises(SyntaxError) as cm:
46            from test import badsyntax_future4
47        self.check_syntax_error(cm.exception, "badsyntax_future4", 3)
48
49    def test_badfuture5(self):
50        with self.assertRaises(SyntaxError) as cm:
51            from test import badsyntax_future5
52        self.check_syntax_error(cm.exception, "badsyntax_future5", 4)
53
54    def test_badfuture6(self):
55        with self.assertRaises(SyntaxError) as cm:
56            from test import badsyntax_future6
57        self.check_syntax_error(cm.exception, "badsyntax_future6", 3)
58
59    def test_badfuture7(self):
60        with self.assertRaises(SyntaxError) as cm:
61            from test import badsyntax_future7
62        self.check_syntax_error(cm.exception, "badsyntax_future7", 3, 53)
63
64    def test_badfuture8(self):
65        with self.assertRaises(SyntaxError) as cm:
66            from test import badsyntax_future8
67        self.check_syntax_error(cm.exception, "badsyntax_future8", 3)
68
69    def test_badfuture9(self):
70        with self.assertRaises(SyntaxError) as cm:
71            from test import badsyntax_future9
72        self.check_syntax_error(cm.exception, "badsyntax_future9", 3)
73
74    def test_badfuture10(self):
75        with self.assertRaises(SyntaxError) as cm:
76            from test import badsyntax_future10
77        self.check_syntax_error(cm.exception, "badsyntax_future10", 3)
78
79    def test_ensure_flags_dont_clash(self):
80        # bpo-39562: test that future flags and compiler flags doesn't clash
81
82        # obtain future flags (CO_FUTURE_***) from the __future__ module
83        flags = {
84            f"CO_FUTURE_{future.upper()}": getattr(__future__, future).compiler_flag
85            for future in __future__.all_feature_names
86        }
87        # obtain some of the exported compiler flags (PyCF_***) from the ast module
88        flags.update({
89            flag: getattr(ast, flag)
90            for flag in dir(ast) if flag.startswith("PyCF_")
91        })
92        self.assertCountEqual(set(flags.values()), flags.values())
93
94    def test_parserhack(self):
95        # test that the parser.c::future_hack function works as expected
96        # Note: although this test must pass, it's not testing the original
97        #       bug as of 2.6 since the with statement is not optional and
98        #       the parser hack disabled. If a new keyword is introduced in
99        #       2.6, change this to refer to the new future import.
100        try:
101            exec("from __future__ import print_function; print 0")
102        except SyntaxError:
103            pass
104        else:
105            self.fail("syntax error didn't occur")
106
107        try:
108            exec("from __future__ import (print_function); print 0")
109        except SyntaxError:
110            pass
111        else:
112            self.fail("syntax error didn't occur")
113
114    def test_multiple_features(self):
115        with support.CleanImport("test.test_future5"):
116            from test import test_future5
117
118    def test_unicode_literals_exec(self):
119        scope = {}
120        exec("from __future__ import unicode_literals; x = ''", {}, scope)
121        self.assertIsInstance(scope["x"], str)
122
123class AnnotationsFutureTestCase(unittest.TestCase):
124    template = dedent(
125        """
126        from __future__ import annotations
127        def f() -> {ann}:
128            ...
129        def g(arg: {ann}) -> None:
130            ...
131        var: {ann}
132        var2: {ann} = None
133        """
134    )
135
136    def getActual(self, annotation):
137        scope = {}
138        exec(self.template.format(ann=annotation), {}, scope)
139        func_ret_ann = scope['f'].__annotations__['return']
140        func_arg_ann = scope['g'].__annotations__['arg']
141        var_ann1 = scope['__annotations__']['var']
142        var_ann2 = scope['__annotations__']['var2']
143        self.assertEqual(func_ret_ann, func_arg_ann)
144        self.assertEqual(func_ret_ann, var_ann1)
145        self.assertEqual(func_ret_ann, var_ann2)
146        return func_ret_ann
147
148    def assertAnnotationEqual(
149        self, annotation, expected=None, drop_parens=False, is_tuple=False,
150    ):
151        actual = self.getActual(annotation)
152        if expected is None:
153            expected = annotation if not is_tuple else annotation[1:-1]
154        if drop_parens:
155            self.assertNotEqual(actual, expected)
156            actual = actual.replace("(", "").replace(")", "")
157
158        self.assertEqual(actual, expected)
159
160    def test_annotations(self):
161        eq = self.assertAnnotationEqual
162        eq('...')
163        eq("'some_string'")
164        eq("b'\\xa3'")
165        eq('Name')
166        eq('None')
167        eq('True')
168        eq('False')
169        eq('1')
170        eq('1.0')
171        eq('1j')
172        eq('True or False')
173        eq('True or False or None')
174        eq('True and False')
175        eq('True and False and None')
176        eq('Name1 and Name2 or Name3')
177        eq('Name1 and (Name2 or Name3)')
178        eq('Name1 or Name2 and Name3')
179        eq('(Name1 or Name2) and Name3')
180        eq('Name1 and Name2 or Name3 and Name4')
181        eq('Name1 or Name2 and Name3 or Name4')
182        eq('a + b + (c + d)')
183        eq('a * b * (c * d)')
184        eq('(a ** b) ** c ** d')
185        eq('v1 << 2')
186        eq('1 >> v2')
187        eq('1 % finished')
188        eq('1 + v2 - v3 * 4 ^ 5 ** v6 / 7 // 8')
189        eq('not great')
190        eq('not not great')
191        eq('~great')
192        eq('+value')
193        eq('++value')
194        eq('-1')
195        eq('~int and not v1 ^ 123 + v2 | True')
196        eq('a + (not b)')
197        eq('lambda: None')
198        eq('lambda arg: None')
199        eq('lambda a=True: a')
200        eq('lambda a, b, c=True: a')
201        eq("lambda a, b, c=True, *, d=1 << v2, e='str': a")
202        eq("lambda a, b, c=True, *vararg, d, e='str', **kwargs: a + b")
203        eq("lambda a, /, b, c=True, *vararg, d, e='str', **kwargs: a + b")
204        eq('lambda x, /: x')
205        eq('lambda x=1, /: x')
206        eq('lambda x, /, y: x + y')
207        eq('lambda x=1, /, y=2: x + y')
208        eq('lambda x, /, y=1: x + y')
209        eq('lambda x, /, y=1, *, z=3: x + y + z')
210        eq('lambda x=1, /, y=2, *, z=3: x + y + z')
211        eq('lambda x=1, /, y=2, *, z: x + y + z')
212        eq('lambda x=1, y=2, z=3, /, w=4, *, l, l2: x + y + z + w + l + l2')
213        eq('lambda x=1, y=2, z=3, /, w=4, *, l, l2, **kwargs: x + y + z + w + l + l2')
214        eq('lambda x, /, y=1, *, z: x + y + z')
215        eq('lambda x: lambda y: x + y')
216        eq('1 if True else 2')
217        eq('str or None if int or True else str or bytes or None')
218        eq('str or None if (1 if True else 2) else str or bytes or None')
219        eq("0 if not x else 1 if x > 0 else -1")
220        eq("(1 if x > 0 else -1) if x else 0")
221        eq("{'2.7': dead, '3.7': long_live or die_hard}")
222        eq("{'2.7': dead, '3.7': long_live or die_hard, **{'3.6': verygood}}")
223        eq("{**a, **b, **c}")
224        eq("{'2.7', '3.6', '3.7', '3.8', '3.9', '4.0' if gilectomy else '3.10'}")
225        eq("{*a, *b, *c}")
226        eq("({'a': 'b'}, True or False, +value, 'string', b'bytes') or None")
227        eq("()")
228        eq("(a,)")
229        eq("(a, b)")
230        eq("(a, b, c)")
231        eq("(*a, *b, *c)")
232        eq("[]")
233        eq("[1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or A, 11 or B, 12 or C]")
234        eq("[*a, *b, *c]")
235        eq("{i for i in (1, 2, 3)}")
236        eq("{i ** 2 for i in (1, 2, 3)}")
237        eq("{i ** 2 for i, _ in ((1, 'a'), (2, 'b'), (3, 'c'))}")
238        eq("{i ** 2 + j for i in (1, 2, 3) for j in (1, 2, 3)}")
239        eq("[i for i in (1, 2, 3)]")
240        eq("[i ** 2 for i in (1, 2, 3)]")
241        eq("[i ** 2 for i, _ in ((1, 'a'), (2, 'b'), (3, 'c'))]")
242        eq("[i ** 2 + j for i in (1, 2, 3) for j in (1, 2, 3)]")
243        eq("(i for i in (1, 2, 3))")
244        eq("(i ** 2 for i in (1, 2, 3))")
245        eq("(i ** 2 for i, _ in ((1, 'a'), (2, 'b'), (3, 'c')))")
246        eq("(i ** 2 + j for i in (1, 2, 3) for j in (1, 2, 3))")
247        eq("{i: 0 for i in (1, 2, 3)}")
248        eq("{i: j for i, j in ((1, 'a'), (2, 'b'), (3, 'c'))}")
249        eq("[(x, y) for x, y in (a, b)]")
250        eq("[(x,) for x, in (a,)]")
251        eq("Python3 > Python2 > COBOL")
252        eq("Life is Life")
253        eq("call()")
254        eq("call(arg)")
255        eq("call(kwarg='hey')")
256        eq("call(arg, kwarg='hey')")
257        eq("call(arg, *args, another, kwarg='hey')")
258        eq("call(arg, another, kwarg='hey', **kwargs, kwarg2='ho')")
259        eq("lukasz.langa.pl")
260        eq("call.me(maybe)")
261        eq("1 .real")
262        eq("1.0.real")
263        eq("....__class__")
264        eq("list[str]")
265        eq("dict[str, int]")
266        eq("set[str,]")
267        eq("tuple[str, ...]")
268        eq("tuple[(str, *types)]")
269        eq("tuple[xx:yy, (*types,)]")
270        eq("tuple[str, int, (str, int)]")
271        eq("tuple[(*int, str, str, (str, int))]")
272        eq("tuple[str, int, float, dict[str, int]]")
273        eq("slice[0]")
274        eq("slice[0:1]")
275        eq("slice[0:1:2]")
276        eq("slice[:]")
277        eq("slice[:-1]")
278        eq("slice[1:]")
279        eq("slice[::-1]")
280        eq("slice[:,]")
281        eq("slice[1:2,]")
282        eq("slice[1:2:3,]")
283        eq("slice[1:2, 1]")
284        eq("slice[1:2, 2, 3]")
285        eq("slice[()]")
286        eq("slice[a, b:c, d:e:f]")
287        eq("slice[(x for x in a)]")
288        eq('str or None if sys.version_info[0] > (3,) else str or bytes or None')
289        eq("f'f-string without formatted values is just a string'")
290        eq("f'{{NOT a formatted value}}'")
291        eq("f'some f-string with {a} {few():.2f} {formatted.values!r}'")
292        eq('''f"{f'{nested} inner'} outer"''')
293        eq("f'space between opening braces: { {a for a in (1, 2, 3)}}'")
294        eq("f'{(lambda x: x)}'")
295        eq("f'{(None if a else lambda x: x)}'")
296        eq("f'{x}'")
297        eq("f'{x!r}'")
298        eq("f'{x!a}'")
299        eq('(yield from outside_of_generator)')
300        eq('(yield)')
301        eq('(yield a + b)')
302        eq('await some.complicated[0].call(with_args=True or 1 is not 1)')
303        eq('[x for x in (a if b else c)]')
304        eq('[x for x in a if (b if c else d)]')
305        eq('f(x for x in a)')
306        eq('f(1, (x for x in a))')
307        eq('f((x for x in a), 2)')
308        eq('(((a)))', 'a')
309        eq('(((a, b)))', '(a, b)')
310        eq("(x:=10)")
311        eq("f'{(x:=10):=10}'")
312
313    def test_fstring_debug_annotations(self):
314        # f-strings with '=' don't round trip very well, so set the expected
315        # result explicitely.
316        self.assertAnnotationEqual("f'{x=!r}'", expected="f'x={x!r}'")
317        self.assertAnnotationEqual("f'{x=:}'", expected="f'x={x:}'")
318        self.assertAnnotationEqual("f'{x=:.2f}'", expected="f'x={x:.2f}'")
319        self.assertAnnotationEqual("f'{x=!r}'", expected="f'x={x!r}'")
320        self.assertAnnotationEqual("f'{x=!a}'", expected="f'x={x!a}'")
321        self.assertAnnotationEqual("f'{x=!s:*^20}'", expected="f'x={x!s:*^20}'")
322
323
324if __name__ == "__main__":
325    unittest.main()
326