• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import ast
2import types
3import decimal
4import unittest
5
6a_global = 'global variable'
7
8# You could argue that I'm too strict in looking for specific error
9#  values with assertRaisesRegex, but without it it's way too easy to
10#  make a syntax error in the test strings. Especially with all of the
11#  triple quotes, raw strings, backslashes, etc. I think it's a
12#  worthwhile tradeoff. When I switched to this method, I found many
13#  examples where I wasn't testing what I thought I was.
14
15class TestCase(unittest.TestCase):
16    def assertAllRaise(self, exception_type, regex, error_strings):
17        for str in error_strings:
18            with self.subTest(str=str):
19                with self.assertRaisesRegex(exception_type, regex):
20                    eval(str)
21
22    def test__format__lookup(self):
23        # Make sure __format__ is looked up on the type, not the instance.
24        class X:
25            def __format__(self, spec):
26                return 'class'
27
28        x = X()
29
30        # Add a bound __format__ method to the 'y' instance, but not
31        #  the 'x' instance.
32        y = X()
33        y.__format__ = types.MethodType(lambda self, spec: 'instance', y)
34
35        self.assertEqual(f'{y}', format(y))
36        self.assertEqual(f'{y}', 'class')
37        self.assertEqual(format(x), format(y))
38
39        # __format__ is not called this way, but still make sure it
40        #  returns what we expect (so we can make sure we're bypassing
41        #  it).
42        self.assertEqual(x.__format__(''), 'class')
43        self.assertEqual(y.__format__(''), 'instance')
44
45        # This is how __format__ is actually called.
46        self.assertEqual(type(x).__format__(x, ''), 'class')
47        self.assertEqual(type(y).__format__(y, ''), 'class')
48
49    def test_ast(self):
50        # Inspired by http://bugs.python.org/issue24975
51        class X:
52            def __init__(self):
53                self.called = False
54            def __call__(self):
55                self.called = True
56                return 4
57        x = X()
58        expr = """
59a = 10
60f'{a * x()}'"""
61        t = ast.parse(expr)
62        c = compile(t, '', 'exec')
63
64        # Make sure x was not called.
65        self.assertFalse(x.called)
66
67        # Actually run the code.
68        exec(c)
69
70        # Make sure x was called.
71        self.assertTrue(x.called)
72
73    def test_ast_line_numbers(self):
74        expr = """
75a = 10
76f'{a * x()}'"""
77        t = ast.parse(expr)
78        self.assertEqual(type(t), ast.Module)
79        self.assertEqual(len(t.body), 2)
80        # check `a = 10`
81        self.assertEqual(type(t.body[0]), ast.Assign)
82        self.assertEqual(t.body[0].lineno, 2)
83        # check `f'...'`
84        self.assertEqual(type(t.body[1]), ast.Expr)
85        self.assertEqual(type(t.body[1].value), ast.JoinedStr)
86        self.assertEqual(len(t.body[1].value.values), 1)
87        self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)
88        self.assertEqual(t.body[1].lineno, 3)
89        self.assertEqual(t.body[1].value.lineno, 3)
90        self.assertEqual(t.body[1].value.values[0].lineno, 3)
91        # check the binop location
92        binop = t.body[1].value.values[0].value
93        self.assertEqual(type(binop), ast.BinOp)
94        self.assertEqual(type(binop.left), ast.Name)
95        self.assertEqual(type(binop.op), ast.Mult)
96        self.assertEqual(type(binop.right), ast.Call)
97        self.assertEqual(binop.lineno, 3)
98        self.assertEqual(binop.left.lineno, 3)
99        self.assertEqual(binop.right.lineno, 3)
100        self.assertEqual(binop.col_offset, 3)
101        self.assertEqual(binop.left.col_offset, 3)
102        self.assertEqual(binop.right.col_offset, 7)
103
104    def test_ast_line_numbers_multiple_formattedvalues(self):
105        expr = """
106f'no formatted values'
107f'eggs {a * x()} spam {b + y()}'"""
108        t = ast.parse(expr)
109        self.assertEqual(type(t), ast.Module)
110        self.assertEqual(len(t.body), 2)
111        # check `f'no formatted value'`
112        self.assertEqual(type(t.body[0]), ast.Expr)
113        self.assertEqual(type(t.body[0].value), ast.JoinedStr)
114        self.assertEqual(t.body[0].lineno, 2)
115        # check `f'...'`
116        self.assertEqual(type(t.body[1]), ast.Expr)
117        self.assertEqual(type(t.body[1].value), ast.JoinedStr)
118        self.assertEqual(len(t.body[1].value.values), 4)
119        self.assertEqual(type(t.body[1].value.values[0]), ast.Str)
120        self.assertEqual(type(t.body[1].value.values[1]), ast.FormattedValue)
121        self.assertEqual(type(t.body[1].value.values[2]), ast.Str)
122        self.assertEqual(type(t.body[1].value.values[3]), ast.FormattedValue)
123        self.assertEqual(t.body[1].lineno, 3)
124        self.assertEqual(t.body[1].value.lineno, 3)
125        self.assertEqual(t.body[1].value.values[0].lineno, 3)
126        self.assertEqual(t.body[1].value.values[1].lineno, 3)
127        self.assertEqual(t.body[1].value.values[2].lineno, 3)
128        self.assertEqual(t.body[1].value.values[3].lineno, 3)
129        # check the first binop location
130        binop1 = t.body[1].value.values[1].value
131        self.assertEqual(type(binop1), ast.BinOp)
132        self.assertEqual(type(binop1.left), ast.Name)
133        self.assertEqual(type(binop1.op), ast.Mult)
134        self.assertEqual(type(binop1.right), ast.Call)
135        self.assertEqual(binop1.lineno, 3)
136        self.assertEqual(binop1.left.lineno, 3)
137        self.assertEqual(binop1.right.lineno, 3)
138        self.assertEqual(binop1.col_offset, 8)
139        self.assertEqual(binop1.left.col_offset, 8)
140        self.assertEqual(binop1.right.col_offset, 12)
141        # check the second binop location
142        binop2 = t.body[1].value.values[3].value
143        self.assertEqual(type(binop2), ast.BinOp)
144        self.assertEqual(type(binop2.left), ast.Name)
145        self.assertEqual(type(binop2.op), ast.Add)
146        self.assertEqual(type(binop2.right), ast.Call)
147        self.assertEqual(binop2.lineno, 3)
148        self.assertEqual(binop2.left.lineno, 3)
149        self.assertEqual(binop2.right.lineno, 3)
150        self.assertEqual(binop2.col_offset, 23)
151        self.assertEqual(binop2.left.col_offset, 23)
152        self.assertEqual(binop2.right.col_offset, 27)
153
154    def test_ast_line_numbers_nested(self):
155        expr = """
156a = 10
157f'{a * f"-{x()}-"}'"""
158        t = ast.parse(expr)
159        self.assertEqual(type(t), ast.Module)
160        self.assertEqual(len(t.body), 2)
161        # check `a = 10`
162        self.assertEqual(type(t.body[0]), ast.Assign)
163        self.assertEqual(t.body[0].lineno, 2)
164        # check `f'...'`
165        self.assertEqual(type(t.body[1]), ast.Expr)
166        self.assertEqual(type(t.body[1].value), ast.JoinedStr)
167        self.assertEqual(len(t.body[1].value.values), 1)
168        self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)
169        self.assertEqual(t.body[1].lineno, 3)
170        self.assertEqual(t.body[1].value.lineno, 3)
171        self.assertEqual(t.body[1].value.values[0].lineno, 3)
172        # check the binop location
173        binop = t.body[1].value.values[0].value
174        self.assertEqual(type(binop), ast.BinOp)
175        self.assertEqual(type(binop.left), ast.Name)
176        self.assertEqual(type(binop.op), ast.Mult)
177        self.assertEqual(type(binop.right), ast.JoinedStr)
178        self.assertEqual(binop.lineno, 3)
179        self.assertEqual(binop.left.lineno, 3)
180        self.assertEqual(binop.right.lineno, 3)
181        self.assertEqual(binop.col_offset, 3)
182        self.assertEqual(binop.left.col_offset, 3)
183        self.assertEqual(binop.right.col_offset, 7)
184        # check the nested call location
185        self.assertEqual(len(binop.right.values), 3)
186        self.assertEqual(type(binop.right.values[0]), ast.Str)
187        self.assertEqual(type(binop.right.values[1]), ast.FormattedValue)
188        self.assertEqual(type(binop.right.values[2]), ast.Str)
189        self.assertEqual(binop.right.values[0].lineno, 3)
190        self.assertEqual(binop.right.values[1].lineno, 3)
191        self.assertEqual(binop.right.values[2].lineno, 3)
192        call = binop.right.values[1].value
193        self.assertEqual(type(call), ast.Call)
194        self.assertEqual(call.lineno, 3)
195        self.assertEqual(call.col_offset, 11)
196
197    def test_ast_line_numbers_duplicate_expression(self):
198        """Duplicate expression
199
200        NOTE: this is currently broken, always sets location of the first
201        expression.
202        """
203        expr = """
204a = 10
205f'{a * x()} {a * x()} {a * x()}'
206"""
207        t = ast.parse(expr)
208        self.assertEqual(type(t), ast.Module)
209        self.assertEqual(len(t.body), 2)
210        # check `a = 10`
211        self.assertEqual(type(t.body[0]), ast.Assign)
212        self.assertEqual(t.body[0].lineno, 2)
213        # check `f'...'`
214        self.assertEqual(type(t.body[1]), ast.Expr)
215        self.assertEqual(type(t.body[1].value), ast.JoinedStr)
216        self.assertEqual(len(t.body[1].value.values), 5)
217        self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)
218        self.assertEqual(type(t.body[1].value.values[1]), ast.Str)
219        self.assertEqual(type(t.body[1].value.values[2]), ast.FormattedValue)
220        self.assertEqual(type(t.body[1].value.values[3]), ast.Str)
221        self.assertEqual(type(t.body[1].value.values[4]), ast.FormattedValue)
222        self.assertEqual(t.body[1].lineno, 3)
223        self.assertEqual(t.body[1].value.lineno, 3)
224        self.assertEqual(t.body[1].value.values[0].lineno, 3)
225        self.assertEqual(t.body[1].value.values[1].lineno, 3)
226        self.assertEqual(t.body[1].value.values[2].lineno, 3)
227        self.assertEqual(t.body[1].value.values[3].lineno, 3)
228        self.assertEqual(t.body[1].value.values[4].lineno, 3)
229        # check the first binop location
230        binop = t.body[1].value.values[0].value
231        self.assertEqual(type(binop), ast.BinOp)
232        self.assertEqual(type(binop.left), ast.Name)
233        self.assertEqual(type(binop.op), ast.Mult)
234        self.assertEqual(type(binop.right), ast.Call)
235        self.assertEqual(binop.lineno, 3)
236        self.assertEqual(binop.left.lineno, 3)
237        self.assertEqual(binop.right.lineno, 3)
238        self.assertEqual(binop.col_offset, 3)
239        self.assertEqual(binop.left.col_offset, 3)
240        self.assertEqual(binop.right.col_offset, 7)
241        # check the second binop location
242        binop = t.body[1].value.values[2].value
243        self.assertEqual(type(binop), ast.BinOp)
244        self.assertEqual(type(binop.left), ast.Name)
245        self.assertEqual(type(binop.op), ast.Mult)
246        self.assertEqual(type(binop.right), ast.Call)
247        self.assertEqual(binop.lineno, 3)
248        self.assertEqual(binop.left.lineno, 3)
249        self.assertEqual(binop.right.lineno, 3)
250        self.assertEqual(binop.col_offset, 3)  # FIXME: this is wrong
251        self.assertEqual(binop.left.col_offset, 3)  # FIXME: this is wrong
252        self.assertEqual(binop.right.col_offset, 7)  # FIXME: this is wrong
253        # check the third binop location
254        binop = t.body[1].value.values[4].value
255        self.assertEqual(type(binop), ast.BinOp)
256        self.assertEqual(type(binop.left), ast.Name)
257        self.assertEqual(type(binop.op), ast.Mult)
258        self.assertEqual(type(binop.right), ast.Call)
259        self.assertEqual(binop.lineno, 3)
260        self.assertEqual(binop.left.lineno, 3)
261        self.assertEqual(binop.right.lineno, 3)
262        self.assertEqual(binop.col_offset, 3)  # FIXME: this is wrong
263        self.assertEqual(binop.left.col_offset, 3)  # FIXME: this is wrong
264        self.assertEqual(binop.right.col_offset, 7)  # FIXME: this is wrong
265
266    def test_ast_line_numbers_multiline_fstring(self):
267        # FIXME: This test demonstrates invalid behavior due to JoinedStr's
268        # immediate child nodes containing the wrong lineno.  The enclosed
269        # expressions have valid line information and column offsets.
270        # See bpo-16806 and bpo-30465 for details.
271        expr = """
272a = 10
273f'''
274  {a
275     *
276       x()}
277non-important content
278'''
279"""
280        t = ast.parse(expr)
281        self.assertEqual(type(t), ast.Module)
282        self.assertEqual(len(t.body), 2)
283        # check `a = 10`
284        self.assertEqual(type(t.body[0]), ast.Assign)
285        self.assertEqual(t.body[0].lineno, 2)
286        # check `f'...'`
287        self.assertEqual(type(t.body[1]), ast.Expr)
288        self.assertEqual(type(t.body[1].value), ast.JoinedStr)
289        self.assertEqual(len(t.body[1].value.values), 3)
290        self.assertEqual(type(t.body[1].value.values[0]), ast.Str)
291        self.assertEqual(type(t.body[1].value.values[1]), ast.FormattedValue)
292        self.assertEqual(type(t.body[1].value.values[2]), ast.Str)
293        # NOTE: the following invalid behavior is described in bpo-16806.
294        # - line number should be the *first* line (3), not the *last* (8)
295        # - column offset should not be -1
296        self.assertEqual(t.body[1].lineno, 8)
297        self.assertEqual(t.body[1].value.lineno, 8)
298        self.assertEqual(t.body[1].value.values[0].lineno, 8)
299        self.assertEqual(t.body[1].value.values[1].lineno, 8)
300        self.assertEqual(t.body[1].value.values[2].lineno, 8)
301        self.assertEqual(t.body[1].col_offset, -1)
302        self.assertEqual(t.body[1].value.col_offset, -1)
303        self.assertEqual(t.body[1].value.values[0].col_offset, -1)
304        self.assertEqual(t.body[1].value.values[1].col_offset, -1)
305        self.assertEqual(t.body[1].value.values[2].col_offset, -1)
306        # NOTE: the following lineno information and col_offset is correct for
307        # expressions within FormattedValues.
308        binop = t.body[1].value.values[1].value
309        self.assertEqual(type(binop), ast.BinOp)
310        self.assertEqual(type(binop.left), ast.Name)
311        self.assertEqual(type(binop.op), ast.Mult)
312        self.assertEqual(type(binop.right), ast.Call)
313        self.assertEqual(binop.lineno, 4)
314        self.assertEqual(binop.left.lineno, 4)
315        self.assertEqual(binop.right.lineno, 6)
316        self.assertEqual(binop.col_offset, 3)
317        self.assertEqual(binop.left.col_offset, 3)
318        self.assertEqual(binop.right.col_offset, 7)
319
320    def test_docstring(self):
321        def f():
322            f'''Not a docstring'''
323        self.assertIsNone(f.__doc__)
324        def g():
325            '''Not a docstring''' \
326            f''
327        self.assertIsNone(g.__doc__)
328
329    def test_literal_eval(self):
330        with self.assertRaisesRegex(ValueError, 'malformed node or string'):
331            ast.literal_eval("f'x'")
332
333    def test_ast_compile_time_concat(self):
334        x = ['']
335
336        expr = """x[0] = 'foo' f'{3}'"""
337        t = ast.parse(expr)
338        c = compile(t, '', 'exec')
339        exec(c)
340        self.assertEqual(x[0], 'foo3')
341
342    def test_compile_time_concat_errors(self):
343        self.assertAllRaise(SyntaxError,
344                            'cannot mix bytes and nonbytes literals',
345                            [r"""f'' b''""",
346                             r"""b'' f''""",
347                             ])
348
349    def test_literal(self):
350        self.assertEqual(f'', '')
351        self.assertEqual(f'a', 'a')
352        self.assertEqual(f' ', ' ')
353
354    def test_unterminated_string(self):
355        self.assertAllRaise(SyntaxError, 'f-string: unterminated string',
356                            [r"""f'{"x'""",
357                             r"""f'{"x}'""",
358                             r"""f'{("x'""",
359                             r"""f'{("x}'""",
360                             ])
361
362    def test_mismatched_parens(self):
363        self.assertAllRaise(SyntaxError, 'f-string: mismatched',
364                            ["f'{((}'",
365                             ])
366
367    def test_double_braces(self):
368        self.assertEqual(f'{{', '{')
369        self.assertEqual(f'a{{', 'a{')
370        self.assertEqual(f'{{b', '{b')
371        self.assertEqual(f'a{{b', 'a{b')
372        self.assertEqual(f'}}', '}')
373        self.assertEqual(f'a}}', 'a}')
374        self.assertEqual(f'}}b', '}b')
375        self.assertEqual(f'a}}b', 'a}b')
376        self.assertEqual(f'{{}}', '{}')
377        self.assertEqual(f'a{{}}', 'a{}')
378        self.assertEqual(f'{{b}}', '{b}')
379        self.assertEqual(f'{{}}c', '{}c')
380        self.assertEqual(f'a{{b}}', 'a{b}')
381        self.assertEqual(f'a{{}}c', 'a{}c')
382        self.assertEqual(f'{{b}}c', '{b}c')
383        self.assertEqual(f'a{{b}}c', 'a{b}c')
384
385        self.assertEqual(f'{{{10}', '{10')
386        self.assertEqual(f'}}{10}', '}10')
387        self.assertEqual(f'}}{{{10}', '}{10')
388        self.assertEqual(f'}}a{{{10}', '}a{10')
389
390        self.assertEqual(f'{10}{{', '10{')
391        self.assertEqual(f'{10}}}', '10}')
392        self.assertEqual(f'{10}}}{{', '10}{')
393        self.assertEqual(f'{10}}}a{{' '}', '10}a{}')
394
395        # Inside of strings, don't interpret doubled brackets.
396        self.assertEqual(f'{"{{}}"}', '{{}}')
397
398        self.assertAllRaise(TypeError, 'unhashable type',
399                            ["f'{ {{}} }'", # dict in a set
400                             ])
401
402    def test_compile_time_concat(self):
403        x = 'def'
404        self.assertEqual('abc' f'## {x}ghi', 'abc## defghi')
405        self.assertEqual('abc' f'{x}' 'ghi', 'abcdefghi')
406        self.assertEqual('abc' f'{x}' 'gh' f'i{x:4}', 'abcdefghidef ')
407        self.assertEqual('{x}' f'{x}', '{x}def')
408        self.assertEqual('{x' f'{x}', '{xdef')
409        self.assertEqual('{x}' f'{x}', '{x}def')
410        self.assertEqual('{{x}}' f'{x}', '{{x}}def')
411        self.assertEqual('{{x' f'{x}', '{{xdef')
412        self.assertEqual('x}}' f'{x}', 'x}}def')
413        self.assertEqual(f'{x}' 'x}}', 'defx}}')
414        self.assertEqual(f'{x}' '', 'def')
415        self.assertEqual('' f'{x}' '', 'def')
416        self.assertEqual('' f'{x}', 'def')
417        self.assertEqual(f'{x}' '2', 'def2')
418        self.assertEqual('1' f'{x}' '2', '1def2')
419        self.assertEqual('1' f'{x}', '1def')
420        self.assertEqual(f'{x}' f'-{x}', 'def-def')
421        self.assertEqual('' f'', '')
422        self.assertEqual('' f'' '', '')
423        self.assertEqual('' f'' '' f'', '')
424        self.assertEqual(f'', '')
425        self.assertEqual(f'' '', '')
426        self.assertEqual(f'' '' f'', '')
427        self.assertEqual(f'' '' f'' '', '')
428
429        self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
430                            ["f'{3' f'}'",  # can't concat to get a valid f-string
431                             ])
432
433    def test_comments(self):
434        # These aren't comments, since they're in strings.
435        d = {'#': 'hash'}
436        self.assertEqual(f'{"#"}', '#')
437        self.assertEqual(f'{d["#"]}', 'hash')
438
439        self.assertAllRaise(SyntaxError, "f-string expression part cannot include '#'",
440                            ["f'{1#}'",   # error because the expression becomes "(1#)"
441                             "f'{3(#)}'",
442                             "f'{#}'",
443                             "f'{)#}'",   # When wrapped in parens, this becomes
444                                          #  '()#)'.  Make sure that doesn't compile.
445                             ])
446
447    def test_many_expressions(self):
448        # Create a string with many expressions in it. Note that
449        #  because we have a space in here as a literal, we're actually
450        #  going to use twice as many ast nodes: one for each literal
451        #  plus one for each expression.
452        def build_fstr(n, extra=''):
453            return "f'" + ('{x} ' * n) + extra + "'"
454
455        x = 'X'
456        width = 1
457
458        # Test around 256.
459        for i in range(250, 260):
460            self.assertEqual(eval(build_fstr(i)), (x+' ')*i)
461
462        # Test concatenating 2 largs fstrings.
463        self.assertEqual(eval(build_fstr(255)*256), (x+' ')*(255*256))
464
465        s = build_fstr(253, '{x:{width}} ')
466        self.assertEqual(eval(s), (x+' ')*254)
467
468        # Test lots of expressions and constants, concatenated.
469        s = "f'{1}' 'x' 'y'" * 1024
470        self.assertEqual(eval(s), '1xy' * 1024)
471
472    def test_format_specifier_expressions(self):
473        width = 10
474        precision = 4
475        value = decimal.Decimal('12.34567')
476        self.assertEqual(f'result: {value:{width}.{precision}}', 'result:      12.35')
477        self.assertEqual(f'result: {value:{width!r}.{precision}}', 'result:      12.35')
478        self.assertEqual(f'result: {value:{width:0}.{precision:1}}', 'result:      12.35')
479        self.assertEqual(f'result: {value:{1}{0:0}.{precision:1}}', 'result:      12.35')
480        self.assertEqual(f'result: {value:{ 1}{ 0:0}.{ precision:1}}', 'result:      12.35')
481        self.assertEqual(f'{10:#{1}0x}', '       0xa')
482        self.assertEqual(f'{10:{"#"}1{0}{"x"}}', '       0xa')
483        self.assertEqual(f'{-10:-{"#"}1{0}x}', '      -0xa')
484        self.assertEqual(f'{-10:{"-"}#{1}0{"x"}}', '      -0xa')
485        self.assertEqual(f'{10:#{3 != {4:5} and width}x}', '       0xa')
486
487        self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
488                            ["""f'{"s"!r{":10"}}'""",
489
490                             # This looks like a nested format spec.
491                             ])
492
493        self.assertAllRaise(SyntaxError, "invalid syntax",
494                            [# Invalid syntax inside a nested spec.
495                             "f'{4:{/5}}'",
496                             ])
497
498        self.assertAllRaise(SyntaxError, "f-string: expressions nested too deeply",
499                            [# Can't nest format specifiers.
500                             "f'result: {value:{width:{0}}.{precision:1}}'",
501                             ])
502
503        self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character',
504                            [# No expansion inside conversion or for
505                             #  the : or ! itself.
506                             """f'{"s"!{"r"}}'""",
507                             ])
508
509    def test_side_effect_order(self):
510        class X:
511            def __init__(self):
512                self.i = 0
513            def __format__(self, spec):
514                self.i += 1
515                return str(self.i)
516
517        x = X()
518        self.assertEqual(f'{x} {x}', '1 2')
519
520    def test_missing_expression(self):
521        self.assertAllRaise(SyntaxError, 'f-string: empty expression not allowed',
522                            ["f'{}'",
523                             "f'{ }'"
524                             "f' {} '",
525                             "f'{!r}'",
526                             "f'{ !r}'",
527                             "f'{10:{ }}'",
528                             "f' { } '",
529
530                             # The Python parser ignores also the following
531                             # whitespace characters in additional to a space.
532                             "f'''{\t\f\r\n}'''",
533
534                             # Catch the empty expression before the
535                             #  invalid conversion.
536                             "f'{!x}'",
537                             "f'{ !xr}'",
538                             "f'{!x:}'",
539                             "f'{!x:a}'",
540                             "f'{ !xr:}'",
541                             "f'{ !xr:a}'",
542
543                             "f'{!}'",
544                             "f'{:}'",
545
546                             # We find the empty expression before the
547                             #  missing closing brace.
548                             "f'{!'",
549                             "f'{!s:'",
550                             "f'{:'",
551                             "f'{:x'",
552                             ])
553
554        # Different error message is raised for other whitespace characters.
555        self.assertAllRaise(SyntaxError, 'invalid character in identifier',
556                            ["f'''{\xa0}'''",
557                             "\xa0",
558                             ])
559
560    def test_parens_in_expressions(self):
561        self.assertEqual(f'{3,}', '(3,)')
562
563        # Add these because when an expression is evaluated, parens
564        #  are added around it. But we shouldn't go from an invalid
565        #  expression to a valid one. The added parens are just
566        #  supposed to allow whitespace (including newlines).
567        self.assertAllRaise(SyntaxError, 'invalid syntax',
568                            ["f'{,}'",
569                             "f'{,}'",  # this is (,), which is an error
570                             ])
571
572        self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
573                            ["f'{3)+(4}'",
574                             ])
575
576        self.assertAllRaise(SyntaxError, 'EOL while scanning string literal',
577                            ["f'{\n}'",
578                             ])
579
580    def test_backslashes_in_string_part(self):
581        self.assertEqual(f'\t', '\t')
582        self.assertEqual(r'\t', '\\t')
583        self.assertEqual(rf'\t', '\\t')
584        self.assertEqual(f'{2}\t', '2\t')
585        self.assertEqual(f'{2}\t{3}', '2\t3')
586        self.assertEqual(f'\t{3}', '\t3')
587
588        self.assertEqual(f'\u0394', '\u0394')
589        self.assertEqual(r'\u0394', '\\u0394')
590        self.assertEqual(rf'\u0394', '\\u0394')
591        self.assertEqual(f'{2}\u0394', '2\u0394')
592        self.assertEqual(f'{2}\u0394{3}', '2\u03943')
593        self.assertEqual(f'\u0394{3}', '\u03943')
594
595        self.assertEqual(f'\U00000394', '\u0394')
596        self.assertEqual(r'\U00000394', '\\U00000394')
597        self.assertEqual(rf'\U00000394', '\\U00000394')
598        self.assertEqual(f'{2}\U00000394', '2\u0394')
599        self.assertEqual(f'{2}\U00000394{3}', '2\u03943')
600        self.assertEqual(f'\U00000394{3}', '\u03943')
601
602        self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}', '\u0394')
603        self.assertEqual(f'{2}\N{GREEK CAPITAL LETTER DELTA}', '2\u0394')
604        self.assertEqual(f'{2}\N{GREEK CAPITAL LETTER DELTA}{3}', '2\u03943')
605        self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}{3}', '\u03943')
606        self.assertEqual(f'2\N{GREEK CAPITAL LETTER DELTA}', '2\u0394')
607        self.assertEqual(f'2\N{GREEK CAPITAL LETTER DELTA}3', '2\u03943')
608        self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}3', '\u03943')
609
610        self.assertEqual(f'\x20', ' ')
611        self.assertEqual(r'\x20', '\\x20')
612        self.assertEqual(rf'\x20', '\\x20')
613        self.assertEqual(f'{2}\x20', '2 ')
614        self.assertEqual(f'{2}\x20{3}', '2 3')
615        self.assertEqual(f'\x20{3}', ' 3')
616
617        self.assertEqual(f'2\x20', '2 ')
618        self.assertEqual(f'2\x203', '2 3')
619        self.assertEqual(f'\x203', ' 3')
620
621        with self.assertWarns(DeprecationWarning):  # invalid escape sequence
622            value = eval(r"f'\{6*7}'")
623        self.assertEqual(value, '\\42')
624        self.assertEqual(f'\\{6*7}', '\\42')
625        self.assertEqual(fr'\{6*7}', '\\42')
626
627        AMPERSAND = 'spam'
628        # Get the right unicode character (&), or pick up local variable
629        # depending on the number of backslashes.
630        self.assertEqual(f'\N{AMPERSAND}', '&')
631        self.assertEqual(f'\\N{AMPERSAND}', '\\Nspam')
632        self.assertEqual(fr'\N{AMPERSAND}', '\\Nspam')
633        self.assertEqual(f'\\\N{AMPERSAND}', '\\&')
634
635    def test_misformed_unicode_character_name(self):
636        # These test are needed because unicode names are parsed
637        # differently inside f-strings.
638        self.assertAllRaise(SyntaxError, r"\(unicode error\) 'unicodeescape' codec can't decode bytes in position .*: malformed \\N character escape",
639                            [r"f'\N'",
640                             r"f'\N{'",
641                             r"f'\N{GREEK CAPITAL LETTER DELTA'",
642
643                             # Here are the non-f-string versions,
644                             #  which should give the same errors.
645                             r"'\N'",
646                             r"'\N{'",
647                             r"'\N{GREEK CAPITAL LETTER DELTA'",
648                             ])
649
650    def test_no_backslashes_in_expression_part(self):
651        self.assertAllRaise(SyntaxError, 'f-string expression part cannot include a backslash',
652                            [r"f'{\'a\'}'",
653                             r"f'{\t3}'",
654                             r"f'{\}'",
655                             r"rf'{\'a\'}'",
656                             r"rf'{\t3}'",
657                             r"rf'{\}'",
658                             r"""rf'{"\N{LEFT CURLY BRACKET}"}'""",
659                             r"f'{\n}'",
660                             ])
661
662    def test_no_escapes_for_braces(self):
663        """
664        Only literal curly braces begin an expression.
665        """
666        # \x7b is '{'.
667        self.assertEqual(f'\x7b1+1}}', '{1+1}')
668        self.assertEqual(f'\x7b1+1', '{1+1')
669        self.assertEqual(f'\u007b1+1', '{1+1')
670        self.assertEqual(f'\N{LEFT CURLY BRACKET}1+1\N{RIGHT CURLY BRACKET}', '{1+1}')
671
672    def test_newlines_in_expressions(self):
673        self.assertEqual(f'{0}', '0')
674        self.assertEqual(rf'''{3+
6754}''', '7')
676
677    def test_lambda(self):
678        x = 5
679        self.assertEqual(f'{(lambda y:x*y)("8")!r}', "'88888'")
680        self.assertEqual(f'{(lambda y:x*y)("8")!r:10}', "'88888'   ")
681        self.assertEqual(f'{(lambda y:x*y)("8"):10}', "88888     ")
682
683        # lambda doesn't work without parens, because the colon
684        #  makes the parser think it's a format_spec
685        self.assertAllRaise(SyntaxError, 'unexpected EOF while parsing',
686                            ["f'{lambda x:x}'",
687                             ])
688
689    def test_yield(self):
690        # Not terribly useful, but make sure the yield turns
691        #  a function into a generator
692        def fn(y):
693            f'y:{yield y*2}'
694
695        g = fn(4)
696        self.assertEqual(next(g), 8)
697
698    def test_yield_send(self):
699        def fn(x):
700            yield f'x:{yield (lambda i: x * i)}'
701
702        g = fn(10)
703        the_lambda = next(g)
704        self.assertEqual(the_lambda(4), 40)
705        self.assertEqual(g.send('string'), 'x:string')
706
707    def test_expressions_with_triple_quoted_strings(self):
708        self.assertEqual(f"{'''x'''}", 'x')
709        self.assertEqual(f"{'''eric's'''}", "eric's")
710
711        # Test concatenation within an expression
712        self.assertEqual(f'{"x" """eric"s""" "y"}', 'xeric"sy')
713        self.assertEqual(f'{"x" """eric"s"""}', 'xeric"s')
714        self.assertEqual(f'{"""eric"s""" "y"}', 'eric"sy')
715        self.assertEqual(f'{"""x""" """eric"s""" "y"}', 'xeric"sy')
716        self.assertEqual(f'{"""x""" """eric"s""" """y"""}', 'xeric"sy')
717        self.assertEqual(f'{r"""x""" """eric"s""" """y"""}', 'xeric"sy')
718
719    def test_multiple_vars(self):
720        x = 98
721        y = 'abc'
722        self.assertEqual(f'{x}{y}', '98abc')
723
724        self.assertEqual(f'X{x}{y}', 'X98abc')
725        self.assertEqual(f'{x}X{y}', '98Xabc')
726        self.assertEqual(f'{x}{y}X', '98abcX')
727
728        self.assertEqual(f'X{x}Y{y}', 'X98Yabc')
729        self.assertEqual(f'X{x}{y}Y', 'X98abcY')
730        self.assertEqual(f'{x}X{y}Y', '98XabcY')
731
732        self.assertEqual(f'X{x}Y{y}Z', 'X98YabcZ')
733
734    def test_closure(self):
735        def outer(x):
736            def inner():
737                return f'x:{x}'
738            return inner
739
740        self.assertEqual(outer('987')(), 'x:987')
741        self.assertEqual(outer(7)(), 'x:7')
742
743    def test_arguments(self):
744        y = 2
745        def f(x, width):
746            return f'x={x*y:{width}}'
747
748        self.assertEqual(f('foo', 10), 'x=foofoo    ')
749        x = 'bar'
750        self.assertEqual(f(10, 10), 'x=        20')
751
752    def test_locals(self):
753        value = 123
754        self.assertEqual(f'v:{value}', 'v:123')
755
756    def test_missing_variable(self):
757        with self.assertRaises(NameError):
758            f'v:{value}'
759
760    def test_missing_format_spec(self):
761        class O:
762            def __format__(self, spec):
763                if not spec:
764                    return '*'
765                return spec
766
767        self.assertEqual(f'{O():x}', 'x')
768        self.assertEqual(f'{O()}', '*')
769        self.assertEqual(f'{O():}', '*')
770
771        self.assertEqual(f'{3:}', '3')
772        self.assertEqual(f'{3!s:}', '3')
773
774    def test_global(self):
775        self.assertEqual(f'g:{a_global}', 'g:global variable')
776        self.assertEqual(f'g:{a_global!r}', "g:'global variable'")
777
778        a_local = 'local variable'
779        self.assertEqual(f'g:{a_global} l:{a_local}',
780                         'g:global variable l:local variable')
781        self.assertEqual(f'g:{a_global!r}',
782                         "g:'global variable'")
783        self.assertEqual(f'g:{a_global} l:{a_local!r}',
784                         "g:global variable l:'local variable'")
785
786        self.assertIn("module 'unittest' from", f'{unittest}')
787
788    def test_shadowed_global(self):
789        a_global = 'really a local'
790        self.assertEqual(f'g:{a_global}', 'g:really a local')
791        self.assertEqual(f'g:{a_global!r}', "g:'really a local'")
792
793        a_local = 'local variable'
794        self.assertEqual(f'g:{a_global} l:{a_local}',
795                         'g:really a local l:local variable')
796        self.assertEqual(f'g:{a_global!r}',
797                         "g:'really a local'")
798        self.assertEqual(f'g:{a_global} l:{a_local!r}',
799                         "g:really a local l:'local variable'")
800
801    def test_call(self):
802        def foo(x):
803            return 'x=' + str(x)
804
805        self.assertEqual(f'{foo(10)}', 'x=10')
806
807    def test_nested_fstrings(self):
808        y = 5
809        self.assertEqual(f'{f"{0}"*3}', '000')
810        self.assertEqual(f'{f"{y}"*3}', '555')
811
812    def test_invalid_string_prefixes(self):
813        self.assertAllRaise(SyntaxError, 'unexpected EOF while parsing',
814                            ["fu''",
815                             "uf''",
816                             "Fu''",
817                             "fU''",
818                             "Uf''",
819                             "uF''",
820                             "ufr''",
821                             "urf''",
822                             "fur''",
823                             "fru''",
824                             "rfu''",
825                             "ruf''",
826                             "FUR''",
827                             "Fur''",
828                             "fb''",
829                             "fB''",
830                             "Fb''",
831                             "FB''",
832                             "bf''",
833                             "bF''",
834                             "Bf''",
835                             "BF''",
836                             ])
837
838    def test_leading_trailing_spaces(self):
839        self.assertEqual(f'{ 3}', '3')
840        self.assertEqual(f'{  3}', '3')
841        self.assertEqual(f'{3 }', '3')
842        self.assertEqual(f'{3  }', '3')
843
844        self.assertEqual(f'expr={ {x: y for x, y in [(1, 2), ]}}',
845                         'expr={1: 2}')
846        self.assertEqual(f'expr={ {x: y for x, y in [(1, 2), ]} }',
847                         'expr={1: 2}')
848
849    def test_not_equal(self):
850        # There's a special test for this because there's a special
851        #  case in the f-string parser to look for != as not ending an
852        #  expression. Normally it would, while looking for !s or !r.
853
854        self.assertEqual(f'{3!=4}', 'True')
855        self.assertEqual(f'{3!=4:}', 'True')
856        self.assertEqual(f'{3!=4!s}', 'True')
857        self.assertEqual(f'{3!=4!s:.3}', 'Tru')
858
859    def test_conversions(self):
860        self.assertEqual(f'{3.14:10.10}', '      3.14')
861        self.assertEqual(f'{3.14!s:10.10}', '3.14      ')
862        self.assertEqual(f'{3.14!r:10.10}', '3.14      ')
863        self.assertEqual(f'{3.14!a:10.10}', '3.14      ')
864
865        self.assertEqual(f'{"a"}', 'a')
866        self.assertEqual(f'{"a"!r}', "'a'")
867        self.assertEqual(f'{"a"!a}', "'a'")
868
869        # Not a conversion.
870        self.assertEqual(f'{"a!r"}', "a!r")
871
872        # Not a conversion, but show that ! is allowed in a format spec.
873        self.assertEqual(f'{3.14:!<10.10}', '3.14!!!!!!')
874
875        self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character',
876                            ["f'{3!g}'",
877                             "f'{3!A}'",
878                             "f'{3!3}'",
879                             "f'{3!G}'",
880                             "f'{3!!}'",
881                             "f'{3!:}'",
882                             "f'{3! s}'",  # no space before conversion char
883                             ])
884
885        self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
886                            ["f'{x!s{y}}'",
887                             "f'{3!ss}'",
888                             "f'{3!ss:}'",
889                             "f'{3!ss:s}'",
890                             ])
891
892    def test_assignment(self):
893        self.assertAllRaise(SyntaxError, 'invalid syntax',
894                            ["f'' = 3",
895                             "f'{0}' = x",
896                             "f'{x}' = x",
897                             ])
898
899    def test_del(self):
900        self.assertAllRaise(SyntaxError, 'invalid syntax',
901                            ["del f''",
902                             "del '' f''",
903                             ])
904
905    def test_mismatched_braces(self):
906        self.assertAllRaise(SyntaxError, "f-string: single '}' is not allowed",
907                            ["f'{{}'",
908                             "f'{{}}}'",
909                             "f'}'",
910                             "f'x}'",
911                             "f'x}x'",
912                             r"f'\u007b}'",
913
914                             # Can't have { or } in a format spec.
915                             "f'{3:}>10}'",
916                             "f'{3:}}>10}'",
917                             ])
918
919        self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
920                            ["f'{3:{{>10}'",
921                             "f'{3'",
922                             "f'{3!'",
923                             "f'{3:'",
924                             "f'{3!s'",
925                             "f'{3!s:'",
926                             "f'{3!s:3'",
927                             "f'x{'",
928                             "f'x{x'",
929                             "f'{x'",
930                             "f'{3:s'",
931                             "f'{{{'",
932                             "f'{{}}{'",
933                             "f'{'",
934                             ])
935
936        # But these are just normal strings.
937        self.assertEqual(f'{"{"}', '{')
938        self.assertEqual(f'{"}"}', '}')
939        self.assertEqual(f'{3:{"}"}>10}', '}}}}}}}}}3')
940        self.assertEqual(f'{2:{"{"}>10}', '{{{{{{{{{2')
941
942    def test_if_conditional(self):
943        # There's special logic in compile.c to test if the
944        #  conditional for an if (and while) are constants. Exercise
945        #  that code.
946
947        def test_fstring(x, expected):
948            flag = 0
949            if f'{x}':
950                flag = 1
951            else:
952                flag = 2
953            self.assertEqual(flag, expected)
954
955        def test_concat_empty(x, expected):
956            flag = 0
957            if '' f'{x}':
958                flag = 1
959            else:
960                flag = 2
961            self.assertEqual(flag, expected)
962
963        def test_concat_non_empty(x, expected):
964            flag = 0
965            if ' ' f'{x}':
966                flag = 1
967            else:
968                flag = 2
969            self.assertEqual(flag, expected)
970
971        test_fstring('', 2)
972        test_fstring(' ', 1)
973
974        test_concat_empty('', 2)
975        test_concat_empty(' ', 1)
976
977        test_concat_non_empty('', 1)
978        test_concat_non_empty(' ', 1)
979
980    def test_empty_format_specifier(self):
981        x = 'test'
982        self.assertEqual(f'{x}', 'test')
983        self.assertEqual(f'{x:}', 'test')
984        self.assertEqual(f'{x!s:}', 'test')
985        self.assertEqual(f'{x!r:}', "'test'")
986
987    def test_str_format_differences(self):
988        d = {'a': 'string',
989             0: 'integer',
990             }
991        a = 0
992        self.assertEqual(f'{d[0]}', 'integer')
993        self.assertEqual(f'{d["a"]}', 'string')
994        self.assertEqual(f'{d[a]}', 'integer')
995        self.assertEqual('{d[a]}'.format(d=d), 'string')
996        self.assertEqual('{d[0]}'.format(d=d), 'integer')
997
998    def test_invalid_expressions(self):
999        self.assertAllRaise(SyntaxError, 'invalid syntax',
1000                            [r"f'{a[4)}'",
1001                             r"f'{a(4]}'",
1002                            ])
1003
1004    def test_errors(self):
1005        # see issue 26287
1006        self.assertAllRaise(TypeError, 'unsupported',
1007                            [r"f'{(lambda: 0):x}'",
1008                             r"f'{(0,):x}'",
1009                             ])
1010        self.assertAllRaise(ValueError, 'Unknown format code',
1011                            [r"f'{1000:j}'",
1012                             r"f'{1000:j}'",
1013                            ])
1014
1015    def test_loop(self):
1016        for i in range(1000):
1017            self.assertEqual(f'i:{i}', 'i:' + str(i))
1018
1019    def test_dict(self):
1020        d = {'"': 'dquote',
1021             "'": 'squote',
1022             'foo': 'bar',
1023             }
1024        self.assertEqual(f'''{d["'"]}''', 'squote')
1025        self.assertEqual(f"""{d['"']}""", 'dquote')
1026
1027        self.assertEqual(f'{d["foo"]}', 'bar')
1028        self.assertEqual(f"{d['foo']}", 'bar')
1029
1030    def test_backslash_char(self):
1031        # Check eval of a backslash followed by a control char.
1032        # See bpo-30682: this used to raise an assert in pydebug mode.
1033        self.assertEqual(eval('f"\\\n"'), '')
1034        self.assertEqual(eval('f"\\\r"'), '')
1035
1036
1037if __name__ == '__main__':
1038    unittest.main()
1039