Home - Summaries: (main) : (py3.11) : Everything - Nightly builds - Benchmarks - RPython - Builders - About

lib-python/3/test/test_unparse.py::unmodified

== PyPy 3.12.13 (a3c6b428e7a8, Jul 09 2026, 03:54:00) [PyPy 8.0.0-alpha0 with GCC Apple LLVM 16.0.0 (clang-1600.0.26.6)]
== macOS-15.7.7-arm64-arm-64bit little-endian
== Python build: release with_assert
== cwd: /private/tmp/buildbot-arm64/pytest/test_python_worker_59822æ
== CPU count: 8
== encodings: locale=UTF-8 FS=utf-8
== resources (3): curses,gui,network

Using random seed: 4124811808
Raised RLIMIT_NOFILE: 256 -> 1024
0:00:00 load avg: 2.33 Run 1 test sequentially in a single process
0:00:00 load avg: 2.33 [1/1] test_unparse
test_backslash_in_format_spec (test.test_unparse.CosmeticTestCase.test_backslash_in_format_spec) ... ok
test_class_bases_and_keywords (test.test_unparse.CosmeticTestCase.test_class_bases_and_keywords) ... ok
test_docstrings (test.test_unparse.CosmeticTestCase.test_docstrings) ... ok
test_docstrings_negative_cases (test.test_unparse.CosmeticTestCase.test_docstrings_negative_cases) ... ok
test_fstrings (test.test_unparse.CosmeticTestCase.test_fstrings) ... ok
test_lambda_parameters (test.test_unparse.CosmeticTestCase.test_lambda_parameters) ... ok
test_multiquote_joined_string (test.test_unparse.CosmeticTestCase.test_multiquote_joined_string) ... 
  test_multiquote_joined_string (test.test_unparse.CosmeticTestCase.test_multiquote_joined_string) (code1='f\'"""{1}\'\'\' ', ast_parse_kwargs={}) ... FAIL
  test_multiquote_joined_string (test.test_unparse.CosmeticTestCase.test_multiquote_joined_string) (code1='f\'"""{"\\n"}\'\'\' ', ast_parse_kwargs={}) ... FAIL
