Jeremy Hylton | 62e2c7e | 2001-02-28 17:48:06 +0000 | [diff] [blame] | 1 | # Test various flavors of legal and illegal future statements |
| 2 | |
Batuhan Taşkaya | 4454057 | 2020-04-22 19:09:03 +0300 | [diff] [blame] | 3 | import __future__ |
| 4 | import ast |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 5 | import unittest |
Benjamin Peterson | ee8712c | 2008-05-20 21:35:26 +0000 | [diff] [blame] | 6 | from test import support |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 7 | from textwrap import dedent |
Serhiy Storchaka | 8b58339 | 2016-12-11 14:39:01 +0200 | [diff] [blame] | 8 | import os |
Jeremy Hylton | 62e2c7e | 2001-02-28 17:48:06 +0000 | [diff] [blame] | 9 | import re |
Batuhan Taşkaya | 258f517 | 2020-04-14 01:51:31 +0300 | [diff] [blame] | 10 | import sys |
Jeremy Hylton | 62e2c7e | 2001-02-28 17:48:06 +0000 | [diff] [blame] | 11 | |
R David Murray | 44b548d | 2016-09-08 13:59:53 -0400 | [diff] [blame] | 12 | rx = re.compile(r'\((\S+).py, line (\d+)') |
Jeremy Hylton | 62e2c7e | 2001-02-28 17:48:06 +0000 | [diff] [blame] | 13 | |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 14 | def get_error_location(msg): |
| 15 | mo = rx.search(str(msg)) |
| 16 | return mo.group(1, 2) |
Jeremy Hylton | 62e2c7e | 2001-02-28 17:48:06 +0000 | [diff] [blame] | 17 | |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 18 | class FutureTest(unittest.TestCase): |
Jeremy Hylton | 62e2c7e | 2001-02-28 17:48:06 +0000 | [diff] [blame] | 19 | |
Ammar Askar | 025eb98 | 2018-09-24 17:12:49 -0400 | [diff] [blame] | 20 | def check_syntax_error(self, err, basename, lineno, offset=1): |
Serhiy Storchaka | 8b58339 | 2016-12-11 14:39:01 +0200 | [diff] [blame] | 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 | |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 26 | def test_future1(self): |
Ezio Melotti | 1ed6be3 | 2013-02-27 10:00:03 +0200 | [diff] [blame] | 27 | with support.CleanImport('future_test1'): |
| 28 | from test import future_test1 |
| 29 | self.assertEqual(future_test1.result, 6) |
Jeremy Hylton | 62e2c7e | 2001-02-28 17:48:06 +0000 | [diff] [blame] | 30 | |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 31 | def test_future2(self): |
Ezio Melotti | 1ed6be3 | 2013-02-27 10:00:03 +0200 | [diff] [blame] | 32 | with support.CleanImport('future_test2'): |
| 33 | from test import future_test2 |
| 34 | self.assertEqual(future_test2.result, 6) |
Jeremy Hylton | 62e2c7e | 2001-02-28 17:48:06 +0000 | [diff] [blame] | 35 | |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 36 | def test_future3(self): |
Ezio Melotti | 1ed6be3 | 2013-02-27 10:00:03 +0200 | [diff] [blame] | 37 | with support.CleanImport('test_future3'): |
| 38 | from test import test_future3 |
Jeremy Hylton | 8471a35 | 2001-08-20 20:33:42 +0000 | [diff] [blame] | 39 | |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 40 | def test_badfuture3(self): |
Serhiy Storchaka | 8b58339 | 2016-12-11 14:39:01 +0200 | [diff] [blame] | 41 | with self.assertRaises(SyntaxError) as cm: |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 42 | from test import badsyntax_future3 |
Serhiy Storchaka | 8b58339 | 2016-12-11 14:39:01 +0200 | [diff] [blame] | 43 | self.check_syntax_error(cm.exception, "badsyntax_future3", 3) |
Jeremy Hylton | 62e2c7e | 2001-02-28 17:48:06 +0000 | [diff] [blame] | 44 | |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 45 | def test_badfuture4(self): |
Serhiy Storchaka | 8b58339 | 2016-12-11 14:39:01 +0200 | [diff] [blame] | 46 | with self.assertRaises(SyntaxError) as cm: |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 47 | from test import badsyntax_future4 |
Serhiy Storchaka | 8b58339 | 2016-12-11 14:39:01 +0200 | [diff] [blame] | 48 | self.check_syntax_error(cm.exception, "badsyntax_future4", 3) |
Jeremy Hylton | 62e2c7e | 2001-02-28 17:48:06 +0000 | [diff] [blame] | 49 | |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 50 | def test_badfuture5(self): |
Serhiy Storchaka | 8b58339 | 2016-12-11 14:39:01 +0200 | [diff] [blame] | 51 | with self.assertRaises(SyntaxError) as cm: |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 52 | from test import badsyntax_future5 |
Serhiy Storchaka | 8b58339 | 2016-12-11 14:39:01 +0200 | [diff] [blame] | 53 | self.check_syntax_error(cm.exception, "badsyntax_future5", 4) |
Jeremy Hylton | 62e2c7e | 2001-02-28 17:48:06 +0000 | [diff] [blame] | 54 | |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 55 | def test_badfuture6(self): |
Serhiy Storchaka | 8b58339 | 2016-12-11 14:39:01 +0200 | [diff] [blame] | 56 | with self.assertRaises(SyntaxError) as cm: |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 57 | from test import badsyntax_future6 |
Serhiy Storchaka | 8b58339 | 2016-12-11 14:39:01 +0200 | [diff] [blame] | 58 | self.check_syntax_error(cm.exception, "badsyntax_future6", 3) |
Jeremy Hylton | 62e2c7e | 2001-02-28 17:48:06 +0000 | [diff] [blame] | 59 | |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 60 | def test_badfuture7(self): |
Serhiy Storchaka | 8b58339 | 2016-12-11 14:39:01 +0200 | [diff] [blame] | 61 | with self.assertRaises(SyntaxError) as cm: |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 62 | from test import badsyntax_future7 |
Serhiy Storchaka | 8b58339 | 2016-12-11 14:39:01 +0200 | [diff] [blame] | 63 | self.check_syntax_error(cm.exception, "badsyntax_future7", 3, 53) |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 64 | |
| 65 | def test_badfuture8(self): |
Serhiy Storchaka | 8b58339 | 2016-12-11 14:39:01 +0200 | [diff] [blame] | 66 | with self.assertRaises(SyntaxError) as cm: |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 67 | from test import badsyntax_future8 |
Serhiy Storchaka | 8b58339 | 2016-12-11 14:39:01 +0200 | [diff] [blame] | 68 | self.check_syntax_error(cm.exception, "badsyntax_future8", 3) |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 69 | |
| 70 | def test_badfuture9(self): |
Serhiy Storchaka | 8b58339 | 2016-12-11 14:39:01 +0200 | [diff] [blame] | 71 | with self.assertRaises(SyntaxError) as cm: |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 72 | from test import badsyntax_future9 |
Ammar Askar | 025eb98 | 2018-09-24 17:12:49 -0400 | [diff] [blame] | 73 | self.check_syntax_error(cm.exception, "badsyntax_future9", 3) |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 74 | |
Benjamin Peterson | 2d6acd2 | 2013-03-16 09:15:47 -0700 | [diff] [blame] | 75 | def test_badfuture10(self): |
Serhiy Storchaka | 8b58339 | 2016-12-11 14:39:01 +0200 | [diff] [blame] | 76 | with self.assertRaises(SyntaxError) as cm: |
Benjamin Peterson | 2d6acd2 | 2013-03-16 09:15:47 -0700 | [diff] [blame] | 77 | from test import badsyntax_future10 |
Ammar Askar | 025eb98 | 2018-09-24 17:12:49 -0400 | [diff] [blame] | 78 | self.check_syntax_error(cm.exception, "badsyntax_future10", 3) |
Benjamin Peterson | 2d6acd2 | 2013-03-16 09:15:47 -0700 | [diff] [blame] | 79 | |
Batuhan Taşkaya | 4454057 | 2020-04-22 19:09:03 +0300 | [diff] [blame] | 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 | |
Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 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: |
Benjamin Peterson | 9aebc61 | 2008-10-26 20:58:53 +0000 | [diff] [blame] | 102 | exec("from __future__ import print_function; print 0") |
Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 103 | except SyntaxError: |
| 104 | pass |
| 105 | else: |
| 106 | self.fail("syntax error didn't occur") |
| 107 | |
| 108 | try: |
Benjamin Peterson | 9aebc61 | 2008-10-26 20:58:53 +0000 | [diff] [blame] | 109 | exec("from __future__ import (print_function); print 0") |
Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 110 | except SyntaxError: |
| 111 | pass |
| 112 | else: |
| 113 | self.fail("syntax error didn't occur") |
| 114 | |
Benjamin Peterson | 9aebc61 | 2008-10-26 20:58:53 +0000 | [diff] [blame] | 115 | def test_multiple_features(self): |
Ezio Melotti | 1ed6be3 | 2013-02-27 10:00:03 +0200 | [diff] [blame] | 116 | with support.CleanImport("test.test_future5"): |
| 117 | from test import test_future5 |
Benjamin Peterson | 9aebc61 | 2008-10-26 20:58:53 +0000 | [diff] [blame] | 118 | |
Benjamin Peterson | f216c94 | 2008-10-31 02:28:05 +0000 | [diff] [blame] | 119 | def test_unicode_literals_exec(self): |
| 120 | scope = {} |
| 121 | exec("from __future__ import unicode_literals; x = ''", {}, scope) |
Ezio Melotti | e961593 | 2010-01-24 19:26:24 +0000 | [diff] [blame] | 122 | self.assertIsInstance(scope["x"], str) |
Benjamin Peterson | f216c94 | 2008-10-31 02:28:05 +0000 | [diff] [blame] | 123 | |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 124 | class AnnotationsFutureTestCase(unittest.TestCase): |
| 125 | template = dedent( |
| 126 | """ |
| 127 | from __future__ import annotations |
| 128 | def f() -> {ann}: |
| 129 | ... |
| 130 | def g(arg: {ann}) -> None: |
| 131 | ... |
Pablo Galindo | d112c60 | 2020-03-18 23:02:09 +0000 | [diff] [blame] | 132 | async def f2() -> {ann}: |
| 133 | ... |
| 134 | async def g2(arg: {ann}) -> None: |
| 135 | ... |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 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'] |
Pablo Galindo | d112c60 | 2020-03-18 23:02:09 +0000 | [diff] [blame] | 146 | async_func_ret_ann = scope['f2'].__annotations__['return'] |
| 147 | async_func_arg_ann = scope['g2'].__annotations__['arg'] |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 148 | var_ann1 = scope['__annotations__']['var'] |
| 149 | var_ann2 = scope['__annotations__']['var2'] |
| 150 | self.assertEqual(func_ret_ann, func_arg_ann) |
Pablo Galindo | d112c60 | 2020-03-18 23:02:09 +0000 | [diff] [blame] | 151 | self.assertEqual(func_ret_ann, async_func_ret_ann) |
| 152 | self.assertEqual(func_ret_ann, async_func_arg_ann) |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 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'") |
Batuhan Taşkaya | aade1cc | 2020-04-14 21:55:01 +0300 | [diff] [blame] | 173 | eq("u'some_string'") |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 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') |
Serhiy Storchaka | 64fddc4 | 2018-05-17 06:17:48 +0300 | [diff] [blame] | 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') |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 195 | eq('v1 << 2') |
| 196 | eq('1 >> v2') |
Serhiy Storchaka | 64fddc4 | 2018-05-17 06:17:48 +0300 | [diff] [blame] | 197 | eq('1 % finished') |
| 198 | eq('1 + v2 - v3 * 4 ^ 5 ** v6 / 7 // 8') |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 199 | eq('not great') |
Serhiy Storchaka | 64fddc4 | 2018-05-17 06:17:48 +0300 | [diff] [blame] | 200 | eq('not not great') |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 201 | eq('~great') |
| 202 | eq('+value') |
Serhiy Storchaka | 64fddc4 | 2018-05-17 06:17:48 +0300 | [diff] [blame] | 203 | eq('++value') |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 204 | eq('-1') |
Serhiy Storchaka | 64fddc4 | 2018-05-17 06:17:48 +0300 | [diff] [blame] | 205 | eq('~int and not v1 ^ 123 + v2 | True') |
| 206 | eq('a + (not b)') |
Serhiy Storchaka | 2a2940e | 2018-09-30 21:07:05 +0300 | [diff] [blame] | 207 | eq('lambda: None') |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 208 | eq('lambda arg: None') |
| 209 | eq('lambda a=True: a') |
| 210 | eq('lambda a, b, c=True: a') |
Serhiy Storchaka | 64fddc4 | 2018-05-17 06:17:48 +0300 | [diff] [blame] | 211 | eq("lambda a, b, c=True, *, d=1 << v2, e='str': a") |
Serhiy Storchaka | 2a2940e | 2018-09-30 21:07:05 +0300 | [diff] [blame] | 212 | eq("lambda a, b, c=True, *vararg, d, e='str', **kwargs: a + b") |
Pablo Galindo | da6129e | 2019-05-18 23:40:22 +0100 | [diff] [blame] | 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') |
Serhiy Storchaka | 64fddc4 | 2018-05-17 06:17:48 +0300 | [diff] [blame] | 225 | eq('lambda x: lambda y: x + y') |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 226 | eq('1 if True else 2') |
Serhiy Storchaka | 64fddc4 | 2018-05-17 06:17:48 +0300 | [diff] [blame] | 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}}") |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 233 | eq("{**a, **b, **c}") |
Serhiy Storchaka | 64fddc4 | 2018-05-17 06:17:48 +0300 | [diff] [blame] | 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") |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 237 | eq("()") |
Serhiy Storchaka | 64fddc4 | 2018-05-17 06:17:48 +0300 | [diff] [blame] | 238 | eq("(a,)") |
| 239 | eq("(a, b)") |
| 240 | eq("(a, b, c)") |
| 241 | eq("(*a, *b, *c)") |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 242 | eq("[]") |
Serhiy Storchaka | 64fddc4 | 2018-05-17 06:17:48 +0300 | [diff] [blame] | 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]") |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 245 | eq("{i for i in (1, 2, 3)}") |
Serhiy Storchaka | 64fddc4 | 2018-05-17 06:17:48 +0300 | [diff] [blame] | 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)}") |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 249 | eq("[i for i in (1, 2, 3)]") |
Serhiy Storchaka | 64fddc4 | 2018-05-17 06:17:48 +0300 | [diff] [blame] | 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)}") |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 258 | eq("{i: j for i, j in ((1, 'a'), (2, 'b'), (3, 'c'))}") |
Serhiy Storchaka | 64fddc4 | 2018-05-17 06:17:48 +0300 | [diff] [blame] | 259 | eq("[(x, y) for x, y in (a, b)]") |
| 260 | eq("[(x,) for x, in (a,)]") |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 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')") |
Serhiy Storchaka | 64fddc4 | 2018-05-17 06:17:48 +0300 | [diff] [blame] | 267 | eq("call(arg, *args, another, kwarg='hey')") |
| 268 | eq("call(arg, another, kwarg='hey', **kwargs, kwarg2='ho')") |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 269 | eq("lukasz.langa.pl") |
| 270 | eq("call.me(maybe)") |
| 271 | eq("1 .real") |
Serhiy Storchaka | 3f22811 | 2018-09-27 17:42:37 +0300 | [diff] [blame] | 272 | eq("1.0.real") |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 273 | eq("....__class__") |
| 274 | eq("list[str]") |
| 275 | eq("dict[str, int]") |
Serhiy Storchaka | 64fddc4 | 2018-05-17 06:17:48 +0300 | [diff] [blame] | 276 | eq("set[str,]") |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 277 | eq("tuple[str, ...]") |
Batuhan Taskaya | 2135e10 | 2020-05-18 21:23:48 +0300 | [diff] [blame^] | 278 | eq("tuple[(str, *types)]") |
| 279 | eq("tuple[str, int, (str, int)]") |
| 280 | eq("tuple[(*int, str, str, (str, int))]") |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 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]") |
Batuhan Taşkaya | 185903d | 2020-03-01 23:07:22 +0300 | [diff] [blame] | 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]") |
Serhiy Storchaka | 64fddc4 | 2018-05-17 06:17:48 +0300 | [diff] [blame] | 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') |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 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)}}'") |
Serhiy Storchaka | 64fddc4 | 2018-05-17 06:17:48 +0300 | [diff] [blame] | 303 | eq("f'{(lambda x: x)}'") |
| 304 | eq("f'{(None if a else lambda x: x)}'") |
Eric V. Smith | 9a4135e | 2019-05-08 16:28:48 -0400 | [diff] [blame] | 305 | eq("f'{x}'") |
| 306 | eq("f'{x!r}'") |
| 307 | eq("f'{x!a}'") |
Guido van Rossum | 95e4d58 | 2018-01-26 08:20:18 -0800 | [diff] [blame] | 308 | eq('(yield from outside_of_generator)') |
| 309 | eq('(yield)') |
Serhiy Storchaka | 64fddc4 | 2018-05-17 06:17:48 +0300 | [diff] [blame] | 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)') |
Hakan Çelik | ce57883 | 2020-04-18 19:17:19 +0300 | [diff] [blame] | 319 | eq("(x := 10)") |
| 320 | eq("f'{(x := 10):=10}'") |
Pablo Galindo | d112c60 | 2020-03-18 23:02:09 +0000 | [diff] [blame] | 321 | eq("1 + 2 + 3") |
Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 322 | |
Eric V. Smith | f83d1db | 2019-05-29 03:55:44 -0400 | [diff] [blame] | 323 | def test_fstring_debug_annotations(self): |
Eric V. Smith | 6f6ff8a | 2019-05-27 15:31:52 -0400 | [diff] [blame] | 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 | |
Batuhan Taşkaya | 258f517 | 2020-04-14 01:51:31 +0300 | [diff] [blame] | 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 | |
Neal Norwitz | 328f338 | 2003-12-13 22:43:34 +0000 | [diff] [blame] | 346 | if __name__ == "__main__": |
Ezio Melotti | 1ed6be3 | 2013-02-27 10:00:03 +0200 | [diff] [blame] | 347 | unittest.main() |