diff --git a/crates/ruff_python_formatter/src/expression/binary_like.rs b/crates/ruff_python_formatter/src/expression/binary_like.rs index 6c88db34f6e0f..149449d61cb04 100644 --- a/crates/ruff_python_formatter/src/expression/binary_like.rs +++ b/crates/ruff_python_formatter/src/expression/binary_like.rs @@ -3,7 +3,7 @@ use std::ops::{Deref, Index}; use smallvec::SmallVec; -use ruff_formatter::write; +use ruff_formatter::{write, FormatContext}; use ruff_python_ast::{ Expr, ExprAttribute, ExprBinOp, ExprBoolOp, ExprCompare, ExprUnaryOp, UnaryOp, }; @@ -13,10 +13,10 @@ use ruff_text_size::{Ranged, TextRange}; use crate::comments::{leading_comments, trailing_comments, Comments, SourceComment}; use crate::expression::parentheses::{ - in_parentheses_only_group, in_parentheses_only_soft_line_break, - in_parentheses_only_soft_line_break_or_space, is_expression_parenthesized, - write_in_parentheses_only_group_end_tag, write_in_parentheses_only_group_start_tag, - Parentheses, + in_parentheses_only_group, in_parentheses_only_if_group_breaks, + in_parentheses_only_soft_line_break, in_parentheses_only_soft_line_break_or_space, + is_expression_parenthesized, write_in_parentheses_only_group_end_tag, + write_in_parentheses_only_group_start_tag, Parentheses, }; use crate::expression::string::{AnyString, FormatString, StringLayout}; use crate::expression::OperatorPrecedence; @@ -718,7 +718,11 @@ impl Format> for FlatBinaryExpressionSlice<'_> { ) { hard_line_break().fmt(f)?; - } else if !is_pow { + } else if is_pow { + if f.context().options().preview().is_enabled() { + in_parentheses_only_if_group_breaks(&space()).fmt(f)?; + } + } else { space().fmt(f)?; } diff --git a/crates/ruff_python_formatter/src/expression/parentheses.rs b/crates/ruff_python_formatter/src/expression/parentheses.rs index 971d913146609..d6a40f213b6ad 100644 --- a/crates/ruff_python_formatter/src/expression/parentheses.rs +++ b/crates/ruff_python_formatter/src/expression/parentheses.rs @@ -355,6 +355,26 @@ pub(super) fn write_in_parentheses_only_group_end_tag(f: &mut PyFormatter) { } } +/// Shows prints `content` only if the expression is enclosed by (optional) parentheses (`()`, `[]`, or `{}`) +/// and splits across multiple lines. +pub(super) fn in_parentheses_only_if_group_breaks<'a, T>( + content: T, +) -> impl Format> +where + T: Format>, +{ + format_with(move |f: &mut PyFormatter| match f.context().node_level() { + NodeLevel::TopLevel(_) | NodeLevel::CompoundStatement | NodeLevel::Expression(None) => { + // no-op, not parenthesized + Ok(()) + } + NodeLevel::Expression(Some(parentheses_id)) => if_group_breaks(&content) + .with_group_id(Some(parentheses_id)) + .fmt(f), + NodeLevel::ParenthesizedExpression => if_group_breaks(&content).fmt(f), + }) +} + /// Format comments inside empty parentheses, brackets or curly braces. /// /// Empty `()`, `[]` and `{}` are special because there can be dangling comments, and they can be in diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_power_op_spacing.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_power_op_spacing.py.snap deleted file mode 100644 index f7cb0914c0304..0000000000000 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@cases__preview_power_op_spacing.py.snap +++ /dev/null @@ -1,354 +0,0 @@ ---- -source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_power_op_spacing.py ---- -## Input - -```python -a = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 -b = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 -c = 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 ** 1 -d = 1**1 ** 1**1 ** 1**1 ** 1**1 ** 1**1**1 ** 1 ** 1**1 ** 1**1**1**1**1 ** 1 ** 1**1**1 **1**1** 1 ** 1 ** 1 -e = 𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟 -f = 𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟 - -a = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 -b = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 -c = 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 ** 1.0 -d = 1.0**1.0 ** 1.0**1.0 ** 1.0**1.0 ** 1.0**1.0 ** 1.0**1.0**1.0 ** 1.0 ** 1.0**1.0 ** 1.0**1.0**1.0 -``` - -## Black Differences - -```diff ---- Black -+++ Ruff -@@ -1,83 +1,83 @@ - a = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 - b = ( - 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -- ** 1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 -+ **1 - ) - c = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 - d = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 - e = 𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟 - f = ( - 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -- ** 𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 -+ **𨉟 - ) - - a = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 - b = ( - 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -- ** 1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 -+ **1.0 - ) - c = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 - d = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 -``` - -## Ruff Output - -```python -a = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 -b = ( - 1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 - **1 -) -c = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 -d = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 -e = 𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟 -f = ( - 𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 - **𨉟 -) - -a = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 -b = ( - 1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 - **1.0 -) -c = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 -d = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 -``` - -## Black Output - -```python -a = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 -b = ( - 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 - ** 1 -) -c = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 -d = 1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1**1 -e = 𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟**𨉟 -f = ( - 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 - ** 𨉟 -) - -a = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 -b = ( - 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 - ** 1.0 -) -c = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 -d = 1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0**1.0 -``` - -