test_quote_in_format_spec (test.test_unparse.CosmeticTestCase.test_quote_in_format_spec) ... ok
test_simple_expressions_parens (test.test_unparse.CosmeticTestCase.test_simple_expressions_parens) ... ok
test_slices (test.test_unparse.CosmeticTestCase.test_slices) ... ok
test_star_expr_assign_target (test.test_unparse.CosmeticTestCase.test_star_expr_assign_target) ... ok
test_star_expr_assign_target_multiple (test.test_unparse.CosmeticTestCase.test_star_expr_assign_target_multiple) ... ok
test_unary_op_factor (test.test_unparse.CosmeticTestCase.test_unary_op_factor) ... ok
test_files (test.test_unparse.DirectoryTestCase.test_files) ... Testing /Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_runpy.py
Testing /Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/os.py
Testing /Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/_test_atexit.py
Testing /Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/stat.py
Testing /Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_monitoring.py
Testing /Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_select.py
Testing /Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_ssl.py
Testing /Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_optparse.py
Testing /Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_graphlib.py
Testing /Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_robotparser.py
Testing /Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_fstring.py

  test_files (test.test_unparse.DirectoryTestCase.test_files) (code1='# -*- coding: utf-8 -*-\n# There are tests here with unicode string literals and\n# identifiers. There\'s a code in ast.c that was added because of a\n# failure with a non-ascii-only expression.  So, I have tests for\n# that.  There are workarounds that would let me run tests for that\n# code without unicode identifiers and strings, but just using them\n# directly seems like the easiest and therefore safest thing to do.\n# Unicode identifiers in tests is allowed by PEP 3131.\n\nimport ast\nimport datetime\nimport os\nimport re\nimport types\nimport decimal\nimport unittest\nimport warnings\nfrom test import support\nfrom test.support.os_helper import temp_cwd\nfrom test.support.script_helper import assert_python_failure, assert_python_ok\n\na_global = "global variable"\n\n# You could argue that I\'m too strict in looking for specific error\n#  values with assertRaisesRegex, but without it it\'s way too easy to\n#  make a syntax error in the test strings. Especially with all of the\n#  triple quotes, raw strings, backslashes, etc. I think it\'s a\n#  worthwhile tradeoff. When I switched to this method, I found many\n#  examples where I wasn\'t testing what I thought I was.\n\n\nclass TestCase(unittest.TestCase):\n    def assertAllRaise(self, exception_type, regex, error_strings):\n        for str in error_strings:\n            with self.subTest(str=str):\n                with self.assertRaisesRegex(exception_type, regex):\n                    eval(str)\n\n    def test__format__lookup(self):\n        # Make sure __format__ is looked up on the type, not the instance.\n        class X:\n            def __format__(self, spec):\n                return "class"\n\n        x = X()\n\n        # Add a bound __format__ method to the \'y\' instance, but not\n        #  the \'x\' instance.\n        y = X()\n        y.__format__ = types.MethodType(lambda self, spec: "instance", y)\n\n        self.assertEqual(f"{y}", format(y))\n        self.assertEqual(f"{y}", "class")\n        self.assertEqual(format(x), format(y))\n\n        # __format__ is not called this way, but still make sure it\n        #  returns what we expect (so we can make sure we\'re bypassing\n        #  it).\n        self.assertEqual(x.__format__(""), "class")\n        self.assertEqual(y.__format__(""), "instance")\n\n        # This is how __format__ is actually called.\n        self.assertEqual(type(x).__format__(x, ""), "class")\n        self.assertEqual(type(y).__format__(y, ""), "class")\n\n    def test_ast(self):\n        # Inspired by http://bugs.python.org/issue24975\n        class X:\n            def __init__(self):\n                self.called = False\n\n            def __call__(self):\n                self.called = True\n                return 4\n\n        x = X()\n        expr = """\na = 10\nf\'{a * x()}\'"""\n        t = ast.parse(expr)\n        c = compile(t, "", "exec")\n\n        # Make sure x was not called.\n        self.assertFalse(x.called)\n\n        # Actually run the code.\n        exec(c)\n\n        # Make sure x was called.\n        self.assertTrue(x.called)\n\n    def test_ast_line_numbers(self):\n        expr = """\na = 10\nf\'{a * x()}\'"""\n        t = ast.parse(expr)\n        self.assertEqual(type(t), ast.Module)\n        self.assertEqual(len(t.body), 2)\n        # check `a = 10`\n        self.assertEqual(type(t.body[0]), ast.Assign)\n        self.assertEqual(t.body[0].lineno, 2)\n        # check `f\'...\'`\n        self.assertEqual(type(t.body[1]), ast.Expr)\n        self.assertEqual(type(t.body[1].value), ast.JoinedStr)\n        self.assertEqual(len(t.body[1].value.values), 1)\n        self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)\n        self.assertEqual(t.body[1].lineno, 3)\n        self.assertEqual(t.body[1].value.lineno, 3)\n        self.assertEqual(t.body[1].value.values[0].lineno, 3)\n        # check the binop location\n        binop = t.body[1].value.values[0].value\n        self.assertEqual(type(binop), ast.BinOp)\n        self.assertEqual(type(binop.left), ast.Name)\n        self.assertEqual(type(binop.op), ast.Mult)\n        self.assertEqual(type(binop.right), ast.Call)\n        self.assertEqual(binop.lineno, 3)\n        self.assertEqual(binop.left.lineno, 3)\n        self.assertEqual(binop.right.lineno, 3)\n        self.assertEqual(binop.col_offset, 3)\n        self.assertEqual(binop.left.col_offset, 3)\n        self.assertEqual(binop.right.col_offset, 7)\n\n    def test_ast_line_numbers_multiple_formattedvalues(self):\n        expr = """\nf\'no formatted values\'\nf\'eggs {a * x()} spam {b + y()}\'"""\n        t = ast.parse(expr)\n        self.assertEqual(type(t), ast.Module)\n        self.assertEqual(len(t.body), 2)\n        # check `f\'no formatted value\'`\n        self.assertEqual(type(t.body[0]), ast.Expr)\n        self.assertEqual(type(t.body[0].value), ast.JoinedStr)\n        self.assertEqual(t.body[0].lineno, 2)\n        # check `f\'...\'`\n        self.assertEqual(type(t.body[1]), ast.Expr)\n        self.assertEqual(type(t.body[1].value), ast.JoinedStr)\n        self.assertEqual(len(t.body[1].value.values), 4)\n        self.assertEqual(type(t.body[1].value.values[0]), ast.Constant)\n        self.assertEqual(type(t.body[1].value.values[0].value), str)\n        self.assertEqual(type(t.body[1].value.values[1]), ast.FormattedValue)\n        self.assertEqual(type(t.body[1].value.values[2]), ast.Constant)\n        self.assertEqual(type(t.body[1].value.values[2].value), str)\n        self.assertEqual(type(t.body[1].value.values[3]), ast.FormattedValue)\n        self.assertEqual(t.body[1].lineno, 3)\n        self.assertEqual(t.body[1].value.lineno, 3)\n        self.assertEqual(t.body[1].value.values[0].lineno, 3)\n        self.assertEqual(t.body[1].value.values[1].lineno, 3)\n        self.assertEqual(t.body[1].value.values[2].lineno, 3)\n        self.assertEqual(t.body[1].value.values[3].lineno, 3)\n        # check the first binop location\n        binop1 = t.body[1].value.values[1].value\n        self.assertEqual(type(binop1), ast.BinOp)\n        self.assertEqual(type(binop1.left), ast.Name)\n        self.assertEqual(type(binop1.op), ast.Mult)\n        self.assertEqual(type(binop1.right), ast.Call)\n        self.assertEqual(binop1.lineno, 3)\n        self.assertEqual(binop1.left.lineno, 3)\n        self.assertEqual(binop1.right.lineno, 3)\n        self.assertEqual(binop1.col_offset, 8)\n        self.assertEqual(binop1.left.col_offset, 8)\n        self.assertEqual(binop1.right.col_offset, 12)\n        # check the second binop location\n        binop2 = t.body[1].value.values[3].value\n        self.assertEqual(type(binop2), ast.BinOp)\n        self.assertEqual(type(binop2.left), ast.Name)\n        self.assertEqual(type(binop2.op), ast.Add)\n        self.assertEqual(type(binop2.right), ast.Call)\n        self.assertEqual(binop2.lineno, 3)\n        self.assertEqual(binop2.left.lineno, 3)\n        self.assertEqual(binop2.right.lineno, 3)\n        self.assertEqual(binop2.col_offset, 23)\n        self.assertEqual(binop2.left.col_offset, 23)\n        self.assertEqual(binop2.right.col_offset, 27)\n\n    def test_ast_line_numbers_nested(self):\n        expr = """\na = 10\nf\'{a * f"-{x()}-"}\'"""\n        t = ast.parse(expr)\n        self.assertEqual(type(t), ast.Module)\n        self.assertEqual(len(t.body), 2)\n        # check `a = 10`\n        self.assertEqual(type(t.body[0]), ast.Assign)\n        self.assertEqual(t.body[0].lineno, 2)\n        # check `f\'...\'`\n        self.assertEqual(type(t.body[1]), ast.Expr)\n        self.assertEqual(type(t.body[1].value), ast.JoinedStr)\n        self.assertEqual(len(t.body[1].value.values), 1)\n        self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)\n        self.assertEqual(t.body[1].lineno, 3)\n        self.assertEqual(t.body[1].value.lineno, 3)\n        self.assertEqual(t.body[1].value.values[0].lineno, 3)\n        # check the binop location\n        binop = t.body[1].value.values[0].value\n        self.assertEqual(type(binop), ast.BinOp)\n        self.assertEqual(type(binop.left), ast.Name)\n        self.assertEqual(type(binop.op), ast.Mult)\n        self.assertEqual(type(binop.right), ast.JoinedStr)\n        self.assertEqual(binop.lineno, 3)\n        self.assertEqual(binop.left.lineno, 3)\n        self.assertEqual(binop.right.lineno, 3)\n        self.assertEqual(binop.col_offset, 3)\n        self.assertEqual(binop.left.col_offset, 3)\n        self.assertEqual(binop.right.col_offset, 7)\n        # check the nested call location\n        self.assertEqual(len(binop.right.values), 3)\n        self.assertEqual(type(binop.right.values[0]), ast.Constant)\n        self.assertEqual(type(binop.right.values[0].value), str)\n        self.assertEqual(type(binop.right.values[1]), ast.FormattedValue)\n        self.assertEqual(type(binop.right.values[2]), ast.Constant)\n        self.assertEqual(type(binop.right.values[2].value), str)\n        self.assertEqual(binop.right.values[0].lineno, 3)\n        self.assertEqual(binop.right.values[1].lineno, 3)\n        self.assertEqual(binop.right.values[2].lineno, 3)\n        call = binop.right.values[1].value\n        self.assertEqual(type(call), ast.Call)\n        self.assertEqual(call.lineno, 3)\n        self.assertEqual(call.col_offset, 11)\n\n    def test_ast_line_numbers_duplicate_expression(self):\n        expr = """\na = 10\nf\'{a * x()} {a * x()} {a * x()}\'\n"""\n        t = ast.parse(expr)\n        self.assertEqual(type(t), ast.Module)\n        self.assertEqual(len(t.body), 2)\n        # check `a = 10`\n        self.assertEqual(type(t.body[0]), ast.Assign)\n        self.assertEqual(t.body[0].lineno, 2)\n        # check `f\'...\'`\n        self.assertEqual(type(t.body[1]), ast.Expr)\n        self.assertEqual(type(t.body[1].value), ast.JoinedStr)\n        self.assertEqual(len(t.body[1].value.values), 5)\n        self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)\n        self.assertEqual(type(t.body[1].value.values[1]), ast.Constant)\n        self.assertEqual(type(t.body[1].value.values[1].value), str)\n        self.assertEqual(type(t.body[1].value.values[2]), ast.FormattedValue)\n        self.assertEqual(type(t.body[1].value.values[3]), ast.Constant)\n        self.assertEqual(type(t.body[1].value.values[3].value), str)\n        self.assertEqual(type(t.body[1].value.values[4]), ast.FormattedValue)\n        self.assertEqual(t.body[1].lineno, 3)\n        self.assertEqual(t.body[1].value.lineno, 3)\n        self.assertEqual(t.body[1].value.values[0].lineno, 3)\n        self.assertEqual(t.body[1].value.values[1].lineno, 3)\n        self.assertEqual(t.body[1].value.values[2].lineno, 3)\n        self.assertEqual(t.body[1].value.values[3].lineno, 3)\n        self.assertEqual(t.body[1].value.values[4].lineno, 3)\n        # check the first binop location\n        binop = t.body[1].value.values[0].value\n        self.assertEqual(type(binop), ast.BinOp)\n        self.assertEqual(type(binop.left), ast.Name)\n        self.assertEqual(type(binop.op), ast.Mult)\n        self.assertEqual(type(binop.right), ast.Call)\n        self.assertEqual(binop.lineno, 3)\n        self.assertEqual(binop.left.lineno, 3)\n        self.assertEqual(binop.right.lineno, 3)\n        self.assertEqual(binop.col_offset, 3)\n        self.assertEqual(binop.left.col_offset, 3)\n        self.assertEqual(binop.right.col_offset, 7)\n        # check the second binop location\n        binop = t.body[1].value.values[2].value\n        self.assertEqual(type(binop), ast.BinOp)\n        self.assertEqual(type(binop.left), ast.Name)\n        self.assertEqual(type(binop.op), ast.Mult)\n        self.assertEqual(type(binop.right), ast.Call)\n        self.assertEqual(binop.lineno, 3)\n        self.assertEqual(binop.left.lineno, 3)\n        self.assertEqual(binop.right.lineno, 3)\n        self.assertEqual(binop.col_offset, 13)\n        self.assertEqual(binop.left.col_offset, 13)\n        self.assertEqual(binop.right.col_offset, 17)\n        # check the third binop location\n        binop = t.body[1].value.values[4].value\n        self.assertEqual(type(binop), ast.BinOp)\n        self.assertEqual(type(binop.left), ast.Name)\n        self.assertEqual(type(binop.op), ast.Mult)\n        self.assertEqual(type(binop.right), ast.Call)\n        self.assertEqual(binop.lineno, 3)\n        self.assertEqual(binop.left.lineno, 3)\n        self.assertEqual(binop.right.lineno, 3)\n        self.assertEqual(binop.col_offset, 23)\n        self.assertEqual(binop.left.col_offset, 23)\n        self.assertEqual(binop.right.col_offset, 27)\n\n    def test_ast_numbers_fstring_with_formatting(self):\n        t = ast.parse(\'f"Here is that pesky {xxx:.3f} again"\')\n        self.assertEqual(len(t.body), 1)\n        self.assertEqual(t.body[0].lineno, 1)\n\n        self.assertEqual(type(t.body[0]), ast.Expr)\n        self.assertEqual(type(t.body[0].value), ast.JoinedStr)\n        self.assertEqual(len(t.body[0].value.values), 3)\n\n        self.assertEqual(type(t.body[0].value.values[0]), ast.Constant)\n        self.assertEqual(type(t.body[0].value.values[1]), ast.FormattedValue)\n        self.assertEqual(type(t.body[0].value.values[2]), ast.Constant)\n\n        _, expr, _ = t.body[0].value.values\n\n        name = expr.value\n        self.assertEqual(type(name), ast.Name)\n        self.assertEqual(name.lineno, 1)\n        self.assertEqual(name.end_lineno, 1)\n        self.assertEqual(name.col_offset, 22)\n        self.assertEqual(name.end_col_offset, 25)\n\n    def test_ast_line_numbers_multiline_fstring(self):\n        # See bpo-30465 for details.\n        expr = """\na = 10\nf\'\'\'\n  {a\n     *\n       x()}\nnon-important content\n\'\'\'\n"""\n        t = ast.parse(expr)\n        self.assertEqual(type(t), ast.Module)\n        self.assertEqual(len(t.body), 2)\n        # check `a = 10`\n        self.assertEqual(type(t.body[0]), ast.Assign)\n        self.assertEqual(t.body[0].lineno, 2)\n        # check `f\'...\'`\n        self.assertEqual(type(t.body[1]), ast.Expr)\n        self.assertEqual(type(t.body[1].value), ast.JoinedStr)\n        self.assertEqual(len(t.body[1].value.values), 3)\n        self.assertEqual(type(t.body[1].value.values[0]), ast.Constant)\n        self.assertEqual(type(t.body[1].value.values[0].value), str)\n        self.assertEqual(type(t.body[1].value.values[1]), ast.FormattedValue)\n        self.assertEqual(type(t.body[1].value.values[2]), ast.Constant)\n        self.assertEqual(type(t.body[1].value.values[2].value), str)\n        self.assertEqual(t.body[1].lineno, 3)\n        self.assertEqual(t.body[1].value.lineno, 3)\n        self.assertEqual(t.body[1].value.values[0].lineno, 3)\n        self.assertEqual(t.body[1].value.values[1].lineno, 4)\n        self.assertEqual(t.body[1].value.values[2].lineno, 6)\n        self.assertEqual(t.body[1].col_offset, 0)\n        self.assertEqual(t.body[1].value.col_offset, 0)\n        self.assertEqual(t.body[1].value.values[0].col_offset, 4)\n        self.assertEqual(t.body[1].value.values[1].col_offset, 2)\n        self.assertEqual(t.body[1].value.values[2].col_offset, 11)\n        # NOTE: the following lineno information and col_offset is correct for\n        # expressions within FormattedValues.\n        binop = t.body[1].value.values[1].value\n        self.assertEqual(type(binop), ast.BinOp)\n        self.assertEqual(type(binop.left), ast.Name)\n        self.assertEqual(type(binop.op), ast.Mult)\n        self.assertEqual(type(binop.right), ast.Call)\n        self.assertEqual(binop.lineno, 4)\n        self.assertEqual(binop.left.lineno, 4)\n        self.assertEqual(binop.right.lineno, 6)\n        self.assertEqual(binop.col_offset, 3)\n        self.assertEqual(binop.left.col_offset, 3)\n        self.assertEqual(binop.right.col_offset, 7)\n\n        expr = """\na = f\'\'\'\n          {blech}\n    \'\'\'\n"""\n        t = ast.parse(expr)\n        self.assertEqual(type(t), ast.Module)\n        self.assertEqual(len(t.body), 1)\n        # Check f\'...\'\n        self.assertEqual(type(t.body[0]), ast.Assign)\n        self.assertEqual(type(t.body[0].value), ast.JoinedStr)\n        self.assertEqual(len(t.body[0].value.values), 3)\n        self.assertEqual(type(t.body[0].value.values[1]), ast.FormattedValue)\n        self.assertEqual(t.body[0].lineno, 2)\n        self.assertEqual(t.body[0].value.lineno, 2)\n        self.assertEqual(t.body[0].value.values[0].lineno, 2)\n        self.assertEqual(t.body[0].value.values[1].lineno, 3)\n        self.assertEqual(t.body[0].value.values[2].lineno, 3)\n        self.assertEqual(t.body[0].col_offset, 0)\n        self.assertEqual(t.body[0].value.col_offset, 4)\n        self.assertEqual(t.body[0].value.values[0].col_offset, 8)\n        self.assertEqual(t.body[0].value.values[1].col_offset, 10)\n        self.assertEqual(t.body[0].value.values[2].col_offset, 17)\n        # Check {blech}\n        self.assertEqual(t.body[0].value.values[1].value.lineno, 3)\n        self.assertEqual(t.body[0].value.values[1].value.end_lineno, 3)\n        self.assertEqual(t.body[0].value.values[1].value.col_offset, 11)\n        self.assertEqual(t.body[0].value.values[1].value.end_col_offset, 16)\n\n    def test_ast_line_numbers_with_parentheses(self):\n        expr = """\nx = (\n    f" {test(t)}"\n)"""\n        t = ast.parse(expr)\n        self.assertEqual(type(t), ast.Module)\n        self.assertEqual(len(t.body), 1)\n        # check the joinedstr location\n        joinedstr = t.body[0].value\n        self.assertEqual(type(joinedstr), ast.JoinedStr)\n        self.assertEqual(joinedstr.lineno, 3)\n        self.assertEqual(joinedstr.end_lineno, 3)\n        self.assertEqual(joinedstr.col_offset, 4)\n        self.assertEqual(joinedstr.end_col_offset, 17)\n        # check the formatted value location\n        fv = t.body[0].value.values[1]\n        self.assertEqual(type(fv), ast.FormattedValue)\n        self.assertEqual(fv.lineno, 3)\n        self.assertEqual(fv.end_lineno, 3)\n        self.assertEqual(fv.col_offset, 7)\n        self.assertEqual(fv.end_col_offset, 16)\n        # check the test(t) location\n        call = t.body[0].value.values[1].value\n        self.assertEqual(type(call), ast.Call)\n        self.assertEqual(call.lineno, 3)\n        self.assertEqual(call.end_lineno, 3)\n        self.assertEqual(call.col_offset, 8)\n        self.assertEqual(call.end_col_offset, 15)\n\n        expr = """\nx = (\n    u\'wat\',\n    u"wat",\n    b\'wat\',\n    b"wat",\n    f\'wat\',\n    f"wat",\n)\n\ny = (\n    u\'\'\'wat\'\'\',\n    u\\"\\"\\"wat\\"\\"\\",\n    b\'\'\'wat\'\'\',\n    b\\"\\"\\"wat\\"\\"\\",\n    f\'\'\'wat\'\'\',\n    f\\"\\"\\"wat\\"\\"\\",\n)\n        """\n        t = ast.parse(expr)\n        self.assertEqual(type(t), ast.Module)\n        self.assertEqual(len(t.body), 2)\n        x, y = t.body\n\n        # Check the single quoted string offsets first.\n        offsets = [(elt.col_offset, elt.end_col_offset) for elt in x.value.elts]\n        self.assertTrue(all(offset == (4, 10) for offset in offsets))\n\n        # Check the triple quoted string offsets.\n        offsets = [(elt.col_offset, elt.end_col_offset) for elt in y.value.elts]\n        self.assertTrue(all(offset == (4, 14) for offset in offsets))\n\n        expr = """\nx = (\n        \'PERL_MM_OPT\', (\n            f\'wat\'\n            f\'some_string={f(x)} \'\n            f\'wat\'\n        ),\n)\n"""\n        t = ast.parse(expr)\n        self.assertEqual(type(t), ast.Module)\n        self.assertEqual(len(t.body), 1)\n        # check the fstring\n        fstring = t.body[0].value.elts[1]\n        self.assertEqual(type(fstring), ast.JoinedStr)\n        self.assertEqual(len(fstring.values), 3)\n        wat1, middle, wat2 = fstring.values\n        # check the first wat\n        self.assertEqual(type(wat1), ast.Constant)\n        self.assertEqual(wat1.lineno, 4)\n        self.assertEqual(wat1.end_lineno, 5)\n        self.assertEqual(wat1.col_offset, 14)\n        self.assertEqual(wat1.end_col_offset, 26)\n        # check the call\n        call = middle.value\n        self.assertEqual(type(call), ast.Call)\n        self.assertEqual(call.lineno, 5)\n        self.assertEqual(call.end_lineno, 5)\n        self.assertEqual(call.col_offset, 27)\n        self.assertEqual(call.end_col_offset, 31)\n        # check the second wat\n        self.assertEqual(type(wat2), ast.Constant)\n        self.assertEqual(wat2.lineno, 5)\n        self.assertEqual(wat2.end_lineno, 6)\n        self.assertEqual(wat2.col_offset, 32)\n        # wat ends at the offset 17, but the whole f-string\n        # ends at the offset 18 (since the quote is part of the\n        # f-string but not the wat string)\n        self.assertEqual(wat2.end_col_offset, 17)\n        self.assertEqual(fstring.end_col_offset, 18)\n\n    def test_ast_fstring_empty_format_spec(self):\n        expr = "f\'{expr:}\'"\n\n        mod = ast.parse(expr)\n        self.assertEqual(type(mod), ast.Module)\n        self.assertEqual(len(mod.body), 1)\n\n        fstring = mod.body[0].value\n        self.assertEqual(type(fstring), ast.JoinedStr)\n        self.assertEqual(len(fstring.values), 1)\n\n        fv = fstring.values[0]\n        self.assertEqual(type(fv), ast.FormattedValue)\n\n        format_spec = fv.format_spec\n        self.assertEqual(type(format_spec), ast.JoinedStr)\n        self.assertEqual(len(format_spec.values), 0)\n\n    def test_docstring(self):\n        def f():\n            f"""Not a docstring"""\n\n        self.assertIsNone(f.__doc__)\n\n        def g():\n            """Not a docstring""" f""\n\n        self.assertIsNone(g.__doc__)\n\n    def test_literal_eval(self):\n        with self.assertRaisesRegex(ValueError, "malformed node or string"):\n            ast.literal_eval("f\'x\'")\n\n    def test_ast_compile_time_concat(self):\n        x = [""]\n\n        expr = """x[0] = \'foo\' f\'{3}\'"""\n        t = ast.parse(expr)\n        c = compile(t, "", "exec")\n        exec(c)\n        self.assertEqual(x[0], "foo3")\n\n    def test_compile_time_concat_errors(self):\n        self.assertAllRaise(\n            SyntaxError,\n            "cannot mix bytes and nonbytes literals",\n            [\n                r"""f\'\' b\'\'""",\n                r"""b\'\' f\'\'""",\n            ],\n        )\n\n    def test_literal(self):\n        self.assertEqual(f"", "")\n        self.assertEqual(f"a", "a")\n        self.assertEqual(f" ", " ")\n\n    def test_unterminated_string(self):\n        self.assertAllRaise(\n            SyntaxError,\n            "unterminated string",\n            [\n                r"""f\'{"x\'""",\n                r"""f\'{"x}\'""",\n                r"""f\'{("x\'""",\n                r"""f\'{("x}\'""",\n            ],\n        )\n\n    @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")\n    def test_mismatched_parens(self):\n        self.assertAllRaise(\n            SyntaxError,\n            r"closing parenthesis \'\\}\' " r"does not match opening parenthesis \'\\(\'",\n            [\n                "f\'{((}\'",\n            ],\n        )\n        self.assertAllRaise(\n            SyntaxError,\n            r"closing parenthesis \'\\)\' " r"does not match opening parenthesis \'\\[\'",\n            [\n                "f\'{a[4)}\'",\n            ],\n        )\n        self.assertAllRaise(\n            SyntaxError,\n            r"closing parenthesis \'\\]\' " r"does not match opening parenthesis \'\\(\'",\n            [\n                "f\'{a(4]}\'",\n            ],\n        )\n        self.assertAllRaise(\n            SyntaxError,\n            r"closing parenthesis \'\\}\' " r"does not match opening parenthesis \'\\[\'",\n            [\n                "f\'{a[4}\'",\n            ],\n        )\n        self.assertAllRaise(\n            SyntaxError,\n            r"closing parenthesis \'\\}\' " r"does not match opening parenthesis \'\\(\'",\n            [\n                "f\'{a(4}\'",\n            ],\n        )\n        self.assertRaises(SyntaxError, eval, "f\'{" + "(" * 500 + "}\'")\n\n    @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")\n    def test_fstring_nested_too_deeply(self):\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expressions nested too deeply",\n            [\'f"{1+2:{1+2:{1+1:{1}}}}"\'],\n        )\n\n        def create_nested_fstring(n):\n            if n == 0:\n                return "1+1"\n            prev = create_nested_fstring(n - 1)\n            return f\'f"{{{prev}}}"\'\n\n        self.assertAllRaise(\n            SyntaxError, "too many nested f-strings", [create_nested_fstring(160)]\n        )\n\n    def test_syntax_error_in_nested_fstring(self):\n        # See gh-104016 for more information on this crash\n        self.assertAllRaise(\n            SyntaxError, "invalid syntax", [\'f"{1 1:\' + (\'{f"1:\' * 199)]\n        )\n\n    def test_double_braces(self):\n        self.assertEqual(f"{{", "{")\n        self.assertEqual(f"a{{", "a{")\n        self.assertEqual(f"{{b", "{b")\n        self.assertEqual(f"a{{b", "a{b")\n        self.assertEqual(f"}}", "}")\n        self.assertEqual(f"a}}", "a}")\n        self.assertEqual(f"}}b", "}b")\n        self.assertEqual(f"a}}b", "a}b")\n        self.assertEqual(f"{{}}", "{}")\n        self.assertEqual(f"a{{}}", "a{}")\n        self.assertEqual(f"{{b}}", "{b}")\n        self.assertEqual(f"{{}}c", "{}c")\n        self.assertEqual(f"a{{b}}", "a{b}")\n        self.assertEqual(f"a{{}}c", "a{}c")\n        self.assertEqual(f"{{b}}c", "{b}c")\n        self.assertEqual(f"a{{b}}c", "a{b}c")\n\n        self.assertEqual(f"{{{10}", "{10")\n        self.assertEqual(f"}}{10}", "}10")\n        self.assertEqual(f"}}{{{10}", "}{10")\n        self.assertEqual(f"}}a{{{10}", "}a{10")\n\n        self.assertEqual(f"{10}{{", "10{")\n        self.assertEqual(f"{10}}}", "10}")\n        self.assertEqual(f"{10}}}{{", "10}{")\n        self.assertEqual(f"{10}}}a{{" "}", "10}a{}")\n\n        # Inside of strings, don\'t interpret doubled brackets.\n        self.assertEqual(f\'{"{{}}"}\', "{{}}")\n\n        self.assertAllRaise(\n            TypeError,\n            "unhashable type",\n            [\n                "f\'{ {{}} }\'",  # dict in a set\n            ],\n        )\n\n    def test_compile_time_concat(self):\n        x = "def"\n        self.assertEqual("abc" f"## {x}ghi", "abc## defghi")\n        self.assertEqual("abc" f"{x}" "ghi", "abcdefghi")\n        self.assertEqual("abc" f"{x}" "gh" f"i{x:4}", "abcdefghidef ")\n        self.assertEqual("{x}" f"{x}", "{x}def")\n        self.assertEqual("{x" f"{x}", "{xdef")\n        self.assertEqual("{x}" f"{x}", "{x}def")\n        self.assertEqual("{{x}}" f"{x}", "{{x}}def")\n        self.assertEqual("{{x" f"{x}", "{{xdef")\n        self.assertEqual("x}}" f"{x}", "x}}def")\n        self.assertEqual(f"{x}" "x}}", "defx}}")\n        self.assertEqual(f"{x}" "", "def")\n        self.assertEqual("" f"{x}" "", "def")\n        self.assertEqual("" f"{x}", "def")\n        self.assertEqual(f"{x}" "2", "def2")\n        self.assertEqual("1" f"{x}" "2", "1def2")\n        self.assertEqual("1" f"{x}", "1def")\n        self.assertEqual(f"{x}" f"-{x}", "def-def")\n        self.assertEqual("" f"", "")\n        self.assertEqual("" f"" "", "")\n        self.assertEqual("" f"" "" f"", "")\n        self.assertEqual(f"", "")\n        self.assertEqual(f"" "", "")\n        self.assertEqual(f"" "" f"", "")\n        self.assertEqual(f"" "" f"" "", "")\n\n        # This is not really [f\'{\'] + [f\'}\'] since we treat the inside\n        # of braces as a purely new context, so it is actually f\'{ and\n        # then eval(\'  f\') (a valid expression) and then }\' which would\n        # constitute a valid f-string.\n        self.assertEqual(f\'{\' f\'}\', " f")\n\n        self.assertAllRaise(\n            SyntaxError,\n            "expecting \'}\'",\n            [\n                \'\'\'f\'{3\' f"}"\'\'\',  # can\'t concat to get a valid f-string\n            ],\n        )\n\n    def test_comments(self):\n        # These aren\'t comments, since they\'re in strings.\n        d = {"#": "hash"}\n        self.assertEqual(f\'{"#"}\', "#")\n        self.assertEqual(f\'{d["#"]}\', "hash")\n\n        self.assertAllRaise(\n            SyntaxError,\n            "\'{\' was never closed",\n            [\n                "f\'{1#}\'",  # error because everything after \'#\' is a comment\n                "f\'{#}\'",\n                "f\'one: {1#}\'",\n                "f\'{1# one} {2 this is a comment still#}\'",\n            ],\n        )\n        self.assertAllRaise(\n            SyntaxError,\n            r"f-string: unmatched \'\\)\'",\n            [\n                "f\'{)#}\'",  # When wrapped in parens, this becomes\n                #  \'()#)\'.  Make sure that doesn\'t compile.\n            ],\n        )\n        self.assertEqual(\n            f"""A complex trick: {\n2  # two\n}""",\n            "A complex trick: 2",\n        )\n        self.assertEqual(\n            f"""\n{\n40 # forty\n+  # plus\n2  # two\n}""",\n            "\\n42",\n        )\n        self.assertEqual(\n            f"""\n{\n40 # forty\n+  # plus\n2  # two\n}""",\n            "\\n42",\n        )\n\n        self.assertEqual(\n            f"""\n# this is not a comment\n{ # the following operation it\'s\n3 # this is a number\n* 2}""",\n            "\\n# this is not a comment\\n6",\n        )\n        self.assertEqual(\n            f"""\n{# f\'a {comment}\'\n86 # constant\n# nothing more\n}""",\n            "\\n86",\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            r"f-string: valid expression required before \'}\'",\n            [\n                """f\'\'\'\n{\n# only a comment\n}\'\'\'\n""",  # this is equivalent to f\'{}\'\n            ],\n        )\n\n    def test_many_expressions(self):\n        # Create a string with many expressions in it. Note that\n        #  because we have a space in here as a literal, we\'re actually\n        #  going to use twice as many ast nodes: one for each literal\n        #  plus one for each expression.\n        def build_fstr(n, extra=""):\n            return "f\'" + ("{x} " * n) + extra + "\'"\n\n        x = "X"\n        width = 1\n\n        # Test around 256.\n        for i in range(250, 260):\n            self.assertEqual(eval(build_fstr(i)), (x + " ") * i)\n\n        # Test concatenating 2 largs fstrings.\n        self.assertEqual(eval(build_fstr(255) * 256), (x + " ") * (255 * 256))\n\n        s = build_fstr(253, "{x:{width}} ")\n        self.assertEqual(eval(s), (x + " ") * 254)\n\n        # Test lots of expressions and constants, concatenated.\n        s = "f\'{1}\' \'x\' \'y\'" * 1024\n        self.assertEqual(eval(s), "1xy" * 1024)\n\n    def test_format_specifier_expressions(self):\n        width = 10\n        precision = 4\n        value = decimal.Decimal("12.34567")\n        self.assertEqual(f"result: {value:{width}.{precision}}", "result:      12.35")\n        self.assertEqual(f"result: {value:{width!r}.{precision}}", "result:      12.35")\n        self.assertEqual(\n            f"result: {value:{width:0}.{precision:1}}", "result:      12.35"\n        )\n        self.assertEqual(\n            f"result: {value:{1}{0:0}.{precision:1}}", "result:      12.35"\n        )\n        self.assertEqual(\n            f"result: {value:{ 1}{ 0:0}.{ precision:1}}", "result:      12.35"\n        )\n        self.assertEqual(f"{10:#{1}0x}", "       0xa")\n        self.assertEqual(f\'{10:{"#"}1{0}{"x"}}\', "       0xa")\n        self.assertEqual(f\'{-10:-{"#"}1{0}x}\', "      -0xa")\n        self.assertEqual(f\'{-10:{"-"}#{1}0{"x"}}\', "      -0xa")\n        self.assertEqual(f"{10:#{3 != {4:5} and width}x}", "       0xa")\n        self.assertEqual(\n            f"result: {value:{width:{0}}.{precision:1}}", "result:      12.35"\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expecting \':\' or \'}\'",\n            [\n                """f\'{"s"!r{":10"}}\'""",\n                # This looks like a nested format spec.\n            ],\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expecting a valid expression after \'{\'",\n            [  # Invalid syntax inside a nested spec.\n                "f\'{4:{/5}}\'",\n            ],\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: invalid conversion character",\n            [  # No expansion inside conversion or for\n                #  the : or ! itself.\n                """f\'{"s"!{"r"}}\'""",\n            ],\n        )\n\n    def test_custom_format_specifier(self):\n        class CustomFormat:\n            def __format__(self, format_spec):\n                return format_spec\n\n        self.assertEqual(f"{CustomFormat():\\n}", "\\n")\n        self.assertEqual(f"{CustomFormat():\\u2603}", "☃")\n        with self.assertWarns(SyntaxWarning):\n            exec(r\'f"{F():¯\\_(ツ)_/¯}"\', {"F": CustomFormat})\n\n    def test_side_effect_order(self):\n        class X:\n            def __init__(self):\n                self.i = 0\n\n            def __format__(self, spec):\n                self.i += 1\n                return str(self.i)\n\n        x = X()\n        self.assertEqual(f"{x} {x}", "1 2")\n\n    def test_missing_expression(self):\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: valid expression required before \'}\'",\n            [\n                "f\'{}\'",\n                "f\'{ }\'" "f\' {} \'",\n                "f\'{10:{ }}\'",\n                "f\' { } \'",\n                # The Python parser ignores also the following\n                # whitespace characters in additional to a space.\n                "f\'\'\'{\\t\\f\\r\\n}\'\'\'",\n            ],\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: valid expression required before \'!\'",\n            [\n                "f\'{!r}\'",\n                "f\'{ !r}\'",\n                "f\'{!}\'",\n                "f\'\'\'{\\t\\f\\r\\n!a}\'\'\'",\n                # Catch empty expression before the\n                #  missing closing brace.\n                "f\'{!\'",\n                "f\'{!s:\'",\n                # Catch empty expression before the\n                #  invalid conversion.\n                "f\'{!x}\'",\n                "f\'{ !xr}\'",\n                "f\'{!x:}\'",\n                "f\'{!x:a}\'",\n                "f\'{ !xr:}\'",\n                "f\'{ !xr:a}\'",\n            ],\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: valid expression required before \':\'",\n            [\n                "f\'{:}\'",\n                "f\'{ :!}\'",\n                "f\'{:2}\'",\n                "f\'\'\'{\\t\\f\\r\\n:a}\'\'\'",\n                "f\'{:\'",\n                "F\'{[F\'{:\'}[F\'{:\'}]]]",\n            ],\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: valid expression required before \'=\'",\n            [\n                "f\'{=}\'",\n                "f\'{ =}\'",\n                "f\'{ =:}\'",\n                "f\'{   =!}\'",\n                "f\'\'\'{\\t\\f\\r\\n=}\'\'\'",\n                "f\'{=\'",\n            ],\n        )\n\n        # Different error message is raised for other whitespace characters.\n        self.assertAllRaise(\n            SyntaxError,\n            r"invalid non-printable character U\\+00A0",\n            [\n                "f\'\'\'{\\xa0}\'\'\'",\n                "\\xa0",\n            ],\n        )\n\n    def test_parens_in_expressions(self):\n        self.assertEqual(f"{3,}", "(3,)")\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expecting a valid expression after \'{\'",\n            [\n                "f\'{,}\'",\n            ],\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            r"f-string: unmatched \'\\)\'",\n            [\n                "f\'{3)+(4}\'",\n            ],\n        )\n\n    def test_newlines_before_syntax_error(self):\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expecting a valid expression after \'{\'",\n            ["f\'{.}\'", "\\nf\'{.}\'", "\\n\\nf\'{.}\'"],\n        )\n\n    def test_backslashes_in_string_part(self):\n        self.assertEqual(f"\\t", "\\t")\n        self.assertEqual(r"\\t", "\\\\t")\n        self.assertEqual(rf"\\t", "\\\\t")\n        self.assertEqual(f"{2}\\t", "2\\t")\n        self.assertEqual(f"{2}\\t{3}", "2\\t3")\n        self.assertEqual(f"\\t{3}", "\\t3")\n\n        self.assertEqual(f"\\u0394", "\\u0394")\n        self.assertEqual(r"\\u0394", "\\\\u0394")\n        self.assertEqual(rf"\\u0394", "\\\\u0394")\n        self.assertEqual(f"{2}\\u0394", "2\\u0394")\n        self.assertEqual(f"{2}\\u0394{3}", "2\\u03943")\n        self.assertEqual(f"\\u0394{3}", "\\u03943")\n\n        self.assertEqual(f"\\U00000394", "\\u0394")\n        self.assertEqual(r"\\U00000394", "\\\\U00000394")\n        self.assertEqual(rf"\\U00000394", "\\\\U00000394")\n        self.assertEqual(f"{2}\\U00000394", "2\\u0394")\n        self.assertEqual(f"{2}\\U00000394{3}", "2\\u03943")\n        self.assertEqual(f"\\U00000394{3}", "\\u03943")\n\n        self.assertEqual(f"\\N{GREEK CAPITAL LETTER DELTA}", "\\u0394")\n        self.assertEqual(f"{2}\\N{GREEK CAPITAL LETTER DELTA}", "2\\u0394")\n        self.assertEqual(f"{2}\\N{GREEK CAPITAL LETTER DELTA}{3}", "2\\u03943")\n        self.assertEqual(f"\\N{GREEK CAPITAL LETTER DELTA}{3}", "\\u03943")\n        self.assertEqual(f"2\\N{GREEK CAPITAL LETTER DELTA}", "2\\u0394")\n        self.assertEqual(f"2\\N{GREEK CAPITAL LETTER DELTA}3", "2\\u03943")\n        self.assertEqual(f"\\N{GREEK CAPITAL LETTER DELTA}3", "\\u03943")\n\n        self.assertEqual(f"\\x20", " ")\n        self.assertEqual(r"\\x20", "\\\\x20")\n        self.assertEqual(rf"\\x20", "\\\\x20")\n        self.assertEqual(f"{2}\\x20", "2 ")\n        self.assertEqual(f"{2}\\x20{3}", "2 3")\n        self.assertEqual(f"\\x20{3}", " 3")\n\n        self.assertEqual(f"2\\x20", "2 ")\n        self.assertEqual(f"2\\x203", "2 3")\n        self.assertEqual(f"\\x203", " 3")\n\n        with self.assertWarns(SyntaxWarning):  # invalid escape sequence\n            value = eval(r"f\'\\{6*7}\'")\n        self.assertEqual(value, "\\\\42")\n        with self.assertWarns(SyntaxWarning):  # invalid escape sequence\n            value = eval(r"f\'\\g\'")\n        self.assertEqual(value, "\\\\g")\n        self.assertEqual(f"\\\\{6*7}", "\\\\42")\n        self.assertEqual(rf"\\{6*7}", "\\\\42")\n\n        AMPERSAND = "spam"\n        # Get the right unicode character (&), or pick up local variable\n        # depending on the number of backslashes.\n        self.assertEqual(f"\\N{AMPERSAND}", "&")\n        self.assertEqual(f"\\\\N{AMPERSAND}", "\\\\Nspam")\n        self.assertEqual(rf"\\N{AMPERSAND}", "\\\\Nspam")\n        self.assertEqual(f"\\\\\\N{AMPERSAND}", "\\\\&")\n\n    def test_misformed_unicode_character_name(self):\n        # These test are needed because unicode names are parsed\n        # differently inside f-strings.\n        self.assertAllRaise(\n            SyntaxError,\n            r"\\(unicode error\\) \'unicodeescape\' codec can\'t decode bytes in position .*: malformed \\\\N character escape",\n            [\n                r"f\'\\N\'",\n                r"f\'\\N \'",\n                r"f\'\\N  \'",  # See bpo-46503.\n                r"f\'\\N{\'",\n                r"f\'\\N{GREEK CAPITAL LETTER DELTA\'",\n                # Here are the non-f-string versions,\n                #  which should give the same errors.\n                r"\'\\N\'",\n                r"\'\\N \'",\n                r"\'\\N  \'",\n                r"\'\\N{\'",\n                r"\'\\N{GREEK CAPITAL LETTER DELTA\'",\n            ],\n        )\n\n    def test_backslashes_in_expression_part(self):\n        self.assertEqual(\n            f"{(\n                        1 +\n                        2\n        )}",\n            "3",\n        )\n\n        self.assertEqual("\\N{LEFT CURLY BRACKET}", "{")\n        self.assertEqual(f\'{"\\N{LEFT CURLY BRACKET}"}\', "{")\n        self.assertEqual(rf\'{"\\N{LEFT CURLY BRACKET}"}\', "{")\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: valid expression required before \'}\'",\n            [\n                "f\'{\\n}\'",\n            ],\n        )\n\n    def test_invalid_backslashes_inside_fstring_context(self):\n        # All of these variations are invalid python syntax,\n        # so they are also invalid in f-strings as well.\n        cases = [\n            formatting.format(expr=expr)\n            for formatting in [\n                "{expr}",\n                "f\'{{{expr}}}\'",\n                "rf\'{{{expr}}}\'",\n            ]\n            for expr in [\n                r"\\\'a\\\'",\n                r"\\t3",\n                r"\\\\"[0],\n            ]\n        ]\n        self.assertAllRaise(\n            SyntaxError, "unexpected character after line continuation", cases\n        )\n\n    def test_no_escapes_for_braces(self):\n        """\n        Only literal curly braces begin an expression.\n        """\n        # \\x7b is \'{\'.\n        self.assertEqual(f"\\x7b1+1}}", "{1+1}")\n        self.assertEqual(f"\\x7b1+1", "{1+1")\n        self.assertEqual(f"\\u007b1+1", "{1+1")\n        self.assertEqual(f"\\N{LEFT CURLY BRACKET}1+1\\N{RIGHT CURLY BRACKET}", "{1+1}")\n\n    def test_newlines_in_expressions(self):\n        self.assertEqual(f"{0}", "0")\n        self.assertEqual(\n            rf"""{3+\n4}""",\n            "7",\n        )\n\n    def test_lambda(self):\n        x = 5\n        self.assertEqual(f\'{(lambda y:x*y)("8")!r}\', "\'88888\'")\n        self.assertEqual(f\'{(lambda y:x*y)("8")!r:10}\', "\'88888\'   ")\n        self.assertEqual(f\'{(lambda y:x*y)("8"):10}\', "88888     ")\n\n        # lambda doesn\'t work without parens, because the colon\n        # makes the parser think it\'s a format_spec\n        # emit warning if we can match a format_spec\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: lambda expressions are not allowed " "without parentheses",\n            [\n                "f\'{lambda x:x}\'",\n                "f\'{lambda :x}\'",\n                "f\'{lambda *arg, :x}\'",\n                "f\'{1, lambda:x}\'",\n                "f\'{lambda x:}\'",\n                "f\'{lambda :}\'",\n            ],\n        )\n        # Ensure the detection of invalid lambdas doesn\'t trigger detection\n        # for valid lambdas in the second error pass\n        with self.assertRaisesRegex(SyntaxError, "invalid syntax"):\n            compile("lambda name_3=f\'{name_4}\': {name_3}\\n1 $ 1", "<string>", "exec")\n\n        # but don\'t emit the paren warning in general cases\n        with self.assertRaisesRegex(\n            SyntaxError, "f-string: expecting a valid expression after \'{\'"\n        ):\n            eval("f\'{+ lambda:None}\'")\n\n    def test_valid_prefixes(self):\n        self.assertEqual(f"{1}", "1")\n        self.assertEqual(Rf"{2}", "2")\n        self.assertEqual(Rf"{3}", "3")\n\n    def test_roundtrip_raw_quotes(self):\n        self.assertEqual(rf"\\\'", "\\\\\'")\n        self.assertEqual(rf"\\"", \'\\\\"\')\n        self.assertEqual(rf"\\"\\\'", "\\\\\\"\\\\\'")\n        self.assertEqual(rf"\\\'\\"", "\\\\\'\\\\\\"")\n        self.assertEqual(rf"\\"\\\'\\"", \'\\\\"\\\\\\\'\\\\"\')\n        self.assertEqual(rf"\\\'\\"\\\'", "\\\\\'\\\\\\"\\\\\'")\n        self.assertEqual(rf"\\"\\\'\\"\\\'", "\\\\\\"\\\\\'\\\\\\"\\\\\'")\n\n    def test_fstring_backslash_before_double_bracket(self):\n        deprecated_cases = [\n            (r"f\'\\{{\\}}\'", "\\\\{\\\\}"),\n            (r"f\'\\{{\'", "\\\\{"),\n            (r"f\'\\{{{1+1}\'", "\\\\{2"),\n            (r"f\'\\}}{1+1}\'", "\\\\}2"),\n            (r"f\'{1+1}\\}}\'", "2\\\\}"),\n        ]\n        for case, expected_result in deprecated_cases:\n            with self.subTest(case=case, expected_result=expected_result):\n                with self.assertWarns(SyntaxWarning):\n                    result = eval(case)\n                self.assertEqual(result, expected_result)\n        self.assertEqual(rf"\\{{\\}}", "\\\\{\\\\}")\n        self.assertEqual(rf"\\{{", "\\\\{")\n        self.assertEqual(rf"\\{{{1+1}", "\\\\{2")\n        self.assertEqual(rf"\\}}{1+1}", "\\\\}2")\n        self.assertEqual(rf"{1+1}\\}}", "2\\\\}")\n\n    def test_fstring_backslash_before_double_bracket_warns_once(self):\n        with self.assertWarns(SyntaxWarning) as w:\n            eval(r"f\'\\{{\'")\n        self.assertEqual(len(w.warnings), 1)\n        self.assertEqual(w.warnings[0].category, SyntaxWarning)\n\n    def test_fstring_backslash_prefix_raw(self):\n        self.assertEqual(f"\\\\", "\\\\")\n        self.assertEqual(f"\\\\\\\\", "\\\\\\\\")\n        self.assertEqual(rf"\\\\", r"\\\\")\n        self.assertEqual(rf"\\\\\\\\", r"\\\\\\\\")\n        self.assertEqual(rf"\\\\", r"\\\\")\n        self.assertEqual(rf"\\\\\\\\", r"\\\\\\\\")\n        self.assertEqual(Rf"\\\\", R"\\\\")\n        self.assertEqual(Rf"\\\\\\\\", R"\\\\\\\\")\n        self.assertEqual(Rf"\\\\", R"\\\\")\n        self.assertEqual(Rf"\\\\\\\\", R"\\\\\\\\")\n        self.assertEqual(Rf"\\\\", R"\\\\")\n        self.assertEqual(Rf"\\\\\\\\", R"\\\\\\\\")\n\n    def test_fstring_format_spec_greedy_matching(self):\n        self.assertEqual(f"{1:}}}", "1}")\n        self.assertEqual(f"{1:>3{5}}}}", "                                  1}")\n\n    def test_yield(self):\n        # Not terribly useful, but make sure the yield turns\n        #  a function into a generator\n        def fn(y):\n            f"y:{yield y*2}"\n            f"{yield}"\n\n        g = fn(4)\n        self.assertEqual(next(g), 8)\n        self.assertEqual(next(g), None)\n\n    def test_yield_send(self):\n        def fn(x):\n            yield f"x:{yield (lambda i: x * i)}"\n\n        g = fn(10)\n        the_lambda = next(g)\n        self.assertEqual(the_lambda(4), 40)\n        self.assertEqual(g.send("string"), "x:string")\n\n    def test_expressions_with_triple_quoted_strings(self):\n        self.assertEqual(f"{\'\'\'x\'\'\'}", "x")\n        self.assertEqual(f"{\'\'\'eric\'s\'\'\'}", "eric\'s")\n\n        # Test concatenation within an expression\n        self.assertEqual(f\'{"x" """eric"s""" "y"}\', \'xeric"sy\')\n        self.assertEqual(f\'{"x" """eric"s"""}\', \'xeric"s\')\n        self.assertEqual(f\'{"""eric"s""" "y"}\', \'eric"sy\')\n        self.assertEqual(f\'{"""x""" """eric"s""" "y"}\', \'xeric"sy\')\n        self.assertEqual(f\'{"""x""" """eric"s""" """y"""}\', \'xeric"sy\')\n        self.assertEqual(f\'{r"""x""" """eric"s""" """y"""}\', \'xeric"sy\')\n\n    def test_multiple_vars(self):\n        x = 98\n        y = "abc"\n        self.assertEqual(f"{x}{y}", "98abc")\n\n        self.assertEqual(f"X{x}{y}", "X98abc")\n        self.assertEqual(f"{x}X{y}", "98Xabc")\n        self.assertEqual(f"{x}{y}X", "98abcX")\n\n        self.assertEqual(f"X{x}Y{y}", "X98Yabc")\n        self.assertEqual(f"X{x}{y}Y", "X98abcY")\n        self.assertEqual(f"{x}X{y}Y", "98XabcY")\n\n        self.assertEqual(f"X{x}Y{y}Z", "X98YabcZ")\n\n    def test_closure(self):\n        def outer(x):\n            def inner():\n                return f"x:{x}"\n\n            return inner\n\n        self.assertEqual(outer("987")(), "x:987")\n        self.assertEqual(outer(7)(), "x:7")\n\n    def test_arguments(self):\n        y = 2\n\n        def f(x, width):\n            return f"x={x*y:{width}}"\n\n        self.assertEqual(f("foo", 10), "x=foofoo    ")\n        x = "bar"\n        self.assertEqual(f(10, 10), "x=        20")\n\n    def test_locals(self):\n        value = 123\n        self.assertEqual(f"v:{value}", "v:123")\n\n    def test_missing_variable(self):\n        with self.assertRaises(NameError):\n            f"v:{value}"\n\n    def test_missing_format_spec(self):\n        class O:\n            def __format__(self, spec):\n                if not spec:\n                    return "*"\n                return spec\n\n        self.assertEqual(f"{O():x}", "x")\n        self.assertEqual(f"{O()}", "*")\n        self.assertEqual(f"{O():}", "*")\n\n        self.assertEqual(f"{3:}", "3")\n        self.assertEqual(f"{3!s:}", "3")\n\n    def test_global(self):\n        self.assertEqual(f"g:{a_global}", "g:global variable")\n        self.assertEqual(f"g:{a_global!r}", "g:\'global variable\'")\n\n        a_local = "local variable"\n        self.assertEqual(\n            f"g:{a_global} l:{a_local}", "g:global variable l:local variable"\n        )\n        self.assertEqual(f"g:{a_global!r}", "g:\'global variable\'")\n        self.assertEqual(\n            f"g:{a_global} l:{a_local!r}", "g:global variable l:\'local variable\'"\n        )\n\n        self.assertIn("module \'unittest\' from", f"{unittest}")\n\n    def test_shadowed_global(self):\n        a_global = "really a local"\n        self.assertEqual(f"g:{a_global}", "g:really a local")\n        self.assertEqual(f"g:{a_global!r}", "g:\'really a local\'")\n\n        a_local = "local variable"\n        self.assertEqual(\n            f"g:{a_global} l:{a_local}", "g:really a local l:local variable"\n        )\n        self.assertEqual(f"g:{a_global!r}", "g:\'really a local\'")\n        self.assertEqual(\n            f"g:{a_global} l:{a_local!r}", "g:really a local l:\'local variable\'"\n        )\n\n    def test_call(self):\n        def foo(x):\n            return "x=" + str(x)\n\n        self.assertEqual(f"{foo(10)}", "x=10")\n\n    def test_nested_fstrings(self):\n        y = 5\n        self.assertEqual(f\'{f"{0}"*3}\', "000")\n        self.assertEqual(f\'{f"{y}"*3}\', "555")\n\n    def test_invalid_string_prefixes(self):\n        single_quote_cases = [\n            "fu\'\'",\n            "uf\'\'",\n            "Fu\'\'",\n            "fU\'\'",\n            "Uf\'\'",\n            "uF\'\'",\n            "ufr\'\'",\n            "urf\'\'",\n            "fur\'\'",\n            "fru\'\'",\n            "rfu\'\'",\n            "ruf\'\'",\n            "FUR\'\'",\n            "Fur\'\'",\n            "fb\'\'",\n            "fB\'\'",\n            "Fb\'\'",\n            "FB\'\'",\n            "bf\'\'",\n            "bF\'\'",\n            "Bf\'\'",\n            "BF\'\'",\n        ]\n        double_quote_cases = [case.replace("\'", \'"\') for case in single_quote_cases]\n        self.assertAllRaise(\n            SyntaxError, "invalid syntax", single_quote_cases + double_quote_cases\n        )\n\n    def test_leading_trailing_spaces(self):\n        self.assertEqual(f"{ 3}", "3")\n        self.assertEqual(f"{  3}", "3")\n        self.assertEqual(f"{3 }", "3")\n        self.assertEqual(f"{3  }", "3")\n\n        self.assertEqual(f"expr={ {x: y for x, y in [(1, 2), ]}}", "expr={1: 2}")\n        self.assertEqual(f"expr={ {x: y for x, y in [(1, 2), ]} }", "expr={1: 2}")\n\n    def test_not_equal(self):\n        # There\'s a special test for this because there\'s a special\n        #  case in the f-string parser to look for != as not ending an\n        #  expression. Normally it would, while looking for !s or !r.\n\n        self.assertEqual(f"{3!=4}", "True")\n        self.assertEqual(f"{3!=4:}", "True")\n        self.assertEqual(f"{3!=4!s}", "True")\n        self.assertEqual(f"{3!=4!s:.3}", "Tru")\n\n    def test_equal_equal(self):\n        # Because an expression ending in = has special meaning,\n        # there\'s a special test for ==. Make sure it works.\n\n        self.assertEqual(f"{0==1}", "False")\n\n    def test_conversions(self):\n        self.assertEqual(f"{3.14:10.10}", "      3.14")\n        self.assertEqual(f"{3.14!s:10.10}", "3.14      ")\n        self.assertEqual(f"{3.14!r:10.10}", "3.14      ")\n        self.assertEqual(f"{3.14!a:10.10}", "3.14      ")\n\n        self.assertEqual(f\'{"a"}\', "a")\n        self.assertEqual(f\'{"a"!r}\', "\'a\'")\n        self.assertEqual(f\'{"a"!a}\', "\'a\'")\n\n        # Conversions can have trailing whitespace after them since it\n        # does not provide any significance\n        self.assertEqual(f"{3!s  }", "3")\n        self.assertEqual(f"{3.14!s  :10.10}", "3.14      ")\n\n        # Not a conversion.\n        self.assertEqual(f\'{"a!r"}\', "a!r")\n\n        # Not a conversion, but show that ! is allowed in a format spec.\n        self.assertEqual(f"{3.14:!<10.10}", "3.14!!!!!!")\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expecting \'}\'",\n            [\n                "f\'{3!\'",\n                "f\'{3!s\'",\n                "f\'{3!g\'",\n            ],\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: missing conversion character",\n            [\n                "f\'{3!}\'",\n                "f\'{3!:\'",\n                "f\'{3!:}\'",\n            ],\n        )\n\n        for conv_identifier in "g", "A", "G", "ä", "ɐ":\n            self.assertAllRaise(\n                SyntaxError,\n                "f-string: invalid conversion character %r: "\n                "expected \'s\', \'r\', or \'a\'" % conv_identifier,\n                ["f\'{3!" + conv_identifier + "}\'"],\n            )\n\n        for conv_non_identifier in "3", "!":\n            self.assertAllRaise(\n                SyntaxError,\n                "f-string: invalid conversion character",\n                ["f\'{3!" + conv_non_identifier + "}\'"],\n            )\n\n        for conv in " s", " s ":\n            self.assertAllRaise(\n                SyntaxError,\n                "f-string: conversion type must come right after the"\n                " exclamanation mark",\n                ["f\'{3!" + conv + "}\'"],\n            )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: invalid conversion character \'ss\': " "expected \'s\', \'r\', or \'a\'",\n            [\n                "f\'{3!ss}\'",\n                "f\'{3!ss:}\'",\n                "f\'{3!ss:s}\'",\n            ],\n        )\n\n    def test_assignment(self):\n        self.assertAllRaise(\n            SyntaxError,\n            r"invalid syntax",\n            [\n                "f\'\' = 3",\n                "f\'{0}\' = x",\n                "f\'{x}\' = x",\n            ],\n        )\n\n    def test_del(self):\n        self.assertAllRaise(\n            SyntaxError,\n            "invalid syntax",\n            [\n                "del f\'\'",\n                "del \'\' f\'\'",\n            ],\n        )\n\n    def test_mismatched_braces(self):\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: single \'}\' is not allowed",\n            [\n                "f\'{{}\'",\n                "f\'{{}}}\'",\n                "f\'}\'",\n                "f\'x}\'",\n                "f\'x}x\'",\n                r"f\'\\u007b}\'",\n                # Can\'t have { or } in a format spec.\n                "f\'{3:}>10}\'",\n                "f\'{3:}}>10}\'",\n            ],\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expecting \'}\'",\n            [\n                "f\'{3\'",\n                "f\'{3!\'",\n                "f\'{3:\'",\n                "f\'{3!s\'",\n                "f\'{3!s:\'",\n                "f\'{3!s:3\'",\n                "f\'x{\'",\n                "f\'x{x\'",\n                "f\'{x\'",\n                "f\'{3:s\'",\n                "f\'{{{\'",\n                "f\'{{}}{\'",\n                "f\'{\'",\n                "f\'{i=\'",  # See gh-93418.\n            ],\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expecting a valid expression after \'{\'",\n            [\n                "f\'{3:{{>10}\'",\n            ],\n        )\n\n        # But these are just normal strings.\n        self.assertEqual(f\'{"{"}\', "{")\n        self.assertEqual(f\'{"}"}\', "}")\n        self.assertEqual(f\'{3:{"}"}>10}\', "}}}}}}}}}3")\n        self.assertEqual(f\'{2:{"{"}>10}\', "{{{{{{{{{2")\n\n    def test_if_conditional(self):\n        # There\'s special logic in compile.c to test if the\n        #  conditional for an if (and while) are constants. Exercise\n        #  that code.\n\n        def test_fstring(x, expected):\n            flag = 0\n            if f"{x}":\n                flag = 1\n            else:\n                flag = 2\n            self.assertEqual(flag, expected)\n\n        def test_concat_empty(x, expected):\n            flag = 0\n            if "" f"{x}":\n                flag = 1\n            else:\n                flag = 2\n            self.assertEqual(flag, expected)\n\n        def test_concat_non_empty(x, expected):\n            flag = 0\n            if " " f"{x}":\n                flag = 1\n            else:\n                flag = 2\n            self.assertEqual(flag, expected)\n\n        test_fstring("", 2)\n        test_fstring(" ", 1)\n\n        test_concat_empty("", 2)\n        test_concat_empty(" ", 1)\n\n        test_concat_non_empty("", 1)\n        test_concat_non_empty(" ", 1)\n\n    def test_empty_format_specifier(self):\n        x = "test"\n        self.assertEqual(f"{x}", "test")\n        self.assertEqual(f"{x:}", "test")\n        self.assertEqual(f"{x!s:}", "test")\n        self.assertEqual(f"{x!r:}", "\'test\'")\n\n    def test_str_format_differences(self):\n        d = {\n            "a": "string",\n            0: "integer",\n        }\n        a = 0\n        self.assertEqual(f"{d[0]}", "integer")\n        self.assertEqual(f\'{d["a"]}\', "string")\n        self.assertEqual(f"{d[a]}", "integer")\n        self.assertEqual("{d[a]}".format(d=d), "string")\n        self.assertEqual("{d[0]}".format(d=d), "integer")\n\n    def test_errors(self):\n        # see issue 26287\n        self.assertAllRaise(\n            TypeError,\n            "unsupported",\n            [\n                r"f\'{(lambda: 0):x}\'",\n                r"f\'{(0,):x}\'",\n            ],\n        )\n        self.assertAllRaise(\n            ValueError,\n            "Unknown format code",\n            [\n                r"f\'{1000:j}\'",\n                r"f\'{1000:j}\'",\n            ],\n        )\n\n    def test_filename_in_syntaxerror(self):\n        # see issue 38964\n        with temp_cwd() as cwd:\n            file_path = os.path.join(cwd, "t.py")\n            with open(file_path, "w", encoding="utf-8") as f:\n                f.write(\'f"{a b}"\')  # This generates a SyntaxError\n            _, _, stderr = assert_python_failure(file_path, PYTHONIOENCODING="ascii")\n        self.assertIn(file_path.encode("ascii", "backslashreplace"), stderr)\n\n    def test_loop(self):\n        for i in range(1000):\n            self.assertEqual(f"i:{i}", "i:" + str(i))\n\n    def test_dict(self):\n        d = {\n            \'"\': "dquote",\n            "\'": "squote",\n            "foo": "bar",\n        }\n        self.assertEqual(f"""{d["\'"]}""", "squote")\n        self.assertEqual(f"""{d[\'"\']}""", "dquote")\n\n        self.assertEqual(f\'{d["foo"]}\', "bar")\n        self.assertEqual(f"{d[\'foo\']}", "bar")\n\n    def test_backslash_char(self):\n        # Check eval of a backslash followed by a control char.\n        # See bpo-30682: this used to raise an assert in pydebug mode.\n        self.assertEqual(eval(\'f"\\\\\\n"\'), "")\n        self.assertEqual(eval(\'f"\\\\\\r"\'), "")\n\n    def test_debug_conversion(self):\n        x = "A string"\n        self.assertEqual(f"{x=}", "x=" + repr(x))\n        self.assertEqual(f"{x =}", "x =" + repr(x))\n        self.assertEqual(f"{x=!s}", "x=" + str(x))\n        self.assertEqual(f"{x=!r}", "x=" + repr(x))\n        self.assertEqual(f"{x=!a}", "x=" + ascii(x))\n\n        x = 2.71828\n        self.assertEqual(f"{x=:.2f}", "x=" + format(x, ".2f"))\n        self.assertEqual(f"{x=:}", "x=" + format(x, ""))\n        self.assertEqual(f"{x=!r:^20}", "x=" + format(repr(x), "^20"))\n        self.assertEqual(f"{x=!s:^20}", "x=" + format(str(x), "^20"))\n        self.assertEqual(f"{x=!a:^20}", "x=" + format(ascii(x), "^20"))\n\n        x = 9\n        self.assertEqual(f"{3*x+15=}", "3*x+15=42")\n\n        # There is code in ast.c that deals with non-ascii expression values.  So,\n        # use a unicode identifier to trigger that.\n        tenπ = 31.4\n        self.assertEqual(f"{tenπ=:.2f}", "tenπ=31.40")\n\n        # Also test with Unicode in non-identifiers.\n        self.assertEqual(f\'{"Σ"=}\', "\\"Σ\\"=\'Σ\'")\n\n        # Make sure nested fstrings still work.\n        self.assertEqual(f\'{f"{3.1415=:.1f}":*^20}\', "*****3.1415=3.1*****")\n\n        # Make sure text before and after an expression with = works\n        # correctly.\n        pi = "π"\n        self.assertEqual(f"alpha α {pi=} ω omega", "alpha α pi=\'π\' ω omega")\n\n        # Check multi-line expressions.\n        self.assertEqual(\n            f"""{\n3\n=}""",\n            "\\n3\\n=3",\n        )\n\n        # Since = is handled specially, make sure all existing uses of\n        # it still work.\n\n        self.assertEqual(f"{0==1}", "False")\n        self.assertEqual(f"{0!=1}", "True")\n        self.assertEqual(f"{0<=1}", "True")\n        self.assertEqual(f"{0>=1}", "False")\n        self.assertEqual(f\'{(x:="5")}\', "5")\n        self.assertEqual(x, "5")\n        self.assertEqual(f"{(x:=5)}", "5")\n        self.assertEqual(x, 5)\n        self.assertEqual(f\'{"="}\', "=")\n\n        x = 20\n        # This isn\'t an assignment expression, it\'s \'x\', with a format\n        # spec of \'=10\'.  See test_walrus: you need to use parens.\n        self.assertEqual(f"{x:=10}", "        20")\n\n        # Test named function parameters, to make sure \'=\' parsing works\n        # there.\n        def f(a):\n            nonlocal x\n            oldx = x\n            x = a\n            return oldx\n\n        x = 0\n        self.assertEqual(f\'{f(a="3=")}\', "0")\n        self.assertEqual(x, "3=")\n        self.assertEqual(f"{f(a=4)}", "3=")\n        self.assertEqual(x, 4)\n\n        # Check debug expressions in format spec\n        y = 20\n        self.assertEqual(f"{2:{y=}}", "yyyyyyyyyyyyyyyyyyy2")\n        self.assertEqual(\n            f"{datetime.datetime.now():h1{y=}h2{y=}h3{y=}}", "h1y=20h2y=20h3y=20"\n        )\n\n        # Make sure __format__ is being called.\n        class C:\n            def __format__(self, s):\n                return f"FORMAT-{s}"\n\n            def __repr__(self):\n                return "REPR"\n\n        self.assertEqual(f"{C()=}", "C()=REPR")\n        self.assertEqual(f"{C()=!r}", "C()=REPR")\n        self.assertEqual(f"{C()=:}", "C()=FORMAT-")\n        self.assertEqual(f"{C()=: }", "C()=FORMAT- ")\n        self.assertEqual(f"{C()=:x}", "C()=FORMAT-x")\n        self.assertEqual(f"{C()=!r:*^20}", "C()=********REPR********")\n        self.assertEqual(f"{C():{20=}}", "FORMAT-20=20")\n\n        self.assertRaises(SyntaxError, eval, "f\'{C=]\'")\n\n        # Make sure leading and following text works.\n        x = "foo"\n        self.assertEqual(f"X{x=}Y", "Xx=" + repr(x) + "Y")\n\n        # Make sure whitespace around the = works.\n        self.assertEqual(f"X{x  =}Y", "Xx  =" + repr(x) + "Y")\n        self.assertEqual(f"X{x=  }Y", "Xx=  " + repr(x) + "Y")\n        self.assertEqual(f"X{x  =  }Y", "Xx  =  " + repr(x) + "Y")\n        self.assertEqual(f"sadsd {1 + 1 =  :{1 + 1:1d}f}", "sadsd 1 + 1 =  2.000000")\n\n        self.assertEqual(\n            f"{1+2 = # my comment\n  }",\n            "1+2 = \\n  3",\n        )\n\n        # These next lines contains tabs.  Backslash escapes don\'t\n        # work in f-strings.\n        # patchcheck doesn\'t like these tabs.  So the only way to test\n        # this will be to dynamically created and exec the f-strings.  But\n        # that\'s such a hassle I\'ll save it for another day.  For now, convert\n        # the tabs to spaces just to shut up patchcheck.\n        # self.assertEqual(f\'X{x =}Y\', \'Xx\\t=\'+repr(x)+\'Y\')\n        # self.assertEqual(f\'X{x =       }Y\', \'Xx\\t=\\t\'+repr(x)+\'Y\')\n\n    def test_debug_expressions_are_raw_strings(self):\n\n        self.assertEqual(f\'{b"\\N{OX}"=}\', \'b"\\\\N{OX}"=b\\\'\\\\\\\\N{OX}\\\'\')\n        self.assertEqual(f\'{r"\\xff"=}\', \'r"\\\\xff"=\\\'\\\\\\\\xff\\\'\')\n        self.assertEqual(f\'{r"\\n"=}\', \'r"\\\\n"=\\\'\\\\\\\\n\\\'\')\n        self.assertEqual(f"{\'\\\'\'=}", "\'\\\\\'\'=\\"\'\\"")\n        self.assertEqual(f\'{\'\\xc5\'=}\', r"\'\\xc5\'=\'Å\'")\n\n    def test_walrus(self):\n        x = 20\n        # This isn\'t an assignment expression, it\'s \'x\', with a format\n        # spec of \'=10\'.\n        self.assertEqual(f"{x:=10}", "        20")\n\n        # This is an assignment expression, which requires parens.\n        self.assertEqual(f"{(x:=10)}", "10")\n        self.assertEqual(x, 10)\n\n    def test_invalid_syntax_error_message(self):\n        with self.assertRaisesRegex(\n            SyntaxError, "f-string: expecting \'=\', or \'!\', or \':\', or \'}\'"\n        ):\n            compile("f\'{a $ b}\'", "?", "exec")\n\n    def test_with_two_commas_in_format_specifier(self):\n        error_msg = re.escape("Cannot specify \',\' with \',\'.")\n        with self.assertRaisesRegex(ValueError, error_msg):\n            f"{1:,,}"\n\n    def test_with_two_underscore_in_format_specifier(self):\n        error_msg = re.escape("Cannot specify \'_\' with \'_\'.")\n        with self.assertRaisesRegex(ValueError, error_msg):\n            f"{1:__}"\n\n    def test_with_a_commas_and_an_underscore_in_format_specifier(self):\n        error_msg = re.escape("Cannot specify both \',\' and \'_\'.")\n        with self.assertRaisesRegex(ValueError, error_msg):\n            f"{1:,_}"\n\n    def test_with_an_underscore_and_a_comma_in_format_specifier(self):\n        error_msg = re.escape("Cannot specify both \',\' and \'_\'.")\n        with self.assertRaisesRegex(ValueError, error_msg):\n            f"{1:_,}"\n\n    def test_syntax_error_for_starred_expressions(self):\n        with self.assertRaisesRegex(SyntaxError, "can\'t use starred expression here"):\n            compile("f\'{*a}\'", "?", "exec")\n\n        with self.assertRaisesRegex(\n            SyntaxError, "f-string: expecting a valid expression after \'{\'"\n        ):\n            compile("f\'{**a}\'", "?", "exec")\n\n    def test_not_closing_quotes(self):\n        self.assertAllRaise(SyntaxError, "unterminated f-string literal", [\'f"\', "f\'"])\n        self.assertAllRaise(\n            SyntaxError, "unterminated triple-quoted f-string literal", [\'f"""\', "f\'\'\'"]\n        )\n        # Ensure that the errors are reported at the correct line number.\n        data = \'\'\'\\\nx = 1 + 1\ny = 2 + 2\nz = f"""\nsdfjnsdfjsdf\nsdfsdfs{1+\n2} dfigdf {3+\n4}sdufsd""\n\'\'\'\n        try:\n            compile(data, "?", "exec")\n        except SyntaxError as e:\n            self.assertEqual(e.text, \'z = f"""\')\n            self.assertEqual(e.lineno, 3)\n\n    def test_syntax_error_after_debug(self):\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expecting a valid expression after \'{\'",\n            [\n                "f\'{1=}{;\'",\n                "f\'{1=}{+;\'",\n                "f\'{1=}{2}{;\'",\n                "f\'{1=}{3}{;\'",\n            ],\n        )\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expecting \'=\', or \'!\', or \':\', or \'}\'",\n            [\n                "f\'{1=}{1;\'",\n                "f\'{1=}{1;}\'",\n            ],\n        )\n\n    def test_debug_in_file(self):\n        with temp_cwd():\n            script = "script.py"\n            with open("script.py", "w") as f:\n                f.write(f"""\\\nprint(f\'\'\'{{\n3\n=}}\'\'\')""")\n\n            _, stdout, _ = assert_python_ok(script)\n        self.assertEqual(\n            stdout.decode("utf-8").strip().replace("\\r\\n", "\\n").replace("\\r", "\\n"),\n            "3\\n=3",\n        )\n\n    def test_syntax_warning_infinite_recursion_in_file(self):\n        with temp_cwd():\n            script = "script.py"\n            with open(script, "w") as f:\n                f.write(r"print(f\'\\{1}\')")\n\n            _, stdout, stderr = assert_python_ok(script)\n            self.assertIn(rb"\\1", stdout)\n            self.assertEqual(len(stderr.strip().splitlines()), 2)\n\n    def test_gh129093(self):\n        self.assertEqual(f\'{1==2=}\', \'1==2=False\')\n        self.assertEqual(f\'{1 == 2=}\', \'1 == 2=False\')\n        self.assertEqual(f\'{1!=2=}\', \'1!=2=True\')\n        self.assertEqual(f\'{1 != 2=}\', \'1 != 2=True\')\n\n        self.assertEqual(f\'{(1) != 2=}\', \'(1) != 2=True\')\n        self.assertEqual(f\'{(1*2) != (3)=}\', \'(1*2) != (3)=True\')\n\n        self.assertEqual(f\'{1 != 2 == 3 != 4=}\', \'1 != 2 == 3 != 4=False\')\n        self.assertEqual(f\'{1 == 2 != 3 == 4=}\', \'1 == 2 != 3 == 4=False\')\n\n        self.assertEqual(f\'{f\'{1==2=}\'=}\', "f\'{1==2=}\'=\'1==2=False\'")\n        self.assertEqual(f\'{f\'{1 == 2=}\'=}\', "f\'{1 == 2=}\'=\'1 == 2=False\'")\n        self.assertEqual(f\'{f\'{1!=2=}\'=}\', "f\'{1!=2=}\'=\'1!=2=True\'")\n        self.assertEqual(f\'{f\'{1 != 2=}\'=}\', "f\'{1 != 2=}\'=\'1 != 2=True\'")\n\n\nif __name__ == "__main__":\n\n    unittest.main()\n', ast_parse_kwargs={}, filename=PosixPath('/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_fstring.py')) ... FAIL
