From 6db8407e5d1845b73617fe02a7f8192c61064cec Mon Sep 17 00:00:00 2001 From: wayyoungboy <1017761807@qq.com> Date: Sun, 7 Jun 2026 06:02:41 +0800 Subject: [PATCH] Parenthesize singleton tuples in yield expressions --- CHANGES.md | 2 ++ docs/the_black_code_style/future_style.md | 2 ++ src/black/linegen.py | 21 +++++++++++++++++++ src/black/mode.py | 1 + src/black/resources/black.schema.json | 3 ++- tests/data/cases/yield_singleton_tuple.py | 11 ++++++++++ .../cases/yield_singleton_tuple_stable.py | 9 ++++++++ 7 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 tests/data/cases/yield_singleton_tuple.py create mode 100644 tests/data/cases/yield_singleton_tuple_stable.py diff --git a/CHANGES.md b/CHANGES.md index 0110867a208..7fd31394e88 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -34,6 +34,8 @@ - Fix unnecessary parentheses around short RHS expressions in indexed assignments like `x[key] = expr` (#5095) +- Parenthesize tuple expressions in `yield` statements for consistency with function + calls and returns (#5170) - Stop splitting between a variable and its comparator (`not in`, `==`, `is`, ...) when the right-hand side is a bracketed expression. Black now lets the bracket explode instead. This fixes the awkward break that was showing up in comprehension `if` diff --git a/docs/the_black_code_style/future_style.md b/docs/the_black_code_style/future_style.md index d77df240c3e..00cd4af4aeb 100644 --- a/docs/the_black_code_style/future_style.md +++ b/docs/the_black_code_style/future_style.md @@ -41,6 +41,8 @@ Currently, the following features are included in the preview style: - `hug_comparator`: Don't break a comparator (`not in`, `==`, `is`, ...) away from its left operand when the right operand is a bracketed expression that has to break anyway; let the bracket explode instead. ([see below](labels/hug-comparator)) +- `parenthesize_tuple_in_yield`: Add parentheses around tuple expressions in `yield` + statements. (labels/wrap-comprehension-in)= diff --git a/src/black/linegen.py b/src/black/linegen.py index b0f643071d9..edc5cf4a8fb 100644 --- a/src/black/linegen.py +++ b/src/black/linegen.py @@ -681,6 +681,13 @@ def __post_init__(self) -> None: self.visit_expr_stmt = partial(v, keywords=Ø, parens=ASSIGNMENTS) self.visit_return_stmt = partial(v, keywords={"return"}, parens={"return"}) + self.visit_yield_expr = partial( + v, + keywords=Ø, + parens=( + {"yield"} if Preview.parenthesize_tuple_in_yield in self.mode else Ø + ), + ) self.visit_import_from = partial(v, keywords=Ø, parens={"import"}) self.visit_del_stmt = partial(v, keywords=Ø, parens={"del"}) self.visit_async_funcdef = self.visit_async_stmt @@ -1642,6 +1649,18 @@ def normalize_invisible_parens( wrap_in_parentheses(node, child, visible=False) elif isinstance(child, Node) and node.type == syms.with_stmt: remove_with_parens(child, node, mode=mode, features=features) + elif ( + isinstance(child, Node) + and node.type == syms.yield_expr + and child.type == syms.yield_arg + and Preview.parenthesize_tuple_in_yield in mode + ): + if ( + len(child.children) == 1 + and child.children[0].type != syms.atom + and is_one_tuple(child.children[0]) + ): + wrap_in_parentheses(node, child, visible=True) elif child.type == syms.atom and not ( "in" in parens_after and len(child.children) == 3 @@ -1933,6 +1952,8 @@ def maybe_make_parens_invisible_in_atom( syms.expr_stmt, syms.assert_stmt, syms.return_stmt, + syms.yield_arg, + syms.yield_expr, syms.except_clause, syms.funcdef, syms.with_stmt, diff --git a/src/black/mode.py b/src/black/mode.py index 61c02d629fa..9646f218dc4 100644 --- a/src/black/mode.py +++ b/src/black/mode.py @@ -262,6 +262,7 @@ class Preview(Enum): pyi_blank_line_before_decorated_class = auto() pyi_blank_line_after_function_docstring = auto() hug_comparator = auto() + parenthesize_tuple_in_yield = auto() UNSTABLE_FEATURES: set[Preview] = { diff --git a/src/black/resources/black.schema.json b/src/black/resources/black.schema.json index fff404d8b8c..f467f1a6879 100644 --- a/src/black/resources/black.schema.json +++ b/src/black/resources/black.schema.json @@ -91,7 +91,8 @@ "fix_unnecessary_parens_in_indexed_assignment", "pyi_blank_line_before_decorated_class", "pyi_blank_line_after_function_docstring", - "hug_comparator" + "hug_comparator", + "parenthesize_tuple_in_yield" ] }, "description": "Enable specific features included in the `--unstable` style. Requires `--preview`. No compatibility guarantees are provided on the behavior or existence of any unstable features." diff --git a/tests/data/cases/yield_singleton_tuple.py b/tests/data/cases/yield_singleton_tuple.py new file mode 100644 index 00000000000..c357c01dba1 --- /dev/null +++ b/tests/data/cases/yield_singleton_tuple.py @@ -0,0 +1,11 @@ +# flags: --preview + +def f(): + yield x, + + +# output + + +def f(): + yield (x,) diff --git a/tests/data/cases/yield_singleton_tuple_stable.py b/tests/data/cases/yield_singleton_tuple_stable.py new file mode 100644 index 00000000000..8acbf3d96bc --- /dev/null +++ b/tests/data/cases/yield_singleton_tuple_stable.py @@ -0,0 +1,9 @@ +def f(): + yield x, + + +# output + + +def f(): + yield x,