10000 [3.12] gh-108843: fix ast.unparse for f-string with many quotes (GH-1… · python/cpython@2401b98 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2401b98

Browse files
[3.12] gh-108843: fix ast.unparse for f-string with many quotes (GH-108981) (#109541)
gh-108843: fix ast.unparse for f-string with many quotes (GH-108981) (cherry picked from commit 23f9f6f) Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
1 parent f6fc831 commit 2401b98

File tree

3 files changed

+35
-1
lines changed

3 files changed

+35
-1
lines changed

Lib/ast.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1234,17 +1234,36 @@ def visit_JoinedStr(self, node):
12341234

12351235
new_fstring_parts = []
12361236
quote_types = list(_ALL_QUOTES)
1237+
fallback_to_repr = False
12371238
for value, is_constant in fstring_parts:
12381239
if is_constant:
1239-
value, quote_types = self._str_literal_helper(
1240+
value, new_quote_types = self._str_literal_helper(
12401241
value,
12411242
quote_types=quote_types,
12421243
escape_special_whitespace=True,
12431244
)
1245+
if set(new_quote_types).isdisjoint(quote_types):
1246+
fallback_to_repr = True
1247+
break
1248+
quote_types = new_quote_types
12441249
elif "\n" in value:
12451250
quote_types = [q for q in quote_types if q in _MULTI_QUOTES]
1251+
assert quote_types
12461252
new_fstring_parts.append(value)
12471253

1254+
if fallback_to_repr:
1255+
# If we weren't able to find a quote type that works for all parts
1256+
# of the JoinedStr, fallback to using repr and triple single quotes.
1257+
quote_types = ["'''"]
1258+
new_fstring_parts.clear()
1259+
for value, is_constant in fstring_parts:
1260+
if is_constant:
1261+
value = repr('"' + value) # force repr to use single quotes
1262+
expected_prefix = "'\""
1263+
assert value.startswith(expected_prefix), repr(value)
1264+
value = value[len(expected_prefix):-1]
1265+
new_fstring_parts.append(value)
1266+
12481267
value = "".join(new_fstring_parts)
12491268
quote_type = quote_types[0]
12501269
self.write(f"{quote_type}{value}{quote_type}")

Lib/test/test_unparse.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,20 @@ def test_star_expr_assign_target_multiple(self):
635635
self.check_src_roundtrip("[a, b] = [c, d] = [e, f] = g")
636636
self.check_src_roundtrip("a, b = [c, d] = e, f = g")
637637

638+
def test_multiquote_joined_string(self):
639+
self.check_ast_roundtrip("f\"'''{1}\\\"\\\"\\\"\" ")
640+
self.check_ast_roundtrip("""f"'''{1}""\\"" """)
641+
self.check_ast_roundtrip("""f'""\"{1}''' """)
642+
self.check_ast_roundtrip("""f'""\"{1}""\\"' """)
643+
644+
self.check_ast_roundtrip("""f"'''{"\\n"}""\\"" """)
645+
self.check_ast_roundtrip("""f'""\"{"\\n"}''' """)
646+
self.check_ast_roundtrip("""f'""\"{"\\n"}""\\"' """)
647+
648+
self.check_ast_roundtrip("""f'''""\"''\\'{"\\n"}''' """)
649+
self.check_ast_roundtrip("""f'''""\"''\\'{"\\n\\"'"}''' """)
650+
self.check_ast_roundtrip("""f'''""\"''\\'{""\"\\n\\"'''""\" '''\\n'''}''' """)
651+
638652

639653
class ManualASTCreationTestCase(unittest.TestCase):
640654
"""Test that AST nodes created without a type_params field unparse correctly."""
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix an issue in :func:`ast.unparse` when unparsing f-strings containing many quote types.

0 commit comments

Comments
 (0)
0