mirror of
https://github.com/python/cpython.git
synced 2025-08-03 16:39:00 +00:00
bpo-28002: Roundtrip f-strings with ast.unparse better (GH-19612) (GH-23430)
By attempting to avoid backslashes in f-string expressions.
We also now proactively raise errors for some backslashes we can't
avoid while unparsing FormattedValues
Co-authored-by: hauntsaninja <>
Co-authored-by: Shantanu <hauntsaninja@users.noreply.github.com>
Co-authored-by: Batuhan Taskaya <isidentical@gmail.com>
(cherry picked from commit a993e901eb
)
Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
This commit is contained in:
parent
f552f4b2d6
commit
3763cc1dbd
2 changed files with 115 additions and 37 deletions
|
@ -152,6 +152,18 @@ class UnparseTestCase(ASTTestCase):
|
|||
# See issue 25180
|
||||
self.check_ast_roundtrip(r"""f'{f"{0}"*3}'""")
|
||||
self.check_ast_roundtrip(r"""f'{f"{y}"*3}'""")
|
||||
self.check_ast_roundtrip("""f''""")
|
||||
self.check_ast_roundtrip('''f"""'end' "quote\\""""''')
|
||||
|
||||
def test_fstrings_complicated(self):
|
||||
# See issue 28002
|
||||
self.check_ast_roundtrip("""f'''{"'"}'''""")
|
||||
self.check_ast_roundtrip('''f\'\'\'-{f"""*{f"+{f'.{x}.'}+"}*"""}-\'\'\'''')
|
||||
self.check_ast_roundtrip('''f\'\'\'-{f"""*{f"+{f'.{x}.'}+"}*"""}-'single quote\\'\'\'\'''')
|
||||
self.check_ast_roundtrip('f"""{\'\'\'\n\'\'\'}"""')
|
||||
self.check_ast_roundtrip('f"""{g(\'\'\'\n\'\'\')}"""')
|
||||
self.check_ast_roundtrip('''f"a\\r\\nb"''')
|
||||
self.check_ast_roundtrip('''f"\\u2028{'x'}"''')
|
||||
|
||||
def test_strings(self):
|
||||
self.check_ast_roundtrip("u'foo'")
|
||||
|
@ -311,6 +323,9 @@ class UnparseTestCase(ASTTestCase):
|
|||
)
|
||||
)
|
||||
|
||||
def test_invalid_fstring_backslash(self):
|
||||
self.check_invalid(ast.FormattedValue(value=ast.Constant(value="\\\\")))
|
||||
|
||||
def test_invalid_set(self):
|
||||
self.check_invalid(ast.Set(elts=[]))
|
||||
|
||||
|
@ -330,8 +345,8 @@ class UnparseTestCase(ASTTestCase):
|
|||
'\r\\r\t\\t\n\\n',
|
||||
'""">>> content = \"\"\"blabla\"\"\" <<<"""',
|
||||
r'foo\n\x00',
|
||||
'🐍⛎𩸽üéş^\N{LONG RIGHTWARDS SQUIGGLE ARROW}'
|
||||
|
||||
"' \\'\\'\\'\"\"\" \"\"\\'\\' \\'",
|
||||
'🐍⛎𩸽üéş^\\\\X\\\\BB\N{LONG RIGHTWARDS SQUIGGLE ARROW}'
|
||||
)
|
||||
for docstring in docstrings:
|
||||
# check as Module docstrings for easy testing
|
||||
|
@ -416,7 +431,6 @@ class CosmeticTestCase(ASTTestCase):
|
|||
self.check_src_roundtrip("call((yield x))")
|
||||
self.check_src_roundtrip("return x + (yield x)")
|
||||
|
||||
|
||||
def test_class_bases_and_keywords(self):
|
||||
self.check_src_roundtrip("class X:\n pass")
|
||||
self.check_src_roundtrip("class X(A):\n pass")
|
||||
|
@ -429,6 +443,13 @@ class CosmeticTestCase(ASTTestCase):
|
|||
self.check_src_roundtrip("class X(*args):\n pass")
|
||||
self.check_src_roundtrip("class X(*args, **kwargs):\n pass")
|
||||
|
||||
def test_fstrings(self):
|
||||
self.check_src_roundtrip('''f\'\'\'-{f"""*{f"+{f'.{x}.'}+"}*"""}-\'\'\'''')
|
||||
self.check_src_roundtrip('''f"\\u2028{'x'}"''')
|
||||
self.check_src_roundtrip(r"f'{x}\n'")
|
||||
self.check_src_roundtrip('''f''\'{"""\n"""}\\n''\'''')
|
||||
self.check_src_roundtrip('''f''\'{f"""{x}\n"""}\\n''\'''')
|
||||
|
||||
def test_docstrings(self):
|
||||
docstrings = (
|
||||
'"""simple doc string"""',
|
||||
|
@ -443,6 +464,10 @@ class CosmeticTestCase(ASTTestCase):
|
|||
'""""""',
|
||||
'"""\'\'\'"""',
|
||||
'"""\'\'\'\'\'\'"""',
|
||||
'"""🐍⛎𩸽üéş^\\\\X\\\\BB⟿"""',
|
||||
'"""end in single \'quote\'"""',
|
||||
"'''end in double \"quote\"'''",
|
||||
'"""almost end in double "quote"."""',
|
||||
)
|
||||
|
||||
for prefix in docstring_prefixes:
|
||||
|
@ -483,9 +508,8 @@ class DirectoryTestCase(ASTTestCase):
|
|||
|
||||
lib_dir = pathlib.Path(__file__).parent / ".."
|
||||
test_directories = (lib_dir, lib_dir / "test")
|
||||
skip_files = {"test_fstring.py"}
|
||||
run_always_files = {"test_grammar.py", "test_syntax.py", "test_compile.py",
|
||||
"test_ast.py", "test_asdl_parser.py"}
|
||||
"test_ast.py", "test_asdl_parser.py", "test_fstring.py"}
|
||||
|
||||
_files_to_test = None
|
||||
|
||||
|
@ -525,14 +549,6 @@ class DirectoryTestCase(ASTTestCase):
|
|||
if test.support.verbose:
|
||||
print(f"Testing {item.absolute()}")
|
||||
|
||||
# Some f-strings are not correctly round-tripped by
|
||||
# Tools/parser/unparse.py. See issue 28002 for details.
|
||||
# We need to skip files that contain such f-strings.
|
||||
if item.name in self.skip_files:
|
||||
if test.support.verbose:
|
||||
print(f"Skipping {item.absolute()}: see issue 28002")
|
||||
continue
|
||||
|
||||
with self.subTest(filename=item):
|
||||
source = read_pyfile(item)
|
||||
self.check_ast_roundtrip(source)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue