(root)/
Python-3.11.7/
Lib/
test/
test_fstring.py
       1  # -*- coding: utf-8 -*-
       2  # There are tests here with unicode string literals and
       3  # identifiers. There's a code in ast.c that was added because of a
       4  # failure with a non-ascii-only expression.  So, I have tests for
       5  # that.  There are workarounds that would let me run tests for that
       6  # code without unicode identifiers and strings, but just using them
       7  # directly seems like the easiest and therefore safest thing to do.
       8  # Unicode identifiers in tests is allowed by PEP 3131.
       9  
      10  import ast
      11  import os
      12  import re
      13  import types
      14  import decimal
      15  import unittest
      16  from test.support.os_helper import temp_cwd
      17  from test.support.script_helper import assert_python_failure
      18  
      19  a_global = 'global variable'
      20  
      21  # You could argue that I'm too strict in looking for specific error
      22  #  values with assertRaisesRegex, but without it it's way too easy to
      23  #  make a syntax error in the test strings. Especially with all of the
      24  #  triple quotes, raw strings, backslashes, etc. I think it's a
      25  #  worthwhile tradeoff. When I switched to this method, I found many
      26  #  examples where I wasn't testing what I thought I was.
      27  
      28  class ESC[4;38;5;81mTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      29      def assertAllRaise(self, exception_type, regex, error_strings):
      30          for str in error_strings:
      31              with self.subTest(str=str):
      32                  with self.assertRaisesRegex(exception_type, regex):
      33                      eval(str)
      34  
      35      def test__format__lookup(self):
      36          # Make sure __format__ is looked up on the type, not the instance.
      37          class ESC[4;38;5;81mX:
      38              def __format__(self, spec):
      39                  return 'class'
      40  
      41          x = X()
      42  
      43          # Add a bound __format__ method to the 'y' instance, but not
      44          #  the 'x' instance.
      45          y = X()
      46          y.__format__ = types.MethodType(lambda self, spec: 'instance', y)
      47  
      48          self.assertEqual(f'{y}', format(y))
      49          self.assertEqual(f'{y}', 'class')
      50          self.assertEqual(format(x), format(y))
      51  
      52          # __format__ is not called this way, but still make sure it
      53          #  returns what we expect (so we can make sure we're bypassing
      54          #  it).
      55          self.assertEqual(x.__format__(''), 'class')
      56          self.assertEqual(y.__format__(''), 'instance')
      57  
      58          # This is how __format__ is actually called.
      59          self.assertEqual(type(x).__format__(x, ''), 'class')
      60          self.assertEqual(type(y).__format__(y, ''), 'class')
      61  
      62      def test_ast(self):
      63          # Inspired by http://bugs.python.org/issue24975
      64          class ESC[4;38;5;81mX:
      65              def __init__(self):
      66                  self.called = False
      67              def __call__(self):
      68                  self.called = True
      69                  return 4
      70          x = X()
      71          expr = """
      72  a = 10
      73  f'{a * x()}'"""
      74          t = ast.parse(expr)
      75          c = compile(t, '', 'exec')
      76  
      77          # Make sure x was not called.
      78          self.assertFalse(x.called)
      79  
      80          # Actually run the code.
      81          exec(c)
      82  
      83          # Make sure x was called.
      84          self.assertTrue(x.called)
      85  
      86      def test_ast_line_numbers(self):
      87          expr = """
      88  a = 10
      89  f'{a * x()}'"""
      90          t = ast.parse(expr)
      91          self.assertEqual(type(t), ast.Module)
      92          self.assertEqual(len(t.body), 2)
      93          # check `a = 10`
      94          self.assertEqual(type(t.body[0]), ast.Assign)
      95          self.assertEqual(t.body[0].lineno, 2)
      96          # check `f'...'`
      97          self.assertEqual(type(t.body[1]), ast.Expr)
      98          self.assertEqual(type(t.body[1].value), ast.JoinedStr)
      99          self.assertEqual(len(t.body[1].value.values), 1)
     100          self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)
     101          self.assertEqual(t.body[1].lineno, 3)
     102          self.assertEqual(t.body[1].value.lineno, 3)
     103          self.assertEqual(t.body[1].value.values[0].lineno, 3)
     104          # check the binop location
     105          binop = t.body[1].value.values[0].value
     106          self.assertEqual(type(binop), ast.BinOp)
     107          self.assertEqual(type(binop.left), ast.Name)
     108          self.assertEqual(type(binop.op), ast.Mult)
     109          self.assertEqual(type(binop.right), ast.Call)
     110          self.assertEqual(binop.lineno, 3)
     111          self.assertEqual(binop.left.lineno, 3)
     112          self.assertEqual(binop.right.lineno, 3)
     113          self.assertEqual(binop.col_offset, 3)
     114          self.assertEqual(binop.left.col_offset, 3)
     115          self.assertEqual(binop.right.col_offset, 7)
     116  
     117      def test_ast_line_numbers_multiple_formattedvalues(self):
     118          expr = """
     119  f'no formatted values'
     120  f'eggs {a * x()} spam {b + y()}'"""
     121          t = ast.parse(expr)
     122          self.assertEqual(type(t), ast.Module)
     123          self.assertEqual(len(t.body), 2)
     124          # check `f'no formatted value'`
     125          self.assertEqual(type(t.body[0]), ast.Expr)
     126          self.assertEqual(type(t.body[0].value), ast.JoinedStr)
     127          self.assertEqual(t.body[0].lineno, 2)
     128          # check `f'...'`
     129          self.assertEqual(type(t.body[1]), ast.Expr)
     130          self.assertEqual(type(t.body[1].value), ast.JoinedStr)
     131          self.assertEqual(len(t.body[1].value.values), 4)
     132          self.assertEqual(type(t.body[1].value.values[0]), ast.Constant)
     133          self.assertEqual(type(t.body[1].value.values[0].value), str)
     134          self.assertEqual(type(t.body[1].value.values[1]), ast.FormattedValue)
     135          self.assertEqual(type(t.body[1].value.values[2]), ast.Constant)
     136          self.assertEqual(type(t.body[1].value.values[2].value), str)
     137          self.assertEqual(type(t.body[1].value.values[3]), ast.FormattedValue)
     138          self.assertEqual(t.body[1].lineno, 3)
     139          self.assertEqual(t.body[1].value.lineno, 3)
     140          self.assertEqual(t.body[1].value.values[0].lineno, 3)
     141          self.assertEqual(t.body[1].value.values[1].lineno, 3)
     142          self.assertEqual(t.body[1].value.values[2].lineno, 3)
     143          self.assertEqual(t.body[1].value.values[3].lineno, 3)
     144          # check the first binop location
     145          binop1 = t.body[1].value.values[1].value
     146          self.assertEqual(type(binop1), ast.BinOp)
     147          self.assertEqual(type(binop1.left), ast.Name)
     148          self.assertEqual(type(binop1.op), ast.Mult)
     149          self.assertEqual(type(binop1.right), ast.Call)
     150          self.assertEqual(binop1.lineno, 3)
     151          self.assertEqual(binop1.left.lineno, 3)
     152          self.assertEqual(binop1.right.lineno, 3)
     153          self.assertEqual(binop1.col_offset, 8)
     154          self.assertEqual(binop1.left.col_offset, 8)
     155          self.assertEqual(binop1.right.col_offset, 12)
     156          # check the second binop location
     157          binop2 = t.body[1].value.values[3].value
     158          self.assertEqual(type(binop2), ast.BinOp)
     159          self.assertEqual(type(binop2.left), ast.Name)
     160          self.assertEqual(type(binop2.op), ast.Add)
     161          self.assertEqual(type(binop2.right), ast.Call)
     162          self.assertEqual(binop2.lineno, 3)
     163          self.assertEqual(binop2.left.lineno, 3)
     164          self.assertEqual(binop2.right.lineno, 3)
     165          self.assertEqual(binop2.col_offset, 23)
     166          self.assertEqual(binop2.left.col_offset, 23)
     167          self.assertEqual(binop2.right.col_offset, 27)
     168  
     169      def test_ast_line_numbers_nested(self):
     170          expr = """
     171  a = 10
     172  f'{a * f"-{x()}-"}'"""
     173          t = ast.parse(expr)
     174          self.assertEqual(type(t), ast.Module)
     175          self.assertEqual(len(t.body), 2)
     176          # check `a = 10`
     177          self.assertEqual(type(t.body[0]), ast.Assign)
     178          self.assertEqual(t.body[0].lineno, 2)
     179          # check `f'...'`
     180          self.assertEqual(type(t.body[1]), ast.Expr)
     181          self.assertEqual(type(t.body[1].value), ast.JoinedStr)
     182          self.assertEqual(len(t.body[1].value.values), 1)
     183          self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)
     184          self.assertEqual(t.body[1].lineno, 3)
     185          self.assertEqual(t.body[1].value.lineno, 3)
     186          self.assertEqual(t.body[1].value.values[0].lineno, 3)
     187          # check the binop location
     188          binop = t.body[1].value.values[0].value
     189          self.assertEqual(type(binop), ast.BinOp)
     190          self.assertEqual(type(binop.left), ast.Name)
     191          self.assertEqual(type(binop.op), ast.Mult)
     192          self.assertEqual(type(binop.right), ast.JoinedStr)
     193          self.assertEqual(binop.lineno, 3)
     194          self.assertEqual(binop.left.lineno, 3)
     195          self.assertEqual(binop.right.lineno, 3)
     196          self.assertEqual(binop.col_offset, 3)
     197          self.assertEqual(binop.left.col_offset, 3)
     198          self.assertEqual(binop.right.col_offset, 7)
     199          # check the nested call location
     200          self.assertEqual(len(binop.right.values), 3)
     201          self.assertEqual(type(binop.right.values[0]), ast.Constant)
     202          self.assertEqual(type(binop.right.values[0].value), str)
     203          self.assertEqual(type(binop.right.values[1]), ast.FormattedValue)
     204          self.assertEqual(type(binop.right.values[2]), ast.Constant)
     205          self.assertEqual(type(binop.right.values[2].value), str)
     206          self.assertEqual(binop.right.values[0].lineno, 3)
     207          self.assertEqual(binop.right.values[1].lineno, 3)
     208          self.assertEqual(binop.right.values[2].lineno, 3)
     209          call = binop.right.values[1].value
     210          self.assertEqual(type(call), ast.Call)
     211          self.assertEqual(call.lineno, 3)
     212          self.assertEqual(call.col_offset, 11)
     213  
     214      def test_ast_line_numbers_duplicate_expression(self):
     215          expr = """
     216  a = 10
     217  f'{a * x()} {a * x()} {a * x()}'
     218  """
     219          t = ast.parse(expr)
     220          self.assertEqual(type(t), ast.Module)
     221          self.assertEqual(len(t.body), 2)
     222          # check `a = 10`
     223          self.assertEqual(type(t.body[0]), ast.Assign)
     224          self.assertEqual(t.body[0].lineno, 2)
     225          # check `f'...'`
     226          self.assertEqual(type(t.body[1]), ast.Expr)
     227          self.assertEqual(type(t.body[1].value), ast.JoinedStr)
     228          self.assertEqual(len(t.body[1].value.values), 5)
     229          self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)
     230          self.assertEqual(type(t.body[1].value.values[1]), ast.Constant)
     231          self.assertEqual(type(t.body[1].value.values[1].value), str)
     232          self.assertEqual(type(t.body[1].value.values[2]), ast.FormattedValue)
     233          self.assertEqual(type(t.body[1].value.values[3]), ast.Constant)
     234          self.assertEqual(type(t.body[1].value.values[3].value), str)
     235          self.assertEqual(type(t.body[1].value.values[4]), ast.FormattedValue)
     236          self.assertEqual(t.body[1].lineno, 3)
     237          self.assertEqual(t.body[1].value.lineno, 3)
     238          self.assertEqual(t.body[1].value.values[0].lineno, 3)
     239          self.assertEqual(t.body[1].value.values[1].lineno, 3)
     240          self.assertEqual(t.body[1].value.values[2].lineno, 3)
     241          self.assertEqual(t.body[1].value.values[3].lineno, 3)
     242          self.assertEqual(t.body[1].value.values[4].lineno, 3)
     243          # check the first binop location
     244          binop = t.body[1].value.values[0].value
     245          self.assertEqual(type(binop), ast.BinOp)
     246          self.assertEqual(type(binop.left), ast.Name)
     247          self.assertEqual(type(binop.op), ast.Mult)
     248          self.assertEqual(type(binop.right), ast.Call)
     249          self.assertEqual(binop.lineno, 3)
     250          self.assertEqual(binop.left.lineno, 3)
     251          self.assertEqual(binop.right.lineno, 3)
     252          self.assertEqual(binop.col_offset, 3)
     253          self.assertEqual(binop.left.col_offset, 3)
     254          self.assertEqual(binop.right.col_offset, 7)
     255          # check the second binop location
     256          binop = t.body[1].value.values[2].value
     257          self.assertEqual(type(binop), ast.BinOp)
     258          self.assertEqual(type(binop.left), ast.Name)
     259          self.assertEqual(type(binop.op), ast.Mult)
     260          self.assertEqual(type(binop.right), ast.Call)
     261          self.assertEqual(binop.lineno, 3)
     262          self.assertEqual(binop.left.lineno, 3)
     263          self.assertEqual(binop.right.lineno, 3)
     264          self.assertEqual(binop.col_offset, 13)
     265          self.assertEqual(binop.left.col_offset, 13)
     266          self.assertEqual(binop.right.col_offset, 17)
     267          # check the third binop location
     268          binop = t.body[1].value.values[4].value
     269          self.assertEqual(type(binop), ast.BinOp)
     270          self.assertEqual(type(binop.left), ast.Name)
     271          self.assertEqual(type(binop.op), ast.Mult)
     272          self.assertEqual(type(binop.right), ast.Call)
     273          self.assertEqual(binop.lineno, 3)
     274          self.assertEqual(binop.left.lineno, 3)
     275          self.assertEqual(binop.right.lineno, 3)
     276          self.assertEqual(binop.col_offset, 23)
     277          self.assertEqual(binop.left.col_offset, 23)
     278          self.assertEqual(binop.right.col_offset, 27)
     279  
     280      def test_ast_numbers_fstring_with_formatting(self):
     281  
     282          t = ast.parse('f"Here is that pesky {xxx:.3f} again"')
     283          self.assertEqual(len(t.body), 1)
     284          self.assertEqual(t.body[0].lineno, 1)
     285  
     286          self.assertEqual(type(t.body[0]), ast.Expr)
     287          self.assertEqual(type(t.body[0].value), ast.JoinedStr)
     288          self.assertEqual(len(t.body[0].value.values), 3)
     289  
     290          self.assertEqual(type(t.body[0].value.values[0]), ast.Constant)
     291          self.assertEqual(type(t.body[0].value.values[1]), ast.FormattedValue)
     292          self.assertEqual(type(t.body[0].value.values[2]), ast.Constant)
     293  
     294          _, expr, _ = t.body[0].value.values
     295  
     296          name = expr.value
     297          self.assertEqual(type(name), ast.Name)
     298          self.assertEqual(name.lineno, 1)
     299          self.assertEqual(name.end_lineno, 1)
     300          self.assertEqual(name.col_offset, 22)
     301          self.assertEqual(name.end_col_offset, 25)
     302  
     303      def test_ast_line_numbers_multiline_fstring(self):
     304          # See bpo-30465 for details.
     305          expr = """
     306  a = 10
     307  f'''
     308    {a
     309       *
     310         x()}
     311  non-important content
     312  '''
     313  """
     314          t = ast.parse(expr)
     315          self.assertEqual(type(t), ast.Module)
     316          self.assertEqual(len(t.body), 2)
     317          # check `a = 10`
     318          self.assertEqual(type(t.body[0]), ast.Assign)
     319          self.assertEqual(t.body[0].lineno, 2)
     320          # check `f'...'`
     321          self.assertEqual(type(t.body[1]), ast.Expr)
     322          self.assertEqual(type(t.body[1].value), ast.JoinedStr)
     323          self.assertEqual(len(t.body[1].value.values), 3)
     324          self.assertEqual(type(t.body[1].value.values[0]), ast.Constant)
     325          self.assertEqual(type(t.body[1].value.values[0].value), str)
     326          self.assertEqual(type(t.body[1].value.values[1]), ast.FormattedValue)
     327          self.assertEqual(type(t.body[1].value.values[2]), ast.Constant)
     328          self.assertEqual(type(t.body[1].value.values[2].value), str)
     329          self.assertEqual(t.body[1].lineno, 3)
     330          self.assertEqual(t.body[1].value.lineno, 3)
     331          self.assertEqual(t.body[1].value.values[0].lineno, 3)
     332          self.assertEqual(t.body[1].value.values[1].lineno, 3)
     333          self.assertEqual(t.body[1].value.values[2].lineno, 3)
     334          self.assertEqual(t.body[1].col_offset, 0)
     335          self.assertEqual(t.body[1].value.col_offset, 0)
     336          self.assertEqual(t.body[1].value.values[0].col_offset, 0)
     337          self.assertEqual(t.body[1].value.values[1].col_offset, 0)
     338          self.assertEqual(t.body[1].value.values[2].col_offset, 0)
     339          # NOTE: the following lineno information and col_offset is correct for
     340          # expressions within FormattedValues.
     341          binop = t.body[1].value.values[1].value
     342          self.assertEqual(type(binop), ast.BinOp)
     343          self.assertEqual(type(binop.left), ast.Name)
     344          self.assertEqual(type(binop.op), ast.Mult)
     345          self.assertEqual(type(binop.right), ast.Call)
     346          self.assertEqual(binop.lineno, 4)
     347          self.assertEqual(binop.left.lineno, 4)
     348          self.assertEqual(binop.right.lineno, 6)
     349          self.assertEqual(binop.col_offset, 3)
     350          self.assertEqual(binop.left.col_offset, 3)
     351          self.assertEqual(binop.right.col_offset, 7)
     352  
     353          expr = """
     354  a = f'''
     355            {blech}
     356      '''
     357  """
     358          t = ast.parse(expr)
     359          self.assertEqual(type(t), ast.Module)
     360          self.assertEqual(len(t.body), 1)
     361          # Check f'...'
     362          self.assertEqual(type(t.body[0]), ast.Assign)
     363          self.assertEqual(type(t.body[0].value), ast.JoinedStr)
     364          self.assertEqual(len(t.body[0].value.values), 3)
     365          self.assertEqual(type(t.body[0].value.values[1]), ast.FormattedValue)
     366          self.assertEqual(t.body[0].lineno, 2)
     367          self.assertEqual(t.body[0].value.lineno, 2)
     368          self.assertEqual(t.body[0].value.values[0].lineno, 2)
     369          self.assertEqual(t.body[0].value.values[1].lineno, 2)
     370          self.assertEqual(t.body[0].value.values[2].lineno, 2)
     371          self.assertEqual(t.body[0].col_offset, 0)
     372          self.assertEqual(t.body[0].value.col_offset, 4)
     373          self.assertEqual(t.body[0].value.values[0].col_offset, 4)
     374          self.assertEqual(t.body[0].value.values[1].col_offset, 4)
     375          self.assertEqual(t.body[0].value.values[2].col_offset, 4)
     376          # Check {blech}
     377          self.assertEqual(t.body[0].value.values[1].value.lineno, 3)
     378          self.assertEqual(t.body[0].value.values[1].value.end_lineno, 3)
     379          self.assertEqual(t.body[0].value.values[1].value.col_offset, 11)
     380          self.assertEqual(t.body[0].value.values[1].value.end_col_offset, 16)
     381  
     382      def test_ast_line_numbers_with_parentheses(self):
     383          expr = """
     384  x = (
     385      f" {test(t)}"
     386  )"""
     387          t = ast.parse(expr)
     388          self.assertEqual(type(t), ast.Module)
     389          self.assertEqual(len(t.body), 1)
     390          # check the test(t) location
     391          call = t.body[0].value.values[1].value
     392          self.assertEqual(type(call), ast.Call)
     393          self.assertEqual(call.lineno, 3)
     394          self.assertEqual(call.end_lineno, 3)
     395          self.assertEqual(call.col_offset, 8)
     396          self.assertEqual(call.end_col_offset, 15)
     397  
     398          expr = """
     399  x = (
     400          'PERL_MM_OPT', (
     401              f'wat'
     402              f'some_string={f(x)} '
     403              f'wat'
     404          ),
     405  )
     406  """
     407          t = ast.parse(expr)
     408          self.assertEqual(type(t), ast.Module)
     409          self.assertEqual(len(t.body), 1)
     410          # check the fstring
     411          fstring = t.body[0].value.elts[1]
     412          self.assertEqual(type(fstring), ast.JoinedStr)
     413          self.assertEqual(len(fstring.values), 3)
     414          wat1, middle, wat2 = fstring.values
     415          # check the first wat
     416          self.assertEqual(type(wat1), ast.Constant)
     417          self.assertEqual(wat1.lineno, 4)
     418          self.assertEqual(wat1.end_lineno, 6)
     419          self.assertEqual(wat1.col_offset, 12)
     420          self.assertEqual(wat1.end_col_offset, 18)
     421          # check the call
     422          call = middle.value
     423          self.assertEqual(type(call), ast.Call)
     424          self.assertEqual(call.lineno, 5)
     425          self.assertEqual(call.end_lineno, 5)
     426          self.assertEqual(call.col_offset, 27)
     427          self.assertEqual(call.end_col_offset, 31)
     428          # check the second wat
     429          self.assertEqual(type(wat2), ast.Constant)
     430          self.assertEqual(wat2.lineno, 4)
     431          self.assertEqual(wat2.end_lineno, 6)
     432          self.assertEqual(wat2.col_offset, 12)
     433          self.assertEqual(wat2.end_col_offset, 18)
     434  
     435      def test_docstring(self):
     436          def f():
     437              f'''Not a docstring'''
     438          self.assertIsNone(f.__doc__)
     439          def g():
     440              '''Not a docstring''' \
     441              f''
     442          self.assertIsNone(g.__doc__)
     443  
     444      def test_literal_eval(self):
     445          with self.assertRaisesRegex(ValueError, 'malformed node or string'):
     446              ast.literal_eval("f'x'")
     447  
     448      def test_ast_compile_time_concat(self):
     449          x = ['']
     450  
     451          expr = """x[0] = 'foo' f'{3}'"""
     452          t = ast.parse(expr)
     453          c = compile(t, '', 'exec')
     454          exec(c)
     455          self.assertEqual(x[0], 'foo3')
     456  
     457      def test_compile_time_concat_errors(self):
     458          self.assertAllRaise(SyntaxError,
     459                              'cannot mix bytes and nonbytes literals',
     460                              [r"""f'' b''""",
     461                               r"""b'' f''""",
     462                               ])
     463  
     464      def test_literal(self):
     465          self.assertEqual(f'', '')
     466          self.assertEqual(f'a', 'a')
     467          self.assertEqual(f' ', ' ')
     468  
     469      def test_unterminated_string(self):
     470          self.assertAllRaise(SyntaxError, 'f-string: unterminated string',
     471                              [r"""f'{"x'""",
     472                               r"""f'{"x}'""",
     473                               r"""f'{("x'""",
     474                               r"""f'{("x}'""",
     475                               ])
     476  
     477      def test_mismatched_parens(self):
     478          self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\}' "
     479                              r"does not match opening parenthesis '\('",
     480                              ["f'{((}'",
     481                               ])
     482          self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\)' "
     483                              r"does not match opening parenthesis '\['",
     484                              ["f'{a[4)}'",
     485                              ])
     486          self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\]' "
     487                              r"does not match opening parenthesis '\('",
     488                              ["f'{a(4]}'",
     489                              ])
     490          self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\}' "
     491                              r"does not match opening parenthesis '\['",
     492                              ["f'{a[4}'",
     493                              ])
     494          self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\}' "
     495                              r"does not match opening parenthesis '\('",
     496                              ["f'{a(4}'",
     497                              ])
     498          self.assertRaises(SyntaxError, eval, "f'{" + "("*500 + "}'")
     499  
     500      def test_double_braces(self):
     501          self.assertEqual(f'{{', '{')
     502          self.assertEqual(f'a{{', 'a{')
     503          self.assertEqual(f'{{b', '{b')
     504          self.assertEqual(f'a{{b', 'a{b')
     505          self.assertEqual(f'}}', '}')
     506          self.assertEqual(f'a}}', 'a}')
     507          self.assertEqual(f'}}b', '}b')
     508          self.assertEqual(f'a}}b', 'a}b')
     509          self.assertEqual(f'{{}}', '{}')
     510          self.assertEqual(f'a{{}}', 'a{}')
     511          self.assertEqual(f'{{b}}', '{b}')
     512          self.assertEqual(f'{{}}c', '{}c')
     513          self.assertEqual(f'a{{b}}', 'a{b}')
     514          self.assertEqual(f'a{{}}c', 'a{}c')
     515          self.assertEqual(f'{{b}}c', '{b}c')
     516          self.assertEqual(f'a{{b}}c', 'a{b}c')
     517  
     518          self.assertEqual(f'{{{10}', '{10')
     519          self.assertEqual(f'}}{10}', '}10')
     520          self.assertEqual(f'}}{{{10}', '}{10')
     521          self.assertEqual(f'}}a{{{10}', '}a{10')
     522  
     523          self.assertEqual(f'{10}{{', '10{')
     524          self.assertEqual(f'{10}}}', '10}')
     525          self.assertEqual(f'{10}}}{{', '10}{')
     526          self.assertEqual(f'{10}}}a{{' '}', '10}a{}')
     527  
     528          # Inside of strings, don't interpret doubled brackets.
     529          self.assertEqual(f'{"{{}}"}', '{{}}')
     530  
     531          self.assertAllRaise(TypeError, 'unhashable type',
     532                              ["f'{ {{}} }'", # dict in a set
     533                               ])
     534  
     535      def test_compile_time_concat(self):
     536          x = 'def'
     537          self.assertEqual('abc' f'## {x}ghi', 'abc## defghi')
     538          self.assertEqual('abc' f'{x}' 'ghi', 'abcdefghi')
     539          self.assertEqual('abc' f'{x}' 'gh' f'i{x:4}', 'abcdefghidef ')
     540          self.assertEqual('{x}' f'{x}', '{x}def')
     541          self.assertEqual('{x' f'{x}', '{xdef')
     542          self.assertEqual('{x}' f'{x}', '{x}def')
     543          self.assertEqual('{{x}}' f'{x}', '{{x}}def')
     544          self.assertEqual('{{x' f'{x}', '{{xdef')
     545          self.assertEqual('x}}' f'{x}', 'x}}def')
     546          self.assertEqual(f'{x}' 'x}}', 'defx}}')
     547          self.assertEqual(f'{x}' '', 'def')
     548          self.assertEqual('' f'{x}' '', 'def')
     549          self.assertEqual('' f'{x}', 'def')
     550          self.assertEqual(f'{x}' '2', 'def2')
     551          self.assertEqual('1' f'{x}' '2', '1def2')
     552          self.assertEqual('1' f'{x}', '1def')
     553          self.assertEqual(f'{x}' f'-{x}', 'def-def')
     554          self.assertEqual('' f'', '')
     555          self.assertEqual('' f'' '', '')
     556          self.assertEqual('' f'' '' f'', '')
     557          self.assertEqual(f'', '')
     558          self.assertEqual(f'' '', '')
     559          self.assertEqual(f'' '' f'', '')
     560          self.assertEqual(f'' '' f'' '', '')
     561  
     562          self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
     563                              ["f'{3' f'}'",  # can't concat to get a valid f-string
     564                               ])
     565  
     566      def test_comments(self):
     567          # These aren't comments, since they're in strings.
     568          d = {'#': 'hash'}
     569          self.assertEqual(f'{"#"}', '#')
     570          self.assertEqual(f'{d["#"]}', 'hash')
     571  
     572          self.assertAllRaise(SyntaxError, "f-string expression part cannot include '#'",
     573                              ["f'{1#}'",   # error because the expression becomes "(1#)"
     574                               "f'{3(#)}'",
     575                               "f'{#}'",
     576                               ])
     577          self.assertAllRaise(SyntaxError, r"f-string: unmatched '\)'",
     578                              ["f'{)#}'",   # When wrapped in parens, this becomes
     579                                            #  '()#)'.  Make sure that doesn't compile.
     580                               ])
     581  
     582      def test_many_expressions(self):
     583          # Create a string with many expressions in it. Note that
     584          #  because we have a space in here as a literal, we're actually
     585          #  going to use twice as many ast nodes: one for each literal
     586          #  plus one for each expression.
     587          def build_fstr(n, extra=''):
     588              return "f'" + ('{x} ' * n) + extra + "'"
     589  
     590          x = 'X'
     591          width = 1
     592  
     593          # Test around 256.
     594          for i in range(250, 260):
     595              self.assertEqual(eval(build_fstr(i)), (x+' ')*i)
     596  
     597          # Test concatenating 2 largs fstrings.
     598          self.assertEqual(eval(build_fstr(255)*256), (x+' ')*(255*256))
     599  
     600          s = build_fstr(253, '{x:{width}} ')
     601          self.assertEqual(eval(s), (x+' ')*254)
     602  
     603          # Test lots of expressions and constants, concatenated.
     604          s = "f'{1}' 'x' 'y'" * 1024
     605          self.assertEqual(eval(s), '1xy' * 1024)
     606  
     607      def test_format_specifier_expressions(self):
     608          width = 10
     609          precision = 4
     610          value = decimal.Decimal('12.34567')
     611          self.assertEqual(f'result: {value:{width}.{precision}}', 'result:      12.35')
     612          self.assertEqual(f'result: {value:{width!r}.{precision}}', 'result:      12.35')
     613          self.assertEqual(f'result: {value:{width:0}.{precision:1}}', 'result:      12.35')
     614          self.assertEqual(f'result: {value:{1}{0:0}.{precision:1}}', 'result:      12.35')
     615          self.assertEqual(f'result: {value:{ 1}{ 0:0}.{ precision:1}}', 'result:      12.35')
     616          self.assertEqual(f'{10:#{1}0x}', '       0xa')
     617          self.assertEqual(f'{10:{"#"}1{0}{"x"}}', '       0xa')
     618          self.assertEqual(f'{-10:-{"#"}1{0}x}', '      -0xa')
     619          self.assertEqual(f'{-10:{"-"}#{1}0{"x"}}', '      -0xa')
     620          self.assertEqual(f'{10:#{3 != {4:5} and width}x}', '       0xa')
     621  
     622          self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
     623                              ["""f'{"s"!r{":10"}}'""",
     624  
     625                               # This looks like a nested format spec.
     626                               ])
     627  
     628          self.assertAllRaise(SyntaxError, "f-string: invalid syntax",
     629                              [# Invalid syntax inside a nested spec.
     630                               "f'{4:{/5}}'",
     631                               ])
     632  
     633          self.assertAllRaise(SyntaxError, "f-string: expressions nested too deeply",
     634                              [# Can't nest format specifiers.
     635                               "f'result: {value:{width:{0}}.{precision:1}}'",
     636                               ])
     637  
     638          self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character',
     639                              [# No expansion inside conversion or for
     640                               #  the : or ! itself.
     641                               """f'{"s"!{"r"}}'""",
     642                               ])
     643  
     644      def test_side_effect_order(self):
     645          class ESC[4;38;5;81mX:
     646              def __init__(self):
     647                  self.i = 0
     648              def __format__(self, spec):
     649                  self.i += 1
     650                  return str(self.i)
     651  
     652          x = X()
     653          self.assertEqual(f'{x} {x}', '1 2')
     654  
     655      def test_missing_expression(self):
     656          self.assertAllRaise(SyntaxError, 'f-string: empty expression not allowed',
     657                              ["f'{}'",
     658                               "f'{ }'"
     659                               "f' {} '",
     660                               "f'{10:{ }}'",
     661                               "f' { } '",
     662  
     663                               # The Python parser ignores also the following
     664                               # whitespace characters in additional to a space.
     665                               "f'''{\t\f\r\n}'''",
     666                               ])
     667  
     668          # Different error messeges are raised when a specfier ('!', ':' or '=') is used after an empty expression
     669          self.assertAllRaise(SyntaxError, "f-string: expression required before '!'",
     670                              ["f'{!r}'",
     671                               "f'{ !r}'",
     672                               "f'{!}'",
     673                               "f'''{\t\f\r\n!a}'''",
     674  
     675                               # Catch empty expression before the
     676                               #  missing closing brace.
     677                               "f'{!'",
     678                               "f'{!s:'",
     679  
     680                               # Catch empty expression before the
     681                               #  invalid conversion.
     682                               "f'{!x}'",
     683                               "f'{ !xr}'",
     684                               "f'{!x:}'",
     685                               "f'{!x:a}'",
     686                               "f'{ !xr:}'",
     687                               "f'{ !xr:a}'",
     688                               ])
     689  
     690          self.assertAllRaise(SyntaxError, "f-string: expression required before ':'",
     691                              ["f'{:}'",
     692                               "f'{ :!}'",
     693                               "f'{:2}'",
     694                               "f'''{\t\f\r\n:a}'''",
     695                               "f'{:'",
     696                               ])
     697  
     698          self.assertAllRaise(SyntaxError, "f-string: expression required before '='",
     699                              ["f'{=}'",
     700                               "f'{ =}'",
     701                               "f'{ =:}'",
     702                               "f'{   =!}'",
     703                               "f'''{\t\f\r\n=}'''",
     704                               "f'{='",
     705                               ])
     706  
     707          # Different error message is raised for other whitespace characters.
     708          self.assertAllRaise(SyntaxError, r"invalid non-printable character U\+00A0",
     709                              ["f'''{\xa0}'''",
     710                               "\xa0",
     711                               ])
     712  
     713      def test_parens_in_expressions(self):
     714          self.assertEqual(f'{3,}', '(3,)')
     715  
     716          # Add these because when an expression is evaluated, parens
     717          #  are added around it. But we shouldn't go from an invalid
     718          #  expression to a valid one. The added parens are just
     719          #  supposed to allow whitespace (including newlines).
     720          self.assertAllRaise(SyntaxError, 'f-string: invalid syntax',
     721                              ["f'{,}'",
     722                               "f'{,}'",  # this is (,), which is an error
     723                               ])
     724  
     725          self.assertAllRaise(SyntaxError, r"f-string: unmatched '\)'",
     726                              ["f'{3)+(4}'",
     727                               ])
     728  
     729          self.assertAllRaise(SyntaxError, 'unterminated string literal',
     730                              ["f'{\n}'",
     731                               ])
     732      def test_newlines_before_syntax_error(self):
     733          self.assertAllRaise(SyntaxError, "invalid syntax",
     734                  ["f'{.}'", "\nf'{.}'", "\n\nf'{.}'"])
     735  
     736      def test_backslashes_in_string_part(self):
     737          self.assertEqual(f'\t', '\t')
     738          self.assertEqual(r'\t', '\\t')
     739          self.assertEqual(rf'\t', '\\t')
     740          self.assertEqual(f'{2}\t', '2\t')
     741          self.assertEqual(f'{2}\t{3}', '2\t3')
     742          self.assertEqual(f'\t{3}', '\t3')
     743  
     744          self.assertEqual(f'\u0394', '\u0394')
     745          self.assertEqual(r'\u0394', '\\u0394')
     746          self.assertEqual(rf'\u0394', '\\u0394')
     747          self.assertEqual(f'{2}\u0394', '2\u0394')
     748          self.assertEqual(f'{2}\u0394{3}', '2\u03943')
     749          self.assertEqual(f'\u0394{3}', '\u03943')
     750  
     751          self.assertEqual(f'\U00000394', '\u0394')
     752          self.assertEqual(r'\U00000394', '\\U00000394')
     753          self.assertEqual(rf'\U00000394', '\\U00000394')
     754          self.assertEqual(f'{2}\U00000394', '2\u0394')
     755          self.assertEqual(f'{2}\U00000394{3}', '2\u03943')
     756          self.assertEqual(f'\U00000394{3}', '\u03943')
     757  
     758          self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}', '\u0394')
     759          self.assertEqual(f'{2}\N{GREEK CAPITAL LETTER DELTA}', '2\u0394')
     760          self.assertEqual(f'{2}\N{GREEK CAPITAL LETTER DELTA}{3}', '2\u03943')
     761          self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}{3}', '\u03943')
     762          self.assertEqual(f'2\N{GREEK CAPITAL LETTER DELTA}', '2\u0394')
     763          self.assertEqual(f'2\N{GREEK CAPITAL LETTER DELTA}3', '2\u03943')
     764          self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}3', '\u03943')
     765  
     766          self.assertEqual(f'\x20', ' ')
     767          self.assertEqual(r'\x20', '\\x20')
     768          self.assertEqual(rf'\x20', '\\x20')
     769          self.assertEqual(f'{2}\x20', '2 ')
     770          self.assertEqual(f'{2}\x20{3}', '2 3')
     771          self.assertEqual(f'\x20{3}', ' 3')
     772  
     773          self.assertEqual(f'2\x20', '2 ')
     774          self.assertEqual(f'2\x203', '2 3')
     775          self.assertEqual(f'\x203', ' 3')
     776  
     777          with self.assertWarns(DeprecationWarning):  # invalid escape sequence
     778              value = eval(r"f'\{6*7}'")
     779          self.assertEqual(value, '\\42')
     780          self.assertEqual(f'\\{6*7}', '\\42')
     781          self.assertEqual(fr'\{6*7}', '\\42')
     782  
     783          AMPERSAND = 'spam'
     784          # Get the right unicode character (&), or pick up local variable
     785          # depending on the number of backslashes.
     786          self.assertEqual(f'\N{AMPERSAND}', '&')
     787          self.assertEqual(f'\\N{AMPERSAND}', '\\Nspam')
     788          self.assertEqual(fr'\N{AMPERSAND}', '\\Nspam')
     789          self.assertEqual(f'\\\N{AMPERSAND}', '\\&')
     790  
     791      def test_misformed_unicode_character_name(self):
     792          # These test are needed because unicode names are parsed
     793          # differently inside f-strings.
     794          self.assertAllRaise(SyntaxError, r"\(unicode error\) 'unicodeescape' codec can't decode bytes in position .*: malformed \\N character escape",
     795                              [r"f'\N'",
     796                               r"f'\N '",
     797                               r"f'\N  '",  # See bpo-46503.
     798                               r"f'\N{'",
     799                               r"f'\N{GREEK CAPITAL LETTER DELTA'",
     800  
     801                               # Here are the non-f-string versions,
     802                               #  which should give the same errors.
     803                               r"'\N'",
     804                               r"'\N '",
     805                               r"'\N  '",
     806                               r"'\N{'",
     807                               r"'\N{GREEK CAPITAL LETTER DELTA'",
     808                               ])
     809  
     810      def test_no_backslashes_in_expression_part(self):
     811          self.assertAllRaise(SyntaxError, 'f-string expression part cannot include a backslash',
     812                              [r"f'{\'a\'}'",
     813                               r"f'{\t3}'",
     814                               r"f'{\}'",
     815                               r"rf'{\'a\'}'",
     816                               r"rf'{\t3}'",
     817                               r"rf'{\}'",
     818                               r"""rf'{"\N{LEFT CURLY BRACKET}"}'""",
     819                               r"f'{\n}'",
     820                               ])
     821  
     822      def test_no_escapes_for_braces(self):
     823          """
     824          Only literal curly braces begin an expression.
     825          """
     826          # \x7b is '{'.
     827          self.assertEqual(f'\x7b1+1}}', '{1+1}')
     828          self.assertEqual(f'\x7b1+1', '{1+1')
     829          self.assertEqual(f'\u007b1+1', '{1+1')
     830          self.assertEqual(f'\N{LEFT CURLY BRACKET}1+1\N{RIGHT CURLY BRACKET}', '{1+1}')
     831  
     832      def test_newlines_in_expressions(self):
     833          self.assertEqual(f'{0}', '0')
     834          self.assertEqual(rf'''{3+
     835  4}''', '7')
     836  
     837      def test_lambda(self):
     838          x = 5
     839          self.assertEqual(f'{(lambda y:x*y)("8")!r}', "'88888'")
     840          self.assertEqual(f'{(lambda y:x*y)("8")!r:10}', "'88888'   ")
     841          self.assertEqual(f'{(lambda y:x*y)("8"):10}', "88888     ")
     842  
     843          # lambda doesn't work without parens, because the colon
     844          #  makes the parser think it's a format_spec
     845          self.assertAllRaise(SyntaxError, 'f-string: invalid syntax',
     846                              ["f'{lambda x:x}'",
     847                               ])
     848  
     849      def test_yield(self):
     850          # Not terribly useful, but make sure the yield turns
     851          #  a function into a generator
     852          def fn(y):
     853              f'y:{yield y*2}'
     854              f'{yield}'
     855  
     856          g = fn(4)
     857          self.assertEqual(next(g), 8)
     858          self.assertEqual(next(g), None)
     859  
     860      def test_yield_send(self):
     861          def fn(x):
     862              yield f'x:{yield (lambda i: x * i)}'
     863  
     864          g = fn(10)
     865          the_lambda = next(g)
     866          self.assertEqual(the_lambda(4), 40)
     867          self.assertEqual(g.send('string'), 'x:string')
     868  
     869      def test_expressions_with_triple_quoted_strings(self):
     870          self.assertEqual(f"{'''x'''}", 'x')
     871          self.assertEqual(f"{'''eric's'''}", "eric's")
     872  
     873          # Test concatenation within an expression
     874          self.assertEqual(f'{"x" """eric"s""" "y"}', 'xeric"sy')
     875          self.assertEqual(f'{"x" """eric"s"""}', 'xeric"s')
     876          self.assertEqual(f'{"""eric"s""" "y"}', 'eric"sy')
     877          self.assertEqual(f'{"""x""" """eric"s""" "y"}', 'xeric"sy')
     878          self.assertEqual(f'{"""x""" """eric"s""" """y"""}', 'xeric"sy')
     879          self.assertEqual(f'{r"""x""" """eric"s""" """y"""}', 'xeric"sy')
     880  
     881      def test_multiple_vars(self):
     882          x = 98
     883          y = 'abc'
     884          self.assertEqual(f'{x}{y}', '98abc')
     885  
     886          self.assertEqual(f'X{x}{y}', 'X98abc')
     887          self.assertEqual(f'{x}X{y}', '98Xabc')
     888          self.assertEqual(f'{x}{y}X', '98abcX')
     889  
     890          self.assertEqual(f'X{x}Y{y}', 'X98Yabc')
     891          self.assertEqual(f'X{x}{y}Y', 'X98abcY')
     892          self.assertEqual(f'{x}X{y}Y', '98XabcY')
     893  
     894          self.assertEqual(f'X{x}Y{y}Z', 'X98YabcZ')
     895  
     896      def test_closure(self):
     897          def outer(x):
     898              def inner():
     899                  return f'x:{x}'
     900              return inner
     901  
     902          self.assertEqual(outer('987')(), 'x:987')
     903          self.assertEqual(outer(7)(), 'x:7')
     904  
     905      def test_arguments(self):
     906          y = 2
     907          def f(x, width):
     908              return f'x={x*y:{width}}'
     909  
     910          self.assertEqual(f('foo', 10), 'x=foofoo    ')
     911          x = 'bar'
     912          self.assertEqual(f(10, 10), 'x=        20')
     913  
     914      def test_locals(self):
     915          value = 123
     916          self.assertEqual(f'v:{value}', 'v:123')
     917  
     918      def test_missing_variable(self):
     919          with self.assertRaises(NameError):
     920              f'v:{value}'
     921  
     922      def test_missing_format_spec(self):
     923          class ESC[4;38;5;81mO:
     924              def __format__(self, spec):
     925                  if not spec:
     926                      return '*'
     927                  return spec
     928  
     929          self.assertEqual(f'{O():x}', 'x')
     930          self.assertEqual(f'{O()}', '*')
     931          self.assertEqual(f'{O():}', '*')
     932  
     933          self.assertEqual(f'{3:}', '3')
     934          self.assertEqual(f'{3!s:}', '3')
     935  
     936      def test_global(self):
     937          self.assertEqual(f'g:{a_global}', 'g:global variable')
     938          self.assertEqual(f'g:{a_global!r}', "g:'global variable'")
     939  
     940          a_local = 'local variable'
     941          self.assertEqual(f'g:{a_global} l:{a_local}',
     942                           'g:global variable l:local variable')
     943          self.assertEqual(f'g:{a_global!r}',
     944                           "g:'global variable'")
     945          self.assertEqual(f'g:{a_global} l:{a_local!r}',
     946                           "g:global variable l:'local variable'")
     947  
     948          self.assertIn("module 'unittest' from", f'{unittest}')
     949  
     950      def test_shadowed_global(self):
     951          a_global = 'really a local'
     952          self.assertEqual(f'g:{a_global}', 'g:really a local')
     953          self.assertEqual(f'g:{a_global!r}', "g:'really a local'")
     954  
     955          a_local = 'local variable'
     956          self.assertEqual(f'g:{a_global} l:{a_local}',
     957                           'g:really a local l:local variable')
     958          self.assertEqual(f'g:{a_global!r}',
     959                           "g:'really a local'")
     960          self.assertEqual(f'g:{a_global} l:{a_local!r}',
     961                           "g:really a local l:'local variable'")
     962  
     963      def test_call(self):
     964          def foo(x):
     965              return 'x=' + str(x)
     966  
     967          self.assertEqual(f'{foo(10)}', 'x=10')
     968  
     969      def test_nested_fstrings(self):
     970          y = 5
     971          self.assertEqual(f'{f"{0}"*3}', '000')
     972          self.assertEqual(f'{f"{y}"*3}', '555')
     973  
     974      def test_invalid_string_prefixes(self):
     975          single_quote_cases = ["fu''",
     976                               "uf''",
     977                               "Fu''",
     978                               "fU''",
     979                               "Uf''",
     980                               "uF''",
     981                               "ufr''",
     982                               "urf''",
     983                               "fur''",
     984                               "fru''",
     985                               "rfu''",
     986                               "ruf''",
     987                               "FUR''",
     988                               "Fur''",
     989                               "fb''",
     990                               "fB''",
     991                               "Fb''",
     992                               "FB''",
     993                               "bf''",
     994                               "bF''",
     995                               "Bf''",
     996                               "BF''",]
     997          double_quote_cases = [case.replace("'", '"') for case in single_quote_cases]
     998          self.assertAllRaise(SyntaxError, 'invalid syntax',
     999                              single_quote_cases + double_quote_cases)
    1000  
    1001      def test_leading_trailing_spaces(self):
    1002          self.assertEqual(f'{ 3}', '3')
    1003          self.assertEqual(f'{  3}', '3')
    1004          self.assertEqual(f'{3 }', '3')
    1005          self.assertEqual(f'{3  }', '3')
    1006  
    1007          self.assertEqual(f'expr={ {x: y for x, y in [(1, 2), ]}}',
    1008                           'expr={1: 2}')
    1009          self.assertEqual(f'expr={ {x: y for x, y in [(1, 2), ]} }',
    1010                           'expr={1: 2}')
    1011  
    1012      def test_not_equal(self):
    1013          # There's a special test for this because there's a special
    1014          #  case in the f-string parser to look for != as not ending an
    1015          #  expression. Normally it would, while looking for !s or !r.
    1016  
    1017          self.assertEqual(f'{3!=4}', 'True')
    1018          self.assertEqual(f'{3!=4:}', 'True')
    1019          self.assertEqual(f'{3!=4!s}', 'True')
    1020          self.assertEqual(f'{3!=4!s:.3}', 'Tru')
    1021  
    1022      def test_equal_equal(self):
    1023          # Because an expression ending in = has special meaning,
    1024          # there's a special test for ==. Make sure it works.
    1025  
    1026          self.assertEqual(f'{0==1}', 'False')
    1027  
    1028      def test_conversions(self):
    1029          self.assertEqual(f'{3.14:10.10}', '      3.14')
    1030          self.assertEqual(f'{3.14!s:10.10}', '3.14      ')
    1031          self.assertEqual(f'{3.14!r:10.10}', '3.14      ')
    1032          self.assertEqual(f'{3.14!a:10.10}', '3.14      ')
    1033  
    1034          self.assertEqual(f'{"a"}', 'a')
    1035          self.assertEqual(f'{"a"!r}', "'a'")
    1036          self.assertEqual(f'{"a"!a}', "'a'")
    1037  
    1038          # Not a conversion.
    1039          self.assertEqual(f'{"a!r"}', "a!r")
    1040  
    1041          # Not a conversion, but show that ! is allowed in a format spec.
    1042          self.assertEqual(f'{3.14:!<10.10}', '3.14!!!!!!')
    1043  
    1044          self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character',
    1045                              ["f'{3!g}'",
    1046                               "f'{3!A}'",
    1047                               "f'{3!3}'",
    1048                               "f'{3!G}'",
    1049                               "f'{3!!}'",
    1050                               "f'{3!:}'",
    1051                               "f'{3! s}'",  # no space before conversion char
    1052                               ])
    1053  
    1054          self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
    1055                              ["f'{x!s{y}}'",
    1056                               "f'{3!ss}'",
    1057                               "f'{3!ss:}'",
    1058                               "f'{3!ss:s}'",
    1059                               ])
    1060  
    1061      def test_assignment(self):
    1062          self.assertAllRaise(SyntaxError, r'invalid syntax',
    1063                              ["f'' = 3",
    1064                               "f'{0}' = x",
    1065                               "f'{x}' = x",
    1066                               ])
    1067  
    1068      def test_del(self):
    1069          self.assertAllRaise(SyntaxError, 'invalid syntax',
    1070                              ["del f''",
    1071                               "del '' f''",
    1072                               ])
    1073  
    1074      def test_mismatched_braces(self):
    1075          self.assertAllRaise(SyntaxError, "f-string: single '}' is not allowed",
    1076                              ["f'{{}'",
    1077                               "f'{{}}}'",
    1078                               "f'}'",
    1079                               "f'x}'",
    1080                               "f'x}x'",
    1081                               r"f'\u007b}'",
    1082  
    1083                               # Can't have { or } in a format spec.
    1084                               "f'{3:}>10}'",
    1085                               "f'{3:}}>10}'",
    1086                               ])
    1087  
    1088          self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
    1089                              ["f'{3:{{>10}'",
    1090                               "f'{3'",
    1091                               "f'{3!'",
    1092                               "f'{3:'",
    1093                               "f'{3!s'",
    1094                               "f'{3!s:'",
    1095                               "f'{3!s:3'",
    1096                               "f'x{'",
    1097                               "f'x{x'",
    1098                               "f'{x'",
    1099                               "f'{3:s'",
    1100                               "f'{{{'",
    1101                               "f'{{}}{'",
    1102                               "f'{'",
    1103                               "f'x{<'",  # See bpo-46762.
    1104                               "f'x{>'",
    1105                               "f'{i='",  # See gh-93418.
    1106                               ])
    1107  
    1108          # But these are just normal strings.
    1109          self.assertEqual(f'{"{"}', '{')
    1110          self.assertEqual(f'{"}"}', '}')
    1111          self.assertEqual(f'{3:{"}"}>10}', '}}}}}}}}}3')
    1112          self.assertEqual(f'{2:{"{"}>10}', '{{{{{{{{{2')
    1113  
    1114      def test_if_conditional(self):
    1115          # There's special logic in compile.c to test if the
    1116          #  conditional for an if (and while) are constants. Exercise
    1117          #  that code.
    1118  
    1119          def test_fstring(x, expected):
    1120              flag = 0
    1121              if f'{x}':
    1122                  flag = 1
    1123              else:
    1124                  flag = 2
    1125              self.assertEqual(flag, expected)
    1126  
    1127          def test_concat_empty(x, expected):
    1128              flag = 0
    1129              if '' f'{x}':
    1130                  flag = 1
    1131              else:
    1132                  flag = 2
    1133              self.assertEqual(flag, expected)
    1134  
    1135          def test_concat_non_empty(x, expected):
    1136              flag = 0
    1137              if ' ' f'{x}':
    1138                  flag = 1
    1139              else:
    1140                  flag = 2
    1141              self.assertEqual(flag, expected)
    1142  
    1143          test_fstring('', 2)
    1144          test_fstring(' ', 1)
    1145  
    1146          test_concat_empty('', 2)
    1147          test_concat_empty(' ', 1)
    1148  
    1149          test_concat_non_empty('', 1)
    1150          test_concat_non_empty(' ', 1)
    1151  
    1152      def test_empty_format_specifier(self):
    1153          x = 'test'
    1154          self.assertEqual(f'{x}', 'test')
    1155          self.assertEqual(f'{x:}', 'test')
    1156          self.assertEqual(f'{x!s:}', 'test')
    1157          self.assertEqual(f'{x!r:}', "'test'")
    1158  
    1159      def test_str_format_differences(self):
    1160          d = {'a': 'string',
    1161               0: 'integer',
    1162               }
    1163          a = 0
    1164          self.assertEqual(f'{d[0]}', 'integer')
    1165          self.assertEqual(f'{d["a"]}', 'string')
    1166          self.assertEqual(f'{d[a]}', 'integer')
    1167          self.assertEqual('{d[a]}'.format(d=d), 'string')
    1168          self.assertEqual('{d[0]}'.format(d=d), 'integer')
    1169  
    1170      def test_errors(self):
    1171          # see issue 26287
    1172          self.assertAllRaise(TypeError, 'unsupported',
    1173                              [r"f'{(lambda: 0):x}'",
    1174                               r"f'{(0,):x}'",
    1175                               ])
    1176          self.assertAllRaise(ValueError, 'Unknown format code',
    1177                              [r"f'{1000:j}'",
    1178                               r"f'{1000:j}'",
    1179                              ])
    1180  
    1181      def test_filename_in_syntaxerror(self):
    1182          # see issue 38964
    1183          with temp_cwd() as cwd:
    1184              file_path = os.path.join(cwd, 't.py')
    1185              with open(file_path, 'w', encoding="utf-8") as f:
    1186                  f.write('f"{a b}"') # This generates a SyntaxError
    1187              _, _, stderr = assert_python_failure(file_path,
    1188                                                   PYTHONIOENCODING='ascii')
    1189          self.assertIn(file_path.encode('ascii', 'backslashreplace'), stderr)
    1190  
    1191      def test_loop(self):
    1192          for i in range(1000):
    1193              self.assertEqual(f'i:{i}', 'i:' + str(i))
    1194  
    1195      def test_dict(self):
    1196          d = {'"': 'dquote',
    1197               "'": 'squote',
    1198               'foo': 'bar',
    1199               }
    1200          self.assertEqual(f'''{d["'"]}''', 'squote')
    1201          self.assertEqual(f"""{d['"']}""", 'dquote')
    1202  
    1203          self.assertEqual(f'{d["foo"]}', 'bar')
    1204          self.assertEqual(f"{d['foo']}", 'bar')
    1205  
    1206      def test_backslash_char(self):
    1207          # Check eval of a backslash followed by a control char.
    1208          # See bpo-30682: this used to raise an assert in pydebug mode.
    1209          self.assertEqual(eval('f"\\\n"'), '')
    1210          self.assertEqual(eval('f"\\\r"'), '')
    1211  
    1212      def test_debug_conversion(self):
    1213          x = 'A string'
    1214          self.assertEqual(f'{x=}', 'x=' + repr(x))
    1215          self.assertEqual(f'{x =}', 'x =' + repr(x))
    1216          self.assertEqual(f'{x=!s}', 'x=' + str(x))
    1217          self.assertEqual(f'{x=!r}', 'x=' + repr(x))
    1218          self.assertEqual(f'{x=!a}', 'x=' + ascii(x))
    1219  
    1220          x = 2.71828
    1221          self.assertEqual(f'{x=:.2f}', 'x=' + format(x, '.2f'))
    1222          self.assertEqual(f'{x=:}', 'x=' + format(x, ''))
    1223          self.assertEqual(f'{x=!r:^20}', 'x=' + format(repr(x), '^20'))
    1224          self.assertEqual(f'{x=!s:^20}', 'x=' + format(str(x), '^20'))
    1225          self.assertEqual(f'{x=!a:^20}', 'x=' + format(ascii(x), '^20'))
    1226  
    1227          x = 9
    1228          self.assertEqual(f'{3*x+15=}', '3*x+15=42')
    1229  
    1230          # There is code in ast.c that deals with non-ascii expression values.  So,
    1231          # use a unicode identifier to trigger that.
    1232          tenπ = 31.4
    1233          self.assertEqual(f'{tenπ=:.2f}', 'tenπ=31.40')
    1234  
    1235          # Also test with Unicode in non-identifiers.
    1236          self.assertEqual(f'{"Σ"=}', '"Σ"=\'Σ\'')
    1237  
    1238          # Make sure nested fstrings still work.
    1239          self.assertEqual(f'{f"{3.1415=:.1f}":*^20}', '*****3.1415=3.1*****')
    1240  
    1241          # Make sure text before and after an expression with = works
    1242          # correctly.
    1243          pi = 'π'
    1244          self.assertEqual(f'alpha α {pi=} ω omega', "alpha α pi='π' ω omega")
    1245  
    1246          # Check multi-line expressions.
    1247          self.assertEqual(f'''{
    1248  3
    1249  =}''', '\n3\n=3')
    1250  
    1251          # Since = is handled specially, make sure all existing uses of
    1252          # it still work.
    1253  
    1254          self.assertEqual(f'{0==1}', 'False')
    1255          self.assertEqual(f'{0!=1}', 'True')
    1256          self.assertEqual(f'{0<=1}', 'True')
    1257          self.assertEqual(f'{0>=1}', 'False')
    1258          self.assertEqual(f'{(x:="5")}', '5')
    1259          self.assertEqual(x, '5')
    1260          self.assertEqual(f'{(x:=5)}', '5')
    1261          self.assertEqual(x, 5)
    1262          self.assertEqual(f'{"="}', '=')
    1263  
    1264          x = 20
    1265          # This isn't an assignment expression, it's 'x', with a format
    1266          # spec of '=10'.  See test_walrus: you need to use parens.
    1267          self.assertEqual(f'{x:=10}', '        20')
    1268  
    1269          # Test named function parameters, to make sure '=' parsing works
    1270          # there.
    1271          def f(a):
    1272              nonlocal x
    1273              oldx = x
    1274              x = a
    1275              return oldx
    1276          x = 0
    1277          self.assertEqual(f'{f(a="3=")}', '0')
    1278          self.assertEqual(x, '3=')
    1279          self.assertEqual(f'{f(a=4)}', '3=')
    1280          self.assertEqual(x, 4)
    1281  
    1282          # Make sure __format__ is being called.
    1283          class ESC[4;38;5;81mC:
    1284              def __format__(self, s):
    1285                  return f'FORMAT-{s}'
    1286              def __repr__(self):
    1287                  return 'REPR'
    1288  
    1289          self.assertEqual(f'{C()=}', 'C()=REPR')
    1290          self.assertEqual(f'{C()=!r}', 'C()=REPR')
    1291          self.assertEqual(f'{C()=:}', 'C()=FORMAT-')
    1292          self.assertEqual(f'{C()=: }', 'C()=FORMAT- ')
    1293          self.assertEqual(f'{C()=:x}', 'C()=FORMAT-x')
    1294          self.assertEqual(f'{C()=!r:*^20}', 'C()=********REPR********')
    1295  
    1296          self.assertRaises(SyntaxError, eval, "f'{C=]'")
    1297  
    1298          # Make sure leading and following text works.
    1299          x = 'foo'
    1300          self.assertEqual(f'X{x=}Y', 'Xx='+repr(x)+'Y')
    1301  
    1302          # Make sure whitespace around the = works.
    1303          self.assertEqual(f'X{x  =}Y', 'Xx  ='+repr(x)+'Y')
    1304          self.assertEqual(f'X{x=  }Y', 'Xx=  '+repr(x)+'Y')
    1305          self.assertEqual(f'X{x  =  }Y', 'Xx  =  '+repr(x)+'Y')
    1306  
    1307          # These next lines contains tabs.  Backslash escapes don't
    1308          # work in f-strings.
    1309          # patchcheck doesn't like these tabs.  So the only way to test
    1310          # this will be to dynamically created and exec the f-strings.  But
    1311          # that's such a hassle I'll save it for another day.  For now, convert
    1312          # the tabs to spaces just to shut up patchcheck.
    1313          #self.assertEqual(f'X{x =}Y', 'Xx\t='+repr(x)+'Y')
    1314          #self.assertEqual(f'X{x =       }Y', 'Xx\t=\t'+repr(x)+'Y')
    1315  
    1316      def test_walrus(self):
    1317          x = 20
    1318          # This isn't an assignment expression, it's 'x', with a format
    1319          # spec of '=10'.
    1320          self.assertEqual(f'{x:=10}', '        20')
    1321  
    1322          # This is an assignment expression, which requires parens.
    1323          self.assertEqual(f'{(x:=10)}', '10')
    1324          self.assertEqual(x, 10)
    1325  
    1326      def test_invalid_syntax_error_message(self):
    1327          with self.assertRaisesRegex(SyntaxError, "f-string: invalid syntax"):
    1328              compile("f'{a $ b}'", "?", "exec")
    1329  
    1330      def test_with_two_commas_in_format_specifier(self):
    1331          error_msg = re.escape("Cannot specify ',' with ','.")
    1332          with self.assertRaisesRegex(ValueError, error_msg):
    1333              f'{1:,,}'
    1334  
    1335      def test_with_two_underscore_in_format_specifier(self):
    1336          error_msg = re.escape("Cannot specify '_' with '_'.")
    1337          with self.assertRaisesRegex(ValueError, error_msg):
    1338              f'{1:__}'
    1339  
    1340      def test_with_a_commas_and_an_underscore_in_format_specifier(self):
    1341          error_msg = re.escape("Cannot specify both ',' and '_'.")
    1342          with self.assertRaisesRegex(ValueError, error_msg):
    1343              f'{1:,_}'
    1344  
    1345      def test_with_an_underscore_and_a_comma_in_format_specifier(self):
    1346          error_msg = re.escape("Cannot specify both ',' and '_'.")
    1347          with self.assertRaisesRegex(ValueError, error_msg):
    1348              f'{1:_,}'
    1349  
    1350      def test_syntax_error_for_starred_expressions(self):
    1351          error_msg = re.escape("cannot use starred expression here")
    1352          with self.assertRaisesRegex(SyntaxError, error_msg):
    1353              compile("f'{*a}'", "?", "exec")
    1354  
    1355          error_msg = re.escape("cannot use double starred expression here")
    1356          with self.assertRaisesRegex(SyntaxError, error_msg):
    1357              compile("f'{**a}'", "?", "exec")
    1358  
    1359  if __name__ == '__main__':
    1360      unittest.main()