From 5d0a469e8e2a6b83163ea27c9da654cb97f05e8a Mon Sep 17 00:00:00 2001
From: Zsolt Dollenstein <zsol.zsol@gmail.com>
Date: Sat, 9 Jun 2018 21:30:49 +0200
Subject: [PATCH] Fix string normalization sometimes producing invalid fstrings
 (#327)

---
 README.md             |  5 +++++
 black.py              |  6 ++++++
 tests/data/fstring.py | 18 +++++++++++++++++-
 3 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 7ae640c..533a1f8 100644
--- a/README.md
+++ b/README.md
@@ -807,6 +807,11 @@ More details can be found in [CONTRIBUTING](CONTRIBUTING.md).
 
 ## Change Log
 
+### 18.6b3
+
+* fixed improper formatting of f-strings with quotes inside interpolated
+  expressions (#322)
+
 ### 18.6b2
 
 * added `--config` (#65)
diff --git a/black.py b/black.py
index 6db661c..35daaa9 100644
--- a/black.py
+++ b/black.py
@@ -2549,6 +2549,12 @@ def normalize_string_quotes(leaf: Leaf) -> None:
             leaf.value = f"{prefix}{orig_quote}{body}{orig_quote}"
         new_body = sub_twice(escaped_orig_quote, rf"\1\2{orig_quote}", new_body)
         new_body = sub_twice(unescaped_new_quote, rf"\1\\{new_quote}", new_body)
+    if "f" in prefix.casefold():
+        matches = re.findall(r"[^{]\{(.*?)\}[^}]", new_body)
+        for m in matches:
+            if "\\" in str(m):
+                # Do not introduce backslashes in interpolated expressions
+                return
     if new_quote == '"""' and new_body[-1:] == '"':
         # edge case:
         new_body = new_body[:-1] + '\\"'
diff --git a/tests/data/fstring.py b/tests/data/fstring.py
index b288cbc..4b33231 100644
--- a/tests/data/fstring.py
+++ b/tests/data/fstring.py
@@ -1,5 +1,21 @@
 f"f-string without formatted values is just a string"
 f"{{NOT a formatted value}}"
+f"{{NOT 'a' \"formatted\" \"value\"}}"
 f"some f-string with {a} {few():.2f} {formatted.values!r}"
-f"{f'{nested} inner'} outer"
+f'some f-string with {a} {few(""):.2f} {formatted.values!r}'
+f"{f'''{'nested'} inner'''} outer"
+f"\"{f'{nested} inner'}\" outer"
 f"space between opening braces: { {a for a in (1, 2, 3)}}"
+f'Hello \'{tricky + "example"}\''
+
+# output
+
+f"f-string without formatted values is just a string"
+f"{{NOT a formatted value}}"
+f'{{NOT \'a\' "formatted" "value"}}'
+f"some f-string with {a} {few():.2f} {formatted.values!r}"
+f'some f-string with {a} {few(""):.2f} {formatted.values!r}'
+f"{f'''{'nested'} inner'''} outer"
+f"\"{f'{nested} inner'}\" outer"
+f"space between opening braces: { {a for a in (1, 2, 3)}}"
+f'Hello \'{tricky + "example"}\''
-- 
2.39.5