]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.11] gh-108843: fix ast.unparse for f-string with many quotes (#108980)
authorShantanu <12621235+hauntsaninja@users.noreply.github.com>
Mon, 18 Sep 2023 14:11:56 +0000 (07:11 -0700)
committerGitHub <noreply@github.com>
Mon, 18 Sep 2023 14:11:56 +0000 (15:11 +0100)
* [3.11] gh-108843: fix ast.unparse for f-string with many quotes

* ðŸ“œðŸ¤– Added by blurb_it.

* simplify

---------

Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
Lib/ast.py
Lib/test/test_unparse.py
Misc/NEWS.d/next/Library/2023-09-06-04-30-05.gh-issue-108843.WJMhsS.rst [new file with mode: 0644]

index 623b9a1b805d0eff8384a37ab0de75bd63d7805a..d84d75e1f3a8e1babe50174119de2c603d28a66c 100644 (file)
@@ -1175,13 +1175,29 @@ class _Unparser(NodeVisitor):
 
         new_fstring_parts = []
         quote_types = list(_ALL_QUOTES)
+        fallback_to_repr = False
         for value, is_constant in fstring_parts:
-            value, quote_types = self._str_literal_helper(
+            value, new_quote_types = self._str_literal_helper(
                 value,
                 quote_types=quote_types,
                 escape_special_whitespace=is_constant,
             )
             new_fstring_parts.append(value)
+            if set(new_quote_types).isdisjoint(quote_types):
+                fallback_to_repr = True
+                break
+            quote_types = new_quote_types
+
+        if fallback_to_repr:
+            # If we weren't able to find a quote type that works for all parts
+            # of the JoinedStr, fallback to using repr and triple single quotes.
+            quote_types = ["'''"]
+            new_fstring_parts.clear()
+            for value, is_constant in fstring_parts:
+                value = repr('"' + value)  # force repr to use single quotes
+                expected_prefix = "'\""
+                assert value.startswith(expected_prefix), repr(value)
+                new_fstring_parts.append(value[len(expected_prefix):-1])
 
         value = "".join(new_fstring_parts)
         quote_type = quote_types[0]
index f1f1dd5dc26be8473e6b2d27340b0bab4a32ff6c..d8f0060b3a4ef9e7c70973755aa6cc366d3b72af 100644 (file)
@@ -662,6 +662,11 @@ class CosmeticTestCase(ASTTestCase):
         self.check_src_roundtrip("[a, b] = [c, d] = [e, f] = g")
         self.check_src_roundtrip("a, b = [c, d] = e, f = g")
 
+    def test_multiquote_joined_string(self):
+        self.check_ast_roundtrip("f\"'''{1}\\\"\\\"\\\"\" ")
+        self.check_ast_roundtrip("""f"'''{1}""\\"" """)
+        self.check_ast_roundtrip("""f'""\"{1}''' """)
+        self.check_ast_roundtrip("""f'""\"{1}""\\"' """)
 
 
 class DirectoryTestCase(ASTTestCase):
diff --git a/Misc/NEWS.d/next/Library/2023-09-06-04-30-05.gh-issue-108843.WJMhsS.rst b/Misc/NEWS.d/next/Library/2023-09-06-04-30-05.gh-issue-108843.WJMhsS.rst
new file mode 100644 (file)
index 0000000..0f15761
--- /dev/null
@@ -0,0 +1 @@
+Fix an issue in :func:`ast.unparse` when unparsing f-strings containing many quote types.