xref: /third_party/python/Lib/test/test_fstring.py (revision 7db96d56)
17db96d56Sopenharmony_ci# -*- coding: utf-8 -*-
27db96d56Sopenharmony_ci# There are tests here with unicode string literals and
37db96d56Sopenharmony_ci# identifiers. There's a code in ast.c that was added because of a
47db96d56Sopenharmony_ci# failure with a non-ascii-only expression.  So, I have tests for
57db96d56Sopenharmony_ci# that.  There are workarounds that would let me run tests for that
67db96d56Sopenharmony_ci# code without unicode identifiers and strings, but just using them
77db96d56Sopenharmony_ci# directly seems like the easiest and therefore safest thing to do.
87db96d56Sopenharmony_ci# Unicode identifiers in tests is allowed by PEP 3131.
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_ciimport ast
117db96d56Sopenharmony_ciimport os
127db96d56Sopenharmony_ciimport re
137db96d56Sopenharmony_ciimport types
147db96d56Sopenharmony_ciimport decimal
157db96d56Sopenharmony_ciimport unittest
167db96d56Sopenharmony_cifrom test.support.os_helper import temp_cwd
177db96d56Sopenharmony_cifrom test.support.script_helper import assert_python_failure
187db96d56Sopenharmony_ci
197db96d56Sopenharmony_cia_global = 'global variable'
207db96d56Sopenharmony_ci
217db96d56Sopenharmony_ci# You could argue that I'm too strict in looking for specific error
227db96d56Sopenharmony_ci#  values with assertRaisesRegex, but without it it's way too easy to
237db96d56Sopenharmony_ci#  make a syntax error in the test strings. Especially with all of the
247db96d56Sopenharmony_ci#  triple quotes, raw strings, backslashes, etc. I think it's a
257db96d56Sopenharmony_ci#  worthwhile tradeoff. When I switched to this method, I found many
267db96d56Sopenharmony_ci#  examples where I wasn't testing what I thought I was.
277db96d56Sopenharmony_ci
287db96d56Sopenharmony_ciclass TestCase(unittest.TestCase):
297db96d56Sopenharmony_ci    def assertAllRaise(self, exception_type, regex, error_strings):
307db96d56Sopenharmony_ci        for str in error_strings:
317db96d56Sopenharmony_ci            with self.subTest(str=str):
327db96d56Sopenharmony_ci                with self.assertRaisesRegex(exception_type, regex):
337db96d56Sopenharmony_ci                    eval(str)
347db96d56Sopenharmony_ci
357db96d56Sopenharmony_ci    def test__format__lookup(self):
367db96d56Sopenharmony_ci        # Make sure __format__ is looked up on the type, not the instance.
377db96d56Sopenharmony_ci        class X:
387db96d56Sopenharmony_ci            def __format__(self, spec):
397db96d56Sopenharmony_ci                return 'class'
407db96d56Sopenharmony_ci
417db96d56Sopenharmony_ci        x = X()
427db96d56Sopenharmony_ci
437db96d56Sopenharmony_ci        # Add a bound __format__ method to the 'y' instance, but not
447db96d56Sopenharmony_ci        #  the 'x' instance.
457db96d56Sopenharmony_ci        y = X()
467db96d56Sopenharmony_ci        y.__format__ = types.MethodType(lambda self, spec: 'instance', y)
477db96d56Sopenharmony_ci
487db96d56Sopenharmony_ci        self.assertEqual(f'{y}', format(y))
497db96d56Sopenharmony_ci        self.assertEqual(f'{y}', 'class')
507db96d56Sopenharmony_ci        self.assertEqual(format(x), format(y))
517db96d56Sopenharmony_ci
527db96d56Sopenharmony_ci        # __format__ is not called this way, but still make sure it
537db96d56Sopenharmony_ci        #  returns what we expect (so we can make sure we're bypassing
547db96d56Sopenharmony_ci        #  it).
557db96d56Sopenharmony_ci        self.assertEqual(x.__format__(''), 'class')
567db96d56Sopenharmony_ci        self.assertEqual(y.__format__(''), 'instance')
577db96d56Sopenharmony_ci
587db96d56Sopenharmony_ci        # This is how __format__ is actually called.
597db96d56Sopenharmony_ci        self.assertEqual(type(x).__format__(x, ''), 'class')
607db96d56Sopenharmony_ci        self.assertEqual(type(y).__format__(y, ''), 'class')
617db96d56Sopenharmony_ci
627db96d56Sopenharmony_ci    def test_ast(self):
637db96d56Sopenharmony_ci        # Inspired by http://bugs.python.org/issue24975
647db96d56Sopenharmony_ci        class X:
657db96d56Sopenharmony_ci            def __init__(self):
667db96d56Sopenharmony_ci                self.called = False
677db96d56Sopenharmony_ci            def __call__(self):
687db96d56Sopenharmony_ci                self.called = True
697db96d56Sopenharmony_ci                return 4
707db96d56Sopenharmony_ci        x = X()
717db96d56Sopenharmony_ci        expr = """
727db96d56Sopenharmony_cia = 10
737db96d56Sopenharmony_cif'{a * x()}'"""
747db96d56Sopenharmony_ci        t = ast.parse(expr)
757db96d56Sopenharmony_ci        c = compile(t, '', 'exec')
767db96d56Sopenharmony_ci
777db96d56Sopenharmony_ci        # Make sure x was not called.
787db96d56Sopenharmony_ci        self.assertFalse(x.called)
797db96d56Sopenharmony_ci
807db96d56Sopenharmony_ci        # Actually run the code.
817db96d56Sopenharmony_ci        exec(c)
827db96d56Sopenharmony_ci
837db96d56Sopenharmony_ci        # Make sure x was called.
847db96d56Sopenharmony_ci        self.assertTrue(x.called)
857db96d56Sopenharmony_ci
867db96d56Sopenharmony_ci    def test_ast_line_numbers(self):
877db96d56Sopenharmony_ci        expr = """
887db96d56Sopenharmony_cia = 10
897db96d56Sopenharmony_cif'{a * x()}'"""
907db96d56Sopenharmony_ci        t = ast.parse(expr)
917db96d56Sopenharmony_ci        self.assertEqual(type(t), ast.Module)
927db96d56Sopenharmony_ci        self.assertEqual(len(t.body), 2)
937db96d56Sopenharmony_ci        # check `a = 10`
947db96d56Sopenharmony_ci        self.assertEqual(type(t.body[0]), ast.Assign)
957db96d56Sopenharmony_ci        self.assertEqual(t.body[0].lineno, 2)
967db96d56Sopenharmony_ci        # check `f'...'`
977db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1]), ast.Expr)
987db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value), ast.JoinedStr)
997db96d56Sopenharmony_ci        self.assertEqual(len(t.body[1].value.values), 1)
1007db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)
1017db96d56Sopenharmony_ci        self.assertEqual(t.body[1].lineno, 3)
1027db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.lineno, 3)
1037db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.values[0].lineno, 3)
1047db96d56Sopenharmony_ci        # check the binop location
1057db96d56Sopenharmony_ci        binop = t.body[1].value.values[0].value
1067db96d56Sopenharmony_ci        self.assertEqual(type(binop), ast.BinOp)
1077db96d56Sopenharmony_ci        self.assertEqual(type(binop.left), ast.Name)
1087db96d56Sopenharmony_ci        self.assertEqual(type(binop.op), ast.Mult)
1097db96d56Sopenharmony_ci        self.assertEqual(type(binop.right), ast.Call)
1107db96d56Sopenharmony_ci        self.assertEqual(binop.lineno, 3)
1117db96d56Sopenharmony_ci        self.assertEqual(binop.left.lineno, 3)
1127db96d56Sopenharmony_ci        self.assertEqual(binop.right.lineno, 3)
1137db96d56Sopenharmony_ci        self.assertEqual(binop.col_offset, 3)
1147db96d56Sopenharmony_ci        self.assertEqual(binop.left.col_offset, 3)
1157db96d56Sopenharmony_ci        self.assertEqual(binop.right.col_offset, 7)
1167db96d56Sopenharmony_ci
1177db96d56Sopenharmony_ci    def test_ast_line_numbers_multiple_formattedvalues(self):
1187db96d56Sopenharmony_ci        expr = """
1197db96d56Sopenharmony_cif'no formatted values'
1207db96d56Sopenharmony_cif'eggs {a * x()} spam {b + y()}'"""
1217db96d56Sopenharmony_ci        t = ast.parse(expr)
1227db96d56Sopenharmony_ci        self.assertEqual(type(t), ast.Module)
1237db96d56Sopenharmony_ci        self.assertEqual(len(t.body), 2)
1247db96d56Sopenharmony_ci        # check `f'no formatted value'`
1257db96d56Sopenharmony_ci        self.assertEqual(type(t.body[0]), ast.Expr)
1267db96d56Sopenharmony_ci        self.assertEqual(type(t.body[0].value), ast.JoinedStr)
1277db96d56Sopenharmony_ci        self.assertEqual(t.body[0].lineno, 2)
1287db96d56Sopenharmony_ci        # check `f'...'`
1297db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1]), ast.Expr)
1307db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value), ast.JoinedStr)
1317db96d56Sopenharmony_ci        self.assertEqual(len(t.body[1].value.values), 4)
1327db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[0]), ast.Constant)
1337db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[0].value), str)
1347db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[1]), ast.FormattedValue)
1357db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[2]), ast.Constant)
1367db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[2].value), str)
1377db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[3]), ast.FormattedValue)
1387db96d56Sopenharmony_ci        self.assertEqual(t.body[1].lineno, 3)
1397db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.lineno, 3)
1407db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.values[0].lineno, 3)
1417db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.values[1].lineno, 3)
1427db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.values[2].lineno, 3)
1437db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.values[3].lineno, 3)
1447db96d56Sopenharmony_ci        # check the first binop location
1457db96d56Sopenharmony_ci        binop1 = t.body[1].value.values[1].value
1467db96d56Sopenharmony_ci        self.assertEqual(type(binop1), ast.BinOp)
1477db96d56Sopenharmony_ci        self.assertEqual(type(binop1.left), ast.Name)
1487db96d56Sopenharmony_ci        self.assertEqual(type(binop1.op), ast.Mult)
1497db96d56Sopenharmony_ci        self.assertEqual(type(binop1.right), ast.Call)
1507db96d56Sopenharmony_ci        self.assertEqual(binop1.lineno, 3)
1517db96d56Sopenharmony_ci        self.assertEqual(binop1.left.lineno, 3)
1527db96d56Sopenharmony_ci        self.assertEqual(binop1.right.lineno, 3)
1537db96d56Sopenharmony_ci        self.assertEqual(binop1.col_offset, 8)
1547db96d56Sopenharmony_ci        self.assertEqual(binop1.left.col_offset, 8)
1557db96d56Sopenharmony_ci        self.assertEqual(binop1.right.col_offset, 12)
1567db96d56Sopenharmony_ci        # check the second binop location
1577db96d56Sopenharmony_ci        binop2 = t.body[1].value.values[3].value
1587db96d56Sopenharmony_ci        self.assertEqual(type(binop2), ast.BinOp)
1597db96d56Sopenharmony_ci        self.assertEqual(type(binop2.left), ast.Name)
1607db96d56Sopenharmony_ci        self.assertEqual(type(binop2.op), ast.Add)
1617db96d56Sopenharmony_ci        self.assertEqual(type(binop2.right), ast.Call)
1627db96d56Sopenharmony_ci        self.assertEqual(binop2.lineno, 3)
1637db96d56Sopenharmony_ci        self.assertEqual(binop2.left.lineno, 3)
1647db96d56Sopenharmony_ci        self.assertEqual(binop2.right.lineno, 3)
1657db96d56Sopenharmony_ci        self.assertEqual(binop2.col_offset, 23)
1667db96d56Sopenharmony_ci        self.assertEqual(binop2.left.col_offset, 23)
1677db96d56Sopenharmony_ci        self.assertEqual(binop2.right.col_offset, 27)
1687db96d56Sopenharmony_ci
1697db96d56Sopenharmony_ci    def test_ast_line_numbers_nested(self):
1707db96d56Sopenharmony_ci        expr = """
1717db96d56Sopenharmony_cia = 10
1727db96d56Sopenharmony_cif'{a * f"-{x()}-"}'"""
1737db96d56Sopenharmony_ci        t = ast.parse(expr)
1747db96d56Sopenharmony_ci        self.assertEqual(type(t), ast.Module)
1757db96d56Sopenharmony_ci        self.assertEqual(len(t.body), 2)
1767db96d56Sopenharmony_ci        # check `a = 10`
1777db96d56Sopenharmony_ci        self.assertEqual(type(t.body[0]), ast.Assign)
1787db96d56Sopenharmony_ci        self.assertEqual(t.body[0].lineno, 2)
1797db96d56Sopenharmony_ci        # check `f'...'`
1807db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1]), ast.Expr)
1817db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value), ast.JoinedStr)
1827db96d56Sopenharmony_ci        self.assertEqual(len(t.body[1].value.values), 1)
1837db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)
1847db96d56Sopenharmony_ci        self.assertEqual(t.body[1].lineno, 3)
1857db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.lineno, 3)
1867db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.values[0].lineno, 3)
1877db96d56Sopenharmony_ci        # check the binop location
1887db96d56Sopenharmony_ci        binop = t.body[1].value.values[0].value
1897db96d56Sopenharmony_ci        self.assertEqual(type(binop), ast.BinOp)
1907db96d56Sopenharmony_ci        self.assertEqual(type(binop.left), ast.Name)
1917db96d56Sopenharmony_ci        self.assertEqual(type(binop.op), ast.Mult)
1927db96d56Sopenharmony_ci        self.assertEqual(type(binop.right), ast.JoinedStr)
1937db96d56Sopenharmony_ci        self.assertEqual(binop.lineno, 3)
1947db96d56Sopenharmony_ci        self.assertEqual(binop.left.lineno, 3)
1957db96d56Sopenharmony_ci        self.assertEqual(binop.right.lineno, 3)
1967db96d56Sopenharmony_ci        self.assertEqual(binop.col_offset, 3)
1977db96d56Sopenharmony_ci        self.assertEqual(binop.left.col_offset, 3)
1987db96d56Sopenharmony_ci        self.assertEqual(binop.right.col_offset, 7)
1997db96d56Sopenharmony_ci        # check the nested call location
2007db96d56Sopenharmony_ci        self.assertEqual(len(binop.right.values), 3)
2017db96d56Sopenharmony_ci        self.assertEqual(type(binop.right.values[0]), ast.Constant)
2027db96d56Sopenharmony_ci        self.assertEqual(type(binop.right.values[0].value), str)
2037db96d56Sopenharmony_ci        self.assertEqual(type(binop.right.values[1]), ast.FormattedValue)
2047db96d56Sopenharmony_ci        self.assertEqual(type(binop.right.values[2]), ast.Constant)
2057db96d56Sopenharmony_ci        self.assertEqual(type(binop.right.values[2].value), str)
2067db96d56Sopenharmony_ci        self.assertEqual(binop.right.values[0].lineno, 3)
2077db96d56Sopenharmony_ci        self.assertEqual(binop.right.values[1].lineno, 3)
2087db96d56Sopenharmony_ci        self.assertEqual(binop.right.values[2].lineno, 3)
2097db96d56Sopenharmony_ci        call = binop.right.values[1].value
2107db96d56Sopenharmony_ci        self.assertEqual(type(call), ast.Call)
2117db96d56Sopenharmony_ci        self.assertEqual(call.lineno, 3)
2127db96d56Sopenharmony_ci        self.assertEqual(call.col_offset, 11)
2137db96d56Sopenharmony_ci
2147db96d56Sopenharmony_ci    def test_ast_line_numbers_duplicate_expression(self):
2157db96d56Sopenharmony_ci        expr = """
2167db96d56Sopenharmony_cia = 10
2177db96d56Sopenharmony_cif'{a * x()} {a * x()} {a * x()}'
2187db96d56Sopenharmony_ci"""
2197db96d56Sopenharmony_ci        t = ast.parse(expr)
2207db96d56Sopenharmony_ci        self.assertEqual(type(t), ast.Module)
2217db96d56Sopenharmony_ci        self.assertEqual(len(t.body), 2)
2227db96d56Sopenharmony_ci        # check `a = 10`
2237db96d56Sopenharmony_ci        self.assertEqual(type(t.body[0]), ast.Assign)
2247db96d56Sopenharmony_ci        self.assertEqual(t.body[0].lineno, 2)
2257db96d56Sopenharmony_ci        # check `f'...'`
2267db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1]), ast.Expr)
2277db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value), ast.JoinedStr)
2287db96d56Sopenharmony_ci        self.assertEqual(len(t.body[1].value.values), 5)
2297db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)
2307db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[1]), ast.Constant)
2317db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[1].value), str)
2327db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[2]), ast.FormattedValue)
2337db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[3]), ast.Constant)
2347db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[3].value), str)
2357db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[4]), ast.FormattedValue)
2367db96d56Sopenharmony_ci        self.assertEqual(t.body[1].lineno, 3)
2377db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.lineno, 3)
2387db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.values[0].lineno, 3)
2397db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.values[1].lineno, 3)
2407db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.values[2].lineno, 3)
2417db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.values[3].lineno, 3)
2427db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.values[4].lineno, 3)
2437db96d56Sopenharmony_ci        # check the first binop location
2447db96d56Sopenharmony_ci        binop = t.body[1].value.values[0].value
2457db96d56Sopenharmony_ci        self.assertEqual(type(binop), ast.BinOp)
2467db96d56Sopenharmony_ci        self.assertEqual(type(binop.left), ast.Name)
2477db96d56Sopenharmony_ci        self.assertEqual(type(binop.op), ast.Mult)
2487db96d56Sopenharmony_ci        self.assertEqual(type(binop.right), ast.Call)
2497db96d56Sopenharmony_ci        self.assertEqual(binop.lineno, 3)
2507db96d56Sopenharmony_ci        self.assertEqual(binop.left.lineno, 3)
2517db96d56Sopenharmony_ci        self.assertEqual(binop.right.lineno, 3)
2527db96d56Sopenharmony_ci        self.assertEqual(binop.col_offset, 3)
2537db96d56Sopenharmony_ci        self.assertEqual(binop.left.col_offset, 3)
2547db96d56Sopenharmony_ci        self.assertEqual(binop.right.col_offset, 7)
2557db96d56Sopenharmony_ci        # check the second binop location
2567db96d56Sopenharmony_ci        binop = t.body[1].value.values[2].value
2577db96d56Sopenharmony_ci        self.assertEqual(type(binop), ast.BinOp)
2587db96d56Sopenharmony_ci        self.assertEqual(type(binop.left), ast.Name)
2597db96d56Sopenharmony_ci        self.assertEqual(type(binop.op), ast.Mult)
2607db96d56Sopenharmony_ci        self.assertEqual(type(binop.right), ast.Call)
2617db96d56Sopenharmony_ci        self.assertEqual(binop.lineno, 3)
2627db96d56Sopenharmony_ci        self.assertEqual(binop.left.lineno, 3)
2637db96d56Sopenharmony_ci        self.assertEqual(binop.right.lineno, 3)
2647db96d56Sopenharmony_ci        self.assertEqual(binop.col_offset, 13)
2657db96d56Sopenharmony_ci        self.assertEqual(binop.left.col_offset, 13)
2667db96d56Sopenharmony_ci        self.assertEqual(binop.right.col_offset, 17)
2677db96d56Sopenharmony_ci        # check the third binop location
2687db96d56Sopenharmony_ci        binop = t.body[1].value.values[4].value
2697db96d56Sopenharmony_ci        self.assertEqual(type(binop), ast.BinOp)
2707db96d56Sopenharmony_ci        self.assertEqual(type(binop.left), ast.Name)
2717db96d56Sopenharmony_ci        self.assertEqual(type(binop.op), ast.Mult)
2727db96d56Sopenharmony_ci        self.assertEqual(type(binop.right), ast.Call)
2737db96d56Sopenharmony_ci        self.assertEqual(binop.lineno, 3)
2747db96d56Sopenharmony_ci        self.assertEqual(binop.left.lineno, 3)
2757db96d56Sopenharmony_ci        self.assertEqual(binop.right.lineno, 3)
2767db96d56Sopenharmony_ci        self.assertEqual(binop.col_offset, 23)
2777db96d56Sopenharmony_ci        self.assertEqual(binop.left.col_offset, 23)
2787db96d56Sopenharmony_ci        self.assertEqual(binop.right.col_offset, 27)
2797db96d56Sopenharmony_ci
2807db96d56Sopenharmony_ci    def test_ast_numbers_fstring_with_formatting(self):
2817db96d56Sopenharmony_ci
2827db96d56Sopenharmony_ci        t = ast.parse('f"Here is that pesky {xxx:.3f} again"')
2837db96d56Sopenharmony_ci        self.assertEqual(len(t.body), 1)
2847db96d56Sopenharmony_ci        self.assertEqual(t.body[0].lineno, 1)
2857db96d56Sopenharmony_ci
2867db96d56Sopenharmony_ci        self.assertEqual(type(t.body[0]), ast.Expr)
2877db96d56Sopenharmony_ci        self.assertEqual(type(t.body[0].value), ast.JoinedStr)
2887db96d56Sopenharmony_ci        self.assertEqual(len(t.body[0].value.values), 3)
2897db96d56Sopenharmony_ci
2907db96d56Sopenharmony_ci        self.assertEqual(type(t.body[0].value.values[0]), ast.Constant)
2917db96d56Sopenharmony_ci        self.assertEqual(type(t.body[0].value.values[1]), ast.FormattedValue)
2927db96d56Sopenharmony_ci        self.assertEqual(type(t.body[0].value.values[2]), ast.Constant)
2937db96d56Sopenharmony_ci
2947db96d56Sopenharmony_ci        _, expr, _ = t.body[0].value.values
2957db96d56Sopenharmony_ci
2967db96d56Sopenharmony_ci        name = expr.value
2977db96d56Sopenharmony_ci        self.assertEqual(type(name), ast.Name)
2987db96d56Sopenharmony_ci        self.assertEqual(name.lineno, 1)
2997db96d56Sopenharmony_ci        self.assertEqual(name.end_lineno, 1)
3007db96d56Sopenharmony_ci        self.assertEqual(name.col_offset, 22)
3017db96d56Sopenharmony_ci        self.assertEqual(name.end_col_offset, 25)
3027db96d56Sopenharmony_ci
3037db96d56Sopenharmony_ci    def test_ast_line_numbers_multiline_fstring(self):
3047db96d56Sopenharmony_ci        # See bpo-30465 for details.
3057db96d56Sopenharmony_ci        expr = """
3067db96d56Sopenharmony_cia = 10
3077db96d56Sopenharmony_cif'''
3087db96d56Sopenharmony_ci  {a
3097db96d56Sopenharmony_ci     *
3107db96d56Sopenharmony_ci       x()}
3117db96d56Sopenharmony_cinon-important content
3127db96d56Sopenharmony_ci'''
3137db96d56Sopenharmony_ci"""
3147db96d56Sopenharmony_ci        t = ast.parse(expr)
3157db96d56Sopenharmony_ci        self.assertEqual(type(t), ast.Module)
3167db96d56Sopenharmony_ci        self.assertEqual(len(t.body), 2)
3177db96d56Sopenharmony_ci        # check `a = 10`
3187db96d56Sopenharmony_ci        self.assertEqual(type(t.body[0]), ast.Assign)
3197db96d56Sopenharmony_ci        self.assertEqual(t.body[0].lineno, 2)
3207db96d56Sopenharmony_ci        # check `f'...'`
3217db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1]), ast.Expr)
3227db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value), ast.JoinedStr)
3237db96d56Sopenharmony_ci        self.assertEqual(len(t.body[1].value.values), 3)
3247db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[0]), ast.Constant)
3257db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[0].value), str)
3267db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[1]), ast.FormattedValue)
3277db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[2]), ast.Constant)
3287db96d56Sopenharmony_ci        self.assertEqual(type(t.body[1].value.values[2].value), str)
3297db96d56Sopenharmony_ci        self.assertEqual(t.body[1].lineno, 3)
3307db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.lineno, 3)
3317db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.values[0].lineno, 3)
3327db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.values[1].lineno, 3)
3337db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.values[2].lineno, 3)
3347db96d56Sopenharmony_ci        self.assertEqual(t.body[1].col_offset, 0)
3357db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.col_offset, 0)
3367db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.values[0].col_offset, 0)
3377db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.values[1].col_offset, 0)
3387db96d56Sopenharmony_ci        self.assertEqual(t.body[1].value.values[2].col_offset, 0)
3397db96d56Sopenharmony_ci        # NOTE: the following lineno information and col_offset is correct for
3407db96d56Sopenharmony_ci        # expressions within FormattedValues.
3417db96d56Sopenharmony_ci        binop = t.body[1].value.values[1].value
3427db96d56Sopenharmony_ci        self.assertEqual(type(binop), ast.BinOp)
3437db96d56Sopenharmony_ci        self.assertEqual(type(binop.left), ast.Name)
3447db96d56Sopenharmony_ci        self.assertEqual(type(binop.op), ast.Mult)
3457db96d56Sopenharmony_ci        self.assertEqual(type(binop.right), ast.Call)
3467db96d56Sopenharmony_ci        self.assertEqual(binop.lineno, 4)
3477db96d56Sopenharmony_ci        self.assertEqual(binop.left.lineno, 4)
3487db96d56Sopenharmony_ci        self.assertEqual(binop.right.lineno, 6)
3497db96d56Sopenharmony_ci        self.assertEqual(binop.col_offset, 3)
3507db96d56Sopenharmony_ci        self.assertEqual(binop.left.col_offset, 3)
3517db96d56Sopenharmony_ci        self.assertEqual(binop.right.col_offset, 7)
3527db96d56Sopenharmony_ci
3537db96d56Sopenharmony_ci        expr = """
3547db96d56Sopenharmony_cia = f'''
3557db96d56Sopenharmony_ci          {blech}
3567db96d56Sopenharmony_ci    '''
3577db96d56Sopenharmony_ci"""
3587db96d56Sopenharmony_ci        t = ast.parse(expr)
3597db96d56Sopenharmony_ci        self.assertEqual(type(t), ast.Module)
3607db96d56Sopenharmony_ci        self.assertEqual(len(t.body), 1)
3617db96d56Sopenharmony_ci        # Check f'...'
3627db96d56Sopenharmony_ci        self.assertEqual(type(t.body[0]), ast.Assign)
3637db96d56Sopenharmony_ci        self.assertEqual(type(t.body[0].value), ast.JoinedStr)
3647db96d56Sopenharmony_ci        self.assertEqual(len(t.body[0].value.values), 3)
3657db96d56Sopenharmony_ci        self.assertEqual(type(t.body[0].value.values[1]), ast.FormattedValue)
3667db96d56Sopenharmony_ci        self.assertEqual(t.body[0].lineno, 2)
3677db96d56Sopenharmony_ci        self.assertEqual(t.body[0].value.lineno, 2)
3687db96d56Sopenharmony_ci        self.assertEqual(t.body[0].value.values[0].lineno, 2)
3697db96d56Sopenharmony_ci        self.assertEqual(t.body[0].value.values[1].lineno, 2)
3707db96d56Sopenharmony_ci        self.assertEqual(t.body[0].value.values[2].lineno, 2)
3717db96d56Sopenharmony_ci        self.assertEqual(t.body[0].col_offset, 0)
3727db96d56Sopenharmony_ci        self.assertEqual(t.body[0].value.col_offset, 4)
3737db96d56Sopenharmony_ci        self.assertEqual(t.body[0].value.values[0].col_offset, 4)
3747db96d56Sopenharmony_ci        self.assertEqual(t.body[0].value.values[1].col_offset, 4)
3757db96d56Sopenharmony_ci        self.assertEqual(t.body[0].value.values[2].col_offset, 4)
3767db96d56Sopenharmony_ci        # Check {blech}
3777db96d56Sopenharmony_ci        self.assertEqual(t.body[0].value.values[1].value.lineno, 3)
3787db96d56Sopenharmony_ci        self.assertEqual(t.body[0].value.values[1].value.end_lineno, 3)
3797db96d56Sopenharmony_ci        self.assertEqual(t.body[0].value.values[1].value.col_offset, 11)
3807db96d56Sopenharmony_ci        self.assertEqual(t.body[0].value.values[1].value.end_col_offset, 16)
3817db96d56Sopenharmony_ci
3827db96d56Sopenharmony_ci    def test_ast_line_numbers_with_parentheses(self):
3837db96d56Sopenharmony_ci        expr = """
3847db96d56Sopenharmony_cix = (
3857db96d56Sopenharmony_ci    f" {test(t)}"
3867db96d56Sopenharmony_ci)"""
3877db96d56Sopenharmony_ci        t = ast.parse(expr)
3887db96d56Sopenharmony_ci        self.assertEqual(type(t), ast.Module)
3897db96d56Sopenharmony_ci        self.assertEqual(len(t.body), 1)
3907db96d56Sopenharmony_ci        # check the test(t) location
3917db96d56Sopenharmony_ci        call = t.body[0].value.values[1].value
3927db96d56Sopenharmony_ci        self.assertEqual(type(call), ast.Call)
3937db96d56Sopenharmony_ci        self.assertEqual(call.lineno, 3)
3947db96d56Sopenharmony_ci        self.assertEqual(call.end_lineno, 3)
3957db96d56Sopenharmony_ci        self.assertEqual(call.col_offset, 8)
3967db96d56Sopenharmony_ci        self.assertEqual(call.end_col_offset, 15)
3977db96d56Sopenharmony_ci
3987db96d56Sopenharmony_ci        expr = """
3997db96d56Sopenharmony_cix = (
4007db96d56Sopenharmony_ci        'PERL_MM_OPT', (
4017db96d56Sopenharmony_ci            f'wat'
4027db96d56Sopenharmony_ci            f'some_string={f(x)} '
4037db96d56Sopenharmony_ci            f'wat'
4047db96d56Sopenharmony_ci        ),
4057db96d56Sopenharmony_ci)
4067db96d56Sopenharmony_ci"""
4077db96d56Sopenharmony_ci        t = ast.parse(expr)
4087db96d56Sopenharmony_ci        self.assertEqual(type(t), ast.Module)
4097db96d56Sopenharmony_ci        self.assertEqual(len(t.body), 1)
4107db96d56Sopenharmony_ci        # check the fstring
4117db96d56Sopenharmony_ci        fstring = t.body[0].value.elts[1]
4127db96d56Sopenharmony_ci        self.assertEqual(type(fstring), ast.JoinedStr)
4137db96d56Sopenharmony_ci        self.assertEqual(len(fstring.values), 3)
4147db96d56Sopenharmony_ci        wat1, middle, wat2 = fstring.values
4157db96d56Sopenharmony_ci        # check the first wat
4167db96d56Sopenharmony_ci        self.assertEqual(type(wat1), ast.Constant)
4177db96d56Sopenharmony_ci        self.assertEqual(wat1.lineno, 4)
4187db96d56Sopenharmony_ci        self.assertEqual(wat1.end_lineno, 6)
4197db96d56Sopenharmony_ci        self.assertEqual(wat1.col_offset, 12)
4207db96d56Sopenharmony_ci        self.assertEqual(wat1.end_col_offset, 18)
4217db96d56Sopenharmony_ci        # check the call
4227db96d56Sopenharmony_ci        call = middle.value
4237db96d56Sopenharmony_ci        self.assertEqual(type(call), ast.Call)
4247db96d56Sopenharmony_ci        self.assertEqual(call.lineno, 5)
4257db96d56Sopenharmony_ci        self.assertEqual(call.end_lineno, 5)
4267db96d56Sopenharmony_ci        self.assertEqual(call.col_offset, 27)
4277db96d56Sopenharmony_ci        self.assertEqual(call.end_col_offset, 31)
4287db96d56Sopenharmony_ci        # check the second wat
4297db96d56Sopenharmony_ci        self.assertEqual(type(wat2), ast.Constant)
4307db96d56Sopenharmony_ci        self.assertEqual(wat2.lineno, 4)
4317db96d56Sopenharmony_ci        self.assertEqual(wat2.end_lineno, 6)
4327db96d56Sopenharmony_ci        self.assertEqual(wat2.col_offset, 12)
4337db96d56Sopenharmony_ci        self.assertEqual(wat2.end_col_offset, 18)
4347db96d56Sopenharmony_ci
4357db96d56Sopenharmony_ci    def test_docstring(self):
4367db96d56Sopenharmony_ci        def f():
4377db96d56Sopenharmony_ci            f'''Not a docstring'''
4387db96d56Sopenharmony_ci        self.assertIsNone(f.__doc__)
4397db96d56Sopenharmony_ci        def g():
4407db96d56Sopenharmony_ci            '''Not a docstring''' \
4417db96d56Sopenharmony_ci            f''
4427db96d56Sopenharmony_ci        self.assertIsNone(g.__doc__)
4437db96d56Sopenharmony_ci
4447db96d56Sopenharmony_ci    def test_literal_eval(self):
4457db96d56Sopenharmony_ci        with self.assertRaisesRegex(ValueError, 'malformed node or string'):
4467db96d56Sopenharmony_ci            ast.literal_eval("f'x'")
4477db96d56Sopenharmony_ci
4487db96d56Sopenharmony_ci    def test_ast_compile_time_concat(self):
4497db96d56Sopenharmony_ci        x = ['']
4507db96d56Sopenharmony_ci
4517db96d56Sopenharmony_ci        expr = """x[0] = 'foo' f'{3}'"""
4527db96d56Sopenharmony_ci        t = ast.parse(expr)
4537db96d56Sopenharmony_ci        c = compile(t, '', 'exec')
4547db96d56Sopenharmony_ci        exec(c)
4557db96d56Sopenharmony_ci        self.assertEqual(x[0], 'foo3')
4567db96d56Sopenharmony_ci
4577db96d56Sopenharmony_ci    def test_compile_time_concat_errors(self):
4587db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError,
4597db96d56Sopenharmony_ci                            'cannot mix bytes and nonbytes literals',
4607db96d56Sopenharmony_ci                            [r"""f'' b''""",
4617db96d56Sopenharmony_ci                             r"""b'' f''""",
4627db96d56Sopenharmony_ci                             ])
4637db96d56Sopenharmony_ci
4647db96d56Sopenharmony_ci    def test_literal(self):
4657db96d56Sopenharmony_ci        self.assertEqual(f'', '')
4667db96d56Sopenharmony_ci        self.assertEqual(f'a', 'a')
4677db96d56Sopenharmony_ci        self.assertEqual(f' ', ' ')
4687db96d56Sopenharmony_ci
4697db96d56Sopenharmony_ci    def test_unterminated_string(self):
4707db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, 'f-string: unterminated string',
4717db96d56Sopenharmony_ci                            [r"""f'{"x'""",
4727db96d56Sopenharmony_ci                             r"""f'{"x}'""",
4737db96d56Sopenharmony_ci                             r"""f'{("x'""",
4747db96d56Sopenharmony_ci                             r"""f'{("x}'""",
4757db96d56Sopenharmony_ci                             ])
4767db96d56Sopenharmony_ci
4777db96d56Sopenharmony_ci    def test_mismatched_parens(self):
4787db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\}' "
4797db96d56Sopenharmony_ci                            r"does not match opening parenthesis '\('",
4807db96d56Sopenharmony_ci                            ["f'{((}'",
4817db96d56Sopenharmony_ci                             ])
4827db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\)' "
4837db96d56Sopenharmony_ci                            r"does not match opening parenthesis '\['",
4847db96d56Sopenharmony_ci                            ["f'{a[4)}'",
4857db96d56Sopenharmony_ci                            ])
4867db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\]' "
4877db96d56Sopenharmony_ci                            r"does not match opening parenthesis '\('",
4887db96d56Sopenharmony_ci                            ["f'{a(4]}'",
4897db96d56Sopenharmony_ci                            ])
4907db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\}' "
4917db96d56Sopenharmony_ci                            r"does not match opening parenthesis '\['",
4927db96d56Sopenharmony_ci                            ["f'{a[4}'",
4937db96d56Sopenharmony_ci                            ])
4947db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\}' "
4957db96d56Sopenharmony_ci                            r"does not match opening parenthesis '\('",
4967db96d56Sopenharmony_ci                            ["f'{a(4}'",
4977db96d56Sopenharmony_ci                            ])
4987db96d56Sopenharmony_ci        self.assertRaises(SyntaxError, eval, "f'{" + "("*500 + "}'")
4997db96d56Sopenharmony_ci
5007db96d56Sopenharmony_ci    def test_double_braces(self):
5017db96d56Sopenharmony_ci        self.assertEqual(f'{{', '{')
5027db96d56Sopenharmony_ci        self.assertEqual(f'a{{', 'a{')
5037db96d56Sopenharmony_ci        self.assertEqual(f'{{b', '{b')
5047db96d56Sopenharmony_ci        self.assertEqual(f'a{{b', 'a{b')
5057db96d56Sopenharmony_ci        self.assertEqual(f'}}', '}')
5067db96d56Sopenharmony_ci        self.assertEqual(f'a}}', 'a}')
5077db96d56Sopenharmony_ci        self.assertEqual(f'}}b', '}b')
5087db96d56Sopenharmony_ci        self.assertEqual(f'a}}b', 'a}b')
5097db96d56Sopenharmony_ci        self.assertEqual(f'{{}}', '{}')
5107db96d56Sopenharmony_ci        self.assertEqual(f'a{{}}', 'a{}')
5117db96d56Sopenharmony_ci        self.assertEqual(f'{{b}}', '{b}')
5127db96d56Sopenharmony_ci        self.assertEqual(f'{{}}c', '{}c')
5137db96d56Sopenharmony_ci        self.assertEqual(f'a{{b}}', 'a{b}')
5147db96d56Sopenharmony_ci        self.assertEqual(f'a{{}}c', 'a{}c')
5157db96d56Sopenharmony_ci        self.assertEqual(f'{{b}}c', '{b}c')
5167db96d56Sopenharmony_ci        self.assertEqual(f'a{{b}}c', 'a{b}c')
5177db96d56Sopenharmony_ci
5187db96d56Sopenharmony_ci        self.assertEqual(f'{{{10}', '{10')
5197db96d56Sopenharmony_ci        self.assertEqual(f'}}{10}', '}10')
5207db96d56Sopenharmony_ci        self.assertEqual(f'}}{{{10}', '}{10')
5217db96d56Sopenharmony_ci        self.assertEqual(f'}}a{{{10}', '}a{10')
5227db96d56Sopenharmony_ci
5237db96d56Sopenharmony_ci        self.assertEqual(f'{10}{{', '10{')
5247db96d56Sopenharmony_ci        self.assertEqual(f'{10}}}', '10}')
5257db96d56Sopenharmony_ci        self.assertEqual(f'{10}}}{{', '10}{')
5267db96d56Sopenharmony_ci        self.assertEqual(f'{10}}}a{{' '}', '10}a{}')
5277db96d56Sopenharmony_ci
5287db96d56Sopenharmony_ci        # Inside of strings, don't interpret doubled brackets.
5297db96d56Sopenharmony_ci        self.assertEqual(f'{"{{}}"}', '{{}}')
5307db96d56Sopenharmony_ci
5317db96d56Sopenharmony_ci        self.assertAllRaise(TypeError, 'unhashable type',
5327db96d56Sopenharmony_ci                            ["f'{ {{}} }'", # dict in a set
5337db96d56Sopenharmony_ci                             ])
5347db96d56Sopenharmony_ci
5357db96d56Sopenharmony_ci    def test_compile_time_concat(self):
5367db96d56Sopenharmony_ci        x = 'def'
5377db96d56Sopenharmony_ci        self.assertEqual('abc' f'## {x}ghi', 'abc## defghi')
5387db96d56Sopenharmony_ci        self.assertEqual('abc' f'{x}' 'ghi', 'abcdefghi')
5397db96d56Sopenharmony_ci        self.assertEqual('abc' f'{x}' 'gh' f'i{x:4}', 'abcdefghidef ')
5407db96d56Sopenharmony_ci        self.assertEqual('{x}' f'{x}', '{x}def')
5417db96d56Sopenharmony_ci        self.assertEqual('{x' f'{x}', '{xdef')
5427db96d56Sopenharmony_ci        self.assertEqual('{x}' f'{x}', '{x}def')
5437db96d56Sopenharmony_ci        self.assertEqual('{{x}}' f'{x}', '{{x}}def')
5447db96d56Sopenharmony_ci        self.assertEqual('{{x' f'{x}', '{{xdef')
5457db96d56Sopenharmony_ci        self.assertEqual('x}}' f'{x}', 'x}}def')
5467db96d56Sopenharmony_ci        self.assertEqual(f'{x}' 'x}}', 'defx}}')
5477db96d56Sopenharmony_ci        self.assertEqual(f'{x}' '', 'def')
5487db96d56Sopenharmony_ci        self.assertEqual('' f'{x}' '', 'def')
5497db96d56Sopenharmony_ci        self.assertEqual('' f'{x}', 'def')
5507db96d56Sopenharmony_ci        self.assertEqual(f'{x}' '2', 'def2')
5517db96d56Sopenharmony_ci        self.assertEqual('1' f'{x}' '2', '1def2')
5527db96d56Sopenharmony_ci        self.assertEqual('1' f'{x}', '1def')
5537db96d56Sopenharmony_ci        self.assertEqual(f'{x}' f'-{x}', 'def-def')
5547db96d56Sopenharmony_ci        self.assertEqual('' f'', '')
5557db96d56Sopenharmony_ci        self.assertEqual('' f'' '', '')
5567db96d56Sopenharmony_ci        self.assertEqual('' f'' '' f'', '')
5577db96d56Sopenharmony_ci        self.assertEqual(f'', '')
5587db96d56Sopenharmony_ci        self.assertEqual(f'' '', '')
5597db96d56Sopenharmony_ci        self.assertEqual(f'' '' f'', '')
5607db96d56Sopenharmony_ci        self.assertEqual(f'' '' f'' '', '')
5617db96d56Sopenharmony_ci
5627db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
5637db96d56Sopenharmony_ci                            ["f'{3' f'}'",  # can't concat to get a valid f-string
5647db96d56Sopenharmony_ci                             ])
5657db96d56Sopenharmony_ci
5667db96d56Sopenharmony_ci    def test_comments(self):
5677db96d56Sopenharmony_ci        # These aren't comments, since they're in strings.
5687db96d56Sopenharmony_ci        d = {'#': 'hash'}
5697db96d56Sopenharmony_ci        self.assertEqual(f'{"#"}', '#')
5707db96d56Sopenharmony_ci        self.assertEqual(f'{d["#"]}', 'hash')
5717db96d56Sopenharmony_ci
5727db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, "f-string expression part cannot include '#'",
5737db96d56Sopenharmony_ci                            ["f'{1#}'",   # error because the expression becomes "(1#)"
5747db96d56Sopenharmony_ci                             "f'{3(#)}'",
5757db96d56Sopenharmony_ci                             "f'{#}'",
5767db96d56Sopenharmony_ci                             ])
5777db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, r"f-string: unmatched '\)'",
5787db96d56Sopenharmony_ci                            ["f'{)#}'",   # When wrapped in parens, this becomes
5797db96d56Sopenharmony_ci                                          #  '()#)'.  Make sure that doesn't compile.
5807db96d56Sopenharmony_ci                             ])
5817db96d56Sopenharmony_ci
5827db96d56Sopenharmony_ci    def test_many_expressions(self):
5837db96d56Sopenharmony_ci        # Create a string with many expressions in it. Note that
5847db96d56Sopenharmony_ci        #  because we have a space in here as a literal, we're actually
5857db96d56Sopenharmony_ci        #  going to use twice as many ast nodes: one for each literal
5867db96d56Sopenharmony_ci        #  plus one for each expression.
5877db96d56Sopenharmony_ci        def build_fstr(n, extra=''):
5887db96d56Sopenharmony_ci            return "f'" + ('{x} ' * n) + extra + "'"
5897db96d56Sopenharmony_ci
5907db96d56Sopenharmony_ci        x = 'X'
5917db96d56Sopenharmony_ci        width = 1
5927db96d56Sopenharmony_ci
5937db96d56Sopenharmony_ci        # Test around 256.
5947db96d56Sopenharmony_ci        for i in range(250, 260):
5957db96d56Sopenharmony_ci            self.assertEqual(eval(build_fstr(i)), (x+' ')*i)
5967db96d56Sopenharmony_ci
5977db96d56Sopenharmony_ci        # Test concatenating 2 largs fstrings.
5987db96d56Sopenharmony_ci        self.assertEqual(eval(build_fstr(255)*256), (x+' ')*(255*256))
5997db96d56Sopenharmony_ci
6007db96d56Sopenharmony_ci        s = build_fstr(253, '{x:{width}} ')
6017db96d56Sopenharmony_ci        self.assertEqual(eval(s), (x+' ')*254)
6027db96d56Sopenharmony_ci
6037db96d56Sopenharmony_ci        # Test lots of expressions and constants, concatenated.
6047db96d56Sopenharmony_ci        s = "f'{1}' 'x' 'y'" * 1024
6057db96d56Sopenharmony_ci        self.assertEqual(eval(s), '1xy' * 1024)
6067db96d56Sopenharmony_ci
6077db96d56Sopenharmony_ci    def test_format_specifier_expressions(self):
6087db96d56Sopenharmony_ci        width = 10
6097db96d56Sopenharmony_ci        precision = 4
6107db96d56Sopenharmony_ci        value = decimal.Decimal('12.34567')
6117db96d56Sopenharmony_ci        self.assertEqual(f'result: {value:{width}.{precision}}', 'result:      12.35')
6127db96d56Sopenharmony_ci        self.assertEqual(f'result: {value:{width!r}.{precision}}', 'result:      12.35')
6137db96d56Sopenharmony_ci        self.assertEqual(f'result: {value:{width:0}.{precision:1}}', 'result:      12.35')
6147db96d56Sopenharmony_ci        self.assertEqual(f'result: {value:{1}{0:0}.{precision:1}}', 'result:      12.35')
6157db96d56Sopenharmony_ci        self.assertEqual(f'result: {value:{ 1}{ 0:0}.{ precision:1}}', 'result:      12.35')
6167db96d56Sopenharmony_ci        self.assertEqual(f'{10:#{1}0x}', '       0xa')
6177db96d56Sopenharmony_ci        self.assertEqual(f'{10:{"#"}1{0}{"x"}}', '       0xa')
6187db96d56Sopenharmony_ci        self.assertEqual(f'{-10:-{"#"}1{0}x}', '      -0xa')
6197db96d56Sopenharmony_ci        self.assertEqual(f'{-10:{"-"}#{1}0{"x"}}', '      -0xa')
6207db96d56Sopenharmony_ci        self.assertEqual(f'{10:#{3 != {4:5} and width}x}', '       0xa')
6217db96d56Sopenharmony_ci
6227db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
6237db96d56Sopenharmony_ci                            ["""f'{"s"!r{":10"}}'""",
6247db96d56Sopenharmony_ci
6257db96d56Sopenharmony_ci                             # This looks like a nested format spec.
6267db96d56Sopenharmony_ci                             ])
6277db96d56Sopenharmony_ci
6287db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, "f-string: invalid syntax",
6297db96d56Sopenharmony_ci                            [# Invalid syntax inside a nested spec.
6307db96d56Sopenharmony_ci                             "f'{4:{/5}}'",
6317db96d56Sopenharmony_ci                             ])
6327db96d56Sopenharmony_ci
6337db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, "f-string: expressions nested too deeply",
6347db96d56Sopenharmony_ci                            [# Can't nest format specifiers.
6357db96d56Sopenharmony_ci                             "f'result: {value:{width:{0}}.{precision:1}}'",
6367db96d56Sopenharmony_ci                             ])
6377db96d56Sopenharmony_ci
6387db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character',
6397db96d56Sopenharmony_ci                            [# No expansion inside conversion or for
6407db96d56Sopenharmony_ci                             #  the : or ! itself.
6417db96d56Sopenharmony_ci                             """f'{"s"!{"r"}}'""",
6427db96d56Sopenharmony_ci                             ])
6437db96d56Sopenharmony_ci
6447db96d56Sopenharmony_ci    def test_side_effect_order(self):
6457db96d56Sopenharmony_ci        class X:
6467db96d56Sopenharmony_ci            def __init__(self):
6477db96d56Sopenharmony_ci                self.i = 0
6487db96d56Sopenharmony_ci            def __format__(self, spec):
6497db96d56Sopenharmony_ci                self.i += 1
6507db96d56Sopenharmony_ci                return str(self.i)
6517db96d56Sopenharmony_ci
6527db96d56Sopenharmony_ci        x = X()
6537db96d56Sopenharmony_ci        self.assertEqual(f'{x} {x}', '1 2')
6547db96d56Sopenharmony_ci
6557db96d56Sopenharmony_ci    def test_missing_expression(self):
6567db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, 'f-string: empty expression not allowed',
6577db96d56Sopenharmony_ci                            ["f'{}'",
6587db96d56Sopenharmony_ci                             "f'{ }'"
6597db96d56Sopenharmony_ci                             "f' {} '",
6607db96d56Sopenharmony_ci                             "f'{10:{ }}'",
6617db96d56Sopenharmony_ci                             "f' { } '",
6627db96d56Sopenharmony_ci
6637db96d56Sopenharmony_ci                             # The Python parser ignores also the following
6647db96d56Sopenharmony_ci                             # whitespace characters in additional to a space.
6657db96d56Sopenharmony_ci                             "f'''{\t\f\r\n}'''",
6667db96d56Sopenharmony_ci                             ])
6677db96d56Sopenharmony_ci
6687db96d56Sopenharmony_ci        # Different error messeges are raised when a specfier ('!', ':' or '=') is used after an empty expression
6697db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, "f-string: expression required before '!'",
6707db96d56Sopenharmony_ci                            ["f'{!r}'",
6717db96d56Sopenharmony_ci                             "f'{ !r}'",
6727db96d56Sopenharmony_ci                             "f'{!}'",
6737db96d56Sopenharmony_ci                             "f'''{\t\f\r\n!a}'''",
6747db96d56Sopenharmony_ci
6757db96d56Sopenharmony_ci                             # Catch empty expression before the
6767db96d56Sopenharmony_ci                             #  missing closing brace.
6777db96d56Sopenharmony_ci                             "f'{!'",
6787db96d56Sopenharmony_ci                             "f'{!s:'",
6797db96d56Sopenharmony_ci
6807db96d56Sopenharmony_ci                             # Catch empty expression before the
6817db96d56Sopenharmony_ci                             #  invalid conversion.
6827db96d56Sopenharmony_ci                             "f'{!x}'",
6837db96d56Sopenharmony_ci                             "f'{ !xr}'",
6847db96d56Sopenharmony_ci                             "f'{!x:}'",
6857db96d56Sopenharmony_ci                             "f'{!x:a}'",
6867db96d56Sopenharmony_ci                             "f'{ !xr:}'",
6877db96d56Sopenharmony_ci                             "f'{ !xr:a}'",
6887db96d56Sopenharmony_ci                             ])
6897db96d56Sopenharmony_ci
6907db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, "f-string: expression required before ':'",
6917db96d56Sopenharmony_ci                            ["f'{:}'",
6927db96d56Sopenharmony_ci                             "f'{ :!}'",
6937db96d56Sopenharmony_ci                             "f'{:2}'",
6947db96d56Sopenharmony_ci                             "f'''{\t\f\r\n:a}'''",
6957db96d56Sopenharmony_ci                             "f'{:'",
6967db96d56Sopenharmony_ci                             ])
6977db96d56Sopenharmony_ci
6987db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, "f-string: expression required before '='",
6997db96d56Sopenharmony_ci                            ["f'{=}'",
7007db96d56Sopenharmony_ci                             "f'{ =}'",
7017db96d56Sopenharmony_ci                             "f'{ =:}'",
7027db96d56Sopenharmony_ci                             "f'{   =!}'",
7037db96d56Sopenharmony_ci                             "f'''{\t\f\r\n=}'''",
7047db96d56Sopenharmony_ci                             "f'{='",
7057db96d56Sopenharmony_ci                             ])
7067db96d56Sopenharmony_ci
7077db96d56Sopenharmony_ci        # Different error message is raised for other whitespace characters.
7087db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, r"invalid non-printable character U\+00A0",
7097db96d56Sopenharmony_ci                            ["f'''{\xa0}'''",
7107db96d56Sopenharmony_ci                             "\xa0",
7117db96d56Sopenharmony_ci                             ])
7127db96d56Sopenharmony_ci
7137db96d56Sopenharmony_ci    def test_parens_in_expressions(self):
7147db96d56Sopenharmony_ci        self.assertEqual(f'{3,}', '(3,)')
7157db96d56Sopenharmony_ci
7167db96d56Sopenharmony_ci        # Add these because when an expression is evaluated, parens
7177db96d56Sopenharmony_ci        #  are added around it. But we shouldn't go from an invalid
7187db96d56Sopenharmony_ci        #  expression to a valid one. The added parens are just
7197db96d56Sopenharmony_ci        #  supposed to allow whitespace (including newlines).
7207db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, 'f-string: invalid syntax',
7217db96d56Sopenharmony_ci                            ["f'{,}'",
7227db96d56Sopenharmony_ci                             "f'{,}'",  # this is (,), which is an error
7237db96d56Sopenharmony_ci                             ])
7247db96d56Sopenharmony_ci
7257db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, r"f-string: unmatched '\)'",
7267db96d56Sopenharmony_ci                            ["f'{3)+(4}'",
7277db96d56Sopenharmony_ci                             ])
7287db96d56Sopenharmony_ci
7297db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, 'unterminated string literal',
7307db96d56Sopenharmony_ci                            ["f'{\n}'",
7317db96d56Sopenharmony_ci                             ])
7327db96d56Sopenharmony_ci    def test_newlines_before_syntax_error(self):
7337db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, "invalid syntax",
7347db96d56Sopenharmony_ci                ["f'{.}'", "\nf'{.}'", "\n\nf'{.}'"])
7357db96d56Sopenharmony_ci
7367db96d56Sopenharmony_ci    def test_backslashes_in_string_part(self):
7377db96d56Sopenharmony_ci        self.assertEqual(f'\t', '\t')
7387db96d56Sopenharmony_ci        self.assertEqual(r'\t', '\\t')
7397db96d56Sopenharmony_ci        self.assertEqual(rf'\t', '\\t')
7407db96d56Sopenharmony_ci        self.assertEqual(f'{2}\t', '2\t')
7417db96d56Sopenharmony_ci        self.assertEqual(f'{2}\t{3}', '2\t3')
7427db96d56Sopenharmony_ci        self.assertEqual(f'\t{3}', '\t3')
7437db96d56Sopenharmony_ci
7447db96d56Sopenharmony_ci        self.assertEqual(f'\u0394', '\u0394')
7457db96d56Sopenharmony_ci        self.assertEqual(r'\u0394', '\\u0394')
7467db96d56Sopenharmony_ci        self.assertEqual(rf'\u0394', '\\u0394')
7477db96d56Sopenharmony_ci        self.assertEqual(f'{2}\u0394', '2\u0394')
7487db96d56Sopenharmony_ci        self.assertEqual(f'{2}\u0394{3}', '2\u03943')
7497db96d56Sopenharmony_ci        self.assertEqual(f'\u0394{3}', '\u03943')
7507db96d56Sopenharmony_ci
7517db96d56Sopenharmony_ci        self.assertEqual(f'\U00000394', '\u0394')
7527db96d56Sopenharmony_ci        self.assertEqual(r'\U00000394', '\\U00000394')
7537db96d56Sopenharmony_ci        self.assertEqual(rf'\U00000394', '\\U00000394')
7547db96d56Sopenharmony_ci        self.assertEqual(f'{2}\U00000394', '2\u0394')
7557db96d56Sopenharmony_ci        self.assertEqual(f'{2}\U00000394{3}', '2\u03943')
7567db96d56Sopenharmony_ci        self.assertEqual(f'\U00000394{3}', '\u03943')
7577db96d56Sopenharmony_ci
7587db96d56Sopenharmony_ci        self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}', '\u0394')
7597db96d56Sopenharmony_ci        self.assertEqual(f'{2}\N{GREEK CAPITAL LETTER DELTA}', '2\u0394')
7607db96d56Sopenharmony_ci        self.assertEqual(f'{2}\N{GREEK CAPITAL LETTER DELTA}{3}', '2\u03943')
7617db96d56Sopenharmony_ci        self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}{3}', '\u03943')
7627db96d56Sopenharmony_ci        self.assertEqual(f'2\N{GREEK CAPITAL LETTER DELTA}', '2\u0394')
7637db96d56Sopenharmony_ci        self.assertEqual(f'2\N{GREEK CAPITAL LETTER DELTA}3', '2\u03943')
7647db96d56Sopenharmony_ci        self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}3', '\u03943')
7657db96d56Sopenharmony_ci
7667db96d56Sopenharmony_ci        self.assertEqual(f'\x20', ' ')
7677db96d56Sopenharmony_ci        self.assertEqual(r'\x20', '\\x20')
7687db96d56Sopenharmony_ci        self.assertEqual(rf'\x20', '\\x20')
7697db96d56Sopenharmony_ci        self.assertEqual(f'{2}\x20', '2 ')
7707db96d56Sopenharmony_ci        self.assertEqual(f'{2}\x20{3}', '2 3')
7717db96d56Sopenharmony_ci        self.assertEqual(f'\x20{3}', ' 3')
7727db96d56Sopenharmony_ci
7737db96d56Sopenharmony_ci        self.assertEqual(f'2\x20', '2 ')
7747db96d56Sopenharmony_ci        self.assertEqual(f'2\x203', '2 3')
7757db96d56Sopenharmony_ci        self.assertEqual(f'\x203', ' 3')
7767db96d56Sopenharmony_ci
7777db96d56Sopenharmony_ci        with self.assertWarns(DeprecationWarning):  # invalid escape sequence
7787db96d56Sopenharmony_ci            value = eval(r"f'\{6*7}'")
7797db96d56Sopenharmony_ci        self.assertEqual(value, '\\42')
7807db96d56Sopenharmony_ci        self.assertEqual(f'\\{6*7}', '\\42')
7817db96d56Sopenharmony_ci        self.assertEqual(fr'\{6*7}', '\\42')
7827db96d56Sopenharmony_ci
7837db96d56Sopenharmony_ci        AMPERSAND = 'spam'
7847db96d56Sopenharmony_ci        # Get the right unicode character (&), or pick up local variable
7857db96d56Sopenharmony_ci        # depending on the number of backslashes.
7867db96d56Sopenharmony_ci        self.assertEqual(f'\N{AMPERSAND}', '&')
7877db96d56Sopenharmony_ci        self.assertEqual(f'\\N{AMPERSAND}', '\\Nspam')
7887db96d56Sopenharmony_ci        self.assertEqual(fr'\N{AMPERSAND}', '\\Nspam')
7897db96d56Sopenharmony_ci        self.assertEqual(f'\\\N{AMPERSAND}', '\\&')
7907db96d56Sopenharmony_ci
7917db96d56Sopenharmony_ci    def test_misformed_unicode_character_name(self):
7927db96d56Sopenharmony_ci        # These test are needed because unicode names are parsed
7937db96d56Sopenharmony_ci        # differently inside f-strings.
7947db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, r"\(unicode error\) 'unicodeescape' codec can't decode bytes in position .*: malformed \\N character escape",
7957db96d56Sopenharmony_ci                            [r"f'\N'",
7967db96d56Sopenharmony_ci                             r"f'\N '",
7977db96d56Sopenharmony_ci                             r"f'\N  '",  # See bpo-46503.
7987db96d56Sopenharmony_ci                             r"f'\N{'",
7997db96d56Sopenharmony_ci                             r"f'\N{GREEK CAPITAL LETTER DELTA'",
8007db96d56Sopenharmony_ci
8017db96d56Sopenharmony_ci                             # Here are the non-f-string versions,
8027db96d56Sopenharmony_ci                             #  which should give the same errors.
8037db96d56Sopenharmony_ci                             r"'\N'",
8047db96d56Sopenharmony_ci                             r"'\N '",
8057db96d56Sopenharmony_ci                             r"'\N  '",
8067db96d56Sopenharmony_ci                             r"'\N{'",
8077db96d56Sopenharmony_ci                             r"'\N{GREEK CAPITAL LETTER DELTA'",
8087db96d56Sopenharmony_ci                             ])
8097db96d56Sopenharmony_ci
8107db96d56Sopenharmony_ci    def test_no_backslashes_in_expression_part(self):
8117db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, 'f-string expression part cannot include a backslash',
8127db96d56Sopenharmony_ci                            [r"f'{\'a\'}'",
8137db96d56Sopenharmony_ci                             r"f'{\t3}'",
8147db96d56Sopenharmony_ci                             r"f'{\}'",
8157db96d56Sopenharmony_ci                             r"rf'{\'a\'}'",
8167db96d56Sopenharmony_ci                             r"rf'{\t3}'",
8177db96d56Sopenharmony_ci                             r"rf'{\}'",
8187db96d56Sopenharmony_ci                             r"""rf'{"\N{LEFT CURLY BRACKET}"}'""",
8197db96d56Sopenharmony_ci                             r"f'{\n}'",
8207db96d56Sopenharmony_ci                             ])
8217db96d56Sopenharmony_ci
8227db96d56Sopenharmony_ci    def test_no_escapes_for_braces(self):
8237db96d56Sopenharmony_ci        """
8247db96d56Sopenharmony_ci        Only literal curly braces begin an expression.
8257db96d56Sopenharmony_ci        """
8267db96d56Sopenharmony_ci        # \x7b is '{'.
8277db96d56Sopenharmony_ci        self.assertEqual(f'\x7b1+1}}', '{1+1}')
8287db96d56Sopenharmony_ci        self.assertEqual(f'\x7b1+1', '{1+1')
8297db96d56Sopenharmony_ci        self.assertEqual(f'\u007b1+1', '{1+1')
8307db96d56Sopenharmony_ci        self.assertEqual(f'\N{LEFT CURLY BRACKET}1+1\N{RIGHT CURLY BRACKET}', '{1+1}')
8317db96d56Sopenharmony_ci
8327db96d56Sopenharmony_ci    def test_newlines_in_expressions(self):
8337db96d56Sopenharmony_ci        self.assertEqual(f'{0}', '0')
8347db96d56Sopenharmony_ci        self.assertEqual(rf'''{3+
8357db96d56Sopenharmony_ci4}''', '7')
8367db96d56Sopenharmony_ci
8377db96d56Sopenharmony_ci    def test_lambda(self):
8387db96d56Sopenharmony_ci        x = 5
8397db96d56Sopenharmony_ci        self.assertEqual(f'{(lambda y:x*y)("8")!r}', "'88888'")
8407db96d56Sopenharmony_ci        self.assertEqual(f'{(lambda y:x*y)("8")!r:10}', "'88888'   ")
8417db96d56Sopenharmony_ci        self.assertEqual(f'{(lambda y:x*y)("8"):10}', "88888     ")
8427db96d56Sopenharmony_ci
8437db96d56Sopenharmony_ci        # lambda doesn't work without parens, because the colon
8447db96d56Sopenharmony_ci        #  makes the parser think it's a format_spec
8457db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, 'f-string: invalid syntax',
8467db96d56Sopenharmony_ci                            ["f'{lambda x:x}'",
8477db96d56Sopenharmony_ci                             ])
8487db96d56Sopenharmony_ci
8497db96d56Sopenharmony_ci    def test_yield(self):
8507db96d56Sopenharmony_ci        # Not terribly useful, but make sure the yield turns
8517db96d56Sopenharmony_ci        #  a function into a generator
8527db96d56Sopenharmony_ci        def fn(y):
8537db96d56Sopenharmony_ci            f'y:{yield y*2}'
8547db96d56Sopenharmony_ci            f'{yield}'
8557db96d56Sopenharmony_ci
8567db96d56Sopenharmony_ci        g = fn(4)
8577db96d56Sopenharmony_ci        self.assertEqual(next(g), 8)
8587db96d56Sopenharmony_ci        self.assertEqual(next(g), None)
8597db96d56Sopenharmony_ci
8607db96d56Sopenharmony_ci    def test_yield_send(self):
8617db96d56Sopenharmony_ci        def fn(x):
8627db96d56Sopenharmony_ci            yield f'x:{yield (lambda i: x * i)}'
8637db96d56Sopenharmony_ci
8647db96d56Sopenharmony_ci        g = fn(10)
8657db96d56Sopenharmony_ci        the_lambda = next(g)
8667db96d56Sopenharmony_ci        self.assertEqual(the_lambda(4), 40)
8677db96d56Sopenharmony_ci        self.assertEqual(g.send('string'), 'x:string')
8687db96d56Sopenharmony_ci
8697db96d56Sopenharmony_ci    def test_expressions_with_triple_quoted_strings(self):
8707db96d56Sopenharmony_ci        self.assertEqual(f"{'''x'''}", 'x')
8717db96d56Sopenharmony_ci        self.assertEqual(f"{'''eric's'''}", "eric's")
8727db96d56Sopenharmony_ci
8737db96d56Sopenharmony_ci        # Test concatenation within an expression
8747db96d56Sopenharmony_ci        self.assertEqual(f'{"x" """eric"s""" "y"}', 'xeric"sy')
8757db96d56Sopenharmony_ci        self.assertEqual(f'{"x" """eric"s"""}', 'xeric"s')
8767db96d56Sopenharmony_ci        self.assertEqual(f'{"""eric"s""" "y"}', 'eric"sy')
8777db96d56Sopenharmony_ci        self.assertEqual(f'{"""x""" """eric"s""" "y"}', 'xeric"sy')
8787db96d56Sopenharmony_ci        self.assertEqual(f'{"""x""" """eric"s""" """y"""}', 'xeric"sy')
8797db96d56Sopenharmony_ci        self.assertEqual(f'{r"""x""" """eric"s""" """y"""}', 'xeric"sy')
8807db96d56Sopenharmony_ci
8817db96d56Sopenharmony_ci    def test_multiple_vars(self):
8827db96d56Sopenharmony_ci        x = 98
8837db96d56Sopenharmony_ci        y = 'abc'
8847db96d56Sopenharmony_ci        self.assertEqual(f'{x}{y}', '98abc')
8857db96d56Sopenharmony_ci
8867db96d56Sopenharmony_ci        self.assertEqual(f'X{x}{y}', 'X98abc')
8877db96d56Sopenharmony_ci        self.assertEqual(f'{x}X{y}', '98Xabc')
8887db96d56Sopenharmony_ci        self.assertEqual(f'{x}{y}X', '98abcX')
8897db96d56Sopenharmony_ci
8907db96d56Sopenharmony_ci        self.assertEqual(f'X{x}Y{y}', 'X98Yabc')
8917db96d56Sopenharmony_ci        self.assertEqual(f'X{x}{y}Y', 'X98abcY')
8927db96d56Sopenharmony_ci        self.assertEqual(f'{x}X{y}Y', '98XabcY')
8937db96d56Sopenharmony_ci
8947db96d56Sopenharmony_ci        self.assertEqual(f'X{x}Y{y}Z', 'X98YabcZ')
8957db96d56Sopenharmony_ci
8967db96d56Sopenharmony_ci    def test_closure(self):
8977db96d56Sopenharmony_ci        def outer(x):
8987db96d56Sopenharmony_ci            def inner():
8997db96d56Sopenharmony_ci                return f'x:{x}'
9007db96d56Sopenharmony_ci            return inner
9017db96d56Sopenharmony_ci
9027db96d56Sopenharmony_ci        self.assertEqual(outer('987')(), 'x:987')
9037db96d56Sopenharmony_ci        self.assertEqual(outer(7)(), 'x:7')
9047db96d56Sopenharmony_ci
9057db96d56Sopenharmony_ci    def test_arguments(self):
9067db96d56Sopenharmony_ci        y = 2
9077db96d56Sopenharmony_ci        def f(x, width):
9087db96d56Sopenharmony_ci            return f'x={x*y:{width}}'
9097db96d56Sopenharmony_ci
9107db96d56Sopenharmony_ci        self.assertEqual(f('foo', 10), 'x=foofoo    ')
9117db96d56Sopenharmony_ci        x = 'bar'
9127db96d56Sopenharmony_ci        self.assertEqual(f(10, 10), 'x=        20')
9137db96d56Sopenharmony_ci
9147db96d56Sopenharmony_ci    def test_locals(self):
9157db96d56Sopenharmony_ci        value = 123
9167db96d56Sopenharmony_ci        self.assertEqual(f'v:{value}', 'v:123')
9177db96d56Sopenharmony_ci
9187db96d56Sopenharmony_ci    def test_missing_variable(self):
9197db96d56Sopenharmony_ci        with self.assertRaises(NameError):
9207db96d56Sopenharmony_ci            f'v:{value}'
9217db96d56Sopenharmony_ci
9227db96d56Sopenharmony_ci    def test_missing_format_spec(self):
9237db96d56Sopenharmony_ci        class O:
9247db96d56Sopenharmony_ci            def __format__(self, spec):
9257db96d56Sopenharmony_ci                if not spec:
9267db96d56Sopenharmony_ci                    return '*'
9277db96d56Sopenharmony_ci                return spec
9287db96d56Sopenharmony_ci
9297db96d56Sopenharmony_ci        self.assertEqual(f'{O():x}', 'x')
9307db96d56Sopenharmony_ci        self.assertEqual(f'{O()}', '*')
9317db96d56Sopenharmony_ci        self.assertEqual(f'{O():}', '*')
9327db96d56Sopenharmony_ci
9337db96d56Sopenharmony_ci        self.assertEqual(f'{3:}', '3')
9347db96d56Sopenharmony_ci        self.assertEqual(f'{3!s:}', '3')
9357db96d56Sopenharmony_ci
9367db96d56Sopenharmony_ci    def test_global(self):
9377db96d56Sopenharmony_ci        self.assertEqual(f'g:{a_global}', 'g:global variable')
9387db96d56Sopenharmony_ci        self.assertEqual(f'g:{a_global!r}', "g:'global variable'")
9397db96d56Sopenharmony_ci
9407db96d56Sopenharmony_ci        a_local = 'local variable'
9417db96d56Sopenharmony_ci        self.assertEqual(f'g:{a_global} l:{a_local}',
9427db96d56Sopenharmony_ci                         'g:global variable l:local variable')
9437db96d56Sopenharmony_ci        self.assertEqual(f'g:{a_global!r}',
9447db96d56Sopenharmony_ci                         "g:'global variable'")
9457db96d56Sopenharmony_ci        self.assertEqual(f'g:{a_global} l:{a_local!r}',
9467db96d56Sopenharmony_ci                         "g:global variable l:'local variable'")
9477db96d56Sopenharmony_ci
9487db96d56Sopenharmony_ci        self.assertIn("module 'unittest' from", f'{unittest}')
9497db96d56Sopenharmony_ci
9507db96d56Sopenharmony_ci    def test_shadowed_global(self):
9517db96d56Sopenharmony_ci        a_global = 'really a local'
9527db96d56Sopenharmony_ci        self.assertEqual(f'g:{a_global}', 'g:really a local')
9537db96d56Sopenharmony_ci        self.assertEqual(f'g:{a_global!r}', "g:'really a local'")
9547db96d56Sopenharmony_ci
9557db96d56Sopenharmony_ci        a_local = 'local variable'
9567db96d56Sopenharmony_ci        self.assertEqual(f'g:{a_global} l:{a_local}',
9577db96d56Sopenharmony_ci                         'g:really a local l:local variable')
9587db96d56Sopenharmony_ci        self.assertEqual(f'g:{a_global!r}',
9597db96d56Sopenharmony_ci                         "g:'really a local'")
9607db96d56Sopenharmony_ci        self.assertEqual(f'g:{a_global} l:{a_local!r}',
9617db96d56Sopenharmony_ci                         "g:really a local l:'local variable'")
9627db96d56Sopenharmony_ci
9637db96d56Sopenharmony_ci    def test_call(self):
9647db96d56Sopenharmony_ci        def foo(x):
9657db96d56Sopenharmony_ci            return 'x=' + str(x)
9667db96d56Sopenharmony_ci
9677db96d56Sopenharmony_ci        self.assertEqual(f'{foo(10)}', 'x=10')
9687db96d56Sopenharmony_ci
9697db96d56Sopenharmony_ci    def test_nested_fstrings(self):
9707db96d56Sopenharmony_ci        y = 5
9717db96d56Sopenharmony_ci        self.assertEqual(f'{f"{0}"*3}', '000')
9727db96d56Sopenharmony_ci        self.assertEqual(f'{f"{y}"*3}', '555')
9737db96d56Sopenharmony_ci
9747db96d56Sopenharmony_ci    def test_invalid_string_prefixes(self):
9757db96d56Sopenharmony_ci        single_quote_cases = ["fu''",
9767db96d56Sopenharmony_ci                             "uf''",
9777db96d56Sopenharmony_ci                             "Fu''",
9787db96d56Sopenharmony_ci                             "fU''",
9797db96d56Sopenharmony_ci                             "Uf''",
9807db96d56Sopenharmony_ci                             "uF''",
9817db96d56Sopenharmony_ci                             "ufr''",
9827db96d56Sopenharmony_ci                             "urf''",
9837db96d56Sopenharmony_ci                             "fur''",
9847db96d56Sopenharmony_ci                             "fru''",
9857db96d56Sopenharmony_ci                             "rfu''",
9867db96d56Sopenharmony_ci                             "ruf''",
9877db96d56Sopenharmony_ci                             "FUR''",
9887db96d56Sopenharmony_ci                             "Fur''",
9897db96d56Sopenharmony_ci                             "fb''",
9907db96d56Sopenharmony_ci                             "fB''",
9917db96d56Sopenharmony_ci                             "Fb''",
9927db96d56Sopenharmony_ci                             "FB''",
9937db96d56Sopenharmony_ci                             "bf''",
9947db96d56Sopenharmony_ci                             "bF''",
9957db96d56Sopenharmony_ci                             "Bf''",
9967db96d56Sopenharmony_ci                             "BF''",]
9977db96d56Sopenharmony_ci        double_quote_cases = [case.replace("'", '"') for case in single_quote_cases]
9987db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, 'invalid syntax',
9997db96d56Sopenharmony_ci                            single_quote_cases + double_quote_cases)
10007db96d56Sopenharmony_ci
10017db96d56Sopenharmony_ci    def test_leading_trailing_spaces(self):
10027db96d56Sopenharmony_ci        self.assertEqual(f'{ 3}', '3')
10037db96d56Sopenharmony_ci        self.assertEqual(f'{  3}', '3')
10047db96d56Sopenharmony_ci        self.assertEqual(f'{3 }', '3')
10057db96d56Sopenharmony_ci        self.assertEqual(f'{3  }', '3')
10067db96d56Sopenharmony_ci
10077db96d56Sopenharmony_ci        self.assertEqual(f'expr={ {x: y for x, y in [(1, 2), ]}}',
10087db96d56Sopenharmony_ci                         'expr={1: 2}')
10097db96d56Sopenharmony_ci        self.assertEqual(f'expr={ {x: y for x, y in [(1, 2), ]} }',
10107db96d56Sopenharmony_ci                         'expr={1: 2}')
10117db96d56Sopenharmony_ci
10127db96d56Sopenharmony_ci    def test_not_equal(self):
10137db96d56Sopenharmony_ci        # There's a special test for this because there's a special
10147db96d56Sopenharmony_ci        #  case in the f-string parser to look for != as not ending an
10157db96d56Sopenharmony_ci        #  expression. Normally it would, while looking for !s or !r.
10167db96d56Sopenharmony_ci
10177db96d56Sopenharmony_ci        self.assertEqual(f'{3!=4}', 'True')
10187db96d56Sopenharmony_ci        self.assertEqual(f'{3!=4:}', 'True')
10197db96d56Sopenharmony_ci        self.assertEqual(f'{3!=4!s}', 'True')
10207db96d56Sopenharmony_ci        self.assertEqual(f'{3!=4!s:.3}', 'Tru')
10217db96d56Sopenharmony_ci
10227db96d56Sopenharmony_ci    def test_equal_equal(self):
10237db96d56Sopenharmony_ci        # Because an expression ending in = has special meaning,
10247db96d56Sopenharmony_ci        # there's a special test for ==. Make sure it works.
10257db96d56Sopenharmony_ci
10267db96d56Sopenharmony_ci        self.assertEqual(f'{0==1}', 'False')
10277db96d56Sopenharmony_ci
10287db96d56Sopenharmony_ci    def test_conversions(self):
10297db96d56Sopenharmony_ci        self.assertEqual(f'{3.14:10.10}', '      3.14')
10307db96d56Sopenharmony_ci        self.assertEqual(f'{3.14!s:10.10}', '3.14      ')
10317db96d56Sopenharmony_ci        self.assertEqual(f'{3.14!r:10.10}', '3.14      ')
10327db96d56Sopenharmony_ci        self.assertEqual(f'{3.14!a:10.10}', '3.14      ')
10337db96d56Sopenharmony_ci
10347db96d56Sopenharmony_ci        self.assertEqual(f'{"a"}', 'a')
10357db96d56Sopenharmony_ci        self.assertEqual(f'{"a"!r}', "'a'")
10367db96d56Sopenharmony_ci        self.assertEqual(f'{"a"!a}', "'a'")
10377db96d56Sopenharmony_ci
10387db96d56Sopenharmony_ci        # Not a conversion.
10397db96d56Sopenharmony_ci        self.assertEqual(f'{"a!r"}', "a!r")
10407db96d56Sopenharmony_ci
10417db96d56Sopenharmony_ci        # Not a conversion, but show that ! is allowed in a format spec.
10427db96d56Sopenharmony_ci        self.assertEqual(f'{3.14:!<10.10}', '3.14!!!!!!')
10437db96d56Sopenharmony_ci
10447db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character',
10457db96d56Sopenharmony_ci                            ["f'{3!g}'",
10467db96d56Sopenharmony_ci                             "f'{3!A}'",
10477db96d56Sopenharmony_ci                             "f'{3!3}'",
10487db96d56Sopenharmony_ci                             "f'{3!G}'",
10497db96d56Sopenharmony_ci                             "f'{3!!}'",
10507db96d56Sopenharmony_ci                             "f'{3!:}'",
10517db96d56Sopenharmony_ci                             "f'{3! s}'",  # no space before conversion char
10527db96d56Sopenharmony_ci                             ])
10537db96d56Sopenharmony_ci
10547db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
10557db96d56Sopenharmony_ci                            ["f'{x!s{y}}'",
10567db96d56Sopenharmony_ci                             "f'{3!ss}'",
10577db96d56Sopenharmony_ci                             "f'{3!ss:}'",
10587db96d56Sopenharmony_ci                             "f'{3!ss:s}'",
10597db96d56Sopenharmony_ci                             ])
10607db96d56Sopenharmony_ci
10617db96d56Sopenharmony_ci    def test_assignment(self):
10627db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, r'invalid syntax',
10637db96d56Sopenharmony_ci                            ["f'' = 3",
10647db96d56Sopenharmony_ci                             "f'{0}' = x",
10657db96d56Sopenharmony_ci                             "f'{x}' = x",
10667db96d56Sopenharmony_ci                             ])
10677db96d56Sopenharmony_ci
10687db96d56Sopenharmony_ci    def test_del(self):
10697db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, 'invalid syntax',
10707db96d56Sopenharmony_ci                            ["del f''",
10717db96d56Sopenharmony_ci                             "del '' f''",
10727db96d56Sopenharmony_ci                             ])
10737db96d56Sopenharmony_ci
10747db96d56Sopenharmony_ci    def test_mismatched_braces(self):
10757db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, "f-string: single '}' is not allowed",
10767db96d56Sopenharmony_ci                            ["f'{{}'",
10777db96d56Sopenharmony_ci                             "f'{{}}}'",
10787db96d56Sopenharmony_ci                             "f'}'",
10797db96d56Sopenharmony_ci                             "f'x}'",
10807db96d56Sopenharmony_ci                             "f'x}x'",
10817db96d56Sopenharmony_ci                             r"f'\u007b}'",
10827db96d56Sopenharmony_ci
10837db96d56Sopenharmony_ci                             # Can't have { or } in a format spec.
10847db96d56Sopenharmony_ci                             "f'{3:}>10}'",
10857db96d56Sopenharmony_ci                             "f'{3:}}>10}'",
10867db96d56Sopenharmony_ci                             ])
10877db96d56Sopenharmony_ci
10887db96d56Sopenharmony_ci        self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
10897db96d56Sopenharmony_ci                            ["f'{3:{{>10}'",
10907db96d56Sopenharmony_ci                             "f'{3'",
10917db96d56Sopenharmony_ci                             "f'{3!'",
10927db96d56Sopenharmony_ci                             "f'{3:'",
10937db96d56Sopenharmony_ci                             "f'{3!s'",
10947db96d56Sopenharmony_ci                             "f'{3!s:'",
10957db96d56Sopenharmony_ci                             "f'{3!s:3'",
10967db96d56Sopenharmony_ci                             "f'x{'",
10977db96d56Sopenharmony_ci                             "f'x{x'",
10987db96d56Sopenharmony_ci                             "f'{x'",
10997db96d56Sopenharmony_ci                             "f'{3:s'",
11007db96d56Sopenharmony_ci                             "f'{{{'",
11017db96d56Sopenharmony_ci                             "f'{{}}{'",
11027db96d56Sopenharmony_ci                             "f'{'",
11037db96d56Sopenharmony_ci                             "f'x{<'",  # See bpo-46762.
11047db96d56Sopenharmony_ci                             "f'x{>'",
11057db96d56Sopenharmony_ci                             "f'{i='",  # See gh-93418.
11067db96d56Sopenharmony_ci                             ])
11077db96d56Sopenharmony_ci
11087db96d56Sopenharmony_ci        # But these are just normal strings.
11097db96d56Sopenharmony_ci        self.assertEqual(f'{"{"}', '{')
11107db96d56Sopenharmony_ci        self.assertEqual(f'{"}"}', '}')
11117db96d56Sopenharmony_ci        self.assertEqual(f'{3:{"}"}>10}', '}}}}}}}}}3')
11127db96d56Sopenharmony_ci        self.assertEqual(f'{2:{"{"}>10}', '{{{{{{{{{2')
11137db96d56Sopenharmony_ci
11147db96d56Sopenharmony_ci    def test_if_conditional(self):
11157db96d56Sopenharmony_ci        # There's special logic in compile.c to test if the
11167db96d56Sopenharmony_ci        #  conditional for an if (and while) are constants. Exercise
11177db96d56Sopenharmony_ci        #  that code.
11187db96d56Sopenharmony_ci
11197db96d56Sopenharmony_ci        def test_fstring(x, expected):
11207db96d56Sopenharmony_ci            flag = 0
11217db96d56Sopenharmony_ci            if f'{x}':
11227db96d56Sopenharmony_ci                flag = 1
11237db96d56Sopenharmony_ci            else:
11247db96d56Sopenharmony_ci                flag = 2
11257db96d56Sopenharmony_ci            self.assertEqual(flag, expected)
11267db96d56Sopenharmony_ci
11277db96d56Sopenharmony_ci        def test_concat_empty(x, expected):
11287db96d56Sopenharmony_ci            flag = 0
11297db96d56Sopenharmony_ci            if '' f'{x}':
11307db96d56Sopenharmony_ci                flag = 1
11317db96d56Sopenharmony_ci            else:
11327db96d56Sopenharmony_ci                flag = 2
11337db96d56Sopenharmony_ci            self.assertEqual(flag, expected)
11347db96d56Sopenharmony_ci
11357db96d56Sopenharmony_ci        def test_concat_non_empty(x, expected):
11367db96d56Sopenharmony_ci            flag = 0
11377db96d56Sopenharmony_ci            if ' ' f'{x}':
11387db96d56Sopenharmony_ci                flag = 1
11397db96d56Sopenharmony_ci            else:
11407db96d56Sopenharmony_ci                flag = 2
11417db96d56Sopenharmony_ci            self.assertEqual(flag, expected)
11427db96d56Sopenharmony_ci
11437db96d56Sopenharmony_ci        test_fstring('', 2)
11447db96d56Sopenharmony_ci        test_fstring(' ', 1)
11457db96d56Sopenharmony_ci
11467db96d56Sopenharmony_ci        test_concat_empty('', 2)
11477db96d56Sopenharmony_ci        test_concat_empty(' ', 1)
11487db96d56Sopenharmony_ci
11497db96d56Sopenharmony_ci        test_concat_non_empty('', 1)
11507db96d56Sopenharmony_ci        test_concat_non_empty(' ', 1)
11517db96d56Sopenharmony_ci
11527db96d56Sopenharmony_ci    def test_empty_format_specifier(self):
11537db96d56Sopenharmony_ci        x = 'test'
11547db96d56Sopenharmony_ci        self.assertEqual(f'{x}', 'test')
11557db96d56Sopenharmony_ci        self.assertEqual(f'{x:}', 'test')
11567db96d56Sopenharmony_ci        self.assertEqual(f'{x!s:}', 'test')
11577db96d56Sopenharmony_ci        self.assertEqual(f'{x!r:}', "'test'")
11587db96d56Sopenharmony_ci
11597db96d56Sopenharmony_ci    def test_str_format_differences(self):
11607db96d56Sopenharmony_ci        d = {'a': 'string',
11617db96d56Sopenharmony_ci             0: 'integer',
11627db96d56Sopenharmony_ci             }
11637db96d56Sopenharmony_ci        a = 0
11647db96d56Sopenharmony_ci        self.assertEqual(f'{d[0]}', 'integer')
11657db96d56Sopenharmony_ci        self.assertEqual(f'{d["a"]}', 'string')
11667db96d56Sopenharmony_ci        self.assertEqual(f'{d[a]}', 'integer')
11677db96d56Sopenharmony_ci        self.assertEqual('{d[a]}'.format(d=d), 'string')
11687db96d56Sopenharmony_ci        self.assertEqual('{d[0]}'.format(d=d), 'integer')
11697db96d56Sopenharmony_ci
11707db96d56Sopenharmony_ci    def test_errors(self):
11717db96d56Sopenharmony_ci        # see issue 26287
11727db96d56Sopenharmony_ci        self.assertAllRaise(TypeError, 'unsupported',
11737db96d56Sopenharmony_ci                            [r"f'{(lambda: 0):x}'",
11747db96d56Sopenharmony_ci                             r"f'{(0,):x}'",
11757db96d56Sopenharmony_ci                             ])
11767db96d56Sopenharmony_ci        self.assertAllRaise(ValueError, 'Unknown format code',
11777db96d56Sopenharmony_ci                            [r"f'{1000:j}'",
11787db96d56Sopenharmony_ci                             r"f'{1000:j}'",
11797db96d56Sopenharmony_ci                            ])
11807db96d56Sopenharmony_ci
11817db96d56Sopenharmony_ci    def test_filename_in_syntaxerror(self):
11827db96d56Sopenharmony_ci        # see issue 38964
11837db96d56Sopenharmony_ci        with temp_cwd() as cwd:
11847db96d56Sopenharmony_ci            file_path = os.path.join(cwd, 't.py')
11857db96d56Sopenharmony_ci            with open(file_path, 'w', encoding="utf-8") as f:
11867db96d56Sopenharmony_ci                f.write('f"{a b}"') # This generates a SyntaxError
11877db96d56Sopenharmony_ci            _, _, stderr = assert_python_failure(file_path,
11887db96d56Sopenharmony_ci                                                 PYTHONIOENCODING='ascii')
11897db96d56Sopenharmony_ci        self.assertIn(file_path.encode('ascii', 'backslashreplace'), stderr)
11907db96d56Sopenharmony_ci
11917db96d56Sopenharmony_ci    def test_loop(self):
11927db96d56Sopenharmony_ci        for i in range(1000):
11937db96d56Sopenharmony_ci            self.assertEqual(f'i:{i}', 'i:' + str(i))
11947db96d56Sopenharmony_ci
11957db96d56Sopenharmony_ci    def test_dict(self):
11967db96d56Sopenharmony_ci        d = {'"': 'dquote',
11977db96d56Sopenharmony_ci             "'": 'squote',
11987db96d56Sopenharmony_ci             'foo': 'bar',
11997db96d56Sopenharmony_ci             }
12007db96d56Sopenharmony_ci        self.assertEqual(f'''{d["'"]}''', 'squote')
12017db96d56Sopenharmony_ci        self.assertEqual(f"""{d['"']}""", 'dquote')
12027db96d56Sopenharmony_ci
12037db96d56Sopenharmony_ci        self.assertEqual(f'{d["foo"]}', 'bar')
12047db96d56Sopenharmony_ci        self.assertEqual(f"{d['foo']}", 'bar')
12057db96d56Sopenharmony_ci
12067db96d56Sopenharmony_ci    def test_backslash_char(self):
12077db96d56Sopenharmony_ci        # Check eval of a backslash followed by a control char.
12087db96d56Sopenharmony_ci        # See bpo-30682: this used to raise an assert in pydebug mode.
12097db96d56Sopenharmony_ci        self.assertEqual(eval('f"\\\n"'), '')
12107db96d56Sopenharmony_ci        self.assertEqual(eval('f"\\\r"'), '')
12117db96d56Sopenharmony_ci
12127db96d56Sopenharmony_ci    def test_debug_conversion(self):
12137db96d56Sopenharmony_ci        x = 'A string'
12147db96d56Sopenharmony_ci        self.assertEqual(f'{x=}', 'x=' + repr(x))
12157db96d56Sopenharmony_ci        self.assertEqual(f'{x =}', 'x =' + repr(x))
12167db96d56Sopenharmony_ci        self.assertEqual(f'{x=!s}', 'x=' + str(x))
12177db96d56Sopenharmony_ci        self.assertEqual(f'{x=!r}', 'x=' + repr(x))
12187db96d56Sopenharmony_ci        self.assertEqual(f'{x=!a}', 'x=' + ascii(x))
12197db96d56Sopenharmony_ci
12207db96d56Sopenharmony_ci        x = 2.71828
12217db96d56Sopenharmony_ci        self.assertEqual(f'{x=:.2f}', 'x=' + format(x, '.2f'))
12227db96d56Sopenharmony_ci        self.assertEqual(f'{x=:}', 'x=' + format(x, ''))
12237db96d56Sopenharmony_ci        self.assertEqual(f'{x=!r:^20}', 'x=' + format(repr(x), '^20'))
12247db96d56Sopenharmony_ci        self.assertEqual(f'{x=!s:^20}', 'x=' + format(str(x), '^20'))
12257db96d56Sopenharmony_ci        self.assertEqual(f'{x=!a:^20}', 'x=' + format(ascii(x), '^20'))
12267db96d56Sopenharmony_ci
12277db96d56Sopenharmony_ci        x = 9
12287db96d56Sopenharmony_ci        self.assertEqual(f'{3*x+15=}', '3*x+15=42')
12297db96d56Sopenharmony_ci
12307db96d56Sopenharmony_ci        # There is code in ast.c that deals with non-ascii expression values.  So,
12317db96d56Sopenharmony_ci        # use a unicode identifier to trigger that.
12327db96d56Sopenharmony_ci        tenπ = 31.4
12337db96d56Sopenharmony_ci        self.assertEqual(f'{tenπ=:.2f}', 'tenπ=31.40')
12347db96d56Sopenharmony_ci
12357db96d56Sopenharmony_ci        # Also test with Unicode in non-identifiers.
12367db96d56Sopenharmony_ci        self.assertEqual(f'{"Σ"=}', '"Σ"=\'Σ\'')
12377db96d56Sopenharmony_ci
12387db96d56Sopenharmony_ci        # Make sure nested fstrings still work.
12397db96d56Sopenharmony_ci        self.assertEqual(f'{f"{3.1415=:.1f}":*^20}', '*****3.1415=3.1*****')
12407db96d56Sopenharmony_ci
12417db96d56Sopenharmony_ci        # Make sure text before and after an expression with = works
12427db96d56Sopenharmony_ci        # correctly.
12437db96d56Sopenharmony_ci        pi = 'π'
12447db96d56Sopenharmony_ci        self.assertEqual(f'alpha α {pi=} ω omega', "alpha α pi='π' ω omega")
12457db96d56Sopenharmony_ci
12467db96d56Sopenharmony_ci        # Check multi-line expressions.
12477db96d56Sopenharmony_ci        self.assertEqual(f'''{
12487db96d56Sopenharmony_ci3
12497db96d56Sopenharmony_ci=}''', '\n3\n=3')
12507db96d56Sopenharmony_ci
12517db96d56Sopenharmony_ci        # Since = is handled specially, make sure all existing uses of
12527db96d56Sopenharmony_ci        # it still work.
12537db96d56Sopenharmony_ci
12547db96d56Sopenharmony_ci        self.assertEqual(f'{0==1}', 'False')
12557db96d56Sopenharmony_ci        self.assertEqual(f'{0!=1}', 'True')
12567db96d56Sopenharmony_ci        self.assertEqual(f'{0<=1}', 'True')
12577db96d56Sopenharmony_ci        self.assertEqual(f'{0>=1}', 'False')
12587db96d56Sopenharmony_ci        self.assertEqual(f'{(x:="5")}', '5')
12597db96d56Sopenharmony_ci        self.assertEqual(x, '5')
12607db96d56Sopenharmony_ci        self.assertEqual(f'{(x:=5)}', '5')
12617db96d56Sopenharmony_ci        self.assertEqual(x, 5)
12627db96d56Sopenharmony_ci        self.assertEqual(f'{"="}', '=')
12637db96d56Sopenharmony_ci
12647db96d56Sopenharmony_ci        x = 20
12657db96d56Sopenharmony_ci        # This isn't an assignment expression, it's 'x', with a format
12667db96d56Sopenharmony_ci        # spec of '=10'.  See test_walrus: you need to use parens.
12677db96d56Sopenharmony_ci        self.assertEqual(f'{x:=10}', '        20')
12687db96d56Sopenharmony_ci
12697db96d56Sopenharmony_ci        # Test named function parameters, to make sure '=' parsing works
12707db96d56Sopenharmony_ci        # there.
12717db96d56Sopenharmony_ci        def f(a):
12727db96d56Sopenharmony_ci            nonlocal x
12737db96d56Sopenharmony_ci            oldx = x
12747db96d56Sopenharmony_ci            x = a
12757db96d56Sopenharmony_ci            return oldx
12767db96d56Sopenharmony_ci        x = 0
12777db96d56Sopenharmony_ci        self.assertEqual(f'{f(a="3=")}', '0')
12787db96d56Sopenharmony_ci        self.assertEqual(x, '3=')
12797db96d56Sopenharmony_ci        self.assertEqual(f'{f(a=4)}', '3=')
12807db96d56Sopenharmony_ci        self.assertEqual(x, 4)
12817db96d56Sopenharmony_ci
12827db96d56Sopenharmony_ci        # Make sure __format__ is being called.
12837db96d56Sopenharmony_ci        class C:
12847db96d56Sopenharmony_ci            def __format__(self, s):
12857db96d56Sopenharmony_ci                return f'FORMAT-{s}'
12867db96d56Sopenharmony_ci            def __repr__(self):
12877db96d56Sopenharmony_ci                return 'REPR'
12887db96d56Sopenharmony_ci
12897db96d56Sopenharmony_ci        self.assertEqual(f'{C()=}', 'C()=REPR')
12907db96d56Sopenharmony_ci        self.assertEqual(f'{C()=!r}', 'C()=REPR')
12917db96d56Sopenharmony_ci        self.assertEqual(f'{C()=:}', 'C()=FORMAT-')
12927db96d56Sopenharmony_ci        self.assertEqual(f'{C()=: }', 'C()=FORMAT- ')
12937db96d56Sopenharmony_ci        self.assertEqual(f'{C()=:x}', 'C()=FORMAT-x')
12947db96d56Sopenharmony_ci        self.assertEqual(f'{C()=!r:*^20}', 'C()=********REPR********')
12957db96d56Sopenharmony_ci
12967db96d56Sopenharmony_ci        self.assertRaises(SyntaxError, eval, "f'{C=]'")
12977db96d56Sopenharmony_ci
12987db96d56Sopenharmony_ci        # Make sure leading and following text works.
12997db96d56Sopenharmony_ci        x = 'foo'
13007db96d56Sopenharmony_ci        self.assertEqual(f'X{x=}Y', 'Xx='+repr(x)+'Y')
13017db96d56Sopenharmony_ci
13027db96d56Sopenharmony_ci        # Make sure whitespace around the = works.
13037db96d56Sopenharmony_ci        self.assertEqual(f'X{x  =}Y', 'Xx  ='+repr(x)+'Y')
13047db96d56Sopenharmony_ci        self.assertEqual(f'X{x=  }Y', 'Xx=  '+repr(x)+'Y')
13057db96d56Sopenharmony_ci        self.assertEqual(f'X{x  =  }Y', 'Xx  =  '+repr(x)+'Y')
13067db96d56Sopenharmony_ci
13077db96d56Sopenharmony_ci        # These next lines contains tabs.  Backslash escapes don't
13087db96d56Sopenharmony_ci        # work in f-strings.
13097db96d56Sopenharmony_ci        # patchcheck doesn't like these tabs.  So the only way to test
13107db96d56Sopenharmony_ci        # this will be to dynamically created and exec the f-strings.  But
13117db96d56Sopenharmony_ci        # that's such a hassle I'll save it for another day.  For now, convert
13127db96d56Sopenharmony_ci        # the tabs to spaces just to shut up patchcheck.
13137db96d56Sopenharmony_ci        #self.assertEqual(f'X{x =}Y', 'Xx\t='+repr(x)+'Y')
13147db96d56Sopenharmony_ci        #self.assertEqual(f'X{x =       }Y', 'Xx\t=\t'+repr(x)+'Y')
13157db96d56Sopenharmony_ci
13167db96d56Sopenharmony_ci    def test_walrus(self):
13177db96d56Sopenharmony_ci        x = 20
13187db96d56Sopenharmony_ci        # This isn't an assignment expression, it's 'x', with a format
13197db96d56Sopenharmony_ci        # spec of '=10'.
13207db96d56Sopenharmony_ci        self.assertEqual(f'{x:=10}', '        20')
13217db96d56Sopenharmony_ci
13227db96d56Sopenharmony_ci        # This is an assignment expression, which requires parens.
13237db96d56Sopenharmony_ci        self.assertEqual(f'{(x:=10)}', '10')
13247db96d56Sopenharmony_ci        self.assertEqual(x, 10)
13257db96d56Sopenharmony_ci
13267db96d56Sopenharmony_ci    def test_invalid_syntax_error_message(self):
13277db96d56Sopenharmony_ci        with self.assertRaisesRegex(SyntaxError, "f-string: invalid syntax"):
13287db96d56Sopenharmony_ci            compile("f'{a $ b}'", "?", "exec")
13297db96d56Sopenharmony_ci
13307db96d56Sopenharmony_ci    def test_with_two_commas_in_format_specifier(self):
13317db96d56Sopenharmony_ci        error_msg = re.escape("Cannot specify ',' with ','.")
13327db96d56Sopenharmony_ci        with self.assertRaisesRegex(ValueError, error_msg):
13337db96d56Sopenharmony_ci            f'{1:,,}'
13347db96d56Sopenharmony_ci
13357db96d56Sopenharmony_ci    def test_with_two_underscore_in_format_specifier(self):
13367db96d56Sopenharmony_ci        error_msg = re.escape("Cannot specify '_' with '_'.")
13377db96d56Sopenharmony_ci        with self.assertRaisesRegex(ValueError, error_msg):
13387db96d56Sopenharmony_ci            f'{1:__}'
13397db96d56Sopenharmony_ci
13407db96d56Sopenharmony_ci    def test_with_a_commas_and_an_underscore_in_format_specifier(self):
13417db96d56Sopenharmony_ci        error_msg = re.escape("Cannot specify both ',' and '_'.")
13427db96d56Sopenharmony_ci        with self.assertRaisesRegex(ValueError, error_msg):
13437db96d56Sopenharmony_ci            f'{1:,_}'
13447db96d56Sopenharmony_ci
13457db96d56Sopenharmony_ci    def test_with_an_underscore_and_a_comma_in_format_specifier(self):
13467db96d56Sopenharmony_ci        error_msg = re.escape("Cannot specify both ',' and '_'.")
13477db96d56Sopenharmony_ci        with self.assertRaisesRegex(ValueError, error_msg):
13487db96d56Sopenharmony_ci            f'{1:_,}'
13497db96d56Sopenharmony_ci
13507db96d56Sopenharmony_ci    def test_syntax_error_for_starred_expressions(self):
13517db96d56Sopenharmony_ci        error_msg = re.escape("cannot use starred expression here")
13527db96d56Sopenharmony_ci        with self.assertRaisesRegex(SyntaxError, error_msg):
13537db96d56Sopenharmony_ci            compile("f'{*a}'", "?", "exec")
13547db96d56Sopenharmony_ci
13557db96d56Sopenharmony_ci        error_msg = re.escape("cannot use double starred expression here")
13567db96d56Sopenharmony_ci        with self.assertRaisesRegex(SyntaxError, error_msg):
13577db96d56Sopenharmony_ci            compile("f'{**a}'", "?", "exec")
13587db96d56Sopenharmony_ci
13597db96d56Sopenharmony_ciif __name__ == '__main__':
13607db96d56Sopenharmony_ci    unittest.main()
1361