Testing /Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_syntax.py
Testing /Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_grammar.py
Testing /Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_compile.py
Testing /Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_asdl_parser.py
Testing /Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_tokenize.py
Testing /Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_patma.py
Testing /Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_type_params.py
test_async_function (test.test_unparse.ManualASTCreationTestCase.test_async_function) ... ok
test_async_function_with_type_params (test.test_unparse.ManualASTCreationTestCase.test_async_function_with_type_params) ... ok
test_class (test.test_unparse.ManualASTCreationTestCase.test_class) ... ok
test_class_with_type_params (test.test_unparse.ManualASTCreationTestCase.test_class_with_type_params) ... ok
test_function (test.test_unparse.ManualASTCreationTestCase.test_function) ... ok
test_function_with_type_params (test.test_unparse.ManualASTCreationTestCase.test_function_with_type_params) ... ok
test_function_with_type_params_and_bound (test.test_unparse.ManualASTCreationTestCase.test_function_with_type_params_and_bound) ... ok
test_annotations (test.test_unparse.UnparseTestCase.test_annotations) ... ok
test_bytes (test.test_unparse.UnparseTestCase.test_bytes) ... ok
test_chained_comparisons (test.test_unparse.UnparseTestCase.test_chained_comparisons) ... ok
test_class_decorators (test.test_unparse.UnparseTestCase.test_class_decorators) ... ok
test_class_definition (test.test_unparse.UnparseTestCase.test_class_definition) ... ok
test_constant_tuples (test.test_unparse.UnparseTestCase.test_constant_tuples) ... ok
test_del_statement (test.test_unparse.UnparseTestCase.test_del_statement) ... ok
test_dict_comprehension (test.test_unparse.UnparseTestCase.test_dict_comprehension) ... ok
test_dict_unpacking_in_dict (test.test_unparse.UnparseTestCase.test_dict_unpacking_in_dict) ... ok
test_docstrings (test.test_unparse.UnparseTestCase.test_docstrings) ... ok
test_elifs (test.test_unparse.UnparseTestCase.test_elifs) ... ok
test_empty_set (test.test_unparse.UnparseTestCase.test_empty_set) ... ok
test_for_else (test.test_unparse.UnparseTestCase.test_for_else) ... ok
test_fstring_backslash (test.test_unparse.UnparseTestCase.test_fstring_backslash) ... ok
test_fstrings (test.test_unparse.UnparseTestCase.test_fstrings) ... ok
test_fstrings_complicated (test.test_unparse.UnparseTestCase.test_fstrings_complicated) ... ok
test_fstrings_pep701 (test.test_unparse.UnparseTestCase.test_fstrings_pep701) ... ok
test_fstrings_special_chars (test.test_unparse.UnparseTestCase.test_fstrings_special_chars) ... ok
test_function_arguments (test.test_unparse.UnparseTestCase.test_function_arguments) ... ok
test_function_type (test.test_unparse.UnparseTestCase.test_function_type) ... ok
test_huge_float (test.test_unparse.UnparseTestCase.test_huge_float) ... ok
test_imaginary_literals (test.test_unparse.UnparseTestCase.test_imaginary_literals) ... ok
test_import_from_level_none (test.test_unparse.UnparseTestCase.test_import_from_level_none) ... ok
test_integer_parens (test.test_unparse.UnparseTestCase.test_integer_parens) ... ok
test_invalid_fstring_value (test.test_unparse.UnparseTestCase.test_invalid_fstring_value) ... ok
test_invalid_raise (test.test_unparse.UnparseTestCase.test_invalid_raise) ... ok
test_invalid_yield_from (test.test_unparse.UnparseTestCase.test_invalid_yield_from) ... ok
test_lambda_parentheses (test.test_unparse.UnparseTestCase.test_lambda_parentheses) ... ok
test_min_int (test.test_unparse.UnparseTestCase.test_min_int) ... ok
test_nan (test.test_unparse.UnparseTestCase.test_nan) ... ok
test_nonlocal (test.test_unparse.UnparseTestCase.test_nonlocal) ... ok
test_raise_from (test.test_unparse.UnparseTestCase.test_raise_from) ... ok
test_relative_import (test.test_unparse.UnparseTestCase.test_relative_import) ... ok
test_set_comprehension (test.test_unparse.UnparseTestCase.test_set_comprehension) ... ok
test_set_literal (test.test_unparse.UnparseTestCase.test_set_literal) ... ok
test_shifts (test.test_unparse.UnparseTestCase.test_shifts) ... ok
test_slices (test.test_unparse.UnparseTestCase.test_slices) ... ok
test_starred_assignment (test.test_unparse.UnparseTestCase.test_starred_assignment) ... ok
test_strings (test.test_unparse.UnparseTestCase.test_strings) ... ok
test_try_except_finally (test.test_unparse.UnparseTestCase.test_try_except_finally) ... ok
test_try_except_star_finally (test.test_unparse.UnparseTestCase.test_try_except_star_finally) ... ok
test_type_comments (test.test_unparse.UnparseTestCase.test_type_comments) ... ok
test_type_ignore (test.test_unparse.UnparseTestCase.test_type_ignore) ... ok
test_unary_parens (test.test_unparse.UnparseTestCase.test_unary_parens) ... ok
test_while_else (test.test_unparse.UnparseTestCase.test_while_else) ... ok
test_with_as (test.test_unparse.UnparseTestCase.test_with_as) ... ok
test_with_simple (test.test_unparse.UnparseTestCase.test_with_simple) ... ok
test_with_two_items (test.test_unparse.UnparseTestCase.test_with_two_items) ... ok

