diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/with.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/with.py new file mode 100644 index 0000000000..4a664a1d70 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/with.py @@ -0,0 +1,54 @@ +with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: + ... + # trailing + +with a, a: # after colon + ... + # trailing + +with ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, +): + ... + # trailing + + +with ( + a # a + , # comma + b # c + ): # colon + ... + + +with ( + a # a + as # as + b # b + , # comma + c # c + ): # colon + ... # body + # body trailing own + + +with (a,): # magic trailing comma + ... + + +with (a): # should remove brackets + ... + +# TODO: black doesn't wrap this, but maybe we want to anyway? +# if we do want to wrap, do we prefer to wrap the entire WithItem or to let the +# WithItem allow the `aa + bb` content expression to be wrapped +with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb as c: + ... + + +# currently unparsable by black: https://github.com/psf/black/issues/3678 +with (name_2 for name_0 in name_4): + pass +with (a, *b): + pass diff --git a/crates/ruff_python_formatter/src/expression/expr_starred.rs b/crates/ruff_python_formatter/src/expression/expr_starred.rs index 14806cb52b..3711deb92e 100644 --- a/crates/ruff_python_formatter/src/expression/expr_starred.rs +++ b/crates/ruff_python_formatter/src/expression/expr_starred.rs @@ -2,7 +2,7 @@ use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; -use crate::{not_yet_implemented, FormatNodeRule, PyFormatter}; +use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter}; use ruff_formatter::{write, Buffer, FormatResult}; use rustpython_parser::ast::ExprStarred; @@ -10,8 +10,13 @@ use rustpython_parser::ast::ExprStarred; pub struct FormatExprStarred; impl FormatNodeRule for FormatExprStarred { - fn fmt_fields(&self, item: &ExprStarred, f: &mut PyFormatter) -> FormatResult<()> { - write!(f, [not_yet_implemented(item)]) + fn fmt_fields(&self, _item: &ExprStarred, f: &mut PyFormatter) -> FormatResult<()> { + write!( + f, + [not_yet_implemented_custom_text( + "*NOT_YET_IMPLEMENTED_ExprStarred" + )] + ) } } diff --git a/crates/ruff_python_formatter/src/other/with_item.rs b/crates/ruff_python_formatter/src/other/with_item.rs index 3b13b582a0..0c3f696e27 100644 --- a/crates/ruff_python_formatter/src/other/with_item.rs +++ b/crates/ruff_python_formatter/src/other/with_item.rs @@ -1,4 +1,6 @@ -use crate::{not_yet_implemented, FormatNodeRule, PyFormatter}; +use crate::expression::parentheses::Parenthesize; +use crate::prelude::*; +use crate::{FormatNodeRule, PyFormatter}; use ruff_formatter::{write, Buffer, FormatResult}; use rustpython_parser::ast::WithItem; @@ -7,6 +9,22 @@ pub struct FormatWithItem; impl FormatNodeRule for FormatWithItem { fn fmt_fields(&self, item: &WithItem, f: &mut PyFormatter) -> FormatResult<()> { - write!(f, [not_yet_implemented(item)]) + let WithItem { + range: _, + context_expr, + optional_vars, + } = item; + + let inner = format_with(|f| { + write!( + f, + [context_expr.format().with_options(Parenthesize::IfBreaks)] + )?; + if let Some(optional_vars) = optional_vars { + write!(f, [space(), text("as"), space(), optional_vars.format()])?; + } + Ok(()) + }); + write!(f, [group(&inner)]) } } diff --git a/crates/ruff_python_formatter/src/statement/stmt_with.rs b/crates/ruff_python_formatter/src/statement/stmt_with.rs index a68ee33113..c01b8439f9 100644 --- a/crates/ruff_python_formatter/src/statement/stmt_with.rs +++ b/crates/ruff_python_formatter/src/statement/stmt_with.rs @@ -1,5 +1,9 @@ -use crate::{not_yet_implemented, FormatNodeRule, PyFormatter}; +use crate::builders::optional_parentheses; +use crate::comments::trailing_comments; +use crate::prelude::*; +use crate::{FormatNodeRule, PyFormatter}; use ruff_formatter::{write, Buffer, FormatResult}; +use ruff_python_ast::prelude::*; use rustpython_parser::ast::StmtWith; #[derive(Default)] @@ -7,6 +11,33 @@ pub struct FormatStmtWith; impl FormatNodeRule for FormatStmtWith { fn fmt_fields(&self, item: &StmtWith, f: &mut PyFormatter) -> FormatResult<()> { - write!(f, [not_yet_implemented(item)]) + let StmtWith { + range: _, + items, + body, + type_comment: _, + } = item; + + let comments = f.context().comments().clone(); + let dangling_comments = comments.dangling_comments(item.as_any_node_ref()); + + let joined_items = format_with(|f| f.join_comma_separated().nodes(items.iter()).finish()); + + write!( + f, + [ + text("with"), + space(), + group(&optional_parentheses(&joined_items)), + text(":"), + trailing_comments(dangling_comments), + block_indent(&body.format()) + ] + ) + } + + fn fmt_dangling_comments(&self, _node: &StmtWith, _f: &mut PyFormatter) -> FormatResult<()> { + // Handled in `fmt_fields` + Ok(()) } } diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@comments5.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@comments5.py.snap index 269d9cdd25..68ef84e041 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@comments5.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@comments5.py.snap @@ -93,7 +93,7 @@ if __name__ == "__main__": # Comment belongs to the `if` block. # This one belongs to the `while` block. -@@ -8,26 +8,20 @@ +@@ -8,26 +8,21 @@ # This one is properly standalone now. @@ -110,22 +110,23 @@ if __name__ == "__main__": -with open(some_temp_file) as f: - data = f.read() -+NOT_YET_IMPLEMENTED_StmtWith - +- -try: - with open(some_other_file) as w: - w.write(data) -+NOT_YET_IMPLEMENTED_StmtTry ++with NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) as f: ++ data = NOT_IMPLEMENTED_call() -except OSError: - print("problems") -- ++NOT_YET_IMPLEMENTED_StmtTry + -import sys +NOT_YET_IMPLEMENTED_StmtImport # leading function comment -@@ -42,7 +36,7 @@ +@@ -42,7 +37,7 @@ # leading 1 @deco1 # leading 2 @@ -134,7 +135,7 @@ if __name__ == "__main__": # leading 3 @deco3 def decorated1(): -@@ -52,7 +46,7 @@ +@@ -52,7 +47,7 @@ # leading 1 @deco1 # leading 2 @@ -143,7 +144,7 @@ if __name__ == "__main__": # leading function comment def decorated1(): ... -@@ -70,4 +64,4 @@ +@@ -70,4 +65,4 @@ if __name__ == "__main__": @@ -173,7 +174,8 @@ for i in NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg): NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) # and finally we loop around -NOT_YET_IMPLEMENTED_StmtWith +with NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) as f: + data = NOT_IMPLEMENTED_call() NOT_YET_IMPLEMENTED_StmtTry diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@composition.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@composition.py.snap index 25490c1887..127846ac18 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@composition.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@composition.py.snap @@ -193,7 +193,7 @@ class C: ```diff --- Black +++ Ruff -@@ -1,159 +1,42 @@ +@@ -1,23 +1,10 @@ class C: def test(self) -> None: - with patch("black.out", print): @@ -214,18 +214,22 @@ class C: - "2 files reformatted, 2 files left unchanged, 2 files failed to" - " reformat.", - ) -- for i in (a,): -- if ( -- # Rule 1 -- i % 2 == 0 -- # Rule 2 -- and i % 3 == 0 -- ): -- while ( -- # Just a comment ++ with NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg): ++ NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) ++ NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) ++ NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) ++ NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) + for i in (a,): + if ( + # Rule 1 +@@ -27,133 +14,46 @@ + ): + while ( + # Just a comment - call() - # Another -- ): ++ NOT_IMPLEMENTED_call() + ): - print(i) - xxxxxxxxxxxxxxxx = Yyyy2YyyyyYyyyyy( - push_manager=context.request.resource_manager, @@ -235,7 +239,8 @@ class C: - # Only send the first n items. - items=items[:num_items] - ) -+ NOT_YET_IMPLEMENTED_StmtWith ++ # Another ++ NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) + xxxxxxxxxxxxxxxx = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) return ( 'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s' @@ -371,7 +376,7 @@ class C: %3d 0 LOAD_FAST 1 (x) 2 LOAD_CONST 1 (1) 4 COMPARE_OP 2 (==) -@@ -161,21 +44,8 @@ +@@ -161,21 +61,8 @@ 8 STORE_ATTR 0 (x) 10 LOAD_CONST 0 (None) 12 RETURN_VALUE @@ -403,7 +408,24 @@ class C: ```py class C: def test(self) -> None: - NOT_YET_IMPLEMENTED_StmtWith + with NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg): + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) + for i in (a,): + if ( + # Rule 1 + i % 2 == 0 + # Rule 2 + and i % 3 == 0 + ): + while ( + # Just a comment + NOT_IMPLEMENTED_call() + ): + # Another + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) xxxxxxxxxxxxxxxx = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) return ( 'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s' diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@composition_no_trailing_comma.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@composition_no_trailing_comma.py.snap index 30953137ad..21c7c8dc7b 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@composition_no_trailing_comma.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@composition_no_trailing_comma.py.snap @@ -193,7 +193,7 @@ class C: ```diff --- Black +++ Ruff -@@ -1,159 +1,42 @@ +@@ -1,23 +1,10 @@ class C: def test(self) -> None: - with patch("black.out", print): @@ -214,18 +214,22 @@ class C: - "2 files reformatted, 2 files left unchanged, 2 files failed to" - " reformat.", - ) -- for i in (a,): -- if ( -- # Rule 1 -- i % 2 == 0 -- # Rule 2 -- and i % 3 == 0 -- ): -- while ( -- # Just a comment ++ with NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg): ++ NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) ++ NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) ++ NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) ++ NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) + for i in (a,): + if ( + # Rule 1 +@@ -27,133 +14,46 @@ + ): + while ( + # Just a comment - call() - # Another -- ): ++ NOT_IMPLEMENTED_call() + ): - print(i) - xxxxxxxxxxxxxxxx = Yyyy2YyyyyYyyyyy( - push_manager=context.request.resource_manager, @@ -235,7 +239,8 @@ class C: - # Only send the first n items. - items=items[:num_items] - ) -+ NOT_YET_IMPLEMENTED_StmtWith ++ # Another ++ NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) + xxxxxxxxxxxxxxxx = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) return ( 'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s' @@ -371,7 +376,7 @@ class C: %3d 0 LOAD_FAST 1 (x) 2 LOAD_CONST 1 (1) 4 COMPARE_OP 2 (==) -@@ -161,21 +44,8 @@ +@@ -161,21 +61,8 @@ 8 STORE_ATTR 0 (x) 10 LOAD_CONST 0 (None) 12 RETURN_VALUE @@ -403,7 +408,24 @@ class C: ```py class C: def test(self) -> None: - NOT_YET_IMPLEMENTED_StmtWith + with NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg): + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) + for i in (a,): + if ( + # Rule 1 + i % 2 == 0 + # Rule 2 + and i % 3 == 0 + ): + while ( + # Just a comment + NOT_IMPLEMENTED_call() + ): + # Another + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) xxxxxxxxxxxxxxxx = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) return ( 'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s' diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@expression.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@expression.py.snap index 47e1d61f92..0b3a703534 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@expression.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@expression.py.snap @@ -353,10 +353,10 @@ last_call() - 5, -] +[1, 2, 3] -+[NOT_YET_IMPLEMENTED_ExprStarred] -+[NOT_YET_IMPLEMENTED_ExprStarred] -+[NOT_YET_IMPLEMENTED_ExprStarred, 4, 5] -+[4, NOT_YET_IMPLEMENTED_ExprStarred, 5] ++[*NOT_YET_IMPLEMENTED_ExprStarred] ++[*NOT_YET_IMPLEMENTED_ExprStarred] ++[*NOT_YET_IMPLEMENTED_ExprStarred, 4, 5] ++[4, *NOT_YET_IMPLEMENTED_ExprStarred, 5] [ - 4, - *a, @@ -367,7 +367,7 @@ last_call() element, another, - *more, -+ NOT_YET_IMPLEMENTED_ExprStarred, ++ *NOT_YET_IMPLEMENTED_ExprStarred, ] -{i for i in (1, 2, 3)} -{(i**2) for i in (1, 2, 3)} @@ -512,7 +512,7 @@ last_call() +(i for i in []) +(i for i in []) +(i for i in []) -+(NOT_YET_IMPLEMENTED_ExprStarred,) ++(*NOT_YET_IMPLEMENTED_ExprStarred,) { "id": "1", "type": "type", @@ -544,8 +544,8 @@ last_call() - .order_by(models.Customer.id.asc()) - .all() +e = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) -+f = 1, NOT_YET_IMPLEMENTED_ExprStarred -+g = 1, NOT_YET_IMPLEMENTED_ExprStarred ++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_arg)) + + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) @@ -756,15 +756,15 @@ 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)] [1, 2, 3] -[NOT_YET_IMPLEMENTED_ExprStarred] -[NOT_YET_IMPLEMENTED_ExprStarred] -[NOT_YET_IMPLEMENTED_ExprStarred, 4, 5] -[4, NOT_YET_IMPLEMENTED_ExprStarred, 5] +[*NOT_YET_IMPLEMENTED_ExprStarred] +[*NOT_YET_IMPLEMENTED_ExprStarred] +[*NOT_YET_IMPLEMENTED_ExprStarred, 4, 5] +[4, *NOT_YET_IMPLEMENTED_ExprStarred, 5] [ this_is_a_very_long_variable_which_will_force_a_delimiter_split, element, another, - NOT_YET_IMPLEMENTED_ExprStarred, + *NOT_YET_IMPLEMENTED_ExprStarred, ] {NOT_IMPLEMENTED_set_value for value in NOT_IMPLEMENTED_set} {NOT_IMPLEMENTED_set_value for value in NOT_IMPLEMENTED_set} @@ -856,7 +856,7 @@ SomeName (i for i in []) (i for i in []) (i for i in []) -(NOT_YET_IMPLEMENTED_ExprStarred,) +(*NOT_YET_IMPLEMENTED_ExprStarred,) { "id": "1", "type": "type", @@ -871,8 +871,8 @@ b = (1,) c = 1 d = (1,) + a + (2,) e = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) -f = 1, NOT_YET_IMPLEMENTED_ExprStarred -g = 1, NOT_YET_IMPLEMENTED_ExprStarred +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_arg)) + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@fmtonoff.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@fmtonoff.py.snap index baf9eaa6af..4e210b4109 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@fmtonoff.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@fmtonoff.py.snap @@ -352,7 +352,7 @@ d={'a':1, # fmt: off - a , b = *hello - 'unformatted' -+ a, b = NOT_YET_IMPLEMENTED_ExprStarred ++ a, b = *NOT_YET_IMPLEMENTED_ExprStarred + "unformatted" # fmt: on @@ -607,7 +607,7 @@ def import_as_names(): def testlist_star_expr(): # fmt: off - a, b = NOT_YET_IMPLEMENTED_ExprStarred + a, b = *NOT_YET_IMPLEMENTED_ExprStarred "unformatted" # fmt: on diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@fmtskip8.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@fmtskip8.py.snap index 8e54712280..5e791205c3 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@fmtskip8.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@fmtskip8.py.snap @@ -74,7 +74,7 @@ async def test_async_with(): ```diff --- Black +++ Ruff -@@ -1,62 +1,54 @@ +@@ -1,62 +1,55 @@ # Make sure a leading comment is not removed. -def some_func( unformatted, args ): # fmt: skip - print("I am some_func") @@ -155,7 +155,8 @@ async def test_async_with(): -with give_me_context( unformatted, args ): # fmt: skip - print("Do something") -+NOT_YET_IMPLEMENTED_StmtWith # fmt: skip ++with NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg): # fmt: skip ++ NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) async def test_async_with(): @@ -216,7 +217,8 @@ async def test_async_for(): NOT_YET_IMPLEMENTED_StmtTry -NOT_YET_IMPLEMENTED_StmtWith # fmt: skip +with NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg): # fmt: skip + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) async def test_async_with(): diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@function2.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@function2.py.snap index d70e4ac234..fe0456ee1f 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@function2.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@function2.py.snap @@ -65,12 +65,13 @@ with hmm_but_this_should_get_two_preceding_newlines(): ```diff --- Black +++ Ruff -@@ -2,17 +2,9 @@ +@@ -2,17 +2,11 @@ a, **kwargs, ) -> A: - with cache_dir(): -- if something: ++ with NOT_IMPLEMENTED_call(): + if something: - result = CliRunner().invoke( - black.main, [str(src1), str(src2), "--diff", "--check"] - ) @@ -80,13 +81,13 @@ with hmm_but_this_should_get_two_preceding_newlines(): - very_long_argument_name2=-very.long.value.for_the_argument, - **kwargs, - ) -+ NOT_YET_IMPLEMENTED_StmtWith ++ result = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) # negate top + return NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) def g(): -@@ -21,45 +13,30 @@ +@@ -21,45 +15,31 @@ def inner(): pass @@ -136,8 +137,8 @@ with hmm_but_this_should_get_two_preceding_newlines(): - -with hmm_but_this_should_get_two_preceding_newlines(): -- pass -+NOT_YET_IMPLEMENTED_StmtWith ++with NOT_IMPLEMENTED_call(): + pass ``` ## Ruff Output @@ -147,7 +148,9 @@ def f( a, **kwargs, ) -> A: - NOT_YET_IMPLEMENTED_StmtWith + with NOT_IMPLEMENTED_call(): + if something: + result = NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) # negate top return NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) @@ -184,7 +187,8 @@ else: def foo(): pass -NOT_YET_IMPLEMENTED_StmtWith +with NOT_IMPLEMENTED_call(): + pass ``` ## Black Output diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@remove_newline_after_code_block_open.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@remove_newline_after_code_block_open.py.snap index 05400a9c8d..fef152f5d3 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@remove_newline_after_code_block_open.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@remove_newline_after_code_block_open.py.snap @@ -120,7 +120,7 @@ with open("/path/to/file.txt", mode="r") as read_file: ```diff --- Black +++ Ruff -@@ -1,78 +1,74 @@ +@@ -1,78 +1,78 @@ -import random +NOT_YET_IMPLEMENTED_StmtImport @@ -214,18 +214,22 @@ with open("/path/to/file.txt", mode="r") as read_file: -with open("/path/to/file.txt", mode="w") as file: - file.write("The new line above me is about to be removed!") -+NOT_YET_IMPLEMENTED_StmtWith ++with NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) as file: ++ NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) -with open("/path/to/file.txt", mode="w") as file: - file.write("The new lines above me is about to be removed!") -+NOT_YET_IMPLEMENTED_StmtWith ++with NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) as file: ++ NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) -with open("/path/to/file.txt", mode="r") as read_file: - with open("/path/to/output_file.txt", mode="w") as write_file: - write_file.writelines(read_file.readlines()) -+NOT_YET_IMPLEMENTED_StmtWith ++with NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) as read_file: ++ with NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) as write_file: ++ NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) ``` ## Ruff Output @@ -298,13 +302,17 @@ while True: NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) -NOT_YET_IMPLEMENTED_StmtWith +with NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) as file: + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) -NOT_YET_IMPLEMENTED_StmtWith +with NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) as file: + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) -NOT_YET_IMPLEMENTED_StmtWith +with NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) as read_file: + with NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) as write_file: + NOT_IMPLEMENTED_call(NOT_IMPLEMENTED_arg) ``` ## Black Output diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__with.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__with.py.snap new file mode 100644 index 0000000000..3eb2c3ee7a --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__with.py.snap @@ -0,0 +1,132 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/with.py +--- +## Input +```py +with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: + ... + # trailing + +with a, a: # after colon + ... + # trailing + +with ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, +): + ... + # trailing + + +with ( + a # a + , # comma + b # c + ): # colon + ... + + +with ( + a # a + as # as + b # b + , # comma + c # c + ): # colon + ... # body + # body trailing own + + +with (a,): # magic trailing comma + ... + + +with (a): # should remove brackets + ... + +# TODO: black doesn't wrap this, but maybe we want to anyway? +# if we do want to wrap, do we prefer to wrap the entire WithItem or to let the +# WithItem allow the `aa + bb` content expression to be wrapped +with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb as c: + ... + + +# currently unparsable by black: https://github.com/psf/black/issues/3678 +with (name_2 for name_0 in name_4): + pass +with (a, *b): + pass +``` + +## Output +```py +with ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, +): + ... + # trailing + +with a, a: # after colon + ... + # trailing + +with ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, +): + ... + # trailing + + +with ( + ( + a # a # comma + ), + b, # c +): # colon + ... + + +with ( + ( + a # a # as + ) as b, # b # comma + c, # c +): # colon + ... # body + # body trailing own + + +with ( + a, +): # magic trailing comma + ... + + +with a: # should remove brackets + ... + +# TODO: black doesn't wrap this, but maybe we want to anyway? +# if we do want to wrap, do we prefer to wrap the entire WithItem or to let the +# WithItem allow the `aa + bb` content expression to be wrapped +with ( + ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + ) as c, +): + ... + + +# currently unparsable by black: https://github.com/psf/black/issues/3678 +with (i for i in []): + pass +with (a, *NOT_YET_IMPLEMENTED_ExprStarred): + pass +``` + + +