From e586c2759045c17c55e63903e9310472ef97dc4e Mon Sep 17 00:00:00 2001 From: konstin Date: Mon, 12 Jun 2023 14:55:47 +0200 Subject: [PATCH] Format ExprTuple (#4963) This implements formatting ExprTuple, including magic trailing comma. I intentionally didn't change the settings mechanism but just added a dummy global const flag. Besides the snapshots, I added custom breaking/joining tests and a deeply nested test case. The diffs look better than previously, proper black compatibility depends on parentheses handling. --------- Co-authored-by: Micha Reiser --- .../ruff/expression/tuple_expression.py | 59 ++++ .../src/expression/expr_tuple.rs | 149 +++++++++- crates/ruff_python_formatter/src/lib.rs | 4 + ...er__tests__black_test__collections_py.snap | 40 ++- ...tter__tests__black_test__comments6_py.snap | 23 +- ..._test__comments_non_breaking_space_py.snap | 5 +- ...ter__tests__black_test__expression_py.snap | 85 +++--- ...tter__tests__black_test__fmtonoff2_py.snap | 8 +- ...atter__tests__black_test__fmtonoff_py.snap | 22 +- ...atter__tests__black_test__fmtskip3_py.snap | 4 +- ...atter__tests__black_test__fmtskip5_py.snap | 5 +- ...matter__tests__black_test__fmtskip_py.snap | 5 +- ...atter__tests__black_test__function_py.snap | 9 +- ...lack_test__function_trailing_comma_py.snap | 27 +- ...ests__black_test__power_op_spacing_py.snap | 26 +- ...test__prefer_rhs_split_reformatted_py.snap | 26 +- ...__tests__black_test__remove_parens_py.snap | 9 +- ...ck_test__skip_magic_trailing_comma_py.snap | 21 +- ...rmatter__tests__black_test__slices_py.snap | 34 ++- ...tests__black_test__string_prefixes_py.snap | 62 +++- ...matter__tests__black_test__torture_py.snap | 8 +- ...__trailing_commas_in_leading_parts_py.snap | 21 +- ...er__tests__black_test__tupleassign_py.snap | 28 +- ...est__expression__binary_expression_py.snap | 7 +- ...test__expression__tuple_expression_py.snap | 267 ++++++++++++++++++ 25 files changed, 735 insertions(+), 219 deletions(-) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/tuple_expression.py create mode 100644 crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__expression__tuple_expression_py.snap diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/tuple_expression.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/tuple_expression.py new file mode 100644 index 0000000000..517f5d39e7 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/tuple_expression.py @@ -0,0 +1,59 @@ +# Non-wrapping parentheses checks +a1 = 1, 2 +a2 = (1, 2) +a3 = (1, 2), 3 +a4 = ((1, 2), 3) + +# Wrapping parentheses checks +b1 = (("Michael", "Ende"), ("Der", "satanarchäolügenialkohöllische", "Wunschpunsch"), ("Beelzebub", "Irrwitzer"), ("Tyrannja", "Vamperl"),) +b2 = ("akjdshflkjahdslkfjlasfdahjlfds", "ljklsadhflakfdajflahfdlajfhafldkjalfj", "ljklsadhflakfdajflahfdlajfhafldkjalf2",) +b3 = ("The", "Night", "of", "Wishes:", "Or", "the", "Satanarchaeolidealcohellish", "Notion", "Potion",) + +# Nested wrapping parentheses check +c1 = (("cicero"), ("Qui", "autem,", "si", "maxime", "hoc", "placeat,", "moderatius", "tamen", "id", "uolunt", "fieri,", "difficilem", "quandam", "temperantiam", "postulant", "in", "eo,", "quod", "semel", "admissum", "coerceri", "reprimique", "non", "potest,", "ut", "propemodum", "iustioribus", "utamur", "illis,", "qui", "omnino", "auocent", "a", "philosophia,", "quam", "his,", "qui", "rebus", "infinitis", "modum", "constituant", "in", "reque", "eo", "meliore,", "quo", "maior", "sit,", "mediocritatem", "desiderent."), ("de", "finibus", "bonorum", "et", "malorum")) + +# Deeply nested parentheses +d1 = ((("3D",),),) +d2 = (((((((((((((((((((((((((((("¯\_(ツ)_/¯",),),),),),),),),),),),),),),),),),),),),),),),),),),),) + +# Join and magic trailing comma +e1 = ( + 1, + 2 +) +e2 = ( + 1, + 2, +) +e3 = ( + 1, +) +e4 = ( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor", + "incididunt" +) + +# Empty tuples and comments +f1 = ( + # empty +) +f2 = () + +# Comments in other tuples +g1 = ( # a + # b + 1, # c + # d +) # e +g2 = ( # a + # b + 1, # c + # d + 2, # e + # f +) # g + +# Ensure the correct number of parentheses +h1 = ((((1, 2)))) +h2 = ((((1, "qweiurpoiqwurepqiurpqirpuqoiwrupqoirupqoirupqoiurpqiorupwqiourpqurpqurpqurpqurpqurpqurüqurqpuriq")))) +h3 = 1, "qweiurpoiqwurepqiurpqirpuqoiwrupqoirupqoirupqoiurpqiorupwqiourpqurpqurpqurpqurpqurpqurüqurqpuriq" diff --git a/crates/ruff_python_formatter/src/expression/expr_tuple.rs b/crates/ruff_python_formatter/src/expression/expr_tuple.rs index ba96180a15..e7d1ce0865 100644 --- a/crates/ruff_python_formatter/src/expression/expr_tuple.rs +++ b/crates/ruff_python_formatter/src/expression/expr_tuple.rs @@ -1,17 +1,130 @@ -use crate::comments::Comments; +use crate::comments::{dangling_node_comments, Comments}; +use crate::context::PyFormatContext; 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 crate::trivia::Token; +use crate::trivia::{first_non_trivia_token, TokenKind}; +use crate::{AsFormat, FormatNodeRule, FormattedIterExt, PyFormatter, USE_MAGIC_TRAILING_COMMA}; +use ruff_formatter::formatter::Formatter; +use ruff_formatter::prelude::{ + block_indent, group, if_group_breaks, soft_block_indent, soft_line_break_or_space, text, +}; +use ruff_formatter::{format_args, write, Buffer, Format, FormatResult}; +use ruff_python_ast::prelude::{Expr, Ranged}; +use ruff_text_size::TextRange; use rustpython_parser::ast::ExprTuple; #[derive(Default)] pub struct FormatExprTuple; impl FormatNodeRule for FormatExprTuple { - fn fmt_fields(&self, _item: &ExprTuple, f: &mut PyFormatter) -> FormatResult<()> { - write!(f, [not_yet_implemented_custom_text("(1, 2)")]) + fn fmt_fields(&self, item: &ExprTuple, f: &mut PyFormatter) -> FormatResult<()> { + let ExprTuple { + range, + elts, + ctx: _, + } = item; + + // Handle the edge cases of an empty tuple and a tuple with one element + let last = match &elts[..] { + [] => { + return write!( + f, + [ + // An empty tuple always needs parentheses, but does not have a comma + &text("("), + block_indent(&dangling_node_comments(item)), + &text(")"), + ] + ); + } + [single] => { + return write!( + f, + [group(&format_args![ + // A single element tuple always needs parentheses and a trailing comma + &text("("), + soft_block_indent(&format_args![single.format(), &text(",")]), + &text(")"), + ])] + ); + } + [.., last] => last, + }; + + let magic_trailing_comma = USE_MAGIC_TRAILING_COMMA + && matches!( + first_non_trivia_token(last.range().end(), f.context().contents()), + Some(Token { + kind: TokenKind::Comma, + .. + }) + ); + + if magic_trailing_comma { + // A magic trailing comma forces us to print in expanded mode since we have more than + // one element + write!( + f, + [ + // An expanded group always needs parentheses + &text("("), + block_indent(&ExprSequence::new(elts)), + &text(")"), + ] + )?; + } else if is_parenthesized(*range, elts, f) { + // If the tuple has parentheses, keep them. Note that unlike other expr parentheses, + // those are actually part of the range + write!( + f, + [group(&format_args![ + // If there were previously parentheses, keep them + &text("("), + soft_block_indent(&ExprSequence::new(elts)), + &text(")"), + ])] + )?; + } else { + write!( + f, + [group(&format_args![ + // If there were previously no parentheses, add them only if the group breaks + if_group_breaks(&text("(")), + soft_block_indent(&ExprSequence::new(elts)), + if_group_breaks(&text(")")), + ])] + )?; + } + + Ok(()) + } + + fn fmt_dangling_comments(&self, _node: &ExprTuple, _f: &mut PyFormatter) -> FormatResult<()> { + // Handled in `fmt_fields` + Ok(()) + } +} + +#[derive(Debug)] +struct ExprSequence<'a> { + elts: &'a [Expr], +} + +impl<'a> ExprSequence<'a> { + const fn new(elts: &'a [Expr]) -> Self { + Self { elts } + } +} + +impl Format> for ExprSequence<'_> { + fn fmt(&self, f: &mut Formatter>) -> FormatResult<()> { + f.join_with(&format_args!(text(","), soft_line_break_or_space())) + .entries(self.elts.iter().formatted()) + .finish()?; + // Black style has a trailing comma on the last entry of an expanded group + write!(f, [if_group_breaks(&text(","))]) } } @@ -28,3 +141,29 @@ impl NeedsParentheses for ExprTuple { } } } + +/// Check if a tuple has already had parentheses in the input +fn is_parenthesized( + tuple_range: TextRange, + elts: &[Expr], + f: &mut Formatter>, +) -> bool { + let parentheses = '('; + let first_char = &f.context().contents()[usize::from(tuple_range.start())..] + .chars() + .next(); + let Some(first_char) = first_char else { + return false; + }; + if *first_char != parentheses { + return false; + } + + // Consider `a = (1, 2), 3`: The first char of the current expr starts is a parentheses, but + // it's not its own but that of its first tuple child. We know that it belongs to the child + // because if it wouldn't, the child would start (at least) a char later + let Some(first_child) = elts.first() else { + return false; + }; + first_child.range().start() != tuple_range.start() +} diff --git a/crates/ruff_python_formatter/src/lib.rs b/crates/ruff_python_formatter/src/lib.rs index 51d03c375b..6ad37c5665 100644 --- a/crates/ruff_python_formatter/src/lib.rs +++ b/crates/ruff_python_formatter/src/lib.rs @@ -30,6 +30,10 @@ mod trivia; include!("../../ruff_formatter/shared_traits.rs"); +/// TODO(konstin): hook this up to the settings by replacing `SimpleFormatOptions` with a python +/// specific struct. +pub(crate) const USE_MAGIC_TRAILING_COMMA: bool = true; + /// 'ast is the lifetime of the source code (input), 'buf is the lifetime of the buffer (output) pub(crate) type PyFormatter<'ast, 'buf> = Formatter<'buf, PyFormatContext<'ast>>; diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__collections_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__collections_py.snap index 16be7db816..6a6c2179d6 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__collections_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__collections_py.snap @@ -122,28 +122,25 @@ if True: - 2, - 3, -} --x = (1,) ++c = {1, 2, 3} + x = (1,) -y = (narf(),) -nested = { - (1, 2, 3), - (4, 5, 6), -} --nested_no_trailing_comma = {(1, 2, 3), (4, 5, 6)} -+c = {1, 2, 3} -+x = (1, 2) -+y = (1, 2) -+nested = {(1, 2), (1, 2)} -+nested_no_trailing_comma = {(1, 2), (1, 2)} ++y = (NOT_IMPLEMENTED_call(),) ++nested = {(1, 2, 3), (4, 5, 6)} + nested_no_trailing_comma = {(1, 2, 3), (4, 5, 6)} nested_long_lines = [ - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", - "cccccccccccccccccccccccccccccccccccccccc", -- (1, 2, 3), ++ "NOT_YET_IMPLEMENTED_STRING", ++ "NOT_YET_IMPLEMENTED_STRING", ++ "NOT_YET_IMPLEMENTED_STRING", + (1, 2, 3), - "dddddddddddddddddddddddddddddddddddddddd", -+ "NOT_YET_IMPLEMENTED_STRING", -+ "NOT_YET_IMPLEMENTED_STRING", -+ "NOT_YET_IMPLEMENTED_STRING", -+ (1, 2), + "NOT_YET_IMPLEMENTED_STRING", ] -{ @@ -161,7 +158,7 @@ if True: -) +{NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} +{NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} -+["NOT_YET_IMPLEMENTED_STRING", "NOT_YET_IMPLEMENTED_STRING" % (1, 2)] ++["NOT_YET_IMPLEMENTED_STRING", "NOT_YET_IMPLEMENTED_STRING" % (foo,)] +x = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} +y = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} +NOT_YET_IMPLEMENTED_StmtAssert @@ -181,9 +178,8 @@ if True: -] +[1, 2, 3] --division_result_tuple = (6 / 2,) + division_result_tuple = (6 / 2,) -print("foo %r", (foo.bar,)) -+division_result_tuple = (1, 2) +NOT_IMPLEMENTED_call() if True: @@ -238,20 +234,20 @@ NOT_YET_IMPLEMENTED_StmtImportFrom a = {1, 2, 3} b = {1, 2, 3} c = {1, 2, 3} -x = (1, 2) -y = (1, 2) -nested = {(1, 2), (1, 2)} -nested_no_trailing_comma = {(1, 2), (1, 2)} +x = (1,) +y = (NOT_IMPLEMENTED_call(),) +nested = {(1, 2, 3), (4, 5, 6)} +nested_no_trailing_comma = {(1, 2, 3), (4, 5, 6)} nested_long_lines = [ "NOT_YET_IMPLEMENTED_STRING", "NOT_YET_IMPLEMENTED_STRING", "NOT_YET_IMPLEMENTED_STRING", - (1, 2), + (1, 2, 3), "NOT_YET_IMPLEMENTED_STRING", ] {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} -["NOT_YET_IMPLEMENTED_STRING", "NOT_YET_IMPLEMENTED_STRING" % (1, 2)] +["NOT_YET_IMPLEMENTED_STRING", "NOT_YET_IMPLEMENTED_STRING" % (foo,)] x = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} y = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} NOT_YET_IMPLEMENTED_StmtAssert @@ -262,7 +258,7 @@ NOT_YET_IMPLEMENTED_StmtFor [1, 2, 3] -division_result_tuple = (1, 2) +division_result_tuple = (6 / 2,) NOT_IMPLEMENTED_call() if True: 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 3009fba804..430431fe04 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,15 +49,10 @@ +@@ -49,10 +49,8 @@ element = 0 # type: int another_element = 1 # type: float another_element_with_long_name = 2 # type: int @@ -148,15 +148,9 @@ aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*ite + 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 -- tup = ( -- another_element, -- another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style, -- ) # type: Tuple[int, int] -+ tup = (1, 2) # type: Tuple[int, int] - - a = ( - element -@@ -84,35 +79,22 @@ + tup = ( + another_element, +@@ -84,35 +82,22 @@ def func( @@ -203,7 +197,7 @@ aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*ite +NOT_IMPLEMENTED_call() -aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*items))) # type: ignore[arg-type] -+(1, 2) = NOT_IMPLEMENTED_call() # type: ignore[arg-type] ++aaaaaaaaaaaaa, bbbbbbbbb = NOT_IMPLEMENTED_call() # type: ignore[arg-type] ``` ## Ruff Output @@ -263,7 +257,10 @@ def f( 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 - tup = (1, 2) # type: Tuple[int, int] + tup = ( + another_element, + another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style, + ) # type: Tuple[int, int] a = ( element @@ -308,7 +305,7 @@ AAAAAAAAAAAAA = ( NOT_IMPLEMENTED_call() -(1, 2) = NOT_IMPLEMENTED_call() # type: ignore[arg-type] +aaaaaaaaaaaaa, bbbbbbbbb = NOT_IMPLEMENTED_call() # type: ignore[arg-type] ``` ## Black Output diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments_non_breaking_space_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments_non_breaking_space_py.snap index cddc816cdb..daf0c71385 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments_non_breaking_space_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments_non_breaking_space_py.snap @@ -42,8 +42,7 @@ def function(a:int=42): +NOT_YET_IMPLEMENTED_StmtImportFrom result = 1 # A simple comment --result = (1,) # Another one -+result = (1, 2) # Another one + result = (1,) # Another one result = 1 #  type: ignore result = 1 # This comment is talking about type: ignore @@ -68,7 +67,7 @@ def function(a:int=42): NOT_YET_IMPLEMENTED_StmtImportFrom result = 1 # A simple comment -result = (1, 2) # Another one +result = (1,) # Another one result = 1 #  type: ignore result = 1 # This comment is talking about type: ignore 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 5733bbfdd7..b2cc26d4f2 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 @@ -342,8 +342,6 @@ last_call() -{**a, **b, **c} -{"2.7", "3.6", "3.7", "3.8", "3.9", ("4.0" if gilectomy else "3.10")} -({"a": "b"}, (True or False), (+value), "string", b"bytes") or None --() --(1,) +NOT_YET_IMPLEMENTED_ExprUnaryOp +NOT_YET_IMPLEMENTED_ExprUnaryOp +NOT_YET_IMPLEMENTED_ExprUnaryOp @@ -377,11 +375,10 @@ last_call() + (NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false), +} +NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -+(1, 2) -+(1, 2) -+(1, 2) + () + (1,) (1, 2) --(1, 2, 3) + (1, 2, 3) [] -[1, 2, 3, 4, 5, 6, 7, 8, 9, (10 or A), (11 or B), (12 or C)] [ @@ -395,11 +392,6 @@ last_call() - *a, 4, 5, --] --[ -- 4, -- *a, -- 5, + 6, + 7, + 8, @@ -408,6 +400,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] @@ -541,6 +538,9 @@ last_call() - int, - float, - dict[str, int], +-] +-very_long_variable_name_filters: t.List[ +- t.Tuple[str, t.Union[str, t.List[t.Optional[str]]]], +[ + 1, + 2, @@ -555,9 +555,6 @@ last_call() + NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2, + NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2, ] --very_long_variable_name_filters: t.List[ -- t.Tuple[str, t.Union[str, t.List[t.Optional[str]]]], --] -xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( # type: ignore - sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__) -) @@ -599,7 +596,7 @@ last_call() -[1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or A, 11 or B, 12 or C] (SomeName) SomeName --(Good, Bad, Ugly) + (Good, Bad, Ugly) -(i for i in (1, 2, 3)) -((i**2) for i in (1, 2, 3)) -((i**2) for i, _ in ((1, "a"), (2, "b"), (3, "c"))) @@ -614,38 +611,25 @@ last_call() - "import_session_id": 1, - **kwargs, -} --a = (1,) --b = (1,) -+(1, 2) +(i for i in []) +(i for i in []) +(i for i in []) +(i for i in []) -+(1, 2) ++(NOT_YET_IMPLEMENTED_ExprStarred,) +{NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} -+a = (1, 2) -+b = (1, 2) + a = (1,) + b = (1,) c = 1 --d = (1,) + a + (2,) + d = (1,) + a + (2,) -e = (1,).count(1) -f = 1, *range(10) -g = 1, *"ten" -what_is_up_with_those_new_coord_names = (coord_names + set(vars_to_create)) + set( - vars_to_remove -+d = (1, 2) + a + (1, 2) -+e = NOT_IMPLEMENTED_call() -+f = (1, 2) -+g = (1, 2) -+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( @@ -653,7 +637,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( @@ -663,7 +653,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() -mapping = { @@ -899,10 +892,10 @@ NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false (NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false), } NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 +() +(1,) (1, 2) -(1, 2) -(1, 2) -(1, 2) +(1, 2, 3) [] [ 1, @@ -1020,20 +1013,20 @@ NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false ] (SomeName) SomeName -(1, 2) +(Good, Bad, Ugly) (i for i in []) (i for i in []) (i for i in []) (i for i in []) -(1, 2) +(NOT_YET_IMPLEMENTED_ExprStarred,) {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} -a = (1, 2) -b = (1, 2) +a = (1,) +b = (1,) c = 1 -d = (1, 2) + a + (1, 2) +d = (1,) + a + (2,) e = NOT_IMPLEMENTED_call() -f = (1, 2) -g = (1, 2) +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() diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff2_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff2_py.snap index d4de723ff0..7dc0b255ac 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff2_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff2_py.snap @@ -101,8 +101,8 @@ def test_calculate_fades(): # one is zero/none - (0, 4, 0, 0, 10, 0, 0, 6, 10), - (None, 4, 0, 0, 10, 0, 0, 6, 10), -+ (1, 2), -+ (1, 2), ++ (0, 4, 0, 0, 10, 0, 0, 6, 10), ++ (None, 4, 0, 0, 10, 0, 0, 6, 10), ] # fmt: on @@ -144,8 +144,8 @@ def verify_fader(test): def test_calculate_fades(): calcs = [ # one is zero/none - (1, 2), - (1, 2), + (0, 4, 0, 0, 10, 0, 0, 6, 10), + (None, 4, 0, 0, 10, 0, 0, 6, 10), ] # fmt: on 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 febe1c8ba1..7a3cedbd0b 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 @@ -207,10 +207,10 @@ d={'a':1, +NOT_YET_IMPLEMENTED_StmtImport -from third_party import X, Y, Z -- --from library import some_connection, some_decorator +NOT_YET_IMPLEMENTED_StmtImportFrom +-from library import some_connection, some_decorator +- +NOT_YET_IMPLEMENTED_StmtImportFrom # fmt: off -from third_party import (X, @@ -281,7 +281,7 @@ d={'a':1, - assert task._cancel_stack[: len(old_stack)] == old_stack +def spaces( + a=1, -+ b=(1, 2), ++ b=(), + c=[], + d={NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value}, + e=True, @@ -296,8 +296,7 @@ d={'a':1, def spaces_types( a: int = 1, -- b: tuple = (), -+ b: tuple = (1, 2), + b: tuple = (), c: list = [], - d: dict = {}, + d: dict = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value}, @@ -351,7 +350,7 @@ d={'a':1, # fmt: off - a , b = *hello - 'unformatted' -+ (1, 2) = NOT_YET_IMPLEMENTED_ExprStarred ++ a, b = NOT_YET_IMPLEMENTED_ExprStarred + "NOT_YET_IMPLEMENTED_STRING" # fmt: on @@ -463,9 +462,8 @@ d={'a':1, def single_literal_yapf_disable(): - """Black does not support this.""" -- BAZ = {(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)} # yapf: disable + "NOT_YET_IMPLEMENTED_STRING" -+ BAZ = {(1, 2), (1, 2), (1, 2)} # yapf: disable + BAZ = {(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)} # yapf: disable -cfg.rule( @@ -561,7 +559,7 @@ def function_signature_stress_test( # fmt: on def spaces( a=1, - b=(1, 2), + b=(), c=[], d={NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value}, e=True, @@ -576,7 +574,7 @@ def spaces( def spaces_types( a: int = 1, - b: tuple = (1, 2), + b: tuple = (), c: list = [], d: dict = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value}, e: bool = True, @@ -608,7 +606,7 @@ def import_as_names(): def testlist_star_expr(): # fmt: off - (1, 2) = NOT_YET_IMPLEMENTED_ExprStarred + a, b = NOT_YET_IMPLEMENTED_ExprStarred "NOT_YET_IMPLEMENTED_STRING" # fmt: on @@ -668,7 +666,7 @@ def long_lines(): def single_literal_yapf_disable(): "NOT_YET_IMPLEMENTED_STRING" - BAZ = {(1, 2), (1, 2), (1, 2)} # yapf: disable + BAZ = {(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)} # yapf: disable NOT_IMPLEMENTED_call() diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip3_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip3_py.snap index 1a16430854..4b45e63eaa 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip3_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip3_py.snap @@ -25,7 +25,7 @@ f = ["This is a very long line that should be formatted into a clearer line ", " # fmt: off -b, c = 1, 2 -d = 6 # fmt: skip -+(1, 2) = (1, 2) ++b, c = 1, 2 +d = 6 # fmt: skip e = 5 # fmt: on @@ -41,7 +41,7 @@ f = ["This is a very long line that should be formatted into a clearer line ", " ```py a = 3 # fmt: off -(1, 2) = (1, 2) +b, c = 1, 2 d = 6 # fmt: skip e = 5 # fmt: on 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 9f346191a9..5c4a69a412 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 @@ -23,14 +23,13 @@ else: --- Black +++ Ruff @@ -1,9 +1,5 @@ --a, b, c = 3, 4, 5 + a, b, c = 3, 4, 5 -if ( - a == 3 - and b != 9 # fmt: skip - and c is not None -): - print("I'm good!") -+(1, 2) = (1, 2) +if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: + NOT_IMPLEMENTED_call() else: @@ -41,7 +40,7 @@ else: ## Ruff Output ```py -(1, 2) = (1, 2) +a, b, c = 3, 4, 5 if NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2: NOT_IMPLEMENTED_call() else: diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip_py.snap index 47305ef7ac..c4deeaed9c 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip_py.snap @@ -17,9 +17,8 @@ d = 5 --- Black +++ Ruff @@ -1,3 +1,3 @@ --a, b = 1, 2 + a, b = 1, 2 -c = 6 # fmt: skip -+(1, 2) = (1, 2) +c = 6 # fmt: skip d = 5 ``` @@ -27,7 +26,7 @@ d = 5 ## Ruff Output ```py -(1, 2) = (1, 2) +a, b = 1, 2 c = 6 # fmt: skip d = 5 ``` 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 3e8b74e6cf..1ae6f9a66b 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 @@ -175,7 +175,7 @@ def __await__(): return (yield) - assert task._cancel_stack[: len(old_stack)] == old_stack +def spaces( + a=1, -+ b=(1, 2), ++ b=(), + c=[], + d={NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value}, + e=True, @@ -190,8 +190,7 @@ def __await__(): return (yield) def spaces_types( a: int = 1, -- b: tuple = (), -+ b: tuple = (1, 2), + b: tuple = (), c: list = [], - d: dict = {}, + d: dict = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value}, @@ -348,7 +347,7 @@ def function_signature_stress_test( def spaces( a=1, - b=(1, 2), + b=(), c=[], d={NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value}, e=True, @@ -363,7 +362,7 @@ def spaces( def spaces_types( a: int = 1, - b: tuple = (1, 2), + b: tuple = (), c: list = [], d: dict = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value}, e: bool = True, diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function_trailing_comma_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function_trailing_comma_py.snap index ecc5c3010f..3e472e8729 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function_trailing_comma_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function_trailing_comma_py.snap @@ -74,19 +74,18 @@ some_module.some_function( ```diff --- Black +++ Ruff -@@ -1,69 +1,30 @@ +@@ -1,9 +1,7 @@ def f( a, ): - d = { - "key": "value", - } -- tup = (1,) + d = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} -+ tup = (1, 2) + tup = (1,) - def f2( +@@ -11,10 +9,7 @@ a, b, ): @@ -94,14 +93,11 @@ some_module.some_function( - "key": "value", - "key2": "value2", - } -- tup = ( -- 1, -- 2, -- ) + d = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} -+ tup = (1, 2) - - + tup = ( + 1, + 2, +@@ -24,46 +19,15 @@ def f( a: int = 1, ): @@ -154,7 +150,7 @@ some_module.some_function( # The type annotation shouldn't get a trailing comma since that would change its type. -@@ -80,35 +41,16 @@ +@@ -80,35 +44,16 @@ pass @@ -203,7 +199,7 @@ def f( a, ): d = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} - tup = (1, 2) + tup = (1,) def f2( @@ -211,7 +207,10 @@ def f2( b, ): d = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} - tup = (1, 2) + tup = ( + 1, + 2, + ) def f( 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 7c3bdb253a..4a41269a87 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 @@ -96,11 +96,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) --m = [([2**63], [1, 2**63])] --n = count <= 10**5 --o = settings(max_examples=10**6) --p = {(k, k**2): v**2 for k, v in pairs} --q = [10**i for i in range(6)] +a = 5**NOT_YET_IMPLEMENTED_ExprUnaryOp +b = 5 ** NOT_IMPLEMENTED_call() +c = NOT_YET_IMPLEMENTED_ExprUnaryOp @@ -113,7 +108,11 @@ return np.divide( +j = NOT_IMPLEMENTED_call().NOT_IMPLEMENTED_attr ** 5 +k = [i for i in []] +l = NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right -+m = [(1, 2)] + m = [([2**63], [1, 2**63])] +-n = count <= 10**5 +-o = settings(max_examples=10**6) +-p = {(k, k**2): v**2 for k, v in pairs} +-q = [10**i for i in range(6)] +n = NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right +o = NOT_IMPLEMENTED_call() +p = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} @@ -132,11 +131,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) --m = [([2.0**63.0], [1.0, 2**63.0])] --n = count <= 10**5.0 --o = settings(max_examples=10**6.0) --p = {(k, k**2): v**2.0 for k, v in pairs} --q = [10.5**i for i in range(6)] +a = 5.0**NOT_YET_IMPLEMENTED_ExprUnaryOp +b = 5.0 ** NOT_IMPLEMENTED_call() +c = NOT_YET_IMPLEMENTED_ExprUnaryOp @@ -149,7 +143,11 @@ return np.divide( +j = NOT_IMPLEMENTED_call().NOT_IMPLEMENTED_attr ** 5.0 +k = [i for i in []] +l = NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right -+m = [(1, 2)] + m = [([2.0**63.0], [1.0, 2**63.0])] +-n = count <= 10**5.0 +-o = settings(max_examples=10**6.0) +-p = {(k, k**2): v**2.0 for k, v in pairs} +-q = [10.5**i for i in range(6)] +n = NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right +o = NOT_IMPLEMENTED_call() +p = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} @@ -201,7 +199,7 @@ i = NOT_IMPLEMENTED_call() ** 5 j = NOT_IMPLEMENTED_call().NOT_IMPLEMENTED_attr ** 5 k = [i for i in []] l = NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right -m = [(1, 2)] +m = [([2**63], [1, 2**63])] n = NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right o = NOT_IMPLEMENTED_call() p = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} @@ -220,7 +218,7 @@ i = NOT_IMPLEMENTED_call() ** 5.0 j = NOT_IMPLEMENTED_call().NOT_IMPLEMENTED_attr ** 5.0 k = [i for i in []] l = NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right -m = [(1, 2)] +m = [([2.0**63.0], [1.0, 2**63.0])] n = NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right o = NOT_IMPLEMENTED_call() p = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__prefer_rhs_split_reformatted_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__prefer_rhs_split_reformatted_py.snap index b917eaf3b0..bdc722edb5 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__prefer_rhs_split_reformatted_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__prefer_rhs_split_reformatted_py.snap @@ -25,22 +25,15 @@ xxxxxxxxx_yyy_zzzzzzzz[xx.xxxxxx(x_yyy_zzzzzz.xxxxx[0]), x_yyy_zzzzzz.xxxxxx(xxx ```diff --- Black +++ Ruff -@@ -2,20 +2,8 @@ - - # Left hand side fits in a single line but will still be exploded by the - # magic trailing comma. --( -- first_value, -- ( -- m1, -- m2, -- ), -- third_value, +@@ -9,13 +9,8 @@ + m2, + ), + third_value, -) = xxxxxx_yyyyyy_zzzzzz_wwwwww_uuuuuuu_vvvvvvvvvvv( - arg1, - arg2, -) -+(1, 2) = NOT_IMPLEMENTED_call() ++) = NOT_IMPLEMENTED_call() # Make when when the left side of assignment plus the opening paren "... = (" is # exactly line length limit + 1, it won't be split like that. @@ -57,7 +50,14 @@ xxxxxxxxx_yyy_zzzzzzzz[xx.xxxxxx(x_yyy_zzzzzz.xxxxx[0]), x_yyy_zzzzzz.xxxxxx(xxx # Left hand side fits in a single line but will still be exploded by the # magic trailing comma. -(1, 2) = NOT_IMPLEMENTED_call() +( + first_value, + ( + m1, + m2, + ), + third_value, +) = NOT_IMPLEMENTED_call() # Make when when the left side of assignment plus the opening paren "... = (" is # exactly line length limit + 1, it won't be split like that. diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_parens_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_parens_py.snap index 5e1e16cd2e..edf95a4f94 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_parens_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_parens_py.snap @@ -114,12 +114,7 @@ def example8(): def example4(): -@@ -46,39 +34,15 @@ - - - def example5(): -- return () -+ return (1, 2) +@@ -50,35 +38,11 @@ def example6(): @@ -198,7 +193,7 @@ def example4(): def example5(): - return (1, 2) + return () def example6(): 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 b0626e0c31..2d9a375f59 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 @@ -60,7 +60,7 @@ func( ```diff --- Black +++ Ruff -@@ -1,25 +1,25 @@ +@@ -1,25 +1,30 @@ # We should not remove the trailing comma in a single-element subscript. -a: tuple[int,] -b = tuple[int,] @@ -82,8 +82,7 @@ func( +set_of_types = {NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key]} # Except single element tuples --small_tuple = (1,) -+small_tuple = (1, 2) + small_tuple = (1,) # Trailing commas in multiple chained non-nested parens. -zero(one).two(three).four(five) @@ -93,7 +92,12 @@ func( +NOT_IMPLEMENTED_call() -(a, b, c, d) = func1(arg1) and func2(arg2) -+(1, 2) = NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 ++( ++ a, ++ b, ++ c, ++ d, ++) = NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -func(argument1, (one, two), argument4, argument5, argument6) +NOT_IMPLEMENTED_call() @@ -117,14 +121,19 @@ small_set = {1} set_of_types = {NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key]} # Except single element tuples -small_tuple = (1, 2) +small_tuple = (1,) # Trailing commas in multiple chained non-nested parens. NOT_IMPLEMENTED_call() NOT_IMPLEMENTED_call() -(1, 2) = NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 +( + a, + b, + c, + d, +) = NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 NOT_IMPLEMENTED_call() ``` diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__slices_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__slices_py.snap index 6dc17b505b..1d2e046b96 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__slices_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__slices_py.snap @@ -76,7 +76,7 @@ x[ ```diff --- Black +++ Ruff -@@ -1,59 +1,38 @@ +@@ -1,59 +1,48 @@ -slice[a.b : c.d] -slice[d :: d + 1] -slice[d + 1 :: d] @@ -125,12 +125,22 @@ x[ # These are from PEP-8: -ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:] -ham[lower:upper], ham[lower:upper:], ham[lower::step] -+(1, 2) -+(1, 2) ++( ++ NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], ++ NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], ++ NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], ++ NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], ++ NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], ++) ++( ++ NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], ++ NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], ++ NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], ++) # ham[lower+offset : upper+offset] -ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)] -ham[lower + offset : upper + offset] -+(1, 2) ++NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] +NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] -slice[::, ::] @@ -196,10 +206,20 @@ async def f(): # These are from PEP-8: -(1, 2) -(1, 2) +( + NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], + NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], + NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], + NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], + NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], +) +( + NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], + NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], + NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], +) # ham[lower+offset : upper+offset] -(1, 2) +NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__string_prefixes_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__string_prefixes_py.snap index eb5b0bf26b..9298adaab4 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__string_prefixes_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__string_prefixes_py.snap @@ -33,7 +33,7 @@ def docstring_multiline(): ```diff --- Black +++ Ruff -@@ -1,20 +1,18 @@ +@@ -1,20 +1,36 @@ #!/usr/bin/env python3 -name = "Łukasz" @@ -42,15 +42,33 @@ def docstring_multiline(): -("", "") -(r"", R"") +name = "NOT_YET_IMPLEMENTED_STRING" -+(1, 2) -+(1, 2) -+(1, 2) -+(1, 2) ++(NOT_YET_IMPLEMENTED_ExprJoinedStr, NOT_YET_IMPLEMENTED_ExprJoinedStr) ++(b"NOT_YET_IMPLEMENTED_BYTE_STRING", b"NOT_YET_IMPLEMENTED_BYTE_STRING") ++("NOT_YET_IMPLEMENTED_STRING", "NOT_YET_IMPLEMENTED_STRING") ++("NOT_YET_IMPLEMENTED_STRING", "NOT_YET_IMPLEMENTED_STRING") -(rf"", rf"", Rf"", Rf"", rf"", rf"", Rf"", Rf"") -(rb"", rb"", Rb"", Rb"", rb"", rb"", Rb"", Rb"") -+(1, 2) -+(1, 2) ++( ++ NOT_YET_IMPLEMENTED_ExprJoinedStr, ++ NOT_YET_IMPLEMENTED_ExprJoinedStr, ++ NOT_YET_IMPLEMENTED_ExprJoinedStr, ++ NOT_YET_IMPLEMENTED_ExprJoinedStr, ++ NOT_YET_IMPLEMENTED_ExprJoinedStr, ++ NOT_YET_IMPLEMENTED_ExprJoinedStr, ++ NOT_YET_IMPLEMENTED_ExprJoinedStr, ++ NOT_YET_IMPLEMENTED_ExprJoinedStr, ++) ++( ++ b"NOT_YET_IMPLEMENTED_BYTE_STRING", ++ b"NOT_YET_IMPLEMENTED_BYTE_STRING", ++ b"NOT_YET_IMPLEMENTED_BYTE_STRING", ++ b"NOT_YET_IMPLEMENTED_BYTE_STRING", ++ b"NOT_YET_IMPLEMENTED_BYTE_STRING", ++ b"NOT_YET_IMPLEMENTED_BYTE_STRING", ++ b"NOT_YET_IMPLEMENTED_BYTE_STRING", ++ b"NOT_YET_IMPLEMENTED_BYTE_STRING", ++) def docstring_singleline(): @@ -71,13 +89,31 @@ def docstring_multiline(): #!/usr/bin/env python3 name = "NOT_YET_IMPLEMENTED_STRING" -(1, 2) -(1, 2) -(1, 2) -(1, 2) +(NOT_YET_IMPLEMENTED_ExprJoinedStr, NOT_YET_IMPLEMENTED_ExprJoinedStr) +(b"NOT_YET_IMPLEMENTED_BYTE_STRING", b"NOT_YET_IMPLEMENTED_BYTE_STRING") +("NOT_YET_IMPLEMENTED_STRING", "NOT_YET_IMPLEMENTED_STRING") +("NOT_YET_IMPLEMENTED_STRING", "NOT_YET_IMPLEMENTED_STRING") -(1, 2) -(1, 2) +( + NOT_YET_IMPLEMENTED_ExprJoinedStr, + NOT_YET_IMPLEMENTED_ExprJoinedStr, + NOT_YET_IMPLEMENTED_ExprJoinedStr, + NOT_YET_IMPLEMENTED_ExprJoinedStr, + NOT_YET_IMPLEMENTED_ExprJoinedStr, + NOT_YET_IMPLEMENTED_ExprJoinedStr, + NOT_YET_IMPLEMENTED_ExprJoinedStr, + NOT_YET_IMPLEMENTED_ExprJoinedStr, +) +( + b"NOT_YET_IMPLEMENTED_BYTE_STRING", + b"NOT_YET_IMPLEMENTED_BYTE_STRING", + b"NOT_YET_IMPLEMENTED_BYTE_STRING", + b"NOT_YET_IMPLEMENTED_BYTE_STRING", + b"NOT_YET_IMPLEMENTED_BYTE_STRING", + b"NOT_YET_IMPLEMENTED_BYTE_STRING", + b"NOT_YET_IMPLEMENTED_BYTE_STRING", + b"NOT_YET_IMPLEMENTED_BYTE_STRING", +) def docstring_singleline(): 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 0aee58f5ca..2fe7481d4e 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,11 +42,9 @@ assert ( ```diff --- Black +++ Ruff -@@ -1,58 +1,22 @@ - importA +@@ -2,57 +2,21 @@ ( -- () -+ (1, 2) + () << 0 - ** 101234234242352525425252352352525234890264906820496920680926538059059209922523523525 + **101234234242352525425252352352525234890264906820496920680926538059059209922523523525 @@ -114,7 +112,7 @@ assert ( ```py importA ( - (1, 2) + () << 0 **101234234242352525425252352352525234890264906820496920680926538059059209922523523525 ) # 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 d1a1d68ab9..9999f85e05 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 @@ -46,7 +46,7 @@ assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx( ```diff --- Black +++ Ruff -@@ -1,50 +1,21 @@ +@@ -1,50 +1,26 @@ -zero( - one, -).two( @@ -67,15 +67,15 @@ assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx( -func1(arg1).func2(arg1, (one_tuple,)).func3(arg3) +NOT_IMPLEMENTED_call() --( -- a, -- b, -- c, -- d, + ( + a, + b, + c, + d, -) = func1( - arg1 -) and func2(arg2) -+(1, 2) = NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 ++) = NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 # Example from https://github.com/psf/black/issues/3229 @@ -116,7 +116,12 @@ NOT_IMPLEMENTED_call() # Inner one-element tuple shouldn't explode NOT_IMPLEMENTED_call() -(1, 2) = NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 +( + a, + b, + c, + d, +) = NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 # Example from https://github.com/psf/black/issues/3229 diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__tupleassign_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__tupleassign_py.snap index 643ac351f9..e335debb8b 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__tupleassign_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__tupleassign_py.snap @@ -20,34 +20,36 @@ this_will_be_wrapped_in_parens, = struct.unpack(b"12345678901234567890") ```diff --- Black +++ Ruff -@@ -1,12 +1,7 @@ - # This is a standalone comment. --( -- sdfjklsdfsjldkflkjsf, -- sdfjsdfjlksdljkfsdlkf, -- sdfsdjfklsdfjlksdljkf, -- sdsfsdfjskdflsfsdf, +@@ -4,9 +4,9 @@ + sdfjsdfjlksdljkfsdlkf, + sdfsdjfklsdfjlksdljkf, + sdsfsdfjskdflsfsdf, -) = (1, 2, 3) -+(1, 2) = (1, 2) ++) = 1, 2, 3 # This is as well. -(this_will_be_wrapped_in_parens,) = struct.unpack(b"12345678901234567890") -+(1, 2) = NOT_IMPLEMENTED_call() ++(this_will_be_wrapped_in_parens,) = NOT_IMPLEMENTED_call() -(a,) = call() -+(1, 2) = NOT_IMPLEMENTED_call() ++(a,) = NOT_IMPLEMENTED_call() ``` ## Ruff Output ```py # This is a standalone comment. -(1, 2) = (1, 2) +( + sdfjklsdfsjldkflkjsf, + sdfjsdfjlksdljkfsdlkf, + sdfsdjfklsdfjlksdljkf, + sdsfsdfjskdflsfsdf, +) = 1, 2, 3 # This is as well. -(1, 2) = NOT_IMPLEMENTED_call() +(this_will_be_wrapped_in_parens,) = NOT_IMPLEMENTED_call() -(1, 2) = NOT_IMPLEMENTED_call() +(a,) = NOT_IMPLEMENTED_call() ``` ## Black Output diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__expression__binary_expression_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__expression__binary_expression_py.snap index ab5311bf8a..47374f6ad8 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__expression__binary_expression_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__expression__binary_expression_py.snap @@ -86,7 +86,12 @@ aaaaaaaaaaaaaa + [ dddddddddddddddd, eeeeeee, ] -aaaaaaaaaaaaaa + (1, 2) +aaaaaaaaaaaaaa + ( + bbbbbbbbbbbbbbbbbbbbbb, + ccccccccccccccccccccc, + dddddddddddddddd, + eeeeeee, +) aaaaaaaaaaaaaa + {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} aaaaaaaaaaaaaa + { bbbbbbbbbbbbbbbbbbbbbb, diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__expression__tuple_expression_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__expression__tuple_expression_py.snap new file mode 100644 index 0000000000..70dab6420a --- /dev/null +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__expression__tuple_expression_py.snap @@ -0,0 +1,267 @@ +--- +source: crates/ruff_python_formatter/src/lib.rs +expression: snapshot +--- +## Input +```py +# Non-wrapping parentheses checks +a1 = 1, 2 +a2 = (1, 2) +a3 = (1, 2), 3 +a4 = ((1, 2), 3) + +# Wrapping parentheses checks +b1 = (("Michael", "Ende"), ("Der", "satanarchäolügenialkohöllische", "Wunschpunsch"), ("Beelzebub", "Irrwitzer"), ("Tyrannja", "Vamperl"),) +b2 = ("akjdshflkjahdslkfjlasfdahjlfds", "ljklsadhflakfdajflahfdlajfhafldkjalfj", "ljklsadhflakfdajflahfdlajfhafldkjalf2",) +b3 = ("The", "Night", "of", "Wishes:", "Or", "the", "Satanarchaeolidealcohellish", "Notion", "Potion",) + +# Nested wrapping parentheses check +c1 = (("cicero"), ("Qui", "autem,", "si", "maxime", "hoc", "placeat,", "moderatius", "tamen", "id", "uolunt", "fieri,", "difficilem", "quandam", "temperantiam", "postulant", "in", "eo,", "quod", "semel", "admissum", "coerceri", "reprimique", "non", "potest,", "ut", "propemodum", "iustioribus", "utamur", "illis,", "qui", "omnino", "auocent", "a", "philosophia,", "quam", "his,", "qui", "rebus", "infinitis", "modum", "constituant", "in", "reque", "eo", "meliore,", "quo", "maior", "sit,", "mediocritatem", "desiderent."), ("de", "finibus", "bonorum", "et", "malorum")) + +# Deeply nested parentheses +d1 = ((("3D",),),) +d2 = (((((((((((((((((((((((((((("¯\_(ツ)_/¯",),),),),),),),),),),),),),),),),),),),),),),),),),),),) + +# Join and magic trailing comma +e1 = ( + 1, + 2 +) +e2 = ( + 1, + 2, +) +e3 = ( + 1, +) +e4 = ( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor", + "incididunt" +) + +# Empty tuples and comments +f1 = ( + # empty +) +f2 = () + +# Comments in other tuples +g1 = ( # a + # b + 1, # c + # d +) # e +g2 = ( # a + # b + 1, # c + # d + 2, # e + # f +) # g + +# Ensure the correct number of parentheses +h1 = ((((1, 2)))) +h2 = ((((1, "qweiurpoiqwurepqiurpqirpuqoiwrupqoirupqoirupqoiurpqiorupwqiourpqurpqurpqurpqurpqurpqurüqurqpuriq")))) +h3 = 1, "qweiurpoiqwurepqiurpqirpuqoiwrupqoirupqoirupqoiurpqiorupwqiourpqurpqurpqurpqurpqurpqurüqurqpuriq" +``` + + + +## Output +```py +# Non-wrapping parentheses checks +a1 = 1, 2 +a2 = (1, 2) +a3 = (1, 2), 3 +a4 = ((1, 2), 3) + +# Wrapping parentheses checks +b1 = ( + ("NOT_YET_IMPLEMENTED_STRING", "NOT_YET_IMPLEMENTED_STRING"), + ( + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + ), + ("NOT_YET_IMPLEMENTED_STRING", "NOT_YET_IMPLEMENTED_STRING"), + ("NOT_YET_IMPLEMENTED_STRING", "NOT_YET_IMPLEMENTED_STRING"), +) +b2 = ( + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", +) +b3 = ( + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", +) + +# Nested wrapping parentheses check +c1 = ( + ("NOT_YET_IMPLEMENTED_STRING"), + ( + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + ), + ( + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + "NOT_YET_IMPLEMENTED_STRING", + ), +) + +# Deeply nested parentheses +d1 = ((("NOT_YET_IMPLEMENTED_STRING",),),) +d2 = ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + ( + "NOT_YET_IMPLEMENTED_STRING", + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), + ), +) + +# Join and magic trailing comma +e1 = (1, 2) +e2 = ( + 1, + 2, +) +e3 = (1,) +e4 = ("NOT_YET_IMPLEMENTED_STRING", "NOT_YET_IMPLEMENTED_STRING") + +# Empty tuples and comments +f1 = ( + # empty +) +f2 = () + +# Comments in other tuples +g1 = ( + # a + # b + 1, # c + # d +) # e +g2 = ( + # a + # b + 1, # c + # d + 2, # e + # f +) # g + +# Ensure the correct number of parentheses +h1 = (1, 2) +h2 = (1, "NOT_YET_IMPLEMENTED_STRING") +h3 = 1, "NOT_YET_IMPLEMENTED_STRING" +``` + +