Skip to content

Commit

Permalink
unparse with new fstring syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
sunmy2019 committed Sep 2, 2023
1 parent d9bf98a commit cb043e0
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 17 deletions.
22 changes: 12 additions & 10 deletions Lib/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -1247,11 +1247,17 @@ def visit_JoinedStr(self, node):
new_fstring_parts = []
quote_types = list(_ALL_QUOTES)
for value, is_constant in fstring_parts:
value, quote_types = self._str_literal_helper(
value,
quote_types=quote_types,
escape_special_whitespace=is_constant,
)
if is_constant:
value, quote_types = self._str_literal_helper(
value,
quote_types=quote_types,
escape_special_whitespace=True,
)
elif "\n" in value:
if "'" in quote_types:
quote_types.remove("'")
if '"' in quote_types:
quote_types.remove('"')
new_fstring_parts.append(value)

value = "".join(new_fstring_parts)
Expand All @@ -1273,16 +1279,12 @@ def _write_fstring_inner(self, node):

def visit_FormattedValue(self, node):
def unparse_inner(inner):
unparser = type(self)(_avoid_backslashes=True)
unparser = type(self)(_avoid_backslashes=False)
unparser.set_precedence(_Precedence.TEST.next(), inner)
return unparser.visit(inner)

with self.delimit("{", "}"):
expr = unparse_inner(node.value)
if "\\" in expr:
raise ValueError(
"Unable to avoid backslash in f-string expression part"
)
if expr.startswith("{"):
# Separate pair of opening brackets as "{ {"
self.write(" ")
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_tokenize.py
Original file line number Diff line number Diff line change
Expand Up @@ -1860,7 +1860,7 @@ def test_random_files(self):

testfiles.remove(os.path.join(tempdir, "test_unicode_identifiers.py"))

# TODO: Remove this once we can unparse PEP 701 syntax
# TODO: Remove this once we can untokenize PEP 701 syntax
testfiles.remove(os.path.join(tempdir, "test_fstring.py"))

for f in ('buffer', 'builtin', 'fileio', 'inspect', 'os', 'platform', 'sys'):
Expand Down
19 changes: 13 additions & 6 deletions Lib/test/test_unparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,15 @@ def test_invalid_fstring_value(self):
)
)

def test_invalid_fstring_backslash(self):
self.check_invalid(ast.FormattedValue(value=ast.Constant(value="\\\\")))
def test_fstring_backslash(self):
# valid since Python 3.12
self.assertEqual(ast.unparse(
ast.FormattedValue(
value=ast.Constant(value="\\\\"),
conversion=-1,
format_spec=None,
)
), "{'\\\\\\\\'}")

def test_invalid_yield_from(self):
self.check_invalid(ast.YieldFrom(value=None))
Expand Down Expand Up @@ -506,11 +513,11 @@ def test_class_bases_and_keywords(self):
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("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''\'''')
self.check_src_roundtrip("f'{'\\n'}\\n'")
self.check_src_roundtrip("f'{f'{x}\\n'}\\n'")

def test_docstrings(self):
docstrings = (
Expand Down

0 comments on commit cb043e0

Please sign in to comment.