diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/yield.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/yield.py index 0959855cf5..8700b7ac06 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/yield.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/yield.py @@ -104,3 +104,20 @@ yield ( yield "# * Make sure each ForeignKey and OneToOneField has `on_delete` set " "to the desired behavior" yield "# * Remove `managed = False` lines if you wish to allow " "Django to create, modify, and delete the table" yield "# Feel free to rename the models, but don't rename db_table values or " "field names." + +# Regression test for: https://github.com/astral-sh/ruff/issues/7420 +result = yield self.request( + f"/applications/{int(application_id)}/guilds/{int(scope)}/commands/{int(command_id)}/permissions" +) + +result = yield (self.request( + f"/applications/{int(application_id)}/guilds/{int(scope)}/commands/{int(command_id)}/permissions" +)) + +result = yield + +result = yield (1 + f(1, 2, 3,)) + +result = (yield (1 + f(1, 2, 3,))) + +print((yield x)) diff --git a/crates/ruff_python_formatter/src/expression/expr_yield.rs b/crates/ruff_python_formatter/src/expression/expr_yield.rs index a0d9526dc6..11765d6184 100644 --- a/crates/ruff_python_formatter/src/expression/expr_yield.rs +++ b/crates/ruff_python_formatter/src/expression/expr_yield.rs @@ -4,7 +4,9 @@ use ruff_python_ast::{Expr, ExprYield, ExprYieldFrom}; use ruff_text_size::{Ranged, TextRange}; use crate::expression::maybe_parenthesize_expression; -use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses, Parenthesize}; +use crate::expression::parentheses::{ + is_expression_parenthesized, NeedsParentheses, OptionalParentheses, Parenthesize, +}; use crate::prelude::*; pub(super) enum AnyExpressionYield<'a> { @@ -38,7 +40,7 @@ impl NeedsParentheses for AnyExpressionYield<'_> { fn needs_parentheses( &self, parent: AnyNodeRef, - _context: &PyFormatContext, + context: &PyFormatContext, ) -> OptionalParentheses { // According to https://docs.python.org/3/reference/grammar.html There are two situations // where we do not want to always parenthesize a yield expression: @@ -47,8 +49,24 @@ impl NeedsParentheses for AnyExpressionYield<'_> { // We catch situation 1 below. Situation 2 does not need to be handled here as // FormatStmtExpr, does not add parenthesis if parent.is_stmt_assign() || parent.is_stmt_ann_assign() || parent.is_stmt_aug_assign() { - OptionalParentheses::Multiline + if let Some(value) = self.value() { + if is_expression_parenthesized( + value.into(), + context.comments().ranges(), + context.source(), + ) { + // Ex) `x = yield (1)` + OptionalParentheses::Never + } else { + // Ex) `x = yield f(1, 2, 3)` + value.needs_parentheses(self.into(), context) + } + } else { + // Ex) `x = yield` + OptionalParentheses::Never + } } else { + // Ex) `print((yield))` OptionalParentheses::Always } } @@ -94,7 +112,7 @@ impl Format> for AnyExpressionYield<'_> { )?; } else { // ExprYieldFrom always has Some(value) so we should never get a bare `yield from` - write!(f, [&token(keyword)])?; + write!(f, [token(keyword)])?; } Ok(()) } diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__yield.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__yield.py.snap index 7c78a36180..e6f39afa29 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__yield.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__yield.py.snap @@ -110,6 +110,23 @@ yield ( yield "# * Make sure each ForeignKey and OneToOneField has `on_delete` set " "to the desired behavior" yield "# * Remove `managed = False` lines if you wish to allow " "Django to create, modify, and delete the table" yield "# Feel free to rename the models, but don't rename db_table values or " "field names." + +# Regression test for: https://github.com/astral-sh/ruff/issues/7420 +result = yield self.request( + f"/applications/{int(application_id)}/guilds/{int(scope)}/commands/{int(command_id)}/permissions" +) + +result = yield (self.request( + f"/applications/{int(application_id)}/guilds/{int(scope)}/commands/{int(command_id)}/permissions" +)) + +result = yield + +result = yield (1 + f(1, 2, 3,)) + +result = (yield (1 + f(1, 2, 3,))) + +print((yield x)) ``` ## Output @@ -230,6 +247,39 @@ yield ( "# Feel free to rename the models, but don't rename db_table values or " "field names." ) + +# Regression test for: https://github.com/astral-sh/ruff/issues/7420 +result = yield self.request( + f"/applications/{int(application_id)}/guilds/{int(scope)}/commands/{int(command_id)}/permissions" +) + +result = yield ( + self.request( + f"/applications/{int(application_id)}/guilds/{int(scope)}/commands/{int(command_id)}/permissions" + ) +) + +result = yield + +result = yield ( + 1 + + f( + 1, + 2, + 3, + ) +) + +result = yield ( + 1 + + f( + 1, + 2, + 3, + ) +) + +print((yield x)) ```