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