======================================================================
FAIL: test_multiquote_joined_string (test.test_unparse.CosmeticTestCase.test_multiquote_joined_string) (code1='f\'"""{1}\'\'\' ', ast_parse_kwargs={})
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_unparse.py", line 138, in check_ast_roundtrip
    self.assertASTEqual(ast1, ast2)
         ^^^^^^^^^^^^^^
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 43, in assertASTEqual
    traverse_compare(ast1, ast2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 24, in traverse_compare
    traverse_compare(value1, value2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 28, in traverse_compare
    traverse_compare(node1, node2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 24, in traverse_compare
    traverse_compare(value1, value2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 24, in traverse_compare
    traverse_compare(value1, value2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 40, in traverse_compare
    raise self.failureException(msg) from None
AssertionError: First list contains 1 additional elements.

======================================================================
FAIL: test_multiquote_joined_string (test.test_unparse.CosmeticTestCase.test_multiquote_joined_string) (code1='f\'"""{"\\n"}\'\'\' ', ast_parse_kwargs={})
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_unparse.py", line 138, in check_ast_roundtrip
    self.assertASTEqual(ast1, ast2)
         ^^^^^^^^^^^^^^
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 43, in assertASTEqual
    traverse_compare(ast1, ast2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 24, in traverse_compare
    traverse_compare(value1, value2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 28, in traverse_compare
    traverse_compare(node1, node2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 24, in traverse_compare
    traverse_compare(value1, value2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 24, in traverse_compare
    traverse_compare(value1, value2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 40, in traverse_compare
    raise self.failureException(msg) from None
AssertionError: First list contains 1 additional elements.

======================================================================
FAIL: test_files (test.test_unparse.DirectoryTestCase.test_files) (code1='# -*- coding: utf-8 -*-\n# There are tests here with unicode string literals and\n# identifiers. There\'s a code in ast.c that was added because of a\n# failure with a non-ascii-only expression.  So, I have tests for\n# that.  There are workarounds that would let me run tests for that\n# code without unicode identifiers and strings, but just using them\n# directly seems like the easiest and therefore safest thing to do.\n# Unicode identifiers in tests is allowed by PEP 3131.\n\nimport ast\nimport datetime\nimport os\nimport re\nimport types\nimport decimal\nimport unittest\nimport warnings\nfrom test import support\nfrom test.support.os_helper import temp_cwd\nfrom test.support.script_helper import assert_python_failure, assert_python_ok\n\na_global = "global variable"\n\n# You could argue that I\'m too strict in looking for specific error\n#  values with assertRaisesRegex, but without it it\'s way too easy to\n#  make a syntax error in the test strings. Especially with all of the\n#  triple quotes, raw strings, backslashes, etc. I think it\'s a\n#  worthwhile tradeoff. When I switched to this method, I found many\n#  examples where I wasn\'t testing what I thought I was.\n\n\nclass TestCase(unittest.TestCase):\n    def assertAllRaise(self, exception_type, regex, error_strings):\n        for str in error_strings:\n            with self.subTest(str=str):\n                with self.assertRaisesRegex(exception_type, regex):\n                    eval(str)\n\n    def test__format__lookup(self):\n        # Make sure __format__ is looked up on the type, not the instance.\n        class X:\n            def __format__(self, spec):\n                return "class"\n\n        x = X()\n\n        # Add a bound __format__ method to the \'y\' instance, but not\n        #  the \'x\' instance.\n        y = X()\n        y.__format__ = types.MethodType(lambda self, spec: "instance", y)\n\n        self.assertEqual(f"{y}", format(y))\n        self.assertEqual(f"{y}", "class")\n        self.assertEqual(format(x), format(y))\n\n        # __format__ is not called this way, but still make sure it\n        #  returns what we expect (so we can make sure we\'re bypassing\n        #  it).\n        self.assertEqual(x.__format__(""), "class")\n        self.assertEqual(y.__format__(""), "instance")\n\n        # This is how __format__ is actually called.\n        self.assertEqual(type(x).__format__(x, ""), "class")\n        self.assertEqual(type(y).__format__(y, ""), "class")\n\n    def test_ast(self):\n        # Inspired by http://bugs.python.org/issue24975\n        class X:\n            def __init__(self):\n                self.called = False\n\n            def __call__(self):\n                self.called = True\n                return 4\n\n        x = X()\n        expr = """\na = 10\nf\'{a * x()}\'"""\n        t = ast.parse(expr)\n        c = compile(t, "", "exec")\n\n        # Make sure x was not called.\n        self.assertFalse(x.called)\n\n        # Actually run the code.\n        exec(c)\n\n        # Make sure x was called.\n        self.assertTrue(x.called)\n\n    def test_ast_line_numbers(self):\n        expr = """\na = 10\nf\'{a * x()}\'"""\n        t = ast.parse(expr)\n        self.assertEqual(type(t), ast.Module)\n        self.assertEqual(len(t.body), 2)\n        # check `a = 10`\n        self.assertEqual(type(t.body[0]), ast.Assign)\n        self.assertEqual(t.body[0].lineno, 2)\n        # check `f\'...\'`\n        self.assertEqual(type(t.body[1]), ast.Expr)\n        self.assertEqual(type(t.body[1].value), ast.JoinedStr)\n        self.assertEqual(len(t.body[1].value.values), 1)\n        self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)\n        self.assertEqual(t.body[1].lineno, 3)\n        self.assertEqual(t.body[1].value.lineno, 3)\n        self.assertEqual(t.body[1].value.values[0].lineno, 3)\n        # check the binop location\n        binop = t.body[1].value.values[0].value\n        self.assertEqual(type(binop), ast.BinOp)\n        self.assertEqual(type(binop.left), ast.Name)\n        self.assertEqual(type(binop.op), ast.Mult)\n        self.assertEqual(type(binop.right), ast.Call)\n        self.assertEqual(binop.lineno, 3)\n        self.assertEqual(binop.left.lineno, 3)\n        self.assertEqual(binop.right.lineno, 3)\n        self.assertEqual(binop.col_offset, 3)\n        self.assertEqual(binop.left.col_offset, 3)\n        self.assertEqual(binop.right.col_offset, 7)\n\n    def test_ast_line_numbers_multiple_formattedvalues(self):\n        expr = """\nf\'no formatted values\'\nf\'eggs {a * x()} spam {b + y()}\'"""\n        t = ast.parse(expr)\n        self.assertEqual(type(t), ast.Module)\n        self.assertEqual(len(t.body), 2)\n        # check `f\'no formatted value\'`\n        self.assertEqual(type(t.body[0]), ast.Expr)\n        self.assertEqual(type(t.body[0].value), ast.JoinedStr)\n        self.assertEqual(t.body[0].lineno, 2)\n        # check `f\'...\'`\n        self.assertEqual(type(t.body[1]), ast.Expr)\n        self.assertEqual(type(t.body[1].value), ast.JoinedStr)\n        self.assertEqual(len(t.body[1].value.values), 4)\n        self.assertEqual(type(t.body[1].value.values[0]), ast.Constant)\n        self.assertEqual(type(t.body[1].value.values[0].value), str)\n        self.assertEqual(type(t.body[1].value.values[1]), ast.FormattedValue)\n        self.assertEqual(type(t.body[1].value.values[2]), ast.Constant)\n        self.assertEqual(type(t.body[1].value.values[2].value), str)\n        self.assertEqual(type(t.body[1].value.values[3]), ast.FormattedValue)\n        self.assertEqual(t.body[1].lineno, 3)\n        self.assertEqual(t.body[1].value.lineno, 3)\n        self.assertEqual(t.body[1].value.values[0].lineno, 3)\n        self.assertEqual(t.body[1].value.values[1].lineno, 3)\n        self.assertEqual(t.body[1].value.values[2].lineno, 3)\n        self.assertEqual(t.body[1].value.values[3].lineno, 3)\n        # check the first binop location\n        binop1 = t.body[1].value.values[1].value\n        self.assertEqual(type(binop1), ast.BinOp)\n        self.assertEqual(type(binop1.left), ast.Name)\n        self.assertEqual(type(binop1.op), ast.Mult)\n        self.assertEqual(type(binop1.right), ast.Call)\n        self.assertEqual(binop1.lineno, 3)\n        self.assertEqual(binop1.left.lineno, 3)\n        self.assertEqual(binop1.right.lineno, 3)\n        self.assertEqual(binop1.col_offset, 8)\n        self.assertEqual(binop1.left.col_offset, 8)\n        self.assertEqual(binop1.right.col_offset, 12)\n        # check the second binop location\n        binop2 = t.body[1].value.values[3].value\n        self.assertEqual(type(binop2), ast.BinOp)\n        self.assertEqual(type(binop2.left), ast.Name)\n        self.assertEqual(type(binop2.op), ast.Add)\n        self.assertEqual(type(binop2.right), ast.Call)\n        self.assertEqual(binop2.lineno, 3)\n        self.assertEqual(binop2.left.lineno, 3)\n        self.assertEqual(binop2.right.lineno, 3)\n        self.assertEqual(binop2.col_offset, 23)\n        self.assertEqual(binop2.left.col_offset, 23)\n        self.assertEqual(binop2.right.col_offset, 27)\n\n    def test_ast_line_numbers_nested(self):\n        expr = """\na = 10\nf\'{a * f"-{x()}-"}\'"""\n        t = ast.parse(expr)\n        self.assertEqual(type(t), ast.Module)\n        self.assertEqual(len(t.body), 2)\n        # check `a = 10`\n        self.assertEqual(type(t.body[0]), ast.Assign)\n        self.assertEqual(t.body[0].lineno, 2)\n        # check `f\'...\'`\n        self.assertEqual(type(t.body[1]), ast.Expr)\n        self.assertEqual(type(t.body[1].value), ast.JoinedStr)\n        self.assertEqual(len(t.body[1].value.values), 1)\n        self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)\n        self.assertEqual(t.body[1].lineno, 3)\n        self.assertEqual(t.body[1].value.lineno, 3)\n        self.assertEqual(t.body[1].value.values[0].lineno, 3)\n        # check the binop location\n        binop = t.body[1].value.values[0].value\n        self.assertEqual(type(binop), ast.BinOp)\n        self.assertEqual(type(binop.left), ast.Name)\n        self.assertEqual(type(binop.op), ast.Mult)\n        self.assertEqual(type(binop.right), ast.JoinedStr)\n        self.assertEqual(binop.lineno, 3)\n        self.assertEqual(binop.left.lineno, 3)\n        self.assertEqual(binop.right.lineno, 3)\n        self.assertEqual(binop.col_offset, 3)\n        self.assertEqual(binop.left.col_offset, 3)\n        self.assertEqual(binop.right.col_offset, 7)\n        # check the nested call location\n        self.assertEqual(len(binop.right.values), 3)\n        self.assertEqual(type(binop.right.values[0]), ast.Constant)\n        self.assertEqual(type(binop.right.values[0].value), str)\n        self.assertEqual(type(binop.right.values[1]), ast.FormattedValue)\n        self.assertEqual(type(binop.right.values[2]), ast.Constant)\n        self.assertEqual(type(binop.right.values[2].value), str)\n        self.assertEqual(binop.right.values[0].lineno, 3)\n        self.assertEqual(binop.right.values[1].lineno, 3)\n        self.assertEqual(binop.right.values[2].lineno, 3)\n        call = binop.right.values[1].value\n        self.assertEqual(type(call), ast.Call)\n        self.assertEqual(call.lineno, 3)\n        self.assertEqual(call.col_offset, 11)\n\n    def test_ast_line_numbers_duplicate_expression(self):\n        expr = """\na = 10\nf\'{a * x()} {a * x()} {a * x()}\'\n"""\n        t = ast.parse(expr)\n        self.assertEqual(type(t), ast.Module)\n        self.assertEqual(len(t.body), 2)\n        # check `a = 10`\n        self.assertEqual(type(t.body[0]), ast.Assign)\n        self.assertEqual(t.body[0].lineno, 2)\n        # check `f\'...\'`\n        self.assertEqual(type(t.body[1]), ast.Expr)\n        self.assertEqual(type(t.body[1].value), ast.JoinedStr)\n        self.assertEqual(len(t.body[1].value.values), 5)\n        self.assertEqual(type(t.body[1].value.values[0]), ast.FormattedValue)\n        self.assertEqual(type(t.body[1].value.values[1]), ast.Constant)\n        self.assertEqual(type(t.body[1].value.values[1].value), str)\n        self.assertEqual(type(t.body[1].value.values[2]), ast.FormattedValue)\n        self.assertEqual(type(t.body[1].value.values[3]), ast.Constant)\n        self.assertEqual(type(t.body[1].value.values[3].value), str)\n        self.assertEqual(type(t.body[1].value.values[4]), ast.FormattedValue)\n        self.assertEqual(t.body[1].lineno, 3)\n        self.assertEqual(t.body[1].value.lineno, 3)\n        self.assertEqual(t.body[1].value.values[0].lineno, 3)\n        self.assertEqual(t.body[1].value.values[1].lineno, 3)\n        self.assertEqual(t.body[1].value.values[2].lineno, 3)\n        self.assertEqual(t.body[1].value.values[3].lineno, 3)\n        self.assertEqual(t.body[1].value.values[4].lineno, 3)\n        # check the first binop location\n        binop = t.body[1].value.values[0].value\n        self.assertEqual(type(binop), ast.BinOp)\n        self.assertEqual(type(binop.left), ast.Name)\n        self.assertEqual(type(binop.op), ast.Mult)\n        self.assertEqual(type(binop.right), ast.Call)\n        self.assertEqual(binop.lineno, 3)\n        self.assertEqual(binop.left.lineno, 3)\n        self.assertEqual(binop.right.lineno, 3)\n        self.assertEqual(binop.col_offset, 3)\n        self.assertEqual(binop.left.col_offset, 3)\n        self.assertEqual(binop.right.col_offset, 7)\n        # check the second binop location\n        binop = t.body[1].value.values[2].value\n        self.assertEqual(type(binop), ast.BinOp)\n        self.assertEqual(type(binop.left), ast.Name)\n        self.assertEqual(type(binop.op), ast.Mult)\n        self.assertEqual(type(binop.right), ast.Call)\n        self.assertEqual(binop.lineno, 3)\n        self.assertEqual(binop.left.lineno, 3)\n        self.assertEqual(binop.right.lineno, 3)\n        self.assertEqual(binop.col_offset, 13)\n        self.assertEqual(binop.left.col_offset, 13)\n        self.assertEqual(binop.right.col_offset, 17)\n        # check the third binop location\n        binop = t.body[1].value.values[4].value\n        self.assertEqual(type(binop), ast.BinOp)\n        self.assertEqual(type(binop.left), ast.Name)\n        self.assertEqual(type(binop.op), ast.Mult)\n        self.assertEqual(type(binop.right), ast.Call)\n        self.assertEqual(binop.lineno, 3)\n        self.assertEqual(binop.left.lineno, 3)\n        self.assertEqual(binop.right.lineno, 3)\n        self.assertEqual(binop.col_offset, 23)\n        self.assertEqual(binop.left.col_offset, 23)\n        self.assertEqual(binop.right.col_offset, 27)\n\n    def test_ast_numbers_fstring_with_formatting(self):\n        t = ast.parse(\'f"Here is that pesky {xxx:.3f} again"\')\n        self.assertEqual(len(t.body), 1)\n        self.assertEqual(t.body[0].lineno, 1)\n\n        self.assertEqual(type(t.body[0]), ast.Expr)\n        self.assertEqual(type(t.body[0].value), ast.JoinedStr)\n        self.assertEqual(len(t.body[0].value.values), 3)\n\n        self.assertEqual(type(t.body[0].value.values[0]), ast.Constant)\n        self.assertEqual(type(t.body[0].value.values[1]), ast.FormattedValue)\n        self.assertEqual(type(t.body[0].value.values[2]), ast.Constant)\n\n        _, expr, _ = t.body[0].value.values\n\n        name = expr.value\n        self.assertEqual(type(name), ast.Name)\n        self.assertEqual(name.lineno, 1)\n        self.assertEqual(name.end_lineno, 1)\n        self.assertEqual(name.col_offset, 22)\n        self.assertEqual(name.end_col_offset, 25)\n\n    def test_ast_line_numbers_multiline_fstring(self):\n        # See bpo-30465 for details.\n        expr = """\na = 10\nf\'\'\'\n  {a\n     *\n       x()}\nnon-important content\n\'\'\'\n"""\n        t = ast.parse(expr)\n        self.assertEqual(type(t), ast.Module)\n        self.assertEqual(len(t.body), 2)\n        # check `a = 10`\n        self.assertEqual(type(t.body[0]), ast.Assign)\n        self.assertEqual(t.body[0].lineno, 2)\n        # check `f\'...\'`\n        self.assertEqual(type(t.body[1]), ast.Expr)\n        self.assertEqual(type(t.body[1].value), ast.JoinedStr)\n        self.assertEqual(len(t.body[1].value.values), 3)\n        self.assertEqual(type(t.body[1].value.values[0]), ast.Constant)\n        self.assertEqual(type(t.body[1].value.values[0].value), str)\n        self.assertEqual(type(t.body[1].value.values[1]), ast.FormattedValue)\n        self.assertEqual(type(t.body[1].value.values[2]), ast.Constant)\n        self.assertEqual(type(t.body[1].value.values[2].value), str)\n        self.assertEqual(t.body[1].lineno, 3)\n        self.assertEqual(t.body[1].value.lineno, 3)\n        self.assertEqual(t.body[1].value.values[0].lineno, 3)\n        self.assertEqual(t.body[1].value.values[1].lineno, 4)\n        self.assertEqual(t.body[1].value.values[2].lineno, 6)\n        self.assertEqual(t.body[1].col_offset, 0)\n        self.assertEqual(t.body[1].value.col_offset, 0)\n        self.assertEqual(t.body[1].value.values[0].col_offset, 4)\n        self.assertEqual(t.body[1].value.values[1].col_offset, 2)\n        self.assertEqual(t.body[1].value.values[2].col_offset, 11)\n        # NOTE: the following lineno information and col_offset is correct for\n        # expressions within FormattedValues.\n        binop = t.body[1].value.values[1].value\n        self.assertEqual(type(binop), ast.BinOp)\n        self.assertEqual(type(binop.left), ast.Name)\n        self.assertEqual(type(binop.op), ast.Mult)\n        self.assertEqual(type(binop.right), ast.Call)\n        self.assertEqual(binop.lineno, 4)\n        self.assertEqual(binop.left.lineno, 4)\n        self.assertEqual(binop.right.lineno, 6)\n        self.assertEqual(binop.col_offset, 3)\n        self.assertEqual(binop.left.col_offset, 3)\n        self.assertEqual(binop.right.col_offset, 7)\n\n        expr = """\na = f\'\'\'\n          {blech}\n    \'\'\'\n"""\n        t = ast.parse(expr)\n        self.assertEqual(type(t), ast.Module)\n        self.assertEqual(len(t.body), 1)\n        # Check f\'...\'\n        self.assertEqual(type(t.body[0]), ast.Assign)\n        self.assertEqual(type(t.body[0].value), ast.JoinedStr)\n        self.assertEqual(len(t.body[0].value.values), 3)\n        self.assertEqual(type(t.body[0].value.values[1]), ast.FormattedValue)\n        self.assertEqual(t.body[0].lineno, 2)\n        self.assertEqual(t.body[0].value.lineno, 2)\n        self.assertEqual(t.body[0].value.values[0].lineno, 2)\n        self.assertEqual(t.body[0].value.values[1].lineno, 3)\n        self.assertEqual(t.body[0].value.values[2].lineno, 3)\n        self.assertEqual(t.body[0].col_offset, 0)\n        self.assertEqual(t.body[0].value.col_offset, 4)\n        self.assertEqual(t.body[0].value.values[0].col_offset, 8)\n        self.assertEqual(t.body[0].value.values[1].col_offset, 10)\n        self.assertEqual(t.body[0].value.values[2].col_offset, 17)\n        # Check {blech}\n        self.assertEqual(t.body[0].value.values[1].value.lineno, 3)\n        self.assertEqual(t.body[0].value.values[1].value.end_lineno, 3)\n        self.assertEqual(t.body[0].value.values[1].value.col_offset, 11)\n        self.assertEqual(t.body[0].value.values[1].value.end_col_offset, 16)\n\n    def test_ast_line_numbers_with_parentheses(self):\n        expr = """\nx = (\n    f" {test(t)}"\n)"""\n        t = ast.parse(expr)\n        self.assertEqual(type(t), ast.Module)\n        self.assertEqual(len(t.body), 1)\n        # check the joinedstr location\n        joinedstr = t.body[0].value\n        self.assertEqual(type(joinedstr), ast.JoinedStr)\n        self.assertEqual(joinedstr.lineno, 3)\n        self.assertEqual(joinedstr.end_lineno, 3)\n        self.assertEqual(joinedstr.col_offset, 4)\n        self.assertEqual(joinedstr.end_col_offset, 17)\n        # check the formatted value location\n        fv = t.body[0].value.values[1]\n        self.assertEqual(type(fv), ast.FormattedValue)\n        self.assertEqual(fv.lineno, 3)\n        self.assertEqual(fv.end_lineno, 3)\n        self.assertEqual(fv.col_offset, 7)\n        self.assertEqual(fv.end_col_offset, 16)\n        # check the test(t) location\n        call = t.body[0].value.values[1].value\n        self.assertEqual(type(call), ast.Call)\n        self.assertEqual(call.lineno, 3)\n        self.assertEqual(call.end_lineno, 3)\n        self.assertEqual(call.col_offset, 8)\n        self.assertEqual(call.end_col_offset, 15)\n\n        expr = """\nx = (\n    u\'wat\',\n    u"wat",\n    b\'wat\',\n    b"wat",\n    f\'wat\',\n    f"wat",\n)\n\ny = (\n    u\'\'\'wat\'\'\',\n    u\\"\\"\\"wat\\"\\"\\",\n    b\'\'\'wat\'\'\',\n    b\\"\\"\\"wat\\"\\"\\",\n    f\'\'\'wat\'\'\',\n    f\\"\\"\\"wat\\"\\"\\",\n)\n        """\n        t = ast.parse(expr)\n        self.assertEqual(type(t), ast.Module)\n        self.assertEqual(len(t.body), 2)\n        x, y = t.body\n\n        # Check the single quoted string offsets first.\n        offsets = [(elt.col_offset, elt.end_col_offset) for elt in x.value.elts]\n        self.assertTrue(all(offset == (4, 10) for offset in offsets))\n\n        # Check the triple quoted string offsets.\n        offsets = [(elt.col_offset, elt.end_col_offset) for elt in y.value.elts]\n        self.assertTrue(all(offset == (4, 14) for offset in offsets))\n\n        expr = """\nx = (\n        \'PERL_MM_OPT\', (\n            f\'wat\'\n            f\'some_string={f(x)} \'\n            f\'wat\'\n        ),\n)\n"""\n        t = ast.parse(expr)\n        self.assertEqual(type(t), ast.Module)\n        self.assertEqual(len(t.body), 1)\n        # check the fstring\n        fstring = t.body[0].value.elts[1]\n        self.assertEqual(type(fstring), ast.JoinedStr)\n        self.assertEqual(len(fstring.values), 3)\n        wat1, middle, wat2 = fstring.values\n        # check the first wat\n        self.assertEqual(type(wat1), ast.Constant)\n        self.assertEqual(wat1.lineno, 4)\n        self.assertEqual(wat1.end_lineno, 5)\n        self.assertEqual(wat1.col_offset, 14)\n        self.assertEqual(wat1.end_col_offset, 26)\n        # check the call\n        call = middle.value\n        self.assertEqual(type(call), ast.Call)\n        self.assertEqual(call.lineno, 5)\n        self.assertEqual(call.end_lineno, 5)\n        self.assertEqual(call.col_offset, 27)\n        self.assertEqual(call.end_col_offset, 31)\n        # check the second wat\n        self.assertEqual(type(wat2), ast.Constant)\n        self.assertEqual(wat2.lineno, 5)\n        self.assertEqual(wat2.end_lineno, 6)\n        self.assertEqual(wat2.col_offset, 32)\n        # wat ends at the offset 17, but the whole f-string\n        # ends at the offset 18 (since the quote is part of the\n        # f-string but not the wat string)\n        self.assertEqual(wat2.end_col_offset, 17)\n        self.assertEqual(fstring.end_col_offset, 18)\n\n    def test_ast_fstring_empty_format_spec(self):\n        expr = "f\'{expr:}\'"\n\n        mod = ast.parse(expr)\n        self.assertEqual(type(mod), ast.Module)\n        self.assertEqual(len(mod.body), 1)\n\n        fstring = mod.body[0].value\n        self.assertEqual(type(fstring), ast.JoinedStr)\n        self.assertEqual(len(fstring.values), 1)\n\n        fv = fstring.values[0]\n        self.assertEqual(type(fv), ast.FormattedValue)\n\n        format_spec = fv.format_spec\n        self.assertEqual(type(format_spec), ast.JoinedStr)\n        self.assertEqual(len(format_spec.values), 0)\n\n    def test_docstring(self):\n        def f():\n            f"""Not a docstring"""\n\n        self.assertIsNone(f.__doc__)\n\n        def g():\n            """Not a docstring""" f""\n\n        self.assertIsNone(g.__doc__)\n\n    def test_literal_eval(self):\n        with self.assertRaisesRegex(ValueError, "malformed node or string"):\n            ast.literal_eval("f\'x\'")\n\n    def test_ast_compile_time_concat(self):\n        x = [""]\n\n        expr = """x[0] = \'foo\' f\'{3}\'"""\n        t = ast.parse(expr)\n        c = compile(t, "", "exec")\n        exec(c)\n        self.assertEqual(x[0], "foo3")\n\n    def test_compile_time_concat_errors(self):\n        self.assertAllRaise(\n            SyntaxError,\n            "cannot mix bytes and nonbytes literals",\n            [\n                r"""f\'\' b\'\'""",\n                r"""b\'\' f\'\'""",\n            ],\n        )\n\n    def test_literal(self):\n        self.assertEqual(f"", "")\n        self.assertEqual(f"a", "a")\n        self.assertEqual(f" ", " ")\n\n    def test_unterminated_string(self):\n        self.assertAllRaise(\n            SyntaxError,\n            "unterminated string",\n            [\n                r"""f\'{"x\'""",\n                r"""f\'{"x}\'""",\n                r"""f\'{("x\'""",\n                r"""f\'{("x}\'""",\n            ],\n        )\n\n    @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")\n    def test_mismatched_parens(self):\n        self.assertAllRaise(\n            SyntaxError,\n            r"closing parenthesis \'\\}\' " r"does not match opening parenthesis \'\\(\'",\n            [\n                "f\'{((}\'",\n            ],\n        )\n        self.assertAllRaise(\n            SyntaxError,\n            r"closing parenthesis \'\\)\' " r"does not match opening parenthesis \'\\[\'",\n            [\n                "f\'{a[4)}\'",\n            ],\n        )\n        self.assertAllRaise(\n            SyntaxError,\n            r"closing parenthesis \'\\]\' " r"does not match opening parenthesis \'\\(\'",\n            [\n                "f\'{a(4]}\'",\n            ],\n        )\n        self.assertAllRaise(\n            SyntaxError,\n            r"closing parenthesis \'\\}\' " r"does not match opening parenthesis \'\\[\'",\n            [\n                "f\'{a[4}\'",\n            ],\n        )\n        self.assertAllRaise(\n            SyntaxError,\n            r"closing parenthesis \'\\}\' " r"does not match opening parenthesis \'\\(\'",\n            [\n                "f\'{a(4}\'",\n            ],\n        )\n        self.assertRaises(SyntaxError, eval, "f\'{" + "(" * 500 + "}\'")\n\n    @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")\n    def test_fstring_nested_too_deeply(self):\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expressions nested too deeply",\n            [\'f"{1+2:{1+2:{1+1:{1}}}}"\'],\n        )\n\n        def create_nested_fstring(n):\n            if n == 0:\n                return "1+1"\n            prev = create_nested_fstring(n - 1)\n            return f\'f"{{{prev}}}"\'\n\n        self.assertAllRaise(\n            SyntaxError, "too many nested f-strings", [create_nested_fstring(160)]\n        )\n\n    def test_syntax_error_in_nested_fstring(self):\n        # See gh-104016 for more information on this crash\n        self.assertAllRaise(\n            SyntaxError, "invalid syntax", [\'f"{1 1:\' + (\'{f"1:\' * 199)]\n        )\n\n    def test_double_braces(self):\n        self.assertEqual(f"{{", "{")\n        self.assertEqual(f"a{{", "a{")\n        self.assertEqual(f"{{b", "{b")\n        self.assertEqual(f"a{{b", "a{b")\n        self.assertEqual(f"}}", "}")\n        self.assertEqual(f"a}}", "a}")\n        self.assertEqual(f"}}b", "}b")\n        self.assertEqual(f"a}}b", "a}b")\n        self.assertEqual(f"{{}}", "{}")\n        self.assertEqual(f"a{{}}", "a{}")\n        self.assertEqual(f"{{b}}", "{b}")\n        self.assertEqual(f"{{}}c", "{}c")\n        self.assertEqual(f"a{{b}}", "a{b}")\n        self.assertEqual(f"a{{}}c", "a{}c")\n        self.assertEqual(f"{{b}}c", "{b}c")\n        self.assertEqual(f"a{{b}}c", "a{b}c")\n\n        self.assertEqual(f"{{{10}", "{10")\n        self.assertEqual(f"}}{10}", "}10")\n        self.assertEqual(f"}}{{{10}", "}{10")\n        self.assertEqual(f"}}a{{{10}", "}a{10")\n\n        self.assertEqual(f"{10}{{", "10{")\n        self.assertEqual(f"{10}}}", "10}")\n        self.assertEqual(f"{10}}}{{", "10}{")\n        self.assertEqual(f"{10}}}a{{" "}", "10}a{}")\n\n        # Inside of strings, don\'t interpret doubled brackets.\n        self.assertEqual(f\'{"{{}}"}\', "{{}}")\n\n        self.assertAllRaise(\n            TypeError,\n            "unhashable type",\n            [\n                "f\'{ {{}} }\'",  # dict in a set\n            ],\n        )\n\n    def test_compile_time_concat(self):\n        x = "def"\n        self.assertEqual("abc" f"## {x}ghi", "abc## defghi")\n        self.assertEqual("abc" f"{x}" "ghi", "abcdefghi")\n        self.assertEqual("abc" f"{x}" "gh" f"i{x:4}", "abcdefghidef ")\n        self.assertEqual("{x}" f"{x}", "{x}def")\n        self.assertEqual("{x" f"{x}", "{xdef")\n        self.assertEqual("{x}" f"{x}", "{x}def")\n        self.assertEqual("{{x}}" f"{x}", "{{x}}def")\n        self.assertEqual("{{x" f"{x}", "{{xdef")\n        self.assertEqual("x}}" f"{x}", "x}}def")\n        self.assertEqual(f"{x}" "x}}", "defx}}")\n        self.assertEqual(f"{x}" "", "def")\n        self.assertEqual("" f"{x}" "", "def")\n        self.assertEqual("" f"{x}", "def")\n        self.assertEqual(f"{x}" "2", "def2")\n        self.assertEqual("1" f"{x}" "2", "1def2")\n        self.assertEqual("1" f"{x}", "1def")\n        self.assertEqual(f"{x}" f"-{x}", "def-def")\n        self.assertEqual("" f"", "")\n        self.assertEqual("" f"" "", "")\n        self.assertEqual("" f"" "" f"", "")\n        self.assertEqual(f"", "")\n        self.assertEqual(f"" "", "")\n        self.assertEqual(f"" "" f"", "")\n        self.assertEqual(f"" "" f"" "", "")\n\n        # This is not really [f\'{\'] + [f\'}\'] since we treat the inside\n        # of braces as a purely new context, so it is actually f\'{ and\n        # then eval(\'  f\') (a valid expression) and then }\' which would\n        # constitute a valid f-string.\n        self.assertEqual(f\'{\' f\'}\', " f")\n\n        self.assertAllRaise(\n            SyntaxError,\n            "expecting \'}\'",\n            [\n                \'\'\'f\'{3\' f"}"\'\'\',  # can\'t concat to get a valid f-string\n            ],\n        )\n\n    def test_comments(self):\n        # These aren\'t comments, since they\'re in strings.\n        d = {"#": "hash"}\n        self.assertEqual(f\'{"#"}\', "#")\n        self.assertEqual(f\'{d["#"]}\', "hash")\n\n        self.assertAllRaise(\n            SyntaxError,\n            "\'{\' was never closed",\n            [\n                "f\'{1#}\'",  # error because everything after \'#\' is a comment\n                "f\'{#}\'",\n                "f\'one: {1#}\'",\n                "f\'{1# one} {2 this is a comment still#}\'",\n            ],\n        )\n        self.assertAllRaise(\n            SyntaxError,\n            r"f-string: unmatched \'\\)\'",\n            [\n                "f\'{)#}\'",  # When wrapped in parens, this becomes\n                #  \'()#)\'.  Make sure that doesn\'t compile.\n            ],\n        )\n        self.assertEqual(\n            f"""A complex trick: {\n2  # two\n}""",\n            "A complex trick: 2",\n        )\n        self.assertEqual(\n            f"""\n{\n40 # forty\n+  # plus\n2  # two\n}""",\n            "\\n42",\n        )\n        self.assertEqual(\n            f"""\n{\n40 # forty\n+  # plus\n2  # two\n}""",\n            "\\n42",\n        )\n\n        self.assertEqual(\n            f"""\n# this is not a comment\n{ # the following operation it\'s\n3 # this is a number\n* 2}""",\n            "\\n# this is not a comment\\n6",\n        )\n        self.assertEqual(\n            f"""\n{# f\'a {comment}\'\n86 # constant\n# nothing more\n}""",\n            "\\n86",\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            r"f-string: valid expression required before \'}\'",\n            [\n                """f\'\'\'\n{\n# only a comment\n}\'\'\'\n""",  # this is equivalent to f\'{}\'\n            ],\n        )\n\n    def test_many_expressions(self):\n        # Create a string with many expressions in it. Note that\n        #  because we have a space in here as a literal, we\'re actually\n        #  going to use twice as many ast nodes: one for each literal\n        #  plus one for each expression.\n        def build_fstr(n, extra=""):\n            return "f\'" + ("{x} " * n) + extra + "\'"\n\n        x = "X"\n        width = 1\n\n        # Test around 256.\n        for i in range(250, 260):\n            self.assertEqual(eval(build_fstr(i)), (x + " ") * i)\n\n        # Test concatenating 2 largs fstrings.\n        self.assertEqual(eval(build_fstr(255) * 256), (x + " ") * (255 * 256))\n\n        s = build_fstr(253, "{x:{width}} ")\n        self.assertEqual(eval(s), (x + " ") * 254)\n\n        # Test lots of expressions and constants, concatenated.\n        s = "f\'{1}\' \'x\' \'y\'" * 1024\n        self.assertEqual(eval(s), "1xy" * 1024)\n\n    def test_format_specifier_expressions(self):\n        width = 10\n        precision = 4\n        value = decimal.Decimal("12.34567")\n        self.assertEqual(f"result: {value:{width}.{precision}}", "result:      12.35")\n        self.assertEqual(f"result: {value:{width!r}.{precision}}", "result:      12.35")\n        self.assertEqual(\n            f"result: {value:{width:0}.{precision:1}}", "result:      12.35"\n        )\n        self.assertEqual(\n            f"result: {value:{1}{0:0}.{precision:1}}", "result:      12.35"\n        )\n        self.assertEqual(\n            f"result: {value:{ 1}{ 0:0}.{ precision:1}}", "result:      12.35"\n        )\n        self.assertEqual(f"{10:#{1}0x}", "       0xa")\n        self.assertEqual(f\'{10:{"#"}1{0}{"x"}}\', "       0xa")\n        self.assertEqual(f\'{-10:-{"#"}1{0}x}\', "      -0xa")\n        self.assertEqual(f\'{-10:{"-"}#{1}0{"x"}}\', "      -0xa")\n        self.assertEqual(f"{10:#{3 != {4:5} and width}x}", "       0xa")\n        self.assertEqual(\n            f"result: {value:{width:{0}}.{precision:1}}", "result:      12.35"\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expecting \':\' or \'}\'",\n            [\n                """f\'{"s"!r{":10"}}\'""",\n                # This looks like a nested format spec.\n            ],\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expecting a valid expression after \'{\'",\n            [  # Invalid syntax inside a nested spec.\n                "f\'{4:{/5}}\'",\n            ],\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: invalid conversion character",\n            [  # No expansion inside conversion or for\n                #  the : or ! itself.\n                """f\'{"s"!{"r"}}\'""",\n            ],\n        )\n\n    def test_custom_format_specifier(self):\n        class CustomFormat:\n            def __format__(self, format_spec):\n                return format_spec\n\n        self.assertEqual(f"{CustomFormat():\\n}", "\\n")\n        self.assertEqual(f"{CustomFormat():\\u2603}", "☃")\n        with self.assertWarns(SyntaxWarning):\n            exec(r\'f"{F():¯\\_(ツ)_/¯}"\', {"F": CustomFormat})\n\n    def test_side_effect_order(self):\n        class X:\n            def __init__(self):\n                self.i = 0\n\n            def __format__(self, spec):\n                self.i += 1\n                return str(self.i)\n\n        x = X()\n        self.assertEqual(f"{x} {x}", "1 2")\n\n    def test_missing_expression(self):\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: valid expression required before \'}\'",\n            [\n                "f\'{}\'",\n                "f\'{ }\'" "f\' {} \'",\n                "f\'{10:{ }}\'",\n                "f\' { } \'",\n                # The Python parser ignores also the following\n                # whitespace characters in additional to a space.\n                "f\'\'\'{\\t\\f\\r\\n}\'\'\'",\n            ],\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: valid expression required before \'!\'",\n            [\n                "f\'{!r}\'",\n                "f\'{ !r}\'",\n                "f\'{!}\'",\n                "f\'\'\'{\\t\\f\\r\\n!a}\'\'\'",\n                # Catch empty expression before the\n                #  missing closing brace.\n                "f\'{!\'",\n                "f\'{!s:\'",\n                # Catch empty expression before the\n                #  invalid conversion.\n                "f\'{!x}\'",\n                "f\'{ !xr}\'",\n                "f\'{!x:}\'",\n                "f\'{!x:a}\'",\n                "f\'{ !xr:}\'",\n                "f\'{ !xr:a}\'",\n            ],\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: valid expression required before \':\'",\n            [\n                "f\'{:}\'",\n                "f\'{ :!}\'",\n                "f\'{:2}\'",\n                "f\'\'\'{\\t\\f\\r\\n:a}\'\'\'",\n                "f\'{:\'",\n                "F\'{[F\'{:\'}[F\'{:\'}]]]",\n            ],\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: valid expression required before \'=\'",\n            [\n                "f\'{=}\'",\n                "f\'{ =}\'",\n                "f\'{ =:}\'",\n                "f\'{   =!}\'",\n                "f\'\'\'{\\t\\f\\r\\n=}\'\'\'",\n                "f\'{=\'",\n            ],\n        )\n\n        # Different error message is raised for other whitespace characters.\n        self.assertAllRaise(\n            SyntaxError,\n            r"invalid non-printable character U\\+00A0",\n            [\n                "f\'\'\'{\\xa0}\'\'\'",\n                "\\xa0",\n            ],\n        )\n\n    def test_parens_in_expressions(self):\n        self.assertEqual(f"{3,}", "(3,)")\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expecting a valid expression after \'{\'",\n            [\n                "f\'{,}\'",\n            ],\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            r"f-string: unmatched \'\\)\'",\n            [\n                "f\'{3)+(4}\'",\n            ],\n        )\n\n    def test_newlines_before_syntax_error(self):\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expecting a valid expression after \'{\'",\n            ["f\'{.}\'", "\\nf\'{.}\'", "\\n\\nf\'{.}\'"],\n        )\n\n    def test_backslashes_in_string_part(self):\n        self.assertEqual(f"\\t", "\\t")\n        self.assertEqual(r"\\t", "\\\\t")\n        self.assertEqual(rf"\\t", "\\\\t")\n        self.assertEqual(f"{2}\\t", "2\\t")\n        self.assertEqual(f"{2}\\t{3}", "2\\t3")\n        self.assertEqual(f"\\t{3}", "\\t3")\n\n        self.assertEqual(f"\\u0394", "\\u0394")\n        self.assertEqual(r"\\u0394", "\\\\u0394")\n        self.assertEqual(rf"\\u0394", "\\\\u0394")\n        self.assertEqual(f"{2}\\u0394", "2\\u0394")\n        self.assertEqual(f"{2}\\u0394{3}", "2\\u03943")\n        self.assertEqual(f"\\u0394{3}", "\\u03943")\n\n        self.assertEqual(f"\\U00000394", "\\u0394")\n        self.assertEqual(r"\\U00000394", "\\\\U00000394")\n        self.assertEqual(rf"\\U00000394", "\\\\U00000394")\n        self.assertEqual(f"{2}\\U00000394", "2\\u0394")\n        self.assertEqual(f"{2}\\U00000394{3}", "2\\u03943")\n        self.assertEqual(f"\\U00000394{3}", "\\u03943")\n\n        self.assertEqual(f"\\N{GREEK CAPITAL LETTER DELTA}", "\\u0394")\n        self.assertEqual(f"{2}\\N{GREEK CAPITAL LETTER DELTA}", "2\\u0394")\n        self.assertEqual(f"{2}\\N{GREEK CAPITAL LETTER DELTA}{3}", "2\\u03943")\n        self.assertEqual(f"\\N{GREEK CAPITAL LETTER DELTA}{3}", "\\u03943")\n        self.assertEqual(f"2\\N{GREEK CAPITAL LETTER DELTA}", "2\\u0394")\n        self.assertEqual(f"2\\N{GREEK CAPITAL LETTER DELTA}3", "2\\u03943")\n        self.assertEqual(f"\\N{GREEK CAPITAL LETTER DELTA}3", "\\u03943")\n\n        self.assertEqual(f"\\x20", " ")\n        self.assertEqual(r"\\x20", "\\\\x20")\n        self.assertEqual(rf"\\x20", "\\\\x20")\n        self.assertEqual(f"{2}\\x20", "2 ")\n        self.assertEqual(f"{2}\\x20{3}", "2 3")\n        self.assertEqual(f"\\x20{3}", " 3")\n\n        self.assertEqual(f"2\\x20", "2 ")\n        self.assertEqual(f"2\\x203", "2 3")\n        self.assertEqual(f"\\x203", " 3")\n\n        with self.assertWarns(SyntaxWarning):  # invalid escape sequence\n            value = eval(r"f\'\\{6*7}\'")\n        self.assertEqual(value, "\\\\42")\n        with self.assertWarns(SyntaxWarning):  # invalid escape sequence\n            value = eval(r"f\'\\g\'")\n        self.assertEqual(value, "\\\\g")\n        self.assertEqual(f"\\\\{6*7}", "\\\\42")\n        self.assertEqual(rf"\\{6*7}", "\\\\42")\n\n        AMPERSAND = "spam"\n        # Get the right unicode character (&), or pick up local variable\n        # depending on the number of backslashes.\n        self.assertEqual(f"\\N{AMPERSAND}", "&")\n        self.assertEqual(f"\\\\N{AMPERSAND}", "\\\\Nspam")\n        self.assertEqual(rf"\\N{AMPERSAND}", "\\\\Nspam")\n        self.assertEqual(f"\\\\\\N{AMPERSAND}", "\\\\&")\n\n    def test_misformed_unicode_character_name(self):\n        # These test are needed because unicode names are parsed\n        # differently inside f-strings.\n        self.assertAllRaise(\n            SyntaxError,\n            r"\\(unicode error\\) \'unicodeescape\' codec can\'t decode bytes in position .*: malformed \\\\N character escape",\n            [\n                r"f\'\\N\'",\n                r"f\'\\N \'",\n                r"f\'\\N  \'",  # See bpo-46503.\n                r"f\'\\N{\'",\n                r"f\'\\N{GREEK CAPITAL LETTER DELTA\'",\n                # Here are the non-f-string versions,\n                #  which should give the same errors.\n                r"\'\\N\'",\n                r"\'\\N \'",\n                r"\'\\N  \'",\n                r"\'\\N{\'",\n                r"\'\\N{GREEK CAPITAL LETTER DELTA\'",\n            ],\n        )\n\n    def test_backslashes_in_expression_part(self):\n        self.assertEqual(\n            f"{(\n                        1 +\n                        2\n        )}",\n            "3",\n        )\n\n        self.assertEqual("\\N{LEFT CURLY BRACKET}", "{")\n        self.assertEqual(f\'{"\\N{LEFT CURLY BRACKET}"}\', "{")\n        self.assertEqual(rf\'{"\\N{LEFT CURLY BRACKET}"}\', "{")\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: valid expression required before \'}\'",\n            [\n                "f\'{\\n}\'",\n            ],\n        )\n\n    def test_invalid_backslashes_inside_fstring_context(self):\n        # All of these variations are invalid python syntax,\n        # so they are also invalid in f-strings as well.\n        cases = [\n            formatting.format(expr=expr)\n            for formatting in [\n                "{expr}",\n                "f\'{{{expr}}}\'",\n                "rf\'{{{expr}}}\'",\n            ]\n            for expr in [\n                r"\\\'a\\\'",\n                r"\\t3",\n                r"\\\\"[0],\n            ]\n        ]\n        self.assertAllRaise(\n            SyntaxError, "unexpected character after line continuation", cases\n        )\n\n    def test_no_escapes_for_braces(self):\n        """\n        Only literal curly braces begin an expression.\n        """\n        # \\x7b is \'{\'.\n        self.assertEqual(f"\\x7b1+1}}", "{1+1}")\n        self.assertEqual(f"\\x7b1+1", "{1+1")\n        self.assertEqual(f"\\u007b1+1", "{1+1")\n        self.assertEqual(f"\\N{LEFT CURLY BRACKET}1+1\\N{RIGHT CURLY BRACKET}", "{1+1}")\n\n    def test_newlines_in_expressions(self):\n        self.assertEqual(f"{0}", "0")\n        self.assertEqual(\n            rf"""{3+\n4}""",\n            "7",\n        )\n\n    def test_lambda(self):\n        x = 5\n        self.assertEqual(f\'{(lambda y:x*y)("8")!r}\', "\'88888\'")\n        self.assertEqual(f\'{(lambda y:x*y)("8")!r:10}\', "\'88888\'   ")\n        self.assertEqual(f\'{(lambda y:x*y)("8"):10}\', "88888     ")\n\n        # lambda doesn\'t work without parens, because the colon\n        # makes the parser think it\'s a format_spec\n        # emit warning if we can match a format_spec\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: lambda expressions are not allowed " "without parentheses",\n            [\n                "f\'{lambda x:x}\'",\n                "f\'{lambda :x}\'",\n                "f\'{lambda *arg, :x}\'",\n                "f\'{1, lambda:x}\'",\n                "f\'{lambda x:}\'",\n                "f\'{lambda :}\'",\n            ],\n        )\n        # Ensure the detection of invalid lambdas doesn\'t trigger detection\n        # for valid lambdas in the second error pass\n        with self.assertRaisesRegex(SyntaxError, "invalid syntax"):\n            compile("lambda name_3=f\'{name_4}\': {name_3}\\n1 $ 1", "<string>", "exec")\n\n        # but don\'t emit the paren warning in general cases\n        with self.assertRaisesRegex(\n            SyntaxError, "f-string: expecting a valid expression after \'{\'"\n        ):\n            eval("f\'{+ lambda:None}\'")\n\n    def test_valid_prefixes(self):\n        self.assertEqual(f"{1}", "1")\n        self.assertEqual(Rf"{2}", "2")\n        self.assertEqual(Rf"{3}", "3")\n\n    def test_roundtrip_raw_quotes(self):\n        self.assertEqual(rf"\\\'", "\\\\\'")\n        self.assertEqual(rf"\\"", \'\\\\"\')\n        self.assertEqual(rf"\\"\\\'", "\\\\\\"\\\\\'")\n        self.assertEqual(rf"\\\'\\"", "\\\\\'\\\\\\"")\n        self.assertEqual(rf"\\"\\\'\\"", \'\\\\"\\\\\\\'\\\\"\')\n        self.assertEqual(rf"\\\'\\"\\\'", "\\\\\'\\\\\\"\\\\\'")\n        self.assertEqual(rf"\\"\\\'\\"\\\'", "\\\\\\"\\\\\'\\\\\\"\\\\\'")\n\n    def test_fstring_backslash_before_double_bracket(self):\n        deprecated_cases = [\n            (r"f\'\\{{\\}}\'", "\\\\{\\\\}"),\n            (r"f\'\\{{\'", "\\\\{"),\n            (r"f\'\\{{{1+1}\'", "\\\\{2"),\n            (r"f\'\\}}{1+1}\'", "\\\\}2"),\n            (r"f\'{1+1}\\}}\'", "2\\\\}"),\n        ]\n        for case, expected_result in deprecated_cases:\n            with self.subTest(case=case, expected_result=expected_result):\n                with self.assertWarns(SyntaxWarning):\n                    result = eval(case)\n                self.assertEqual(result, expected_result)\n        self.assertEqual(rf"\\{{\\}}", "\\\\{\\\\}")\n        self.assertEqual(rf"\\{{", "\\\\{")\n        self.assertEqual(rf"\\{{{1+1}", "\\\\{2")\n        self.assertEqual(rf"\\}}{1+1}", "\\\\}2")\n        self.assertEqual(rf"{1+1}\\}}", "2\\\\}")\n\n    def test_fstring_backslash_before_double_bracket_warns_once(self):\n        with self.assertWarns(SyntaxWarning) as w:\n            eval(r"f\'\\{{\'")\n        self.assertEqual(len(w.warnings), 1)\n        self.assertEqual(w.warnings[0].category, SyntaxWarning)\n\n    def test_fstring_backslash_prefix_raw(self):\n        self.assertEqual(f"\\\\", "\\\\")\n        self.assertEqual(f"\\\\\\\\", "\\\\\\\\")\n        self.assertEqual(rf"\\\\", r"\\\\")\n        self.assertEqual(rf"\\\\\\\\", r"\\\\\\\\")\n        self.assertEqual(rf"\\\\", r"\\\\")\n        self.assertEqual(rf"\\\\\\\\", r"\\\\\\\\")\n        self.assertEqual(Rf"\\\\", R"\\\\")\n        self.assertEqual(Rf"\\\\\\\\", R"\\\\\\\\")\n        self.assertEqual(Rf"\\\\", R"\\\\")\n        self.assertEqual(Rf"\\\\\\\\", R"\\\\\\\\")\n        self.assertEqual(Rf"\\\\", R"\\\\")\n        self.assertEqual(Rf"\\\\\\\\", R"\\\\\\\\")\n\n    def test_fstring_format_spec_greedy_matching(self):\n        self.assertEqual(f"{1:}}}", "1}")\n        self.assertEqual(f"{1:>3{5}}}}", "                                  1}")\n\n    def test_yield(self):\n        # Not terribly useful, but make sure the yield turns\n        #  a function into a generator\n        def fn(y):\n            f"y:{yield y*2}"\n            f"{yield}"\n\n        g = fn(4)\n        self.assertEqual(next(g), 8)\n        self.assertEqual(next(g), None)\n\n    def test_yield_send(self):\n        def fn(x):\n            yield f"x:{yield (lambda i: x * i)}"\n\n        g = fn(10)\n        the_lambda = next(g)\n        self.assertEqual(the_lambda(4), 40)\n        self.assertEqual(g.send("string"), "x:string")\n\n    def test_expressions_with_triple_quoted_strings(self):\n        self.assertEqual(f"{\'\'\'x\'\'\'}", "x")\n        self.assertEqual(f"{\'\'\'eric\'s\'\'\'}", "eric\'s")\n\n        # Test concatenation within an expression\n        self.assertEqual(f\'{"x" """eric"s""" "y"}\', \'xeric"sy\')\n        self.assertEqual(f\'{"x" """eric"s"""}\', \'xeric"s\')\n        self.assertEqual(f\'{"""eric"s""" "y"}\', \'eric"sy\')\n        self.assertEqual(f\'{"""x""" """eric"s""" "y"}\', \'xeric"sy\')\n        self.assertEqual(f\'{"""x""" """eric"s""" """y"""}\', \'xeric"sy\')\n        self.assertEqual(f\'{r"""x""" """eric"s""" """y"""}\', \'xeric"sy\')\n\n    def test_multiple_vars(self):\n        x = 98\n        y = "abc"\n        self.assertEqual(f"{x}{y}", "98abc")\n\n        self.assertEqual(f"X{x}{y}", "X98abc")\n        self.assertEqual(f"{x}X{y}", "98Xabc")\n        self.assertEqual(f"{x}{y}X", "98abcX")\n\n        self.assertEqual(f"X{x}Y{y}", "X98Yabc")\n        self.assertEqual(f"X{x}{y}Y", "X98abcY")\n        self.assertEqual(f"{x}X{y}Y", "98XabcY")\n\n        self.assertEqual(f"X{x}Y{y}Z", "X98YabcZ")\n\n    def test_closure(self):\n        def outer(x):\n            def inner():\n                return f"x:{x}"\n\n            return inner\n\n        self.assertEqual(outer("987")(), "x:987")\n        self.assertEqual(outer(7)(), "x:7")\n\n    def test_arguments(self):\n        y = 2\n\n        def f(x, width):\n            return f"x={x*y:{width}}"\n\n        self.assertEqual(f("foo", 10), "x=foofoo    ")\n        x = "bar"\n        self.assertEqual(f(10, 10), "x=        20")\n\n    def test_locals(self):\n        value = 123\n        self.assertEqual(f"v:{value}", "v:123")\n\n    def test_missing_variable(self):\n        with self.assertRaises(NameError):\n            f"v:{value}"\n\n    def test_missing_format_spec(self):\n        class O:\n            def __format__(self, spec):\n                if not spec:\n                    return "*"\n                return spec\n\n        self.assertEqual(f"{O():x}", "x")\n        self.assertEqual(f"{O()}", "*")\n        self.assertEqual(f"{O():}", "*")\n\n        self.assertEqual(f"{3:}", "3")\n        self.assertEqual(f"{3!s:}", "3")\n\n    def test_global(self):\n        self.assertEqual(f"g:{a_global}", "g:global variable")\n        self.assertEqual(f"g:{a_global!r}", "g:\'global variable\'")\n\n        a_local = "local variable"\n        self.assertEqual(\n            f"g:{a_global} l:{a_local}", "g:global variable l:local variable"\n        )\n        self.assertEqual(f"g:{a_global!r}", "g:\'global variable\'")\n        self.assertEqual(\n            f"g:{a_global} l:{a_local!r}", "g:global variable l:\'local variable\'"\n        )\n\n        self.assertIn("module \'unittest\' from", f"{unittest}")\n\n    def test_shadowed_global(self):\n        a_global = "really a local"\n        self.assertEqual(f"g:{a_global}", "g:really a local")\n        self.assertEqual(f"g:{a_global!r}", "g:\'really a local\'")\n\n        a_local = "local variable"\n        self.assertEqual(\n            f"g:{a_global} l:{a_local}", "g:really a local l:local variable"\n        )\n        self.assertEqual(f"g:{a_global!r}", "g:\'really a local\'")\n        self.assertEqual(\n            f"g:{a_global} l:{a_local!r}", "g:really a local l:\'local variable\'"\n        )\n\n    def test_call(self):\n        def foo(x):\n            return "x=" + str(x)\n\n        self.assertEqual(f"{foo(10)}", "x=10")\n\n    def test_nested_fstrings(self):\n        y = 5\n        self.assertEqual(f\'{f"{0}"*3}\', "000")\n        self.assertEqual(f\'{f"{y}"*3}\', "555")\n\n    def test_invalid_string_prefixes(self):\n        single_quote_cases = [\n            "fu\'\'",\n            "uf\'\'",\n            "Fu\'\'",\n            "fU\'\'",\n            "Uf\'\'",\n            "uF\'\'",\n            "ufr\'\'",\n            "urf\'\'",\n            "fur\'\'",\n            "fru\'\'",\n            "rfu\'\'",\n            "ruf\'\'",\n            "FUR\'\'",\n            "Fur\'\'",\n            "fb\'\'",\n            "fB\'\'",\n            "Fb\'\'",\n            "FB\'\'",\n            "bf\'\'",\n            "bF\'\'",\n            "Bf\'\'",\n            "BF\'\'",\n        ]\n        double_quote_cases = [case.replace("\'", \'"\') for case in single_quote_cases]\n        self.assertAllRaise(\n            SyntaxError, "invalid syntax", single_quote_cases + double_quote_cases\n        )\n\n    def test_leading_trailing_spaces(self):\n        self.assertEqual(f"{ 3}", "3")\n        self.assertEqual(f"{  3}", "3")\n        self.assertEqual(f"{3 }", "3")\n        self.assertEqual(f"{3  }", "3")\n\n        self.assertEqual(f"expr={ {x: y for x, y in [(1, 2), ]}}", "expr={1: 2}")\n        self.assertEqual(f"expr={ {x: y for x, y in [(1, 2), ]} }", "expr={1: 2}")\n\n    def test_not_equal(self):\n        # There\'s a special test for this because there\'s a special\n        #  case in the f-string parser to look for != as not ending an\n        #  expression. Normally it would, while looking for !s or !r.\n\n        self.assertEqual(f"{3!=4}", "True")\n        self.assertEqual(f"{3!=4:}", "True")\n        self.assertEqual(f"{3!=4!s}", "True")\n        self.assertEqual(f"{3!=4!s:.3}", "Tru")\n\n    def test_equal_equal(self):\n        # Because an expression ending in = has special meaning,\n        # there\'s a special test for ==. Make sure it works.\n\n        self.assertEqual(f"{0==1}", "False")\n\n    def test_conversions(self):\n        self.assertEqual(f"{3.14:10.10}", "      3.14")\n        self.assertEqual(f"{3.14!s:10.10}", "3.14      ")\n        self.assertEqual(f"{3.14!r:10.10}", "3.14      ")\n        self.assertEqual(f"{3.14!a:10.10}", "3.14      ")\n\n        self.assertEqual(f\'{"a"}\', "a")\n        self.assertEqual(f\'{"a"!r}\', "\'a\'")\n        self.assertEqual(f\'{"a"!a}\', "\'a\'")\n\n        # Conversions can have trailing whitespace after them since it\n        # does not provide any significance\n        self.assertEqual(f"{3!s  }", "3")\n        self.assertEqual(f"{3.14!s  :10.10}", "3.14      ")\n\n        # Not a conversion.\n        self.assertEqual(f\'{"a!r"}\', "a!r")\n\n        # Not a conversion, but show that ! is allowed in a format spec.\n        self.assertEqual(f"{3.14:!<10.10}", "3.14!!!!!!")\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expecting \'}\'",\n            [\n                "f\'{3!\'",\n                "f\'{3!s\'",\n                "f\'{3!g\'",\n            ],\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: missing conversion character",\n            [\n                "f\'{3!}\'",\n                "f\'{3!:\'",\n                "f\'{3!:}\'",\n            ],\n        )\n\n        for conv_identifier in "g", "A", "G", "ä", "ɐ":\n            self.assertAllRaise(\n                SyntaxError,\n                "f-string: invalid conversion character %r: "\n                "expected \'s\', \'r\', or \'a\'" % conv_identifier,\n                ["f\'{3!" + conv_identifier + "}\'"],\n            )\n\n        for conv_non_identifier in "3", "!":\n            self.assertAllRaise(\n                SyntaxError,\n                "f-string: invalid conversion character",\n                ["f\'{3!" + conv_non_identifier + "}\'"],\n            )\n\n        for conv in " s", " s ":\n            self.assertAllRaise(\n                SyntaxError,\n                "f-string: conversion type must come right after the"\n                " exclamanation mark",\n                ["f\'{3!" + conv + "}\'"],\n            )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: invalid conversion character \'ss\': " "expected \'s\', \'r\', or \'a\'",\n            [\n                "f\'{3!ss}\'",\n                "f\'{3!ss:}\'",\n                "f\'{3!ss:s}\'",\n            ],\n        )\n\n    def test_assignment(self):\n        self.assertAllRaise(\n            SyntaxError,\n            r"invalid syntax",\n            [\n                "f\'\' = 3",\n                "f\'{0}\' = x",\n                "f\'{x}\' = x",\n            ],\n        )\n\n    def test_del(self):\n        self.assertAllRaise(\n            SyntaxError,\n            "invalid syntax",\n            [\n                "del f\'\'",\n                "del \'\' f\'\'",\n            ],\n        )\n\n    def test_mismatched_braces(self):\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: single \'}\' is not allowed",\n            [\n                "f\'{{}\'",\n                "f\'{{}}}\'",\n                "f\'}\'",\n                "f\'x}\'",\n                "f\'x}x\'",\n                r"f\'\\u007b}\'",\n                # Can\'t have { or } in a format spec.\n                "f\'{3:}>10}\'",\n                "f\'{3:}}>10}\'",\n            ],\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expecting \'}\'",\n            [\n                "f\'{3\'",\n                "f\'{3!\'",\n                "f\'{3:\'",\n                "f\'{3!s\'",\n                "f\'{3!s:\'",\n                "f\'{3!s:3\'",\n                "f\'x{\'",\n                "f\'x{x\'",\n                "f\'{x\'",\n                "f\'{3:s\'",\n                "f\'{{{\'",\n                "f\'{{}}{\'",\n                "f\'{\'",\n                "f\'{i=\'",  # See gh-93418.\n            ],\n        )\n\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expecting a valid expression after \'{\'",\n            [\n                "f\'{3:{{>10}\'",\n            ],\n        )\n\n        # But these are just normal strings.\n        self.assertEqual(f\'{"{"}\', "{")\n        self.assertEqual(f\'{"}"}\', "}")\n        self.assertEqual(f\'{3:{"}"}>10}\', "}}}}}}}}}3")\n        self.assertEqual(f\'{2:{"{"}>10}\', "{{{{{{{{{2")\n\n    def test_if_conditional(self):\n        # There\'s special logic in compile.c to test if the\n        #  conditional for an if (and while) are constants. Exercise\n        #  that code.\n\n        def test_fstring(x, expected):\n            flag = 0\n            if f"{x}":\n                flag = 1\n            else:\n                flag = 2\n            self.assertEqual(flag, expected)\n\n        def test_concat_empty(x, expected):\n            flag = 0\n            if "" f"{x}":\n                flag = 1\n            else:\n                flag = 2\n            self.assertEqual(flag, expected)\n\n        def test_concat_non_empty(x, expected):\n            flag = 0\n            if " " f"{x}":\n                flag = 1\n            else:\n                flag = 2\n            self.assertEqual(flag, expected)\n\n        test_fstring("", 2)\n        test_fstring(" ", 1)\n\n        test_concat_empty("", 2)\n        test_concat_empty(" ", 1)\n\n        test_concat_non_empty("", 1)\n        test_concat_non_empty(" ", 1)\n\n    def test_empty_format_specifier(self):\n        x = "test"\n        self.assertEqual(f"{x}", "test")\n        self.assertEqual(f"{x:}", "test")\n        self.assertEqual(f"{x!s:}", "test")\n        self.assertEqual(f"{x!r:}", "\'test\'")\n\n    def test_str_format_differences(self):\n        d = {\n            "a": "string",\n            0: "integer",\n        }\n        a = 0\n        self.assertEqual(f"{d[0]}", "integer")\n        self.assertEqual(f\'{d["a"]}\', "string")\n        self.assertEqual(f"{d[a]}", "integer")\n        self.assertEqual("{d[a]}".format(d=d), "string")\n        self.assertEqual("{d[0]}".format(d=d), "integer")\n\n    def test_errors(self):\n        # see issue 26287\n        self.assertAllRaise(\n            TypeError,\n            "unsupported",\n            [\n                r"f\'{(lambda: 0):x}\'",\n                r"f\'{(0,):x}\'",\n            ],\n        )\n        self.assertAllRaise(\n            ValueError,\n            "Unknown format code",\n            [\n                r"f\'{1000:j}\'",\n                r"f\'{1000:j}\'",\n            ],\n        )\n\n    def test_filename_in_syntaxerror(self):\n        # see issue 38964\n        with temp_cwd() as cwd:\n            file_path = os.path.join(cwd, "t.py")\n            with open(file_path, "w", encoding="utf-8") as f:\n                f.write(\'f"{a b}"\')  # This generates a SyntaxError\n            _, _, stderr = assert_python_failure(file_path, PYTHONIOENCODING="ascii")\n        self.assertIn(file_path.encode("ascii", "backslashreplace"), stderr)\n\n    def test_loop(self):\n        for i in range(1000):\n            self.assertEqual(f"i:{i}", "i:" + str(i))\n\n    def test_dict(self):\n        d = {\n            \'"\': "dquote",\n            "\'": "squote",\n            "foo": "bar",\n        }\n        self.assertEqual(f"""{d["\'"]}""", "squote")\n        self.assertEqual(f"""{d[\'"\']}""", "dquote")\n\n        self.assertEqual(f\'{d["foo"]}\', "bar")\n        self.assertEqual(f"{d[\'foo\']}", "bar")\n\n    def test_backslash_char(self):\n        # Check eval of a backslash followed by a control char.\n        # See bpo-30682: this used to raise an assert in pydebug mode.\n        self.assertEqual(eval(\'f"\\\\\\n"\'), "")\n        self.assertEqual(eval(\'f"\\\\\\r"\'), "")\n\n    def test_debug_conversion(self):\n        x = "A string"\n        self.assertEqual(f"{x=}", "x=" + repr(x))\n        self.assertEqual(f"{x =}", "x =" + repr(x))\n        self.assertEqual(f"{x=!s}", "x=" + str(x))\n        self.assertEqual(f"{x=!r}", "x=" + repr(x))\n        self.assertEqual(f"{x=!a}", "x=" + ascii(x))\n\n        x = 2.71828\n        self.assertEqual(f"{x=:.2f}", "x=" + format(x, ".2f"))\n        self.assertEqual(f"{x=:}", "x=" + format(x, ""))\n        self.assertEqual(f"{x=!r:^20}", "x=" + format(repr(x), "^20"))\n        self.assertEqual(f"{x=!s:^20}", "x=" + format(str(x), "^20"))\n        self.assertEqual(f"{x=!a:^20}", "x=" + format(ascii(x), "^20"))\n\n        x = 9\n        self.assertEqual(f"{3*x+15=}", "3*x+15=42")\n\n        # There is code in ast.c that deals with non-ascii expression values.  So,\n        # use a unicode identifier to trigger that.\n        tenπ = 31.4\n        self.assertEqual(f"{tenπ=:.2f}", "tenπ=31.40")\n\n        # Also test with Unicode in non-identifiers.\n        self.assertEqual(f\'{"Σ"=}\', "\\"Σ\\"=\'Σ\'")\n\n        # Make sure nested fstrings still work.\n        self.assertEqual(f\'{f"{3.1415=:.1f}":*^20}\', "*****3.1415=3.1*****")\n\n        # Make sure text before and after an expression with = works\n        # correctly.\n        pi = "π"\n        self.assertEqual(f"alpha α {pi=} ω omega", "alpha α pi=\'π\' ω omega")\n\n        # Check multi-line expressions.\n        self.assertEqual(\n            f"""{\n3\n=}""",\n            "\\n3\\n=3",\n        )\n\n        # Since = is handled specially, make sure all existing uses of\n        # it still work.\n\n        self.assertEqual(f"{0==1}", "False")\n        self.assertEqual(f"{0!=1}", "True")\n        self.assertEqual(f"{0<=1}", "True")\n        self.assertEqual(f"{0>=1}", "False")\n        self.assertEqual(f\'{(x:="5")}\', "5")\n        self.assertEqual(x, "5")\n        self.assertEqual(f"{(x:=5)}", "5")\n        self.assertEqual(x, 5)\n        self.assertEqual(f\'{"="}\', "=")\n\n        x = 20\n        # This isn\'t an assignment expression, it\'s \'x\', with a format\n        # spec of \'=10\'.  See test_walrus: you need to use parens.\n        self.assertEqual(f"{x:=10}", "        20")\n\n        # Test named function parameters, to make sure \'=\' parsing works\n        # there.\n        def f(a):\n            nonlocal x\n            oldx = x\n            x = a\n            return oldx\n\n        x = 0\n        self.assertEqual(f\'{f(a="3=")}\', "0")\n        self.assertEqual(x, "3=")\n        self.assertEqual(f"{f(a=4)}", "3=")\n        self.assertEqual(x, 4)\n\n        # Check debug expressions in format spec\n        y = 20\n        self.assertEqual(f"{2:{y=}}", "yyyyyyyyyyyyyyyyyyy2")\n        self.assertEqual(\n            f"{datetime.datetime.now():h1{y=}h2{y=}h3{y=}}", "h1y=20h2y=20h3y=20"\n        )\n\n        # Make sure __format__ is being called.\n        class C:\n            def __format__(self, s):\n                return f"FORMAT-{s}"\n\n            def __repr__(self):\n                return "REPR"\n\n        self.assertEqual(f"{C()=}", "C()=REPR")\n        self.assertEqual(f"{C()=!r}", "C()=REPR")\n        self.assertEqual(f"{C()=:}", "C()=FORMAT-")\n        self.assertEqual(f"{C()=: }", "C()=FORMAT- ")\n        self.assertEqual(f"{C()=:x}", "C()=FORMAT-x")\n        self.assertEqual(f"{C()=!r:*^20}", "C()=********REPR********")\n        self.assertEqual(f"{C():{20=}}", "FORMAT-20=20")\n\n        self.assertRaises(SyntaxError, eval, "f\'{C=]\'")\n\n        # Make sure leading and following text works.\n        x = "foo"\n        self.assertEqual(f"X{x=}Y", "Xx=" + repr(x) + "Y")\n\n        # Make sure whitespace around the = works.\n        self.assertEqual(f"X{x  =}Y", "Xx  =" + repr(x) + "Y")\n        self.assertEqual(f"X{x=  }Y", "Xx=  " + repr(x) + "Y")\n        self.assertEqual(f"X{x  =  }Y", "Xx  =  " + repr(x) + "Y")\n        self.assertEqual(f"sadsd {1 + 1 =  :{1 + 1:1d}f}", "sadsd 1 + 1 =  2.000000")\n\n        self.assertEqual(\n            f"{1+2 = # my comment\n  }",\n            "1+2 = \\n  3",\n        )\n\n        # These next lines contains tabs.  Backslash escapes don\'t\n        # work in f-strings.\n        # patchcheck doesn\'t like these tabs.  So the only way to test\n        # this will be to dynamically created and exec the f-strings.  But\n        # that\'s such a hassle I\'ll save it for another day.  For now, convert\n        # the tabs to spaces just to shut up patchcheck.\n        # self.assertEqual(f\'X{x =}Y\', \'Xx\\t=\'+repr(x)+\'Y\')\n        # self.assertEqual(f\'X{x =       }Y\', \'Xx\\t=\\t\'+repr(x)+\'Y\')\n\n    def test_debug_expressions_are_raw_strings(self):\n\n        self.assertEqual(f\'{b"\\N{OX}"=}\', \'b"\\\\N{OX}"=b\\\'\\\\\\\\N{OX}\\\'\')\n        self.assertEqual(f\'{r"\\xff"=}\', \'r"\\\\xff"=\\\'\\\\\\\\xff\\\'\')\n        self.assertEqual(f\'{r"\\n"=}\', \'r"\\\\n"=\\\'\\\\\\\\n\\\'\')\n        self.assertEqual(f"{\'\\\'\'=}", "\'\\\\\'\'=\\"\'\\"")\n        self.assertEqual(f\'{\'\\xc5\'=}\', r"\'\\xc5\'=\'Å\'")\n\n    def test_walrus(self):\n        x = 20\n        # This isn\'t an assignment expression, it\'s \'x\', with a format\n        # spec of \'=10\'.\n        self.assertEqual(f"{x:=10}", "        20")\n\n        # This is an assignment expression, which requires parens.\n        self.assertEqual(f"{(x:=10)}", "10")\n        self.assertEqual(x, 10)\n\n    def test_invalid_syntax_error_message(self):\n        with self.assertRaisesRegex(\n            SyntaxError, "f-string: expecting \'=\', or \'!\', or \':\', or \'}\'"\n        ):\n            compile("f\'{a $ b}\'", "?", "exec")\n\n    def test_with_two_commas_in_format_specifier(self):\n        error_msg = re.escape("Cannot specify \',\' with \',\'.")\n        with self.assertRaisesRegex(ValueError, error_msg):\n            f"{1:,,}"\n\n    def test_with_two_underscore_in_format_specifier(self):\n        error_msg = re.escape("Cannot specify \'_\' with \'_\'.")\n        with self.assertRaisesRegex(ValueError, error_msg):\n            f"{1:__}"\n\n    def test_with_a_commas_and_an_underscore_in_format_specifier(self):\n        error_msg = re.escape("Cannot specify both \',\' and \'_\'.")\n        with self.assertRaisesRegex(ValueError, error_msg):\n            f"{1:,_}"\n\n    def test_with_an_underscore_and_a_comma_in_format_specifier(self):\n        error_msg = re.escape("Cannot specify both \',\' and \'_\'.")\n        with self.assertRaisesRegex(ValueError, error_msg):\n            f"{1:_,}"\n\n    def test_syntax_error_for_starred_expressions(self):\n        with self.assertRaisesRegex(SyntaxError, "can\'t use starred expression here"):\n            compile("f\'{*a}\'", "?", "exec")\n\n        with self.assertRaisesRegex(\n            SyntaxError, "f-string: expecting a valid expression after \'{\'"\n        ):\n            compile("f\'{**a}\'", "?", "exec")\n\n    def test_not_closing_quotes(self):\n        self.assertAllRaise(SyntaxError, "unterminated f-string literal", [\'f"\', "f\'"])\n        self.assertAllRaise(\n            SyntaxError, "unterminated triple-quoted f-string literal", [\'f"""\', "f\'\'\'"]\n        )\n        # Ensure that the errors are reported at the correct line number.\n        data = \'\'\'\\\nx = 1 + 1\ny = 2 + 2\nz = f"""\nsdfjnsdfjsdf\nsdfsdfs{1+\n2} dfigdf {3+\n4}sdufsd""\n\'\'\'\n        try:\n            compile(data, "?", "exec")\n        except SyntaxError as e:\n            self.assertEqual(e.text, \'z = f"""\')\n            self.assertEqual(e.lineno, 3)\n\n    def test_syntax_error_after_debug(self):\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expecting a valid expression after \'{\'",\n            [\n                "f\'{1=}{;\'",\n                "f\'{1=}{+;\'",\n                "f\'{1=}{2}{;\'",\n                "f\'{1=}{3}{;\'",\n            ],\n        )\n        self.assertAllRaise(\n            SyntaxError,\n            "f-string: expecting \'=\', or \'!\', or \':\', or \'}\'",\n            [\n                "f\'{1=}{1;\'",\n                "f\'{1=}{1;}\'",\n            ],\n        )\n\n    def test_debug_in_file(self):\n        with temp_cwd():\n            script = "script.py"\n            with open("script.py", "w") as f:\n                f.write(f"""\\\nprint(f\'\'\'{{\n3\n=}}\'\'\')""")\n\n            _, stdout, _ = assert_python_ok(script)\n        self.assertEqual(\n            stdout.decode("utf-8").strip().replace("\\r\\n", "\\n").replace("\\r", "\\n"),\n            "3\\n=3",\n        )\n\n    def test_syntax_warning_infinite_recursion_in_file(self):\n        with temp_cwd():\n            script = "script.py"\n            with open(script, "w") as f:\n                f.write(r"print(f\'\\{1}\')")\n\n            _, stdout, stderr = assert_python_ok(script)\n            self.assertIn(rb"\\1", stdout)\n            self.assertEqual(len(stderr.strip().splitlines()), 2)\n\n    def test_gh129093(self):\n        self.assertEqual(f\'{1==2=}\', \'1==2=False\')\n        self.assertEqual(f\'{1 == 2=}\', \'1 == 2=False\')\n        self.assertEqual(f\'{1!=2=}\', \'1!=2=True\')\n        self.assertEqual(f\'{1 != 2=}\', \'1 != 2=True\')\n\n        self.assertEqual(f\'{(1) != 2=}\', \'(1) != 2=True\')\n        self.assertEqual(f\'{(1*2) != (3)=}\', \'(1*2) != (3)=True\')\n\n        self.assertEqual(f\'{1 != 2 == 3 != 4=}\', \'1 != 2 == 3 != 4=False\')\n        self.assertEqual(f\'{1 == 2 != 3 == 4=}\', \'1 == 2 != 3 == 4=False\')\n\n        self.assertEqual(f\'{f\'{1==2=}\'=}\', "f\'{1==2=}\'=\'1==2=False\'")\n        self.assertEqual(f\'{f\'{1 == 2=}\'=}\', "f\'{1 == 2=}\'=\'1 == 2=False\'")\n        self.assertEqual(f\'{f\'{1!=2=}\'=}\', "f\'{1!=2=}\'=\'1!=2=True\'")\n        self.assertEqual(f\'{f\'{1 != 2=}\'=}\', "f\'{1 != 2=}\'=\'1 != 2=True\'")\n\n\nif __name__ == "__main__":\n\n    unittest.main()\n', ast_parse_kwargs={}, filename=PosixPath('/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_fstring.py'))
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/test_unparse.py", line 138, in check_ast_roundtrip
    self.assertASTEqual(ast1, ast2)
         ^^^^^^^^^^^^^^
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 43, in assertASTEqual
    traverse_compare(ast1, ast2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 24, in traverse_compare
    traverse_compare(value1, value2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 28, in traverse_compare
    traverse_compare(node1, node2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 24, in traverse_compare
    traverse_compare(value1, value2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 28, in traverse_compare
    traverse_compare(node1, node2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 24, in traverse_compare
    traverse_compare(value1, value2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 28, in traverse_compare
    traverse_compare(node1, node2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 24, in traverse_compare
    traverse_compare(value1, value2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 24, in traverse_compare
    traverse_compare(value1, value2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 28, in traverse_compare
    traverse_compare(node1, node2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 24, in traverse_compare
    traverse_compare(value1, value2)
  File "/Users/matti/build-worker-arm64/pypy-c-jit-macos-arm64/build/lib-python/3/test/support/ast_helper.py", line 40, in traverse_compare
    raise self.failureException(msg) from None
AssertionError: First list contains 1 additional elements.

----------------------------------------------------------------------
Ran 69 tests in 1.103s

FAILED (failures=3)
0:00:01 load avg: 2.33 [1/1/1] test_unparse failed (3 failures)

== Tests result: FAILURE ==

1 test failed:
    test_unparse

Total duration: 1.2 sec
Total tests: run=69 failures=3
Total test files: run=1/1 failed=1
Result: FAILURE
<unknown>:1769: SyntaxWarning: invalid escape sequence '\N'
test test_unparse failed
builder: pypy-c-jit-macos-arm64 build #1306+
test: lib-python/3/test/test_unparse.py::unmodified