diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/boolean_operation.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/boolean_operation.py new file mode 100644 index 0000000000..f976491cd1 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/boolean_operation.py @@ -0,0 +1,64 @@ +if ( + self._proc + # has the child process finished? + and self._returncode + # the child process has finished, but the + # transport hasn't been notified yet? + and self._proc.poll() +): + pass + +if ( + self._proc + and self._returncode + and self._proc.poll() + and self._proc + and self._returncode + and self._proc.poll() +): + ... + +if ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + and aaaaaaaaaaaaaaaaa + and aaaaaaaaaaaaaaaaaaaaaa + and aaaaaaaaaaaaaaaaaaaaaaaa + and aaaaaaaaaaaaaaaaaaaaaaaaaa + and aaaaaaaaaaaaaaaaaaaaaaaaaaaa +): + ... + + +if ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaas + and aaaaaaaaaaaaaaaaa +): + ... + + +if [2222, 333] and [ + aaaaaaaaaaaaa, + bbbbbbbbbbbbbbbbbbbb, + cccccccccccccccccccc, + dddddddddddddddddddd, + eeeeeeeeee, +]: + ... + +if [ + aaaaaaaaaaaaa, + bbbbbbbbbbbbbbbbbbbb, + cccccccccccccccccccc, + dddddddddddddddddddd, + eeeeeeeeee, +] and [2222, 333]: + pass + +# Break right only applies for boolean operations with a left and right side +if ( + aaaaaaaaaaaaaaaaaaaaaaaaaa + and bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + and ccccccccccccccccc + and [dddddddddddddd, eeeeeeeeee, fffffffffffffff] +): + pass diff --git a/crates/ruff_python_formatter/src/expression/binary_like.rs b/crates/ruff_python_formatter/src/expression/binary_like.rs new file mode 100644 index 0000000000..eff12b71d9 --- /dev/null +++ b/crates/ruff_python_formatter/src/expression/binary_like.rs @@ -0,0 +1,215 @@ +//! This module provides helper utilities to format an expression that has a left side, an operator, +//! and a right side (binary like). + +use crate::expression::parentheses::Parentheses; +use crate::prelude::*; +use ruff_formatter::{format_args, write}; +use rustpython_parser::ast::Expr; + +/// Trait to implement a binary like syntax that has a left operand, an operator, and a right operand. +pub(super) trait FormatBinaryLike<'ast> { + /// The type implementing the formatting of the operator. + type FormatOperator: Format>; + + /// Formats the binary like expression to `f`. + fn fmt_binary( + &self, + parentheses: Option, + f: &mut PyFormatter<'ast, '_>, + ) -> FormatResult<()> { + let left = self.left()?; + let operator = self.operator(); + let right = self.right()?; + + let layout = if parentheses == Some(Parentheses::Custom) { + self.binary_layout() + } else { + BinaryLayout::Default + }; + + match layout { + BinaryLayout::Default => self.fmt_default(f), + BinaryLayout::ExpandLeft => { + let left = left.format().memoized(); + let right = right.format().memoized(); + write!( + f, + [best_fitting![ + // Everything on a single line + format_args![group(&left), space(), operator, space(), right], + // Break the left over multiple lines, keep the right flat + format_args![ + group(&left).should_expand(true), + space(), + operator, + space(), + right + ], + // The content doesn't fit, indent the content and break before the operator. + format_args![ + text("("), + block_indent(&format_args![ + left, + hard_line_break(), + operator, + space(), + right + ]), + text(")") + ] + ] + .with_mode(BestFittingMode::AllLines)] + ) + } + BinaryLayout::ExpandRight => { + let left_group = f.group_id("BinaryLeft"); + + write!( + f, + [ + // Wrap the left in a group and gives it an id. The printer first breaks the + // right side if `right` contains any line break because the printer breaks + // sequences of groups from right to left. + // Indents the left side if the group breaks. + group(&format_args![ + if_group_breaks(&text("(")), + indent_if_group_breaks( + &format_args![ + soft_line_break(), + left.format(), + soft_line_break_or_space(), + operator, + space() + ], + left_group + ) + ]) + .with_group_id(Some(left_group)), + // Wrap the right in a group and indents its content but only if the left side breaks + group(&indent_if_group_breaks(&right.format(), left_group)), + // If the left side breaks, insert a hard line break to finish the indent and close the open paren. + if_group_breaks(&format_args![hard_line_break(), text(")")]) + .with_group_id(Some(left_group)) + ] + ) + } + BinaryLayout::ExpandRightThenLeft => { + // The formatter expands group-sequences from right to left, and expands both if + // there isn't enough space when expanding only one of them. + write!( + f, + [ + group(&left.format()), + space(), + operator, + space(), + group(&right.format()) + ] + ) + } + } + } + + /// Determines which binary layout to use. + fn binary_layout(&self) -> BinaryLayout { + if let (Ok(left), Ok(right)) = (self.left(), self.right()) { + BinaryLayout::from_left_right(left, right) + } else { + BinaryLayout::Default + } + } + + /// Formats the node according to the default layout. + fn fmt_default(&self, f: &mut PyFormatter<'ast, '_>) -> FormatResult<()>; + + /// Returns the left operator + fn left(&self) -> FormatResult<&Expr>; + + /// Returns the right operator. + fn right(&self) -> FormatResult<&Expr>; + + /// Returns the object that formats the operator. + fn operator(&self) -> Self::FormatOperator; +} + +fn can_break_expr(expr: &Expr) -> bool { + use ruff_python_ast::prelude::*; + + match expr { + Expr::Tuple(ExprTuple { + elts: expressions, .. + }) + | Expr::List(ExprList { + elts: expressions, .. + }) + | Expr::Set(ExprSet { + elts: expressions, .. + }) + | Expr::Dict(ExprDict { + values: expressions, + .. + }) => !expressions.is_empty(), + Expr::Call(ExprCall { args, keywords, .. }) => !(args.is_empty() && keywords.is_empty()), + Expr::ListComp(_) | Expr::SetComp(_) | Expr::DictComp(_) | Expr::GeneratorExp(_) => true, + Expr::UnaryOp(ExprUnaryOp { operand, .. }) => match operand.as_ref() { + Expr::BinOp(_) => true, + _ => can_break_expr(operand.as_ref()), + }, + _ => false, + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub(super) enum BinaryLayout { + /// Put each operand on their own line if either side expands + Default, + + /// Try to expand the left to make it fit. Add parentheses if the left or right don't fit. + /// + ///```python + /// [ + /// a, + /// b + /// ] & c + ///``` + ExpandLeft, + + /// Try to expand the right to make it fix. Add parentheses if the left or right don't fit. + /// + /// ```python + /// a & [ + /// b, + /// c + /// ] + /// ``` + ExpandRight, + + /// Both the left and right side can be expanded. Try in the following order: + /// * expand the right side + /// * expand the left side + /// * expand both sides + /// + /// to make the expression fit + /// + /// ```python + /// [ + /// a, + /// b + /// ] & [ + /// c, + /// d + /// ] + /// ``` + ExpandRightThenLeft, +} + +impl BinaryLayout { + pub(super) fn from_left_right(left: &Expr, right: &Expr) -> BinaryLayout { + match (can_break_expr(left), can_break_expr(right)) { + (false, false) => BinaryLayout::Default, + (true, false) => BinaryLayout::ExpandLeft, + (false, true) => BinaryLayout::ExpandRight, + (true, true) => BinaryLayout::ExpandRightThenLeft, + } + } +} diff --git a/crates/ruff_python_formatter/src/expression/expr_bin_op.rs b/crates/ruff_python_formatter/src/expression/expr_bin_op.rs index 199e689fb2..7c50fdcc51 100644 --- a/crates/ruff_python_formatter/src/expression/expr_bin_op.rs +++ b/crates/ruff_python_formatter/src/expression/expr_bin_op.rs @@ -1,14 +1,12 @@ use crate::comments::{trailing_comments, Comments}; +use crate::expression::binary_like::{BinaryLayout, FormatBinaryLike}; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parenthesize, }; use crate::expression::Parentheses; use crate::prelude::*; use crate::FormatNodeRule; -use ruff_formatter::{ - format_args, write, FormatOwnedWithRule, FormatRefWithRule, FormatRuleWithOptions, -}; -use ruff_python_ast::node::AstNode; +use ruff_formatter::{write, FormatOwnedWithRule, FormatRefWithRule, FormatRuleWithOptions}; use rustpython_parser::ast::{ Constant, Expr, ExprAttribute, ExprBinOp, ExprConstant, ExprUnaryOp, Operator, UnaryOp, }; @@ -29,132 +27,7 @@ impl FormatRuleWithOptions> for FormatExprBinOp { impl FormatNodeRule for FormatExprBinOp { fn fmt_fields(&self, item: &ExprBinOp, f: &mut PyFormatter) -> FormatResult<()> { - let ExprBinOp { - left, - right, - op, - range: _, - } = item; - - let layout = if self.parentheses == Some(Parentheses::Custom) { - BinaryLayout::from(item) - } else { - BinaryLayout::Default - }; - - match layout { - BinaryLayout::Default => { - let comments = f.context().comments().clone(); - let operator_comments = comments.dangling_comments(item.as_any_node_ref()); - let needs_space = !is_simple_power_expression(item); - - let before_operator_space = if needs_space { - soft_line_break_or_space() - } else { - soft_line_break() - }; - - write!( - f, - [ - left.format(), - before_operator_space, - op.format(), - trailing_comments(operator_comments), - ] - )?; - - // Format the operator on its own line if the right side has any leading comments. - if comments.has_leading_comments(right.as_ref()) { - write!(f, [hard_line_break()])?; - } else if needs_space { - write!(f, [space()])?; - } - - write!(f, [group(&right.format())]) - } - - BinaryLayout::ExpandLeft => { - let left = left.format().memoized(); - let right = right.format().memoized(); - write!( - f, - [best_fitting![ - // Everything on a single line - format_args![left, space(), op.format(), space(), right], - // Break the left over multiple lines, keep the right flat - format_args![ - group(&left).should_expand(true), - space(), - op.format(), - space(), - right - ], - // The content doesn't fit, indent the content and break before the operator. - format_args![ - text("("), - block_indent(&format_args![ - left, - hard_line_break(), - op.format(), - space(), - right - ]), - text(")") - ] - ] - .with_mode(BestFittingMode::AllLines)] - ) - } - - BinaryLayout::ExpandRight => { - let left_group = f.group_id("BinaryLeft"); - - write!( - f, - [ - // Wrap the left in a group and gives it an id. The printer first breaks the - // right side if `right` contains any line break because the printer breaks - // sequences of groups from right to left. - // Indents the left side if the group breaks. - group(&format_args![ - if_group_breaks(&text("(")), - indent_if_group_breaks( - &format_args![ - soft_line_break(), - left.format(), - soft_line_break_or_space(), - op.format(), - space() - ], - left_group - ) - ]) - .with_group_id(Some(left_group)), - // Wrap the right in a group and indents its content but only if the left side breaks - group(&indent_if_group_breaks(&right.format(), left_group)), - // If the left side breaks, insert a hard line break to finish the indent and close the open paren. - if_group_breaks(&format_args![hard_line_break(), text(")")]) - .with_group_id(Some(left_group)) - ] - ) - } - - BinaryLayout::ExpandRightThenLeft => { - // The formatter expands group-sequences from right to left, and expands both if - // there isn't enough space when expanding only one of them. - write!( - f, - [ - group(&left.format()), - space(), - op.format(), - space(), - group(&right.format()) - ] - ) - } - } + item.fmt_binary(self.parentheses, f) } fn fmt_dangling_comments(&self, _node: &ExprBinOp, _f: &mut PyFormatter) -> FormatResult<()> { @@ -163,6 +36,60 @@ impl FormatNodeRule for FormatExprBinOp { } } +impl<'ast> FormatBinaryLike<'ast> for ExprBinOp { + type FormatOperator = FormatOwnedWithRule>; + + fn fmt_default(&self, f: &mut PyFormatter<'ast, '_>) -> FormatResult<()> { + let ExprBinOp { + range: _, + left, + op, + right, + } = self; + + let comments = f.context().comments().clone(); + let operator_comments = comments.dangling_comments(self); + let needs_space = !is_simple_power_expression(self); + + let before_operator_space = if needs_space { + soft_line_break_or_space() + } else { + soft_line_break() + }; + + write!( + f, + [ + left.format(), + before_operator_space, + op.format(), + trailing_comments(operator_comments), + ] + )?; + + // Format the operator on its own line if the right side has any leading comments. + if comments.has_leading_comments(right.as_ref()) { + write!(f, [hard_line_break()])?; + } else if needs_space { + write!(f, [space()])?; + } + + write!(f, [group(&right.format())]) + } + + fn left(&self) -> FormatResult<&Expr> { + Ok(&self.left) + } + + fn right(&self) -> FormatResult<&Expr> { + Ok(&self.right) + } + + fn operator(&self) -> Self::FormatOperator { + self.op.into_format() + } +} + const fn is_simple_power_expression(expr: &ExprBinOp) -> bool { expr.op.is_pow() && is_simple_power_operand(&expr.left) && is_simple_power_operand(&expr.right) } @@ -235,7 +162,7 @@ impl NeedsParentheses for ExprBinOp { ) -> Parentheses { match default_expression_needs_parentheses(self.into(), parenthesize, source, comments) { Parentheses::Optional => { - if BinaryLayout::from(self) == BinaryLayout::Default + if self.binary_layout() == BinaryLayout::Default || comments.has_leading_comments(self.right.as_ref()) || comments.has_dangling_comments(self) { @@ -248,85 +175,3 @@ impl NeedsParentheses for ExprBinOp { } } } - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -enum BinaryLayout { - /// Put each operand on their own line if either side expands - Default, - - /// Try to expand the left to make it fit. Add parentheses if the left or right don't fit. - /// - ///```python - /// [ - /// a, - /// b - /// ] & c - ///``` - ExpandLeft, - - /// Try to expand the right to make it fix. Add parentheses if the left or right don't fit. - /// - /// ```python - /// a & [ - /// b, - /// c - /// ] - /// ``` - ExpandRight, - - /// Both the left and right side can be expanded. Try in the following order: - /// * expand the right side - /// * expand the left side - /// * expand both sides - /// - /// to make the expression fit - /// - /// ```python - /// [ - /// a, - /// b - /// ] & [ - /// c, - /// d - /// ] - /// ``` - ExpandRightThenLeft, -} - -impl BinaryLayout { - fn from(expr: &ExprBinOp) -> Self { - match (can_break(&expr.left), can_break(&expr.right)) { - (false, false) => Self::Default, - (true, false) => Self::ExpandLeft, - (false, true) => Self::ExpandRight, - (true, true) => Self::ExpandRightThenLeft, - } - } -} - -fn can_break(expr: &Expr) -> bool { - use ruff_python_ast::prelude::*; - - match expr { - Expr::Tuple(ExprTuple { - elts: expressions, .. - }) - | Expr::List(ExprList { - elts: expressions, .. - }) - | Expr::Set(ExprSet { - elts: expressions, .. - }) - | Expr::Dict(ExprDict { - values: expressions, - .. - }) => !expressions.is_empty(), - Expr::Call(ExprCall { args, keywords, .. }) => !(args.is_empty() && keywords.is_empty()), - Expr::ListComp(_) | Expr::SetComp(_) | Expr::DictComp(_) | Expr::GeneratorExp(_) => true, - Expr::UnaryOp(ExprUnaryOp { operand, .. }) => match operand.as_ref() { - Expr::BinOp(_) => true, - _ => can_break(operand.as_ref()), - }, - _ => false, - } -} diff --git a/crates/ruff_python_formatter/src/expression/expr_bool_op.rs b/crates/ruff_python_formatter/src/expression/expr_bool_op.rs index e975949029..e3fd595bab 100644 --- a/crates/ruff_python_formatter/src/expression/expr_bool_op.rs +++ b/crates/ruff_python_formatter/src/expression/expr_bool_op.rs @@ -1,22 +1,87 @@ -use crate::comments::Comments; +use crate::comments::{leading_comments, Comments}; +use crate::expression::binary_like::{BinaryLayout, FormatBinaryLike}; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; -use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter}; -use ruff_formatter::{write, Buffer, FormatResult}; -use rustpython_parser::ast::ExprBoolOp; +use crate::prelude::*; +use ruff_formatter::{ + write, FormatError, FormatOwnedWithRule, FormatRefWithRule, FormatRuleWithOptions, +}; +use rustpython_parser::ast::{BoolOp, Expr, ExprBoolOp}; #[derive(Default)] -pub struct FormatExprBoolOp; +pub struct FormatExprBoolOp { + parentheses: Option, +} + +impl FormatRuleWithOptions> for FormatExprBoolOp { + type Options = Option; + fn with_options(mut self, options: Self::Options) -> Self { + self.parentheses = options; + self + } +} impl FormatNodeRule for FormatExprBoolOp { - fn fmt_fields(&self, _item: &ExprBoolOp, f: &mut PyFormatter) -> FormatResult<()> { - write!( - f, - [not_yet_implemented_custom_text( - "NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2" - )] - ) + fn fmt_fields(&self, item: &ExprBoolOp, f: &mut PyFormatter) -> FormatResult<()> { + item.fmt_binary(self.parentheses, f) + } +} + +impl<'ast> FormatBinaryLike<'ast> for ExprBoolOp { + type FormatOperator = FormatOwnedWithRule>; + + fn binary_layout(&self) -> BinaryLayout { + match self.values.as_slice() { + [left, right] => BinaryLayout::from_left_right(left, right), + [..] => BinaryLayout::Default, + } + } + + fn fmt_default(&self, f: &mut PyFormatter<'ast, '_>) -> FormatResult<()> { + let ExprBoolOp { + range: _, + op, + values, + } = self; + + let mut values = values.iter(); + let comments = f.context().comments().clone(); + + let Some(first) = values.next() else { + return Ok(()) + }; + + write!(f, [group(&first.format())])?; + + for value in values { + let leading_value_comments = comments.leading_comments(value); + // Format the expressions leading comments **before** the operator + if leading_value_comments.is_empty() { + write!(f, [soft_line_break_or_space()])?; + } else { + write!( + f, + [hard_line_break(), leading_comments(leading_value_comments)] + )?; + } + + write!(f, [op.format(), space(), group(&value.format())])?; + } + + Ok(()) + } + + fn left(&self) -> FormatResult<&Expr> { + self.values.first().ok_or(FormatError::SyntaxError) + } + + fn right(&self) -> FormatResult<&Expr> { + self.values.last().ok_or(FormatError::SyntaxError) + } + + fn operator(&self) -> Self::FormatOperator { + self.op.into_format() } } @@ -27,6 +92,53 @@ impl NeedsParentheses for ExprBoolOp { source: &str, comments: &Comments, ) -> Parentheses { - default_expression_needs_parentheses(self.into(), parenthesize, source, comments) + match default_expression_needs_parentheses(self.into(), parenthesize, source, comments) { + Parentheses::Optional => match self.binary_layout() { + BinaryLayout::Default => Parentheses::Optional, + + BinaryLayout::ExpandRight + | BinaryLayout::ExpandLeft + | BinaryLayout::ExpandRightThenLeft + if self + .values + .last() + .map_or(false, |right| comments.has_leading_comments(right)) => + { + Parentheses::Optional + } + _ => Parentheses::Custom, + }, + parentheses => parentheses, + } + } +} + +#[derive(Copy, Clone)] +pub struct FormatBoolOp; + +impl<'ast> AsFormat> for BoolOp { + type Format<'a> = FormatRefWithRule<'a, BoolOp, FormatBoolOp, PyFormatContext<'ast>>; + + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new(self, FormatBoolOp) + } +} + +impl<'ast> IntoFormat> for BoolOp { + type Format = FormatOwnedWithRule>; + + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new(self, FormatBoolOp) + } +} + +impl FormatRule> for FormatBoolOp { + fn fmt(&self, item: &BoolOp, f: &mut Formatter>) -> FormatResult<()> { + let operator = match item { + BoolOp::And => "and", + BoolOp::Or => "or", + }; + + text(operator).fmt(f) } } diff --git a/crates/ruff_python_formatter/src/expression/expr_unary_op.rs b/crates/ruff_python_formatter/src/expression/expr_unary_op.rs index db3dfc06ad..04151760fa 100644 --- a/crates/ruff_python_formatter/src/expression/expr_unary_op.rs +++ b/crates/ruff_python_formatter/src/expression/expr_unary_op.rs @@ -39,7 +39,7 @@ impl FormatNodeRule for FormatExprUnaryOp { // ``` let leading_operand_comments = comments.leading_comments(operand.as_ref()); let trailing_operator_comments_end = - leading_operand_comments.partition_point(|p| p.position().is_end_of_line()); + leading_operand_comments.partition_point(|p| p.line_position().is_end_of_line()); let (trailing_operator_comments, leading_operand_comments) = leading_operand_comments.split_at(trailing_operator_comments_end); diff --git a/crates/ruff_python_formatter/src/expression/mod.rs b/crates/ruff_python_formatter/src/expression/mod.rs index b6ca41efbd..a3670b1761 100644 --- a/crates/ruff_python_formatter/src/expression/mod.rs +++ b/crates/ruff_python_formatter/src/expression/mod.rs @@ -7,6 +7,7 @@ use ruff_formatter::{ }; use rustpython_parser::ast::Expr; +mod binary_like; pub(crate) mod expr_attribute; pub(crate) mod expr_await; pub(crate) mod expr_bin_op; @@ -59,7 +60,7 @@ impl FormatRule> for FormatExpr { ); let format_expr = format_with(|f| match item { - Expr::BoolOp(expr) => expr.format().fmt(f), + Expr::BoolOp(expr) => expr.format().with_options(Some(parentheses)).fmt(f), Expr::NamedExpr(expr) => expr.format().fmt(f), Expr::BinOp(expr) => expr.format().with_options(Some(parentheses)).fmt(f), Expr::UnaryOp(expr) => expr.format().fmt(f), diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments2_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments2_py.snap index 7869c241a8..3cd87b7335 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments2_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments2_py.snap @@ -227,7 +227,7 @@ instruction()#comment with bad spacing ] not_shareables = [ -@@ -37,50 +33,51 @@ +@@ -37,49 +33,57 @@ # builtin types and objects type, object, @@ -267,13 +267,13 @@ instruction()#comment with bad spacing - children[0], + parameters.NOT_IMPLEMENTED_attr = [ + NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], # (1 -+ body, + body, +- children[-1], # type: ignore + NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], # )1 + ] + parameters.NOT_IMPLEMENTED_attr = [ + NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], - body, -- children[-1], # type: ignore ++ body, + NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], # type: ignore ] else: @@ -286,24 +286,25 @@ instruction()#comment with bad spacing + NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], # )2 ] - parameters.children = [parameters.what_if_this_was_actually_long.children[0], body, parameters.children[-1]] # type: ignore -- if ( -- self._proc is not None -- # has the child process finished? -- and self._returncode is None -- # the child process has finished, but the -- # transport hasn't been notified yet? -- and self._proc.poll() is None -- ): + parameters.NOT_IMPLEMENTED_attr = [ + NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], + body, + NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], + ] # type: ignore -+ if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: + if ( +- self._proc is not None ++ NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right + # has the child process finished? +- and self._returncode is None ++ and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right + # the child process has finished, but the + # transport hasn't been notified yet? +- and self._proc.poll() is None ++ and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right + ): pass # no newline before or after - short = [ -@@ -91,48 +88,14 @@ +@@ -91,48 +95,14 @@ ] # no newline after @@ -357,7 +358,7 @@ instruction()#comment with bad spacing while True: if False: continue -@@ -141,25 +104,13 @@ +@@ -141,25 +111,13 @@ # and round and round we go # let's return @@ -386,7 +387,7 @@ instruction()#comment with bad spacing ####################### -@@ -167,7 +118,7 @@ +@@ -167,7 +125,7 @@ ####################### @@ -479,7 +480,14 @@ def inline_comments_in_brackets_ruin_everything(): body, NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], ] # type: ignore - if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: + if ( + NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right + # has the child process finished? + and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right + # the child process has finished, but the + # transport hasn't been notified yet? + and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right + ): pass # no newline before or after short = [ diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments6_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments6_py.snap index 430431fe04..2f25cc478b 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments6_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments6_py.snap @@ -137,7 +137,7 @@ aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*ite def f( -@@ -49,10 +49,8 @@ +@@ -49,10 +49,11 @@ element = 0 # type: int another_element = 1 # type: float another_element_with_long_name = 2 # type: int @@ -146,11 +146,14 @@ aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*ite - ) # type: int - an_element_with_a_long_value = calls() or more_calls() and more() # type: bool + another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style = 3 # type: int -+ an_element_with_a_long_value = NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 # type: bool ++ an_element_with_a_long_value = ( ++ NOT_IMPLEMENTED_call() ++ or NOT_IMPLEMENTED_call() and NOT_IMPLEMENTED_call() ++ ) # type: bool tup = ( another_element, -@@ -84,35 +82,22 @@ +@@ -84,35 +85,22 @@ def func( @@ -255,7 +258,10 @@ def f( another_element = 1 # type: float another_element_with_long_name = 2 # type: int another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style = 3 # type: int - an_element_with_a_long_value = NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 # type: bool + an_element_with_a_long_value = ( + NOT_IMPLEMENTED_call() + or NOT_IMPLEMENTED_call() and NOT_IMPLEMENTED_call() + ) # type: bool tup = ( another_element, diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__empty_lines_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__empty_lines_py.snap index 03794aac66..099f07777c 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__empty_lines_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__empty_lines_py.snap @@ -105,7 +105,7 @@ def g(): ```diff --- Black +++ Ruff -@@ -1,47 +1,35 @@ +@@ -1,89 +1,79 @@ -"""Docstring.""" +"NOT_YET_IMPLEMENTED_STRING" @@ -142,7 +142,7 @@ def g(): - prevp = preceding_leaf(p) - if not prevp or prevp.type in OPENING_BRACKETS: + prevp = NOT_IMPLEMENTED_call() -+ if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: ++ if not prevp or NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right: return NO - if prevp.type == token.EQUAL: @@ -154,7 +154,10 @@ def g(): - syms.argument, - }: + if NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right: -+ if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: ++ if ( ++ prevp.NOT_IMPLEMENTED_attr ++ and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right ++ ): return NO - elif prevp.type == token.DOUBLESTAR: @@ -166,15 +169,18 @@ def g(): - syms.dictsetmaker, - }: + elif NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right: -+ if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: ++ if ( ++ prevp.NOT_IMPLEMENTED_attr ++ and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right ++ ): return NO -@@ -49,41 +37,34 @@ + ############################################################################### # SECTION BECAUSE SECTIONS ############################################################################### - - + def g(): - NO = "" - SPACE = " " @@ -210,7 +216,7 @@ def g(): + prevp = NOT_IMPLEMENTED_call() - if not prevp or prevp.type in OPENING_BRACKETS: -+ if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: ++ if not prevp or NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right: # Start of the line or a bracketed expression. # More than one line for the comment. return NO @@ -224,7 +230,10 @@ def g(): - syms.argument, - }: + if NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right: -+ if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: ++ if ( ++ prevp.NOT_IMPLEMENTED_attr ++ and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right ++ ): return NO ``` @@ -254,15 +263,21 @@ def f(): prev = leaf.NOT_IMPLEMENTED_attr if not prev: prevp = NOT_IMPLEMENTED_call() - if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: + if not prevp or NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right: return NO if NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right: - if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: + if ( + prevp.NOT_IMPLEMENTED_attr + and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right + ): return NO elif NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right: - if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: + if ( + prevp.NOT_IMPLEMENTED_attr + and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right + ): return NO @@ -293,13 +308,16 @@ def g(): if not prev: prevp = NOT_IMPLEMENTED_call() - if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: + if not prevp or NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right: # Start of the line or a bracketed expression. # More than one line for the comment. return NO if NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right: - if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: + if ( + prevp.NOT_IMPLEMENTED_attr + and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right + ): return NO ``` diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__expression_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__expression_py.snap index a96793d3d2..1bc96c10d0 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__expression_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__expression_py.snap @@ -276,43 +276,10 @@ last_call() Name None True -@@ -7,18 +8,18 @@ - 1 - 1.0 - 1j --True or False --True or False or None --True and False --True and False and None --(Name1 and Name2) or Name3 --Name1 and Name2 or Name3 --Name1 or (Name2 and Name3) --Name1 or Name2 and Name3 --(Name1 and Name2) or (Name3 and Name4) --Name1 and Name2 or Name3 and Name4 --Name1 or (Name2 and Name3) or Name4 --Name1 or Name2 and Name3 or Name4 -+NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -+NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -+NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -+NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -+NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -+NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -+NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -+NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -+NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -+NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -+NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -+NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 - v1 << 2 - 1 >> v2 - 1 % finished -@@ -28,205 +29,204 @@ - ~great - +value +@@ -30,203 +31,178 @@ -1 --~int and not v1 ^ 123 + v2 | True --(~int) and (not ((v1 ^ (123 + v2)) | True)) + ~int and not v1 ^ 123 + v2 | True + (~int) and (not ((v1 ^ (123 + v2)) | True)) -+(really ** -(confusing ** ~(operator**-precedence))) -flags & ~select.EPOLLIN and waiters.write_task is not None -lambda arg: None @@ -337,10 +304,8 @@ last_call() -) -{"2.7": dead, "3.7": (long_live or die_hard)} -{"2.7": dead, "3.7": (long_live or die_hard), **{"3.6": verygood}} -+NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -+NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 ++really ** -confusing ** ~operator**-precedence -+NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 ++flags & ~select.NOT_IMPLEMENTED_attr and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right +lambda x: True +lambda x: True +lambda x: True @@ -356,15 +321,11 @@ last_call() +(NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false) +{ + "NOT_YET_IMPLEMENTED_STRING": dead, -+ "NOT_YET_IMPLEMENTED_STRING": ( -+ NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -+ ), ++ "NOT_YET_IMPLEMENTED_STRING": (long_live or die_hard), +} +{ + "NOT_YET_IMPLEMENTED_STRING": dead, -+ "NOT_YET_IMPLEMENTED_STRING": ( -+ NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -+ ), ++ "NOT_YET_IMPLEMENTED_STRING": (long_live or die_hard), + **{"NOT_YET_IMPLEMENTED_STRING": verygood}, +} {**a, **b, **c} @@ -378,32 +339,31 @@ last_call() + "NOT_YET_IMPLEMENTED_STRING", + (NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false), +} -+NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 ++( ++ {"NOT_YET_IMPLEMENTED_STRING": "NOT_YET_IMPLEMENTED_STRING"}, ++ (True or False), ++ (+value), ++ "NOT_YET_IMPLEMENTED_STRING", ++ b"NOT_YET_IMPLEMENTED_BYTE_STRING", ++) or None () (1,) (1, 2) (1, 2, 3) [] --[1, 2, 3, 4, 5, 6, 7, 8, 9, (10 or A), (11 or B), (12 or C)] - [ - 1, - 2, - 3, + [1, 2, 3, 4, 5, 6, 7, 8, 9, (10 or A), (11 or B), (12 or C)] +-[ +- 1, +- 2, +- 3, -] -[*a] -[*range(10)] -[ - *a, - 4, - 5, -+ 6, -+ 7, -+ 8, -+ 9, -+ (NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2), -+ (NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2), -+ (NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2), - ] +- 4, +- 5, +-] -[ - 4, - *a, @@ -503,7 +463,7 @@ last_call() - k: v - for k, v in this_is_a_very_long_variable_which_will_cause_a_trailing_comma_which_breaks_the_comprehension + "NOT_YET_IMPLEMENTED_STRING": dead, -+ "NOT_YET_IMPLEMENTED_STRING": NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2, ++ "NOT_YET_IMPLEMENTED_STRING": long_live or die_hard, } -Python3 > Python2 > COBOL -Life is Life @@ -540,28 +500,7 @@ last_call() -] -very_long_variable_name_filters: t.List[ - t.Tuple[str, t.Union[str, t.List[t.Optional[str]]]], -+{ -+ "NOT_YET_IMPLEMENTED_STRING", -+ "NOT_YET_IMPLEMENTED_STRING", -+ "NOT_YET_IMPLEMENTED_STRING", -+ "NOT_YET_IMPLEMENTED_STRING", -+ "NOT_YET_IMPLEMENTED_STRING", -+ NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false, -+} -+[ -+ 1, -+ 2, -+ 3, -+ 4, -+ 5, -+ 6, -+ 7, -+ 8, -+ 9, -+ NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2, -+ NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2, -+ NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2, - ] +-] -xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( # type: ignore - sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__) -) @@ -600,7 +539,15 @@ last_call() -(str or None) if (sys.version_info[0] > (3,)) else (str or bytes or None) -{"2.7": dead, "3.7": long_live or die_hard} -{"2.7", "3.6", "3.7", "3.8", "3.9", "4.0" if gilectomy else "3.10"} --[1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or A, 11 or B, 12 or C] ++{ ++ "NOT_YET_IMPLEMENTED_STRING", ++ "NOT_YET_IMPLEMENTED_STRING", ++ "NOT_YET_IMPLEMENTED_STRING", ++ "NOT_YET_IMPLEMENTED_STRING", ++ "NOT_YET_IMPLEMENTED_STRING", ++ NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false, ++} + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or A, 11 or B, 12 or C] (SomeName) SomeName (Good, Bad, Ugly) @@ -638,19 +585,10 @@ last_call() -g = 1, *"ten" -what_is_up_with_those_new_coord_names = (coord_names + set(vars_to_create)) + set( - vars_to_remove -+e = NOT_IMPLEMENTED_call() -+f = 1, NOT_YET_IMPLEMENTED_ExprStarred -+g = 1, NOT_YET_IMPLEMENTED_ExprStarred -+what_is_up_with_those_new_coord_names = ( -+ (coord_names + NOT_IMPLEMENTED_call()) -+ + NOT_IMPLEMENTED_call() - ) +-) -what_is_up_with_those_new_coord_names = (coord_names | set(vars_to_create)) - set( - vars_to_remove -+what_is_up_with_those_new_coord_names = ( -+ (coord_names | NOT_IMPLEMENTED_call()) -+ - NOT_IMPLEMENTED_call() - ) +-) -result = ( - session.query(models.Customer.id) - .filter( @@ -658,7 +596,13 @@ last_call() - ) - .order_by(models.Customer.id.asc()) - .all() --) ++e = NOT_IMPLEMENTED_call() ++f = 1, NOT_YET_IMPLEMENTED_ExprStarred ++g = 1, NOT_YET_IMPLEMENTED_ExprStarred ++what_is_up_with_those_new_coord_names = ( ++ (coord_names + NOT_IMPLEMENTED_call()) ++ + NOT_IMPLEMENTED_call() + ) -result = ( - session.query(models.Customer.id) - .filter( @@ -668,7 +612,10 @@ last_call() - models.Customer.id.asc(), - ) - .all() --) ++what_is_up_with_those_new_coord_names = ( ++ (coord_names | NOT_IMPLEMENTED_call()) ++ - NOT_IMPLEMENTED_call() + ) -Ø = set() -authors.łukasz.say_thanks() +result = NOT_IMPLEMENTED_call() @@ -678,7 +625,7 @@ last_call() mapping = { A: 0.25 * (10.0 / 12), B: 0.1 * (10.0 / 12), -@@ -236,65 +236,35 @@ +@@ -236,64 +212,38 @@ def gen(): @@ -715,7 +662,6 @@ last_call() - ... -for j in 1 + (2 + 3): - ... --while this and that: +NOT_IMPLEMENTED_call() +NOT_IMPLEMENTED_call() +NOT_IMPLEMENTED_call() @@ -727,7 +673,7 @@ last_call() +NOT_YET_IMPLEMENTED_StmtFor +NOT_YET_IMPLEMENTED_StmtFor +NOT_YET_IMPLEMENTED_StmtFor -+while NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: + while this and that: ... -for ( - addr_family, @@ -753,21 +699,22 @@ last_call() - aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp - is not qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz -) --if ( -- threading.current_thread() != threading.main_thread() -- and threading.current_thread() != threading.main_thread() -- or signal.getsignal(signal.SIGINT) != signal.default_int_handler --): +NOT_YET_IMPLEMENTED_StmtFor +a = NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right +a = NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right +a = NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right +a = NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right -+if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: + if ( +- threading.current_thread() != threading.main_thread() +- and threading.current_thread() != threading.main_thread() +- or signal.getsignal(signal.SIGINT) != signal.default_int_handler ++ NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right ++ and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right ++ or NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right + ): return True if ( - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -@@ -327,24 +297,44 @@ +@@ -327,24 +277,44 @@ ): return True if ( @@ -824,7 +771,7 @@ last_call() ): return True ( -@@ -363,8 +353,9 @@ +@@ -363,8 +333,9 @@ bbbb >> bbbb * bbbb ( aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -851,18 +798,18 @@ False 1 1.0 1j -NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 +True or False +True or False or None +True and False +True and False and None +(Name1 and Name2) or Name3 +Name1 and Name2 or Name3 +Name1 or (Name2 and Name3) +Name1 or Name2 and Name3 +(Name1 and Name2) or (Name3 and Name4) +Name1 and Name2 or Name3 and Name4 +Name1 or (Name2 and Name3) or Name4 +Name1 or Name2 and Name3 or Name4 v1 << 2 1 >> v2 1 % finished @@ -872,10 +819,10 @@ not great ~great +value -1 -NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 +~int and not v1 ^ 123 + v2 | True +(~int) and (not ((v1 ^ (123 + v2)) | True)) +really ** -confusing ** ~operator**-precedence -NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 +flags & ~select.NOT_IMPLEMENTED_attr and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right lambda x: True lambda x: True lambda x: True @@ -891,15 +838,11 @@ NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false (NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false) { "NOT_YET_IMPLEMENTED_STRING": dead, - "NOT_YET_IMPLEMENTED_STRING": ( - NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 - ), + "NOT_YET_IMPLEMENTED_STRING": (long_live or die_hard), } { "NOT_YET_IMPLEMENTED_STRING": dead, - "NOT_YET_IMPLEMENTED_STRING": ( - NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 - ), + "NOT_YET_IMPLEMENTED_STRING": (long_live or die_hard), **{"NOT_YET_IMPLEMENTED_STRING": verygood}, } {**a, **b, **c} @@ -911,26 +854,19 @@ NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false "NOT_YET_IMPLEMENTED_STRING", (NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false), } -NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 +( + {"NOT_YET_IMPLEMENTED_STRING": "NOT_YET_IMPLEMENTED_STRING"}, + (True or False), + (+value), + "NOT_YET_IMPLEMENTED_STRING", + b"NOT_YET_IMPLEMENTED_BYTE_STRING", +) or None () (1,) (1, 2) (1, 2, 3) [] -[ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - (NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2), - (NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2), - (NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2), -] +[1, 2, 3, 4, 5, 6, 7, 8, 9, (10 or A), (11 or B), (12 or C)] [1, 2, 3] [NOT_YET_IMPLEMENTED_ExprStarred] [NOT_YET_IMPLEMENTED_ExprStarred] @@ -1010,7 +946,7 @@ NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false { "NOT_YET_IMPLEMENTED_STRING": dead, - "NOT_YET_IMPLEMENTED_STRING": NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2, + "NOT_YET_IMPLEMENTED_STRING": long_live or die_hard, } { "NOT_YET_IMPLEMENTED_STRING", @@ -1020,20 +956,7 @@ NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false "NOT_YET_IMPLEMENTED_STRING", NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false, } -[ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2, - NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2, - NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2, -] +[1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or A, 11 or B, 12 or C] (SomeName) SomeName (Good, Bad, Ugly) @@ -1100,14 +1023,18 @@ NOT_YET_IMPLEMENTED_StmtFor NOT_YET_IMPLEMENTED_StmtFor NOT_YET_IMPLEMENTED_StmtFor NOT_YET_IMPLEMENTED_StmtFor -while NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: +while this and that: ... NOT_YET_IMPLEMENTED_StmtFor a = NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right a = NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right a = NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right a = NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right -if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: +if ( + NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right + and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right + or NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right +): return True if ( aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip5_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip5_py.snap index 5c4a69a412..7ad743ff86 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip5_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip5_py.snap @@ -22,15 +22,17 @@ else: ```diff --- Black +++ Ruff -@@ -1,9 +1,5 @@ +@@ -1,9 +1,9 @@ a, b, c = 3, 4, 5 --if ( + if ( - a == 3 - and b != 9 # fmt: skip - and c is not None --): ++ NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right ++ and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right # fmt: skip ++ and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right + ): - print("I'm good!") -+if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: + NOT_IMPLEMENTED_call() else: - print("I'm bad") @@ -41,7 +43,11 @@ else: ```py a, b, c = 3, 4, 5 -if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: +if ( + NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right + and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right # fmt: skip + and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right +): NOT_IMPLEMENTED_call() else: NOT_IMPLEMENTED_call() diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__skip_magic_trailing_comma_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__skip_magic_trailing_comma_py.snap index 2d9a375f59..0ca6ef0a1f 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__skip_magic_trailing_comma_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__skip_magic_trailing_comma_py.snap @@ -97,7 +97,7 @@ func( + b, + c, + d, -+) = NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 ++) = NOT_IMPLEMENTED_call() and NOT_IMPLEMENTED_call() -func(argument1, (one, two), argument4, argument5, argument6) +NOT_IMPLEMENTED_call() @@ -133,7 +133,7 @@ NOT_IMPLEMENTED_call() b, c, d, -) = NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 +) = NOT_IMPLEMENTED_call() and NOT_IMPLEMENTED_call() NOT_IMPLEMENTED_call() ``` diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__torture_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__torture_py.snap index 2fe7481d4e..e9d41df04d 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__torture_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__torture_py.snap @@ -42,7 +42,7 @@ assert ( ```diff --- Black +++ Ruff -@@ -2,57 +2,21 @@ +@@ -2,57 +2,24 @@ ( () << 0 @@ -96,8 +96,10 @@ assert ( - othr.parameters, - othr.meta_data, - othr.schedule, -- ) -+ return NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 ++ return ( ++ NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right ++ and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right + ) -assert a_function( @@ -128,7 +130,10 @@ NOT_YET_IMPLEMENTED_StmtClassDef def test(self, othr): - return NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 + return ( + NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right + and NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right + ) NOT_YET_IMPLEMENTED_StmtAssert diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_comma_optional_parens1_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_comma_optional_parens1_py.snap index 1528c308d1..9b6fe74f54 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_comma_optional_parens1_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_comma_optional_parens1_py.snap @@ -43,7 +43,7 @@ class A: - _winapi.ERROR_SEM_TIMEOUT, - _winapi.ERROR_PIPE_BUSY, -) or _check_timeout(t): -+if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: ++if NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right or NOT_IMPLEMENTED_call(): pass if x: @@ -82,7 +82,7 @@ class A: ## Ruff Output ```py -if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: +if NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right or NOT_IMPLEMENTED_call(): pass if x: diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_comma_optional_parens2_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_comma_optional_parens2_py.snap index 2f591416f5..2c3f46e706 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_comma_optional_parens2_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_comma_optional_parens2_py.snap @@ -16,20 +16,26 @@ if (e123456.get_tk_patchlevel() >= (8, 6, 0, 'final') or ```diff --- Black +++ Ruff -@@ -1,6 +1,2 @@ +@@ -1,6 +1,5 @@ -if e123456.get_tk_patchlevel() >= (8, 6, 0, "final") or ( - 8, - 5, - 8, -) <= get_tk_patchlevel() < (8, 6): -+if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: ++if ( ++ NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right ++ or NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right ++): pass ``` ## Ruff Output ```py -if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: +if ( + NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right + or NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right +): pass ``` diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_commas_in_leading_parts_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_commas_in_leading_parts_py.snap index 9999f85e05..fbbed48d6e 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_commas_in_leading_parts_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__trailing_commas_in_leading_parts_py.snap @@ -75,7 +75,7 @@ assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx( -) = func1( - arg1 -) and func2(arg2) -+) = NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 ++) = NOT_IMPLEMENTED_call() and NOT_IMPLEMENTED_call() # Example from https://github.com/psf/black/issues/3229 @@ -121,7 +121,7 @@ NOT_IMPLEMENTED_call() b, c, d, -) = NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 +) = NOT_IMPLEMENTED_call() and NOT_IMPLEMENTED_call() # Example from https://github.com/psf/black/issues/3229 diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__expression__boolean_operation_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__expression__boolean_operation_py.snap new file mode 100644 index 0000000000..4bc16ef83a --- /dev/null +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__expression__boolean_operation_py.snap @@ -0,0 +1,143 @@ +--- +source: crates/ruff_python_formatter/src/lib.rs +expression: snapshot +--- +## Input +```py +if ( + self._proc + # has the child process finished? + and self._returncode + # the child process has finished, but the + # transport hasn't been notified yet? + and self._proc.poll() +): + pass + +if ( + self._proc + and self._returncode + and self._proc.poll() + and self._proc + and self._returncode + and self._proc.poll() +): + ... + +if ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + and aaaaaaaaaaaaaaaaa + and aaaaaaaaaaaaaaaaaaaaaa + and aaaaaaaaaaaaaaaaaaaaaaaa + and aaaaaaaaaaaaaaaaaaaaaaaaaa + and aaaaaaaaaaaaaaaaaaaaaaaaaaaa +): + ... + + +if ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaas + and aaaaaaaaaaaaaaaaa +): + ... + + +if [2222, 333] and [ + aaaaaaaaaaaaa, + bbbbbbbbbbbbbbbbbbbb, + cccccccccccccccccccc, + dddddddddddddddddddd, + eeeeeeeeee, +]: + ... + +if [ + aaaaaaaaaaaaa, + bbbbbbbbbbbbbbbbbbbb, + cccccccccccccccccccc, + dddddddddddddddddddd, + eeeeeeeeee, +] and [2222, 333]: + pass + +# Break right only applies for boolean operations with a left and right side +if ( + aaaaaaaaaaaaaaaaaaaaaaaaaa + and bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + and ccccccccccccccccc + and [dddddddddddddd, eeeeeeeeee, fffffffffffffff] +): + pass +``` + + + +## Output +```py +if ( + self.NOT_IMPLEMENTED_attr + # has the child process finished? + and self.NOT_IMPLEMENTED_attr + # the child process has finished, but the + # transport hasn't been notified yet? + and NOT_IMPLEMENTED_call() +): + pass + +if ( + self.NOT_IMPLEMENTED_attr + and self.NOT_IMPLEMENTED_attr + and NOT_IMPLEMENTED_call() + and self.NOT_IMPLEMENTED_attr + and self.NOT_IMPLEMENTED_attr + and NOT_IMPLEMENTED_call() +): + ... + +if ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + and aaaaaaaaaaaaaaaaa + and aaaaaaaaaaaaaaaaaaaaaa + and aaaaaaaaaaaaaaaaaaaaaaaa + and aaaaaaaaaaaaaaaaaaaaaaaaaa + and aaaaaaaaaaaaaaaaaaaaaaaaaaaa +): + ... + + +if ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaas + and aaaaaaaaaaaaaaaaa +): + ... + + +if [2222, 333] and [ + aaaaaaaaaaaaa, + bbbbbbbbbbbbbbbbbbbb, + cccccccccccccccccccc, + dddddddddddddddddddd, + eeeeeeeeee, +]: + ... + +if [ + aaaaaaaaaaaaa, + bbbbbbbbbbbbbbbbbbbb, + cccccccccccccccccccc, + dddddddddddddddddddd, + eeeeeeeeee, +] and [2222, 333]: + pass + +# Break right only applies for boolean operations with a left and right side +if ( + aaaaaaaaaaaaaaaaaaaaaaaaaa + and bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + and ccccccccccccccccc + and [dddddddddddddd, eeeeeeeeee, fffffffffffffff] +): + pass +``` + + diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__statement__while_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__statement__while_py.snap index 804cc9303c..32b93d696d 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__statement__while_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__statement__while_py.snap @@ -61,12 +61,14 @@ while ( else: ... -while NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: # comment +while NOT_IMPLEMENTED_call() and anotherCondition or aThirdCondition: # comment NOT_IMPLEMENTED_call() while ( - NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 # trailing third condition + NOT_IMPLEMENTED_call() # trailing some condition + and anotherCondition + or aThirdCondition # trailing third condition ): # comment NOT_IMPLEMENTED_call() ```