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