diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/unary.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/unary.py new file mode 100644 index 0000000000..a88e20fb75 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/unary.py @@ -0,0 +1,138 @@ +if not aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb: + pass + +a = True +not a + +b = 10 +-b ++b + +## Leading operand comments + +if not ( + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + + +if ~( + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb): + pass + +if -( + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb): + pass + + +if +( + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb): + pass + +if ( + not + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + + +if ( + ~ + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb): + pass + +if ( + - + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb): + pass + + +if ( + + + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb): + pass + +## Parentheses + +if ( + # unary comment + not + # operand comment + ( + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + ) +): + pass + +if (not ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +) +): + pass + +if aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & (not ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +) +): + pass + +if ( + not ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + ) + & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +): + pass + + +## Trailing operator comments + +if ( + not # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + + +if ( + ~ # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + +if ( + - # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + + +if ( + + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + + +## Varia + +if not \ + a: + pass 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 8eb78d3cdf..199e689fb2 100644 --- a/crates/ruff_python_formatter/src/expression/expr_bin_op.rs +++ b/crates/ruff_python_formatter/src/expression/expr_bin_op.rs @@ -323,6 +323,10 @@ fn can_break(expr: &Expr) -> bool { }) => !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_unary_op.rs b/crates/ruff_python_formatter/src/expression/expr_unary_op.rs index 9f91d13e40..db3dfc06ad 100644 --- a/crates/ruff_python_formatter/src/expression/expr_unary_op.rs +++ b/crates/ruff_python_formatter/src/expression/expr_unary_op.rs @@ -1,17 +1,68 @@ -use crate::comments::Comments; +use crate::comments::{trailing_comments, Comments}; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; -use crate::{not_yet_implemented, FormatNodeRule, PyFormatter}; -use ruff_formatter::{write, Buffer, FormatResult}; -use rustpython_parser::ast::ExprUnaryOp; +use crate::prelude::*; +use crate::trivia::{SimpleTokenizer, TokenKind}; +use crate::FormatNodeRule; +use ruff_formatter::FormatContext; +use ruff_python_ast::prelude::UnaryOp; +use ruff_text_size::{TextLen, TextRange}; +use rustpython_parser::ast::{ExprUnaryOp, Ranged}; #[derive(Default)] pub struct FormatExprUnaryOp; impl FormatNodeRule for FormatExprUnaryOp { fn fmt_fields(&self, item: &ExprUnaryOp, f: &mut PyFormatter) -> FormatResult<()> { - write!(f, [not_yet_implemented(item)]) + let ExprUnaryOp { + range: _, + op, + operand, + } = item; + + let operator = match op { + UnaryOp::Invert => "~", + UnaryOp::Not => "not", + UnaryOp::UAdd => "+", + UnaryOp::USub => "-", + }; + + text(operator).fmt(f)?; + + let comments = f.context().comments().clone(); + + // Split off the comments that follow after the operator and format them as trailing comments. + // ```python + // (not # comment + // a) + // ``` + 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()); + let (trailing_operator_comments, leading_operand_comments) = + leading_operand_comments.split_at(trailing_operator_comments_end); + + if !trailing_operator_comments.is_empty() { + trailing_comments(trailing_operator_comments).fmt(f)?; + } + + // Insert a line break if the operand has comments but itself is not parenthesized. + // ```python + // if ( + // not + // # comment + // a) + // ``` + if !leading_operand_comments.is_empty() + && !is_operand_parenthesized(item, f.context().source_code().as_str()) + { + hard_line_break().fmt(f)?; + } else if op.is_not() { + space().fmt(f)?; + } + + operand.format().fmt(f) } } @@ -22,6 +73,37 @@ impl NeedsParentheses for ExprUnaryOp { 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 => { + // We preserve the parentheses of the operand. It should not be necessary to break this expression. + if is_operand_parenthesized(self, source) { + Parentheses::Never + } else { + Parentheses::Optional + } + } + parentheses => parentheses, + } + } +} + +fn is_operand_parenthesized(unary: &ExprUnaryOp, source: &str) -> bool { + let operator_len = match unary.op { + UnaryOp::Invert => '~'.text_len(), + UnaryOp::Not => "not".text_len(), + UnaryOp::UAdd => '+'.text_len(), + UnaryOp::USub => '-'.text_len(), + }; + + let trivia_range = TextRange::new(unary.range.start() + operator_len, unary.operand.start()); + + if let Some(token) = SimpleTokenizer::new(source, trivia_range) + .skip_trivia() + .next() + { + debug_assert_eq!(token.kind(), TokenKind::LParen); + true + } else { + false } } diff --git a/crates/ruff_python_formatter/src/expression/parentheses.rs b/crates/ruff_python_formatter/src/expression/parentheses.rs index 58d083c8c6..7d57fe9df3 100644 --- a/crates/ruff_python_formatter/src/expression/parentheses.rs +++ b/crates/ruff_python_formatter/src/expression/parentheses.rs @@ -42,7 +42,7 @@ pub(super) fn default_expression_needs_parentheses( } /// Configures if the expression should be parenthesized. -#[derive(Copy, Clone, Debug, Default)] +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] pub enum Parenthesize { /// Parenthesize the expression if it has parenthesis in the source. #[default] @@ -56,11 +56,11 @@ pub enum Parenthesize { } impl Parenthesize { - const fn is_if_breaks(self) -> bool { + pub(crate) const fn is_if_breaks(self) -> bool { matches!(self, Parenthesize::IfBreaks) } - const fn is_preserve(self) -> bool { + pub(crate) const fn is_preserve(self) -> bool { matches!(self, Parenthesize::Preserve) } } diff --git a/crates/ruff_python_formatter/src/lib.rs b/crates/ruff_python_formatter/src/lib.rs index b915ac45eb..3f09fd51d6 100644 --- a/crates/ruff_python_formatter/src/lib.rs +++ b/crates/ruff_python_formatter/src/lib.rs @@ -411,11 +411,10 @@ Formatted twice: #[test] fn quick_test() { let src = r#" - -def foo( - b=3 - + 2 # comment -): +if [ + aaaaaa, + BBBB,ccccccccc,ddddddd,eeeeeeeeee,ffffff +] & bbbbbbbbbbbbbbbbbbddddddddddddddddddddddddddddbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb: ... "#; // Tokenize once diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__attribute_access_on_number_literals_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__attribute_access_on_number_literals_py.snap index 81c681bc72..c736be6242 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__attribute_access_on_number_literals_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__attribute_access_on_number_literals_py.snap @@ -67,7 +67,7 @@ y = 100(no) +x = NOT_IMPLEMENTED_call() +x = 0O777 .NOT_IMPLEMENTED_attr +x = NOT_IMPLEMENTED_call() -+x = NOT_YET_IMPLEMENTED_ExprUnaryOp ++x = -100.0000J -if (10).real: +if 10 .NOT_IMPLEMENTED_attr: @@ -97,7 +97,7 @@ x = NOT_IMPLEMENTED_call() x = NOT_IMPLEMENTED_call() x = 0O777 .NOT_IMPLEMENTED_attr x = NOT_IMPLEMENTED_call() -x = NOT_YET_IMPLEMENTED_ExprUnaryOp +x = -100.0000J if 10 .NOT_IMPLEMENTED_attr: ... 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 5446adf8cc..03794aac66 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,89 +1,70 @@ +@@ -1,47 +1,35 @@ -"""Docstring.""" +"NOT_YET_IMPLEMENTED_STRING" @@ -137,11 +137,10 @@ def g(): + NOT_YET_IMPLEMENTED_StmtAssert - prev = leaf.prev_sibling -- if not prev: ++ prev = leaf.NOT_IMPLEMENTED_attr + if not prev: - prevp = preceding_leaf(p) - if not prevp or prevp.type in OPENING_BRACKETS: -+ prev = leaf.NOT_IMPLEMENTED_attr -+ if NOT_YET_IMPLEMENTED_ExprUnaryOp: + prevp = NOT_IMPLEMENTED_call() + if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: return NO @@ -171,11 +170,11 @@ def g(): return NO - ############################################################################### +@@ -49,41 +37,34 @@ # SECTION BECAUSE SECTIONS ############################################################################### -- +- def g(): - NO = "" - SPACE = " " @@ -205,10 +204,9 @@ def g(): + NOT_YET_IMPLEMENTED_StmtAssert - prev = leaf.prev_sibling -- if not prev: -- prevp = preceding_leaf(p) + prev = leaf.NOT_IMPLEMENTED_attr -+ if NOT_YET_IMPLEMENTED_ExprUnaryOp: + if not prev: +- prevp = preceding_leaf(p) + prevp = NOT_IMPLEMENTED_call() - if not prevp or prevp.type in OPENING_BRACKETS: @@ -254,7 +252,7 @@ def f(): NOT_YET_IMPLEMENTED_StmtAssert prev = leaf.NOT_IMPLEMENTED_attr - if NOT_YET_IMPLEMENTED_ExprUnaryOp: + if not prev: prevp = NOT_IMPLEMENTED_call() if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: return NO @@ -292,7 +290,7 @@ def g(): NOT_YET_IMPLEMENTED_StmtAssert prev = leaf.NOT_IMPLEMENTED_attr - if NOT_YET_IMPLEMENTED_ExprUnaryOp: + if not prev: prevp = NOT_IMPLEMENTED_call() if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: 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 bb84670f91..a96793d3d2 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,7 +276,7 @@ last_call() Name None True -@@ -7,226 +8,225 @@ +@@ -7,18 +8,18 @@ 1 1.0 1j @@ -307,12 +307,10 @@ last_call() v1 << 2 1 >> v2 1 % finished - 1 + v2 - v3 * 4 ^ 5**v6 / 7 // 8 - ((1 + v2) - (v3 * 4)) ^ (((5**v6) / 7) // 8) --not great --~great --+value ---1 +@@ -28,205 +29,204 @@ + ~great + +value + -1 -~int and not v1 ^ 123 + v2 | True -(~int) and (not ((v1 ^ (123 + v2)) | True)) -+(really ** -(confusing ** ~(operator**-precedence))) @@ -339,13 +337,9 @@ 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_YET_IMPLEMENTED_ExprUnaryOp -+NOT_YET_IMPLEMENTED_ExprUnaryOp -+NOT_YET_IMPLEMENTED_ExprUnaryOp -+NOT_YET_IMPLEMENTED_ExprUnaryOp +NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 +NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -+NOT_YET_IMPLEMENTED_ExprUnaryOp +++really ** -confusing ** ~operator**-precedence +NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 +lambda x: True +lambda x: True @@ -402,11 +396,6 @@ last_call() - *a, 4, 5, --] --[ -- 4, -- *a, -- 5, + 6, + 7, + 8, @@ -415,6 +404,11 @@ last_call() + (NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2), + (NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2), ] +-[ +- 4, +- *a, +- 5, +-] +[1, 2, 3] +[NOT_YET_IMPLEMENTED_ExprStarred] +[NOT_YET_IMPLEMENTED_ExprStarred] @@ -644,17 +638,6 @@ last_call() -g = 1, *"ten" -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 | set(vars_to_create)) - set( -- vars_to_remove --) --result = ( -- session.query(models.Customer.id) -- .filter( -- models.Customer.account_id == account_id, models.Customer.email == email_address -- ) -- .order_by(models.Customer.id.asc()) -- .all() +e = NOT_IMPLEMENTED_call() +f = 1, NOT_YET_IMPLEMENTED_ExprStarred +g = 1, NOT_YET_IMPLEMENTED_ExprStarred @@ -662,6 +645,20 @@ last_call() + (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( +- models.Customer.account_id == account_id, models.Customer.email == email_address +- ) +- .order_by(models.Customer.id.asc()) +- .all() +-) -result = ( - session.query(models.Customer.id) - .filter( @@ -671,10 +668,7 @@ 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() @@ -714,6 +708,14 @@ last_call() -for (x,) in (1,), (2,), (3,): - ... -for y in (): +- ... +-for z in (i for i in (1, 2, 3)): +- ... +-for i in call(): +- ... +-for j in 1 + (2 + 3): +- ... +-while this and that: +NOT_IMPLEMENTED_call() +NOT_IMPLEMENTED_call() +NOT_IMPLEMENTED_call() @@ -727,14 +729,6 @@ last_call() +NOT_YET_IMPLEMENTED_StmtFor +while NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: ... --for z in (i for i in (1, 2, 3)): -- ... --for i in call(): -- ... --for j in 1 + (2 + 3): -- ... --while this and that: -- ... -for ( - addr_family, - addr_type, @@ -779,7 +773,7 @@ last_call() if ( - ~aaaa.a + aaaa.b - aaaa.c * aaaa.d / aaaa.e - | aaaa.f & aaaa.g % aaaa.h ^ aaaa.i << aaaa.k >> aaaa.l**aaaa.m // aaaa.n -+ NOT_YET_IMPLEMENTED_ExprUnaryOp ++ ~aaaa.NOT_IMPLEMENTED_attr + + aaaa.NOT_IMPLEMENTED_attr + - aaaa.NOT_IMPLEMENTED_attr * aaaa.NOT_IMPLEMENTED_attr / aaaa.NOT_IMPLEMENTED_attr + | aaaa.NOT_IMPLEMENTED_attr @@ -793,7 +787,7 @@ last_call() - ~aaaaaaaa.a + aaaaaaaa.b - aaaaaaaa.c @ aaaaaaaa.d / aaaaaaaa.e - | aaaaaaaa.f & aaaaaaaa.g % aaaaaaaa.h - ^ aaaaaaaa.i << aaaaaaaa.k >> aaaaaaaa.l**aaaaaaaa.m // aaaaaaaa.n -+ NOT_YET_IMPLEMENTED_ExprUnaryOp ++ ~aaaaaaaa.NOT_IMPLEMENTED_attr + + aaaaaaaa.NOT_IMPLEMENTED_attr + - aaaaaaaa.NOT_IMPLEMENTED_attr + @ aaaaaaaa.NOT_IMPLEMENTED_attr @@ -815,7 +809,7 @@ last_call() - ^ aaaaaaaaaaaaaaaa.i - << aaaaaaaaaaaaaaaa.k - >> aaaaaaaaaaaaaaaa.l**aaaaaaaaaaaaaaaa.m // aaaaaaaaaaaaaaaa.n -+ NOT_YET_IMPLEMENTED_ExprUnaryOp ++ ~aaaaaaaaaaaaaaaa.NOT_IMPLEMENTED_attr + + aaaaaaaaaaaaaaaa.NOT_IMPLEMENTED_attr + - aaaaaaaaaaaaaaaa.NOT_IMPLEMENTED_attr + * aaaaaaaaaaaaaaaa.NOT_IMPLEMENTED_attr @@ -874,13 +868,13 @@ v1 << 2 1 % finished 1 + v2 - v3 * 4 ^ 5**v6 / 7 // 8 ((1 + v2) - (v3 * 4)) ^ (((5**v6) / 7) // 8) -NOT_YET_IMPLEMENTED_ExprUnaryOp -NOT_YET_IMPLEMENTED_ExprUnaryOp -NOT_YET_IMPLEMENTED_ExprUnaryOp -NOT_YET_IMPLEMENTED_ExprUnaryOp +not great +~great ++value +-1 NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -NOT_YET_IMPLEMENTED_ExprUnaryOp ++really ** -confusing ** ~operator**-precedence NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 lambda x: True lambda x: True @@ -1146,7 +1140,7 @@ if ( ): return True if ( - NOT_YET_IMPLEMENTED_ExprUnaryOp + ~aaaa.NOT_IMPLEMENTED_attr + aaaa.NOT_IMPLEMENTED_attr - aaaa.NOT_IMPLEMENTED_attr * aaaa.NOT_IMPLEMENTED_attr / aaaa.NOT_IMPLEMENTED_attr | aaaa.NOT_IMPLEMENTED_attr @@ -1157,7 +1151,7 @@ if ( ): return True if ( - NOT_YET_IMPLEMENTED_ExprUnaryOp + ~aaaaaaaa.NOT_IMPLEMENTED_attr + aaaaaaaa.NOT_IMPLEMENTED_attr - aaaaaaaa.NOT_IMPLEMENTED_attr @ aaaaaaaa.NOT_IMPLEMENTED_attr @@ -1172,7 +1166,7 @@ if ( ): return True if ( - NOT_YET_IMPLEMENTED_ExprUnaryOp + ~aaaaaaaaaaaaaaaa.NOT_IMPLEMENTED_attr + aaaaaaaaaaaaaaaa.NOT_IMPLEMENTED_attr - aaaaaaaaaaaaaaaa.NOT_IMPLEMENTED_attr * aaaaaaaaaaaaaaaa.NOT_IMPLEMENTED_attr diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff_py.snap index 2dcad260b6..dc725ba267 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff_py.snap @@ -286,7 +286,7 @@ d={'a':1, + c=[], + d={}, + e=True, -+ f=NOT_YET_IMPLEMENTED_ExprUnaryOp, ++ f=-1, + g=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false, + h="NOT_YET_IMPLEMENTED_STRING", + i="NOT_YET_IMPLEMENTED_STRING", @@ -296,15 +296,13 @@ d={'a':1, def spaces_types( -@@ -50,77 +69,62 @@ - c: list = [], +@@ -51,76 +70,61 @@ d: dict = {}, e: bool = True, -- f: int = -1, + f: int = -1, - g: int = 1 if False else 2, - h: str = "", - i: str = r"", -+ f: int = NOT_YET_IMPLEMENTED_ExprUnaryOp, + g: int = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false, + h: str = "NOT_YET_IMPLEMENTED_STRING", + i: str = "NOT_YET_IMPLEMENTED_STRING", @@ -425,13 +423,11 @@ d={'a':1, - implicit_default=True, - ) - ) -+ NOT_IMPLEMENTED_call() - # fmt: off +- # fmt: off - a = ( - unnecessary_bracket() - ) -+ a = NOT_IMPLEMENTED_call() - # fmt: on +- # fmt: on - _type_comment_re = re.compile( - r""" - ^ @@ -452,9 +448,11 @@ d={'a':1, - ) - $ - """, -- # fmt: off ++ NOT_IMPLEMENTED_call() + # fmt: off - re.MULTILINE|re.VERBOSE -- # fmt: on ++ a = NOT_IMPLEMENTED_call() + # fmt: on - ) + _type_comment_re = NOT_IMPLEMENTED_call() @@ -563,7 +561,7 @@ def spaces( c=[], d={}, e=True, - f=NOT_YET_IMPLEMENTED_ExprUnaryOp, + f=-1, g=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false, h="NOT_YET_IMPLEMENTED_STRING", i="NOT_YET_IMPLEMENTED_STRING", @@ -578,7 +576,7 @@ def spaces_types( c: list = [], d: dict = {}, e: bool = True, - f: int = NOT_YET_IMPLEMENTED_ExprUnaryOp, + f: int = -1, g: int = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false, h: str = "NOT_YET_IMPLEMENTED_STRING", i: str = "NOT_YET_IMPLEMENTED_STRING", diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function_py.snap index a82537bcef..a601ceda63 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function_py.snap @@ -179,7 +179,7 @@ def __await__(): return (yield) + c=[], + d={}, + e=True, -+ f=NOT_YET_IMPLEMENTED_ExprUnaryOp, ++ f=-1, + g=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false, + h="NOT_YET_IMPLEMENTED_STRING", + i="NOT_YET_IMPLEMENTED_STRING", @@ -189,15 +189,13 @@ def __await__(): return (yield) def spaces_types( -@@ -55,71 +61,27 @@ - c: list = [], +@@ -56,70 +62,26 @@ d: dict = {}, e: bool = True, -- f: int = -1, + f: int = -1, - g: int = 1 if False else 2, - h: str = "", - i: str = r"", -+ f: int = NOT_YET_IMPLEMENTED_ExprUnaryOp, + g: int = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false, + h: str = "NOT_YET_IMPLEMENTED_STRING", + i: str = "NOT_YET_IMPLEMENTED_STRING", @@ -341,7 +339,7 @@ def spaces( c=[], d={}, e=True, - f=NOT_YET_IMPLEMENTED_ExprUnaryOp, + f=-1, g=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false, h="NOT_YET_IMPLEMENTED_STRING", i="NOT_YET_IMPLEMENTED_STRING", @@ -356,7 +354,7 @@ def spaces_types( c: list = [], d: dict = {}, e: bool = True, - f: int = NOT_YET_IMPLEMENTED_ExprUnaryOp, + f: int = -1, g: int = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false, h: str = "NOT_YET_IMPLEMENTED_STRING", i: str = "NOT_YET_IMPLEMENTED_STRING", diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__power_op_spacing_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__power_op_spacing_py.snap index 6358e8d7e3..e3b6cde88b 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__power_op_spacing_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__power_op_spacing_py.snap @@ -76,13 +76,13 @@ return np.divide( ```diff --- Black +++ Ruff -@@ -11,53 +11,46 @@ - {**a, **b, **c} +@@ -12,52 +12,45 @@ --a = 5**~4 + a = 5**~4 -b = 5 ** f() --c = -(5**2) ++b = 5 ** NOT_IMPLEMENTED_call() + c = -(5**2) -d = 5 ** f["hi"] -e = lazy(lambda **kwargs: 5) -f = f() ** 5 @@ -92,9 +92,6 @@ return np.divide( -j = super().name ** 5 -k = [(2**idx, value) for idx, value in pairs] -l = mod.weights_[0] == pytest.approx(0.95**100, abs=0.001) -+a = 5**NOT_YET_IMPLEMENTED_ExprUnaryOp -+b = 5 ** NOT_IMPLEMENTED_call() -+c = NOT_YET_IMPLEMENTED_ExprUnaryOp +d = 5 ** NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] +e = NOT_IMPLEMENTED_call() +f = NOT_IMPLEMENTED_call() ** 5 @@ -115,9 +112,10 @@ return np.divide( +q = [i for i in []] r = x**y --a = 5.0**~4.0 + a = 5.0**~4.0 -b = 5.0 ** f() --c = -(5.0**2.0) ++b = 5.0 ** NOT_IMPLEMENTED_call() + c = -(5.0**2.0) -d = 5.0 ** f["hi"] -e = lazy(lambda **kwargs: 5) -f = f() ** 5.0 @@ -127,9 +125,6 @@ return np.divide( -j = super().name ** 5.0 -k = [(2.0**idx, value) for idx, value in pairs] -l = mod.weights_[0] == pytest.approx(0.95**100, abs=0.001) -+a = 5.0**NOT_YET_IMPLEMENTED_ExprUnaryOp -+b = 5.0 ** NOT_IMPLEMENTED_call() -+c = NOT_YET_IMPLEMENTED_ExprUnaryOp +d = 5.0 ** NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] +e = NOT_IMPLEMENTED_call() +f = NOT_IMPLEMENTED_call() ** 5.0 @@ -183,9 +178,9 @@ def function_dont_replace_spaces(): {**a, **b, **c} -a = 5**NOT_YET_IMPLEMENTED_ExprUnaryOp +a = 5**~4 b = 5 ** NOT_IMPLEMENTED_call() -c = NOT_YET_IMPLEMENTED_ExprUnaryOp +c = -(5**2) d = 5 ** NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] e = NOT_IMPLEMENTED_call() f = NOT_IMPLEMENTED_call() ** 5 @@ -202,9 +197,9 @@ p = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_ q = [i for i in []] r = x**y -a = 5.0**NOT_YET_IMPLEMENTED_ExprUnaryOp +a = 5.0**~4.0 b = 5.0 ** NOT_IMPLEMENTED_call() -c = NOT_YET_IMPLEMENTED_ExprUnaryOp +c = -(5.0**2.0) d = 5.0 ** NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] e = NOT_IMPLEMENTED_call() f = NOT_IMPLEMENTED_call() ** 5.0 diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__expression__binary_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__expression__binary_py.snap index a26d01a316..a610419d8b 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__expression__binary_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__expression__binary_py.snap @@ -251,7 +251,7 @@ aaaaaaaaaaaaaa + NOT_YET_IMPLEMENTED_ExprSetComp # But only for expressions that have a statement parent. -NOT_YET_IMPLEMENTED_ExprUnaryOp +not (aaaaaaaaaaaaaa + NOT_YET_IMPLEMENTED_ExprSetComp) [NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right] diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__expression__unary_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__expression__unary_py.snap new file mode 100644 index 0000000000..48e8852375 --- /dev/null +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__expression__unary_py.snap @@ -0,0 +1,302 @@ +--- +source: crates/ruff_python_formatter/src/lib.rs +expression: snapshot +--- +## Input +```py +if not aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb: + pass + +a = True +not a + +b = 10 +-b ++b + +## Leading operand comments + +if not ( + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + + +if ~( + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb): + pass + +if -( + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb): + pass + + +if +( + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb): + pass + +if ( + not + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + + +if ( + ~ + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb): + pass + +if ( + - + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb): + pass + + +if ( + + + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb): + pass + +## Parentheses + +if ( + # unary comment + not + # operand comment + ( + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + ) +): + pass + +if (not ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +) +): + pass + +if aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & (not ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +) +): + pass + +if ( + not ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + ) + & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +): + pass + + +## Trailing operator comments + +if ( + not # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + + +if ( + ~ # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + +if ( + - # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + + +if ( + + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + + +## Varia + +if not \ + a: + pass +``` + + + +## Output +```py +if ( + not aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + +a = True +not a + +b = 10 +-b ++b + +## Leading operand comments + +if not ( + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + + +if ~( + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + +if -( + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + + +if +( + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + +if ( + not + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + + +if ( + ~ + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + +if ( + - + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + + +if ( + + + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + +## Parentheses + +if ( + # unary comment + not ( + # operand comment + # comment + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + ) +): + pass + +if not ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + +if aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & ( + not ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + ) +): + pass + +if ( + not ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + ) + & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +): + pass + + +## Trailing operator comments + +if ( + not aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa # comment + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + + +if ( + ~aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa # comment + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + +if ( + -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa # comment + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + + +if ( + +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa # comment + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +): + pass + + +## Varia + +if not a: + pass +``` + +