Skip to content

Commit f4b644b

Browse files
Prevent wrapping of multiline fstrings in parens (#4325)
1 parent 551ede2 commit f4b644b

File tree

3 files changed

+42
-9
lines changed

3 files changed

+42
-9
lines changed

src/black/linegen.py

+3-8
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
WHITESPACE,
3838
Visitor,
3939
ensure_visible,
40+
fstring_to_string,
4041
get_annotation_type,
4142
is_arith_like,
4243
is_async_stmt_or_funcdef,
@@ -504,7 +505,7 @@ def visit_NUMBER(self, leaf: Leaf) -> Iterator[Line]:
504505

505506
def visit_fstring(self, node: Node) -> Iterator[Line]:
506507
# currently we don't want to format and split f-strings at all.
507-
string_leaf = _fstring_to_string(node)
508+
string_leaf = fstring_to_string(node)
508509
node.replace(string_leaf)
509510
yield from self.visit_STRING(string_leaf)
510511

@@ -574,12 +575,6 @@ def __post_init__(self) -> None:
574575
self.visit_guard = partial(v, keywords=Ø, parens={"if"})
575576

576577

577-
def _fstring_to_string(node: Node) -> Leaf:
578-
"""Converts an fstring node back to a string node."""
579-
string_without_prefix = str(node)[len(node.prefix) :]
580-
return Leaf(token.STRING, string_without_prefix, prefix=node.prefix)
581-
582-
583578
def _hugging_power_ops_line_to_string(
584579
line: Line,
585580
features: Collection[Feature],
@@ -1421,7 +1416,7 @@ def normalize_invisible_parens( # noqa: C901
14211416
# of case will be not parsed as a Python keyword.
14221417
break
14231418

1424-
elif not (isinstance(child, Leaf) and is_multiline_string(child)):
1419+
elif not is_multiline_string(child):
14251420
wrap_in_parentheses(node, child, visible=False)
14261421

14271422
comma_check = child.type == token.COMMA

src/black/nodes.py

+21-1
Original file line numberDiff line numberDiff line change
@@ -762,8 +762,28 @@ def is_vararg(leaf: Leaf, within: Set[NodeType]) -> bool:
762762
return p.type in within
763763

764764

765-
def is_multiline_string(leaf: Leaf) -> bool:
765+
def is_fstring(node: Node) -> bool:
766+
"""Return True if the node is an f-string"""
767+
return node.type == syms.fstring
768+
769+
770+
def fstring_to_string(node: Node) -> Leaf:
771+
"""Converts an fstring node back to a string node."""
772+
string_without_prefix = str(node)[len(node.prefix) :]
773+
string_leaf = Leaf(token.STRING, string_without_prefix, prefix=node.prefix)
774+
string_leaf.lineno = node.get_lineno() or 0
775+
return string_leaf
776+
777+
778+
def is_multiline_string(node: LN) -> bool:
766779
"""Return True if `leaf` is a multiline string that actually spans many lines."""
780+
if isinstance(node, Node) and is_fstring(node):
781+
leaf = fstring_to_string(node)
782+
elif isinstance(node, Leaf):
783+
leaf = node
784+
else:
785+
return False
786+
767787
return has_triple_quotes(leaf.value) and "\n" in leaf.value
768788

769789

tests/data/cases/pep_701.py

+18
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,15 @@
110110
{1}_cte AS ()'''}
111111
"""
112112

113+
value: str = f'''foo
114+
'''
115+
116+
log(
117+
f"Received operation {server_operation.name} from "
118+
f"{self.writer._transport.get_extra_info('peername')}", # type: ignore[attr-defined]
119+
level=0,
120+
)
121+
113122
# output
114123

115124
x = f"foo"
@@ -222,3 +231,12 @@
222231
WITH {f'''
223232
{1}_cte AS ()'''}
224233
"""
234+
235+
value: str = f"""foo
236+
"""
237+
238+
log(
239+
f"Received operation {server_operation.name} from "
240+
f"{self.writer._transport.get_extra_info('peername')}", # type: ignore[attr-defined]
241+
level=0,
242+
)

0 commit comments

Comments
 (0)