diff --git a/CHANGES.md b/CHANGES.md index a63503d539a..e3e37484a59 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -34,6 +34,9 @@ - Fix regression where Black failed to parse a multiline f-string containing another multiline string (#4339) +- Fix regression where Black failed to parse an escaped single quote inside an f-string + (#4401) + - Fix bug with Black incorrectly parsing empty lines with a backslash (#4343) ### Performance diff --git a/src/black/linegen.py b/src/black/linegen.py index 9d22a7e7854..46945ca2a14 100644 --- a/src/black/linegen.py +++ b/src/black/linegen.py @@ -510,6 +510,15 @@ def visit_fstring(self, node: Node) -> Iterator[Line]: # currently we don't want to format and split f-strings at all. string_leaf = fstring_to_string(node) node.replace(string_leaf) + if "\\" in string_leaf.value and any( + "\\" in str(child) + for child in node.children + if child.type == syms.fstring_replacement_field + ): + # string normalization doesn't account for nested quotes, + # causing breakages. skip normalization when nested quotes exist + yield from self.visit_default(string_leaf) + return yield from self.visit_STRING(string_leaf) # TODO: Uncomment Implementation to format f-string children diff --git a/tests/data/cases/pep_701.py b/tests/data/cases/pep_701.py index d72d91c6799..717927d206d 100644 --- a/tests/data/cases/pep_701.py +++ b/tests/data/cases/pep_701.py @@ -128,6 +128,9 @@ f"""{''' '''}""" +f"{'\''}" +f"{f'\''}" + # output x = f"foo" @@ -258,3 +261,6 @@ f"""{''' '''}""" + +f"{'\''}" +f"{f'\''}"