From 68969240c5ad63b79dc8763d4cb0282fd178d4ba Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Thu, 8 Jun 2023 18:07:33 +0200 Subject: [PATCH] Format Function definitions (#4951) --- crates/ruff_python_ast/src/function.rs | 19 ++ crates/ruff_python_formatter/generate.py | 10 +- .../test/fixtures/ruff/statement/function.py | 70 ++++ .../src/comments/format.rs | 5 +- .../ruff_python_formatter/src/comments/mod.rs | 10 +- .../src/comments/placement.rs | 42 ++- ...g_comment_after_single_statement_body.snap | 12 +- .../src/comments/visitor.rs | 7 + .../src/expression/expr_attribute.rs | 10 +- .../src/expression/expr_await.rs | 10 +- .../src/expression/expr_bin_op.rs | 11 +- .../src/expression/expr_bool_op.rs | 10 +- .../src/expression/expr_call.rs | 10 +- .../src/expression/expr_compare.rs | 10 +- .../src/expression/expr_constant.rs | 13 +- .../src/expression/expr_dict.rs | 10 +- .../src/expression/expr_dict_comp.rs | 10 +- .../src/expression/expr_formatted_value.rs | 10 +- .../src/expression/expr_generator_exp.rs | 10 +- .../src/expression/expr_if_exp.rs | 10 +- .../src/expression/expr_joined_str.rs | 10 +- .../src/expression/expr_lambda.rs | 10 +- .../src/expression/expr_list.rs | 11 +- .../src/expression/expr_list_comp.rs | 10 +- .../src/expression/expr_name.rs | 10 +- .../src/expression/expr_named_expr.rs | 10 +- .../src/expression/expr_set.rs | 10 +- .../src/expression/expr_set_comp.rs | 10 +- .../src/expression/expr_slice.rs | 10 +- .../src/expression/expr_starred.rs | 10 +- .../src/expression/expr_subscript.rs | 10 +- .../src/expression/expr_tuple.rs | 10 +- .../src/expression/expr_unary_op.rs | 10 +- .../src/expression/expr_yield.rs | 10 +- .../src/expression/expr_yield_from.rs | 10 +- .../src/expression/mod.rs | 68 ++-- .../src/expression/parentheses.rs | 18 +- crates/ruff_python_formatter/src/generated.rs | 32 ++ crates/ruff_python_formatter/src/lib.rs | 12 +- crates/ruff_python_formatter/src/other/arg.rs | 62 +++- .../src/other/arguments.rs | 185 ++++++++++- .../src/other/decorator.rs | 25 ++ crates/ruff_python_formatter/src/other/mod.rs | 1 + ...lack_test__class_blank_parentheses_py.snap | 21 +- ...est__comment_after_escaped_newline_py.snap | 20 +- ...tter__tests__black_test__comments2_py.snap | 73 +++-- ...tter__tests__black_test__comments3_py.snap | 25 +- ...tter__tests__black_test__comments4_py.snap | 38 ++- ...tter__tests__black_test__comments5_py.snap | 88 +++-- ...tter__tests__black_test__comments6_py.snap | 184 ++++++----- ...tter__tests__black_test__comments9_py.snap | 196 +++++------ ..._test__comments_non_breaking_space_py.snap | 18 +- ...atter__tests__black_test__comments_py.snap | 79 +++-- ...sts__black_test__docstring_preview_py.snap | 80 +++-- ...tter__tests__black_test__docstring_py.snap | 296 +++++++++-------- ...er__tests__black_test__empty_lines_py.snap | 89 +++-- ...ter__tests__black_test__expression_py.snap | 30 +- ...tter__tests__black_test__fmtonoff2_py.snap | 63 ++-- ...tter__tests__black_test__fmtonoff4_py.snap | 25 +- ...tter__tests__black_test__fmtonoff5_py.snap | 32 +- ...atter__tests__black_test__fmtonoff_py.snap | 306 +++++++++++++----- ...atter__tests__black_test__fmtskip8_py.snap | 42 ++- ...tter__tests__black_test__function2_py.snap | 80 +++-- ...atter__tests__black_test__function_py.snap | 182 ++++++++--- ...lack_test__function_trailing_comma_py.snap | 99 +++--- ...ests__black_test__power_op_spacing_py.snap | 25 +- ...s__black_test__remove_await_parens_py.snap | 135 ++++---- ...move_newline_after_code_block_open_py.snap | 45 +-- ...__tests__black_test__remove_parens_py.snap | 85 ++--- ...k_test__return_annotation_brackets_py.snap | 215 +++++------- ...rmatter__tests__black_test__slices_py.snap | 9 +- ...tests__black_test__string_prefixes_py.snap | 16 +- ...matter__tests__black_test__torture_py.snap | 9 +- ...__trailing_commas_in_leading_parts_py.snap | 9 +- ...ts__ruff_test__statement__function_py.snap | 182 +++++++++++ ..._ruff_test__statement__stmt_assign_py.snap | 8 +- .../src/statement/stmt_async_function_def.rs | 16 +- .../src/statement/stmt_function_def.rs | 137 +++++++- .../src/statement/suite.rs | 26 +- 79 files changed, 2607 insertions(+), 1229 deletions(-) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/function.py create mode 100644 crates/ruff_python_formatter/src/other/decorator.rs create mode 100644 crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__statement__function_py.snap diff --git a/crates/ruff_python_ast/src/function.rs b/crates/ruff_python_ast/src/function.rs index 924e729248aef..b9de7613dc146 100644 --- a/crates/ruff_python_ast/src/function.rs +++ b/crates/ruff_python_ast/src/function.rs @@ -112,3 +112,22 @@ impl<'a> From<&'a StmtAsyncFunctionDef> for AnyFunctionDefinition<'a> { Self::AsyncFunctionDefinition(value) } } + +impl<'a> From> for AnyNodeRef<'a> { + fn from(value: AnyFunctionDefinition<'a>) -> Self { + match value { + AnyFunctionDefinition::FunctionDefinition(function_def) => { + AnyNodeRef::StmtFunctionDef(function_def) + } + AnyFunctionDefinition::AsyncFunctionDefinition(async_def) => { + AnyNodeRef::StmtAsyncFunctionDef(async_def) + } + } + } +} + +impl<'a> From<&'a AnyFunctionDefinition<'a>> for AnyNodeRef<'a> { + fn from(value: &'a AnyFunctionDefinition<'a>) -> Self { + (*value).into() + } +} diff --git a/crates/ruff_python_formatter/generate.py b/crates/ruff_python_formatter/generate.py index 272b0e73160b4..f4e83d2edf90f 100644 --- a/crates/ruff_python_formatter/generate.py +++ b/crates/ruff_python_formatter/generate.py @@ -77,6 +77,11 @@ def to_camel_case(node: str) -> str: # ) # src.joinpath(groups[group]).joinpath("mod.rs").write_text(rustfmt(mod_section)) for node in group_nodes: + node_path = src.joinpath(groups[group]).joinpath(f"{to_camel_case(node)}.rs") + # Don't override existing manual implementations + if node_path.exists(): + continue + code = f""" use crate::{{verbatim_text, FormatNodeRule, PyFormatter}}; use ruff_formatter::{{write, Buffer, FormatResult}}; @@ -91,9 +96,8 @@ def to_camel_case(node: str) -> str: }} }} """.strip() # noqa: E501 - src.joinpath(groups[group]).joinpath(f"{to_camel_case(node)}.rs").write_text( - rustfmt(code) - ) + + node_path.write_text(rustfmt(code)) # %% # Generate `FormatRule`, `AsFormat` and `IntoFormat` diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/function.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/function.py new file mode 100644 index 0000000000000..7e4ddaa48b76d --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/function.py @@ -0,0 +1,70 @@ +# Dangling comments +def test( + # comment + + # another + +): ... + + +# Argument empty line spacing +def test( + # comment + a, + + # another + + b, +): ... + + +### Different function argument wrappings + +def single_line(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccccccccc): + pass + +def arguments_on_their_own_line(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccc, ddddddddddddd, eeeeeee): + pass + +def argument_per_line(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccccccccc, ddddddddddddd, eeeeeeeeeeeeeeee, ffffffffffff): + pass + +def last_pos_only_trailing_comma(a, b, /,): + pass + +def last_pos_no_trailing_comma(a, b, /): + pass + + +def varg_with_leading_comments( + a, b, + # comment + *args +): ... + +def kwarg_with_leading_comments( + a, b, + # comment + **kwargs +): ... + +def argument_with_long_default( + a, + b = ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc + [ + dddddddddddddddddddd, eeeeeeeeeeeeeeeeeeee, ffffffffffffffffffffffff + ], + h = [] +): ... + + +def argument_with_long_type_annotation( + a, + b: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy | zzzzzzzzzzzzzzzzzzz = [0, 1, 2, 3], + h = [] +): ... + + +def test(): ... + +# Comment +def with_leading_comment(): ... diff --git a/crates/ruff_python_formatter/src/comments/format.rs b/crates/ruff_python_formatter/src/comments/format.rs index 44e77de3d4f08..7c57709503256 100644 --- a/crates/ruff_python_formatter/src/comments/format.rs +++ b/crates/ruff_python_formatter/src/comments/format.rs @@ -1,7 +1,7 @@ use crate::comments::SourceComment; use crate::context::NodeLevel; use crate::prelude::*; -use crate::trivia::{lines_after, lines_before}; +use crate::trivia::{lines_after, lines_before, skip_trailing_trivia}; use ruff_formatter::{format_args, write, FormatError, SourceCode}; use ruff_python_ast::node::AnyNodeRef; use ruff_python_ast::prelude::AstNode; @@ -86,9 +86,10 @@ impl Format> for FormatLeadingAlternateBranchComments<'_> { write!(f, [leading_comments(self.comments)])?; } else if let Some(last_preceding) = self.last_node { + let full_end = skip_trailing_trivia(last_preceding.end(), f.context().contents()); // The leading comments formatting ensures that it preserves the right amount of lines after // We need to take care of this ourselves, if there's no leading `else` comment. - if lines_after(last_preceding.end(), f.context().contents()) > 1 { + if lines_after(full_end, f.context().contents()) > 1 { write!(f, [empty_line()])?; } } diff --git a/crates/ruff_python_formatter/src/comments/mod.rs b/crates/ruff_python_formatter/src/comments/mod.rs index 6822efb461b23..9267cdd899448 100644 --- a/crates/ruff_python_formatter/src/comments/mod.rs +++ b/crates/ruff_python_formatter/src/comments/mod.rs @@ -103,7 +103,7 @@ use crate::comments::map::MultiMap; use crate::comments::node_key::NodeRefEqualityKey; use crate::comments::visitor::CommentsVisitor; pub(crate) use format::{ - dangling_comments, dangling_node_comments, leading_alternate_branch_comments, + dangling_comments, dangling_node_comments, leading_alternate_branch_comments, leading_comments, leading_node_comments, trailing_comments, trailing_node_comments, }; use ruff_formatter::{SourceCode, SourceCodeSlice}; @@ -295,6 +295,14 @@ impl<'a> Comments<'a> { !self.trailing_comments(node).is_empty() } + /// Returns `true` if the given `node` has any [trailing own line comments](self#trailing-comments). + #[inline] + pub(crate) fn has_trailing_own_line_comments(&self, node: AnyNodeRef) -> bool { + self.trailing_comments(node) + .iter() + .any(|comment| comment.position().is_own_line()) + } + /// Returns an iterator over the [leading](self#leading-comments) and [trailing comments](self#trailing-comments) of `node`. pub(crate) fn leading_trailing_comments( &self, diff --git a/crates/ruff_python_formatter/src/comments/placement.rs b/crates/ruff_python_formatter/src/comments/placement.rs index 7ba015a2d0032..10a9db7baa594 100644 --- a/crates/ruff_python_formatter/src/comments/placement.rs +++ b/crates/ruff_python_formatter/src/comments/placement.rs @@ -28,6 +28,7 @@ pub(super) fn place_comment<'a>( .or_else(|comment| { handle_trailing_binary_expression_left_or_operator_comment(comment, locator) }) + .or_else(handle_leading_function_with_decorators_comment) } /// Handles leading comments in front of a match case or a trailing comment of the `match` statement. @@ -103,9 +104,8 @@ fn handle_match_comment<'a>( } } else { // Comment after the last statement in a match case... - let match_stmt_indentation = whitespace::indentation(locator, match_stmt) - .unwrap_or_default() - .len(); + let match_stmt_indentation = + whitespace::indentation(locator, match_stmt).map_or(usize::MAX, str::len); if comment_indentation <= match_case_indentation && comment_indentation > match_stmt_indentation @@ -379,9 +379,8 @@ fn handle_trailing_body_comment<'a>( let mut grand_parent_body = None; loop { - let child_indentation = whitespace::indentation(locator, ¤t_child) - .map(str::len) - .unwrap_or_default(); + let child_indentation = + whitespace::indentation(locator, ¤t_child).map_or(usize::MAX, str::len); match comment_indentation_len.cmp(&child_indentation) { Ordering::Less => { @@ -511,6 +510,11 @@ fn handle_trailing_end_of_line_condition_comment<'a>( | AnyNodeRef::StmtAsyncWith(StmtAsyncWith { items, .. }) => { items.last().map(AnyNodeRef::from) } + AnyNodeRef::StmtFunctionDef(StmtFunctionDef { returns, args, .. }) + | AnyNodeRef::StmtAsyncFunctionDef(StmtAsyncFunctionDef { returns, args, .. }) => returns + .as_deref() + .map(AnyNodeRef::from) + .or_else(|| Some(AnyNodeRef::from(args.as_ref()))), _ => None, }; @@ -820,6 +824,32 @@ fn find_pos_only_slash_offset( None } +/// Handles own line comments between the last function decorator and the *header* of the function. +/// It attaches these comments as dangling comments to the function instead of making them +/// leading argument comments. +/// +/// ```python +/// @decorator +/// # leading function comment +/// def test(): +/// ... +/// ``` +fn handle_leading_function_with_decorators_comment(comment: DecoratedComment) -> CommentPlacement { + let is_preceding_decorator = comment + .preceding_node() + .map_or(false, |node| node.is_decorator()); + + let is_following_arguments = comment + .following_node() + .map_or(false, |node| node.is_arguments()); + + if comment.text_position().is_own_line() && is_preceding_decorator && is_following_arguments { + CommentPlacement::dangling(comment.enclosing_node(), comment) + } else { + CommentPlacement::Default(comment) + } +} + /// Returns `true` if `right` is `Some` and `left` and `right` are referentially equal. fn are_same_optional<'a, T>(left: AnyNodeRef, right: Option) -> bool where diff --git a/crates/ruff_python_formatter/src/comments/snapshots/ruff_python_formatter__comments__tests__trailing_comment_after_single_statement_body.snap b/crates/ruff_python_formatter/src/comments/snapshots/ruff_python_formatter__comments__tests__trailing_comment_after_single_statement_body.snap index 62b0b6652b643..de19a920624b7 100644 --- a/crates/ruff_python_formatter/src/comments/snapshots/ruff_python_formatter__comments__tests__trailing_comment_after_single_statement_body.snap +++ b/crates/ruff_python_formatter/src/comments/snapshots/ruff_python_formatter__comments__tests__trailing_comment_after_single_statement_body.snap @@ -4,18 +4,18 @@ expression: comments.debug(test_case.source_code) --- { Node { - kind: StmtPass, - range: 12..16, - source: `pass`, + kind: StmtExpr, + range: 29..42, + source: `print("test")`, }: { - "leading": [], - "dangling": [], - "trailing": [ + "leading": [ SourceComment { text: "# Test", position: OwnLine, formatted: false, }, ], + "dangling": [], + "trailing": [], }, } diff --git a/crates/ruff_python_formatter/src/comments/visitor.rs b/crates/ruff_python_formatter/src/comments/visitor.rs index fa1901a41cbcf..d0aef540df4e3 100644 --- a/crates/ruff_python_formatter/src/comments/visitor.rs +++ b/crates/ruff_python_formatter/src/comments/visitor.rs @@ -165,6 +165,13 @@ impl<'ast> PreorderVisitor<'ast> for CommentsVisitor<'ast> { self.finish_node(expr); } + fn visit_decorator(&mut self, decorator: &'ast Decorator) { + if self.start_node(decorator).is_traverse() { + walk_decorator(self, decorator); + } + self.finish_node(decorator); + } + fn visit_expr(&mut self, expr: &'ast Expr) { if self.start_node(expr).is_traverse() { walk_expr(self, expr); diff --git a/crates/ruff_python_formatter/src/expression/expr_attribute.rs b/crates/ruff_python_formatter/src/expression/expr_attribute.rs index 31ca2c9a32a6a..9732025e3563b 100644 --- a/crates/ruff_python_formatter/src/expression/expr_attribute.rs +++ b/crates/ruff_python_formatter/src/expression/expr_attribute.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -39,7 +40,12 @@ impl FormatNodeRule for FormatExprAttribute { } impl NeedsParentheses for ExprAttribute { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - default_expression_needs_parentheses(self.into(), parenthesize, source) + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + default_expression_needs_parentheses(self.into(), parenthesize, source, comments) } } diff --git a/crates/ruff_python_formatter/src/expression/expr_await.rs b/crates/ruff_python_formatter/src/expression/expr_await.rs index 068677ba1fb01..19c6bf5196a5e 100644 --- a/crates/ruff_python_formatter/src/expression/expr_await.rs +++ b/crates/ruff_python_formatter/src/expression/expr_await.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -17,7 +18,12 @@ impl FormatNodeRule for FormatExprAwait { } impl NeedsParentheses for ExprAwait { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - default_expression_needs_parentheses(self.into(), parenthesize, source) + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + default_expression_needs_parentheses(self.into(), parenthesize, source, comments) } } 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 7499b4e4f730e..1016895c2a220 100644 --- a/crates/ruff_python_formatter/src/expression/expr_bin_op.rs +++ b/crates/ruff_python_formatter/src/expression/expr_bin_op.rs @@ -1,4 +1,4 @@ -use crate::comments::trailing_comments; +use crate::comments::{trailing_comments, Comments}; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parenthesize, }; @@ -171,8 +171,13 @@ impl FormatRule> for FormatOperator { } impl NeedsParentheses for ExprBinOp { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - match default_expression_needs_parentheses(self.into(), parenthesize, source) { + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + match default_expression_needs_parentheses(self.into(), parenthesize, source, comments) { Parentheses::Optional => { if should_binary_break_right_side_first(self) { Parentheses::Custom diff --git a/crates/ruff_python_formatter/src/expression/expr_bool_op.rs b/crates/ruff_python_formatter/src/expression/expr_bool_op.rs index 41ebc548965d0..e97594902900c 100644 --- a/crates/ruff_python_formatter/src/expression/expr_bool_op.rs +++ b/crates/ruff_python_formatter/src/expression/expr_bool_op.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -20,7 +21,12 @@ impl FormatNodeRule for FormatExprBoolOp { } impl NeedsParentheses for ExprBoolOp { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - default_expression_needs_parentheses(self.into(), parenthesize, source) + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + default_expression_needs_parentheses(self.into(), parenthesize, source, comments) } } diff --git a/crates/ruff_python_formatter/src/expression/expr_call.rs b/crates/ruff_python_formatter/src/expression/expr_call.rs index 4338619cc8e1e..3f73b6cbbdac8 100644 --- a/crates/ruff_python_formatter/src/expression/expr_call.rs +++ b/crates/ruff_python_formatter/src/expression/expr_call.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -18,8 +19,13 @@ impl FormatNodeRule for FormatExprCall { } impl NeedsParentheses for ExprCall { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - match default_expression_needs_parentheses(self.into(), parenthesize, source) { + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + match default_expression_needs_parentheses(self.into(), parenthesize, source, comments) { Parentheses::Optional => Parentheses::Never, parentheses => parentheses, } diff --git a/crates/ruff_python_formatter/src/expression/expr_compare.rs b/crates/ruff_python_formatter/src/expression/expr_compare.rs index 428f3ed1ce231..54c5301e85101 100644 --- a/crates/ruff_python_formatter/src/expression/expr_compare.rs +++ b/crates/ruff_python_formatter/src/expression/expr_compare.rs @@ -3,6 +3,7 @@ use crate::expression::parentheses::{ }; use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter}; +use crate::comments::Comments; use ruff_formatter::{write, Buffer, FormatResult}; use rustpython_parser::ast::ExprCompare; @@ -21,7 +22,12 @@ impl FormatNodeRule for FormatExprCompare { } impl NeedsParentheses for ExprCompare { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - default_expression_needs_parentheses(self.into(), parenthesize, source) + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + default_expression_needs_parentheses(self.into(), parenthesize, source, comments) } } diff --git a/crates/ruff_python_formatter/src/expression/expr_constant.rs b/crates/ruff_python_formatter/src/expression/expr_constant.rs index 1579ed5b5cf6b..90ee45c1cf731 100644 --- a/crates/ruff_python_formatter/src/expression/expr_constant.rs +++ b/crates/ruff_python_formatter/src/expression/expr_constant.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -41,7 +42,15 @@ impl FormatNodeRule for FormatExprConstant { } impl NeedsParentheses for ExprConstant { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - default_expression_needs_parentheses(self.into(), parenthesize, source) + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + match default_expression_needs_parentheses(self.into(), parenthesize, source, comments) { + Parentheses::Optional => Parentheses::Never, + parentheses => parentheses, + } } } diff --git a/crates/ruff_python_formatter/src/expression/expr_dict.rs b/crates/ruff_python_formatter/src/expression/expr_dict.rs index 6f173b26ab7f9..600841f2da060 100644 --- a/crates/ruff_python_formatter/src/expression/expr_dict.rs +++ b/crates/ruff_python_formatter/src/expression/expr_dict.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -20,8 +21,13 @@ impl FormatNodeRule for FormatExprDict { } impl NeedsParentheses for ExprDict { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - match default_expression_needs_parentheses(self.into(), parenthesize, source) { + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + match default_expression_needs_parentheses(self.into(), parenthesize, source, comments) { Parentheses::Optional => Parentheses::Never, parentheses => parentheses, } diff --git a/crates/ruff_python_formatter/src/expression/expr_dict_comp.rs b/crates/ruff_python_formatter/src/expression/expr_dict_comp.rs index 6a3337f573e39..4121acb76afc2 100644 --- a/crates/ruff_python_formatter/src/expression/expr_dict_comp.rs +++ b/crates/ruff_python_formatter/src/expression/expr_dict_comp.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -20,8 +21,13 @@ impl FormatNodeRule for FormatExprDictComp { } impl NeedsParentheses for ExprDictComp { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - match default_expression_needs_parentheses(self.into(), parenthesize, source) { + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + match default_expression_needs_parentheses(self.into(), parenthesize, source, comments) { Parentheses::Optional => Parentheses::Never, parentheses => parentheses, } diff --git a/crates/ruff_python_formatter/src/expression/expr_formatted_value.rs b/crates/ruff_python_formatter/src/expression/expr_formatted_value.rs index 9578106113eb0..ef2551de32153 100644 --- a/crates/ruff_python_formatter/src/expression/expr_formatted_value.rs +++ b/crates/ruff_python_formatter/src/expression/expr_formatted_value.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -15,7 +16,12 @@ impl FormatNodeRule for FormatExprFormattedValue { } impl NeedsParentheses for ExprFormattedValue { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - default_expression_needs_parentheses(self.into(), parenthesize, source) + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + default_expression_needs_parentheses(self.into(), parenthesize, source, comments) } } diff --git a/crates/ruff_python_formatter/src/expression/expr_generator_exp.rs b/crates/ruff_python_formatter/src/expression/expr_generator_exp.rs index 2cf35598eabe7..54762794e3371 100644 --- a/crates/ruff_python_formatter/src/expression/expr_generator_exp.rs +++ b/crates/ruff_python_formatter/src/expression/expr_generator_exp.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -15,8 +16,13 @@ impl FormatNodeRule for FormatExprGeneratorExp { } impl NeedsParentheses for ExprGeneratorExp { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - match default_expression_needs_parentheses(self.into(), parenthesize, source) { + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + match default_expression_needs_parentheses(self.into(), parenthesize, source, comments) { Parentheses::Optional => Parentheses::Never, parentheses => parentheses, } diff --git a/crates/ruff_python_formatter/src/expression/expr_if_exp.rs b/crates/ruff_python_formatter/src/expression/expr_if_exp.rs index e60ebbf8f0a73..980571d853f0a 100644 --- a/crates/ruff_python_formatter/src/expression/expr_if_exp.rs +++ b/crates/ruff_python_formatter/src/expression/expr_if_exp.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -20,7 +21,12 @@ impl FormatNodeRule for FormatExprIfExp { } impl NeedsParentheses for ExprIfExp { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - default_expression_needs_parentheses(self.into(), parenthesize, source) + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + default_expression_needs_parentheses(self.into(), parenthesize, source, comments) } } diff --git a/crates/ruff_python_formatter/src/expression/expr_joined_str.rs b/crates/ruff_python_formatter/src/expression/expr_joined_str.rs index 86194c9b2b308..a13ff5f38971d 100644 --- a/crates/ruff_python_formatter/src/expression/expr_joined_str.rs +++ b/crates/ruff_python_formatter/src/expression/expr_joined_str.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -15,7 +16,12 @@ impl FormatNodeRule for FormatExprJoinedStr { } impl NeedsParentheses for ExprJoinedStr { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - default_expression_needs_parentheses(self.into(), parenthesize, source) + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + default_expression_needs_parentheses(self.into(), parenthesize, source, comments) } } diff --git a/crates/ruff_python_formatter/src/expression/expr_lambda.rs b/crates/ruff_python_formatter/src/expression/expr_lambda.rs index c1310de391f53..bd63bfa0f63b9 100644 --- a/crates/ruff_python_formatter/src/expression/expr_lambda.rs +++ b/crates/ruff_python_formatter/src/expression/expr_lambda.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -15,7 +16,12 @@ impl FormatNodeRule for FormatExprLambda { } impl NeedsParentheses for ExprLambda { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - default_expression_needs_parentheses(self.into(), parenthesize, source) + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + default_expression_needs_parentheses(self.into(), parenthesize, source, comments) } } diff --git a/crates/ruff_python_formatter/src/expression/expr_list.rs b/crates/ruff_python_formatter/src/expression/expr_list.rs index 869542621e7cf..20153d8aa7868 100644 --- a/crates/ruff_python_formatter/src/expression/expr_list.rs +++ b/crates/ruff_python_formatter/src/expression/expr_list.rs @@ -1,4 +1,4 @@ -use crate::comments::dangling_comments; +use crate::comments::{dangling_comments, Comments}; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -57,8 +57,13 @@ impl FormatNodeRule for FormatExprList { } impl NeedsParentheses for ExprList { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - match default_expression_needs_parentheses(self.into(), parenthesize, source) { + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + match default_expression_needs_parentheses(self.into(), parenthesize, source, comments) { Parentheses::Optional => Parentheses::Never, parentheses => parentheses, } diff --git a/crates/ruff_python_formatter/src/expression/expr_list_comp.rs b/crates/ruff_python_formatter/src/expression/expr_list_comp.rs index 8fddfa5457849..3ab6a61f06e00 100644 --- a/crates/ruff_python_formatter/src/expression/expr_list_comp.rs +++ b/crates/ruff_python_formatter/src/expression/expr_list_comp.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -15,8 +16,13 @@ impl FormatNodeRule for FormatExprListComp { } impl NeedsParentheses for ExprListComp { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - match default_expression_needs_parentheses(self.into(), parenthesize, source) { + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + match default_expression_needs_parentheses(self.into(), parenthesize, source, comments) { Parentheses::Optional => Parentheses::Never, parentheses => parentheses, } diff --git a/crates/ruff_python_formatter/src/expression/expr_name.rs b/crates/ruff_python_formatter/src/expression/expr_name.rs index 57ad099c38c78..25673494818c8 100644 --- a/crates/ruff_python_formatter/src/expression/expr_name.rs +++ b/crates/ruff_python_formatter/src/expression/expr_name.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -26,8 +27,13 @@ impl FormatNodeRule for FormatExprName { } impl NeedsParentheses for ExprName { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - default_expression_needs_parentheses(self.into(), parenthesize, source) + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + default_expression_needs_parentheses(self.into(), parenthesize, source, comments) } } diff --git a/crates/ruff_python_formatter/src/expression/expr_named_expr.rs b/crates/ruff_python_formatter/src/expression/expr_named_expr.rs index 4cf013217d0cc..71d2bae891053 100644 --- a/crates/ruff_python_formatter/src/expression/expr_named_expr.rs +++ b/crates/ruff_python_formatter/src/expression/expr_named_expr.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -15,7 +16,12 @@ impl FormatNodeRule for FormatExprNamedExpr { } impl NeedsParentheses for ExprNamedExpr { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - default_expression_needs_parentheses(self.into(), parenthesize, source) + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + default_expression_needs_parentheses(self.into(), parenthesize, source, comments) } } diff --git a/crates/ruff_python_formatter/src/expression/expr_set.rs b/crates/ruff_python_formatter/src/expression/expr_set.rs index e3bf2d8a50476..7e379d1cea4b2 100644 --- a/crates/ruff_python_formatter/src/expression/expr_set.rs +++ b/crates/ruff_python_formatter/src/expression/expr_set.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -34,8 +35,13 @@ impl FormatNodeRule for FormatExprSet { } impl NeedsParentheses for ExprSet { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - match default_expression_needs_parentheses(self.into(), parenthesize, source) { + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + match default_expression_needs_parentheses(self.into(), parenthesize, source, comments) { Parentheses::Optional => Parentheses::Never, parentheses => parentheses, } diff --git a/crates/ruff_python_formatter/src/expression/expr_set_comp.rs b/crates/ruff_python_formatter/src/expression/expr_set_comp.rs index df3405a2c9d1e..a73ede1c68c17 100644 --- a/crates/ruff_python_formatter/src/expression/expr_set_comp.rs +++ b/crates/ruff_python_formatter/src/expression/expr_set_comp.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -15,8 +16,13 @@ impl FormatNodeRule for FormatExprSetComp { } impl NeedsParentheses for ExprSetComp { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - match default_expression_needs_parentheses(self.into(), parenthesize, source) { + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + match default_expression_needs_parentheses(self.into(), parenthesize, source, comments) { Parentheses::Optional => Parentheses::Never, parentheses => parentheses, } diff --git a/crates/ruff_python_formatter/src/expression/expr_slice.rs b/crates/ruff_python_formatter/src/expression/expr_slice.rs index 35b559f285ccf..529ef4679ba82 100644 --- a/crates/ruff_python_formatter/src/expression/expr_slice.rs +++ b/crates/ruff_python_formatter/src/expression/expr_slice.rs @@ -3,6 +3,7 @@ use crate::expression::parentheses::{ }; use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter}; +use crate::comments::Comments; use ruff_formatter::{write, Buffer, FormatResult}; use rustpython_parser::ast::ExprSlice; @@ -21,7 +22,12 @@ impl FormatNodeRule for FormatExprSlice { } impl NeedsParentheses for ExprSlice { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - default_expression_needs_parentheses(self.into(), parenthesize, source) + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + default_expression_needs_parentheses(self.into(), parenthesize, source, comments) } } diff --git a/crates/ruff_python_formatter/src/expression/expr_starred.rs b/crates/ruff_python_formatter/src/expression/expr_starred.rs index c06a64aaa3f49..14806cb52b7ad 100644 --- a/crates/ruff_python_formatter/src/expression/expr_starred.rs +++ b/crates/ruff_python_formatter/src/expression/expr_starred.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -15,7 +16,12 @@ impl FormatNodeRule for FormatExprStarred { } impl NeedsParentheses for ExprStarred { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - default_expression_needs_parentheses(self.into(), parenthesize, source) + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + default_expression_needs_parentheses(self.into(), parenthesize, source, comments) } } diff --git a/crates/ruff_python_formatter/src/expression/expr_subscript.rs b/crates/ruff_python_formatter/src/expression/expr_subscript.rs index 559f747292d1a..6874b1415a683 100644 --- a/crates/ruff_python_formatter/src/expression/expr_subscript.rs +++ b/crates/ruff_python_formatter/src/expression/expr_subscript.rs @@ -3,6 +3,7 @@ use crate::expression::parentheses::{ }; use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter}; +use crate::comments::Comments; use ruff_formatter::{write, Buffer, FormatResult}; use rustpython_parser::ast::ExprSubscript; @@ -21,7 +22,12 @@ impl FormatNodeRule for FormatExprSubscript { } impl NeedsParentheses for ExprSubscript { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - default_expression_needs_parentheses(self.into(), parenthesize, source) + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + default_expression_needs_parentheses(self.into(), parenthesize, source, comments) } } diff --git a/crates/ruff_python_formatter/src/expression/expr_tuple.rs b/crates/ruff_python_formatter/src/expression/expr_tuple.rs index cc83eb33182c3..ba96180a15ebc 100644 --- a/crates/ruff_python_formatter/src/expression/expr_tuple.rs +++ b/crates/ruff_python_formatter/src/expression/expr_tuple.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -15,8 +16,13 @@ impl FormatNodeRule for FormatExprTuple { } impl NeedsParentheses for ExprTuple { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - match default_expression_needs_parentheses(self.into(), parenthesize, source) { + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + match default_expression_needs_parentheses(self.into(), parenthesize, source, comments) { Parentheses::Optional => Parentheses::Never, parentheses => parentheses, } 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 8df9831255e35..9f91d13e4022d 100644 --- a/crates/ruff_python_formatter/src/expression/expr_unary_op.rs +++ b/crates/ruff_python_formatter/src/expression/expr_unary_op.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -15,7 +16,12 @@ impl FormatNodeRule for FormatExprUnaryOp { } impl NeedsParentheses for ExprUnaryOp { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - default_expression_needs_parentheses(self.into(), parenthesize, source) + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + default_expression_needs_parentheses(self.into(), parenthesize, source, comments) } } diff --git a/crates/ruff_python_formatter/src/expression/expr_yield.rs b/crates/ruff_python_formatter/src/expression/expr_yield.rs index 7e9f27f5da42d..f2ece7ecac66e 100644 --- a/crates/ruff_python_formatter/src/expression/expr_yield.rs +++ b/crates/ruff_python_formatter/src/expression/expr_yield.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -15,7 +16,12 @@ impl FormatNodeRule for FormatExprYield { } impl NeedsParentheses for ExprYield { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - default_expression_needs_parentheses(self.into(), parenthesize, source) + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + default_expression_needs_parentheses(self.into(), parenthesize, source, comments) } } diff --git a/crates/ruff_python_formatter/src/expression/expr_yield_from.rs b/crates/ruff_python_formatter/src/expression/expr_yield_from.rs index 5ed9bd6354667..bfaf10116221c 100644 --- a/crates/ruff_python_formatter/src/expression/expr_yield_from.rs +++ b/crates/ruff_python_formatter/src/expression/expr_yield_from.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::expression::parentheses::{ default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, }; @@ -15,7 +16,12 @@ impl FormatNodeRule for FormatExprYieldFrom { } impl NeedsParentheses for ExprYieldFrom { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { - default_expression_needs_parentheses(self.into(), parenthesize, source) + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { + default_expression_needs_parentheses(self.into(), parenthesize, source, comments) } } diff --git a/crates/ruff_python_formatter/src/expression/mod.rs b/crates/ruff_python_formatter/src/expression/mod.rs index a8059c8b7489e..706c59f29f7ba 100644 --- a/crates/ruff_python_formatter/src/expression/mod.rs +++ b/crates/ruff_python_formatter/src/expression/mod.rs @@ -1,3 +1,4 @@ +use crate::comments::Comments; use crate::context::NodeLevel; use crate::expression::parentheses::{NeedsParentheses, Parentheses, Parenthesize}; use crate::prelude::*; @@ -51,7 +52,11 @@ impl FormatRuleWithOptions> for FormatExpr { impl FormatRule> for FormatExpr { fn fmt(&self, item: &Expr, f: &mut PyFormatter) -> FormatResult<()> { - let parentheses = item.needs_parentheses(self.parenthesize, f.context().contents()); + let parentheses = item.needs_parentheses( + self.parenthesize, + f.context().contents(), + f.context().comments(), + ); let format_expr = format_with(|f| match item { Expr::BoolOp(expr) => expr.format().fmt(f), @@ -118,35 +123,40 @@ impl FormatRule> for FormatExpr { } impl NeedsParentheses for Expr { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses { + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses { match self { - Expr::BoolOp(expr) => expr.needs_parentheses(parenthesize, source), - Expr::NamedExpr(expr) => expr.needs_parentheses(parenthesize, source), - Expr::BinOp(expr) => expr.needs_parentheses(parenthesize, source), - Expr::UnaryOp(expr) => expr.needs_parentheses(parenthesize, source), - Expr::Lambda(expr) => expr.needs_parentheses(parenthesize, source), - Expr::IfExp(expr) => expr.needs_parentheses(parenthesize, source), - Expr::Dict(expr) => expr.needs_parentheses(parenthesize, source), - Expr::Set(expr) => expr.needs_parentheses(parenthesize, source), - Expr::ListComp(expr) => expr.needs_parentheses(parenthesize, source), - Expr::SetComp(expr) => expr.needs_parentheses(parenthesize, source), - Expr::DictComp(expr) => expr.needs_parentheses(parenthesize, source), - Expr::GeneratorExp(expr) => expr.needs_parentheses(parenthesize, source), - Expr::Await(expr) => expr.needs_parentheses(parenthesize, source), - Expr::Yield(expr) => expr.needs_parentheses(parenthesize, source), - Expr::YieldFrom(expr) => expr.needs_parentheses(parenthesize, source), - Expr::Compare(expr) => expr.needs_parentheses(parenthesize, source), - Expr::Call(expr) => expr.needs_parentheses(parenthesize, source), - Expr::FormattedValue(expr) => expr.needs_parentheses(parenthesize, source), - Expr::JoinedStr(expr) => expr.needs_parentheses(parenthesize, source), - Expr::Constant(expr) => expr.needs_parentheses(parenthesize, source), - Expr::Attribute(expr) => expr.needs_parentheses(parenthesize, source), - Expr::Subscript(expr) => expr.needs_parentheses(parenthesize, source), - Expr::Starred(expr) => expr.needs_parentheses(parenthesize, source), - Expr::Name(expr) => expr.needs_parentheses(parenthesize, source), - Expr::List(expr) => expr.needs_parentheses(parenthesize, source), - Expr::Tuple(expr) => expr.needs_parentheses(parenthesize, source), - Expr::Slice(expr) => expr.needs_parentheses(parenthesize, source), + Expr::BoolOp(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::NamedExpr(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::BinOp(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::UnaryOp(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::Lambda(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::IfExp(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::Dict(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::Set(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::ListComp(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::SetComp(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::DictComp(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::GeneratorExp(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::Await(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::Yield(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::YieldFrom(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::Compare(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::Call(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::FormattedValue(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::JoinedStr(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::Constant(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::Attribute(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::Subscript(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::Starred(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::Name(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::List(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::Tuple(expr) => expr.needs_parentheses(parenthesize, source, comments), + Expr::Slice(expr) => expr.needs_parentheses(parenthesize, source, comments), } } } diff --git a/crates/ruff_python_formatter/src/expression/parentheses.rs b/crates/ruff_python_formatter/src/expression/parentheses.rs index 06d599ad2ccae..58d083c8c6f4a 100644 --- a/crates/ruff_python_formatter/src/expression/parentheses.rs +++ b/crates/ruff_python_formatter/src/expression/parentheses.rs @@ -1,15 +1,22 @@ +use crate::comments::Comments; use crate::trivia::{first_non_trivia_token, first_non_trivia_token_rev, Token, TokenKind}; use ruff_python_ast::node::AnyNodeRef; use rustpython_parser::ast::Ranged; pub(crate) trait NeedsParentheses { - fn needs_parentheses(&self, parenthesize: Parenthesize, source: &str) -> Parentheses; + fn needs_parentheses( + &self, + parenthesize: Parenthesize, + source: &str, + comments: &Comments, + ) -> Parentheses; } pub(super) fn default_expression_needs_parentheses( node: AnyNodeRef, parenthesize: Parenthesize, source: &str, + comments: &Comments, ) -> Parentheses { debug_assert!( node.is_expression(), @@ -20,9 +27,14 @@ pub(super) fn default_expression_needs_parentheses( if !parenthesize.is_if_breaks() && is_expression_parenthesized(node, source) { Parentheses::Always } - // `Optional` or `IfBreaks`: Add parentheses if the expression doesn't fit on a line + // `Optional` or `IfBreaks`: Add parentheses if the expression doesn't fit on a line but enforce + // parentheses if the expression has leading comments else if !parenthesize.is_preserve() { - Parentheses::Optional + if comments.has_leading_comments(node) { + Parentheses::Always + } else { + Parentheses::Optional + } } else { //`Preserve` and expression has no parentheses in the source code Parentheses::Never diff --git a/crates/ruff_python_formatter/src/generated.rs b/crates/ruff_python_formatter/src/generated.rs index 3aeaccfe3fb51..d491ef00655ba 100644 --- a/crates/ruff_python_formatter/src/generated.rs +++ b/crates/ruff_python_formatter/src/generated.rs @@ -2858,3 +2858,35 @@ impl<'ast> IntoFormat> for ast::MatchCase { FormatOwnedWithRule::new(self, crate::other::match_case::FormatMatchCase::default()) } } + +impl FormatRule> for crate::other::decorator::FormatDecorator { + #[inline] + fn fmt( + &self, + node: &ast::Decorator, + f: &mut Formatter>, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl<'ast> AsFormat> for ast::Decorator { + type Format<'a> = FormatRefWithRule< + 'a, + ast::Decorator, + crate::other::decorator::FormatDecorator, + PyFormatContext<'ast>, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new(self, crate::other::decorator::FormatDecorator::default()) + } +} +impl<'ast> IntoFormat> for ast::Decorator { + type Format = FormatOwnedWithRule< + ast::Decorator, + crate::other::decorator::FormatDecorator, + PyFormatContext<'ast>, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new(self, crate::other::decorator::FormatDecorator::default()) + } +} diff --git a/crates/ruff_python_formatter/src/lib.rs b/crates/ruff_python_formatter/src/lib.rs index 90dbe79e48811..193e5f546f133 100644 --- a/crates/ruff_python_formatter/src/lib.rs +++ b/crates/ruff_python_formatter/src/lib.rs @@ -225,18 +225,16 @@ impl Format> for VerbatimText { #[cfg(test)] mod tests { - use std::fmt::{Formatter, Write}; - use std::fs; - use std::path::Path; - use anyhow::Result; use insta::assert_snapshot; + use ruff_python_ast::source_code::CommentRangesBuilder; + use ruff_testing_macros::fixture; use rustpython_parser::lexer::lex; use rustpython_parser::{parse_tokens, Mode}; use similar::TextDiff; - - use ruff_python_ast::source_code::CommentRangesBuilder; - use ruff_testing_macros::fixture; + use std::fmt::{Formatter, Write}; + use std::fs; + use std::path::Path; use crate::{format_module, format_node}; diff --git a/crates/ruff_python_formatter/src/other/arg.rs b/crates/ruff_python_formatter/src/other/arg.rs index 44bb3e85e46de..d63fa04f5f772 100644 --- a/crates/ruff_python_formatter/src/other/arg.rs +++ b/crates/ruff_python_formatter/src/other/arg.rs @@ -1,12 +1,66 @@ -use crate::{not_yet_implemented, FormatNodeRule, PyFormatter}; -use ruff_formatter::{write, Buffer, FormatResult}; +use crate::comments::leading_node_comments; +use crate::prelude::*; +use crate::FormatNodeRule; +use ruff_formatter::{write, FormatRuleWithOptions}; +use ruff_text_size::{TextLen, TextRange}; use rustpython_parser::ast::Arg; #[derive(Default)] -pub struct FormatArg; +pub struct FormatArg { + kind: ArgumentKind, +} + +#[derive(Copy, Clone, Debug, Default)] +pub enum ArgumentKind { + /// Positional only, regular argument, or a keyword only argument. + #[default] + Normal, + /// A `*args` arguments + Varg, + /// A `**kwargs` argument + Kwarg, +} impl FormatNodeRule for FormatArg { fn fmt_fields(&self, item: &Arg, f: &mut PyFormatter) -> FormatResult<()> { - write!(f, [not_yet_implemented(item)]) + let Arg { + range, + arg, + annotation, + type_comment: _, + } = item; + write!( + f, + [ + // The name of the argument + source_text_slice( + TextRange::at(range.start(), arg.text_len()), + ContainsNewlines::No + ) + ] + )?; + + if let Some(annotation) = annotation { + write!(f, [text(":"), space(), annotation.format()])?; + } + + Ok(()) + } + + fn fmt_leading_comments(&self, node: &Arg, f: &mut PyFormatter) -> FormatResult<()> { + match self.kind { + ArgumentKind::Normal => leading_node_comments(node).fmt(f), + // Formatted as part of the `Arguments` to avoid emitting leading comments between the `*` and the argument. + ArgumentKind::Kwarg | ArgumentKind::Varg => Ok(()), + } + } +} + +impl FormatRuleWithOptions> for FormatArg { + type Options = ArgumentKind; + + fn with_options(mut self, options: Self::Options) -> Self { + self.kind = options; + self } } diff --git a/crates/ruff_python_formatter/src/other/arguments.rs b/crates/ruff_python_formatter/src/other/arguments.rs index ee0d7b872f7b8..bd7913db4f22e 100644 --- a/crates/ruff_python_formatter/src/other/arguments.rs +++ b/crates/ruff_python_formatter/src/other/arguments.rs @@ -1,12 +1,189 @@ -use crate::{not_yet_implemented, FormatNodeRule, PyFormatter}; -use ruff_formatter::{write, Buffer, FormatResult}; -use rustpython_parser::ast::Arguments; +use crate::comments::{dangling_node_comments, leading_node_comments}; +use crate::context::NodeLevel; +use crate::other::arg::ArgumentKind; +use crate::prelude::*; +use crate::trivia::{first_non_trivia_token, SimpleTokenizer, Token, TokenKind}; +use crate::FormatNodeRule; +use ruff_formatter::{format_args, write, FormatError}; +use ruff_python_ast::node::{AnyNodeRef, AstNode}; +use rustpython_parser::ast::{Arg, Arguments, Expr, Ranged}; +use std::usize; #[derive(Default)] pub struct FormatArguments; impl FormatNodeRule for FormatArguments { fn fmt_fields(&self, item: &Arguments, f: &mut PyFormatter) -> FormatResult<()> { - write!(f, [not_yet_implemented(item)]) + let Arguments { + range: _, + posonlyargs, + args, + defaults, + vararg, + kwonlyargs, + kw_defaults, + kwarg, + } = item; + + let saved_level = f.context().node_level(); + f.context_mut().set_node_level(NodeLevel::Expression); + + let format_inner = format_with(|f: &mut PyFormatter| { + let separator = format_with(|f| write!(f, [text(","), soft_line_break_or_space()])); + let mut joiner = f.join_with(separator); + let mut last_node: Option = None; + + let mut defaults = std::iter::repeat(None) + .take(posonlyargs.len() + args.len() - defaults.len()) + .chain(defaults.iter().map(Some)); + + for positional in posonlyargs { + let default = defaults.next().ok_or(FormatError::SyntaxError)?; + joiner.entry(&ArgumentWithDefault { + argument: positional, + default, + }); + + last_node = Some(default.map_or_else(|| positional.into(), AnyNodeRef::from)); + } + + if !posonlyargs.is_empty() { + joiner.entry(&text("/")); + } + + for argument in args { + let default = defaults.next().ok_or(FormatError::SyntaxError)?; + + joiner.entry(&ArgumentWithDefault { argument, default }); + + last_node = Some(default.map_or_else(|| argument.into(), AnyNodeRef::from)); + } + + if let Some(vararg) = vararg { + joiner.entry(&format_args![ + leading_node_comments(vararg.as_ref()), + text("*"), + vararg.format().with_options(ArgumentKind::Varg) + ]); + last_node = Some(vararg.as_any_node_ref()); + } + + debug_assert!(defaults.next().is_none()); + + let mut defaults = std::iter::repeat(None) + .take(kwonlyargs.len() - kw_defaults.len()) + .chain(kw_defaults.iter().map(Some)); + + for keyword_argument in kwonlyargs { + let default = defaults.next().ok_or(FormatError::SyntaxError)?; + joiner.entry(&ArgumentWithDefault { + argument: keyword_argument, + default, + }); + + last_node = Some(default.map_or_else(|| keyword_argument.into(), AnyNodeRef::from)); + } + + debug_assert!(defaults.next().is_none()); + + if let Some(kwarg) = kwarg { + joiner.entry(&format_args![ + leading_node_comments(kwarg.as_ref()), + text("**"), + kwarg.format().with_options(ArgumentKind::Kwarg) + ]); + last_node = Some(kwarg.as_any_node_ref()); + } + + joiner.finish()?; + + write!(f, [if_group_breaks(&text(","))])?; + + // Expand the group if the source has a trailing *magic* comma. + if let Some(last_node) = last_node { + let ends_with_pos_only_argument_separator = !posonlyargs.is_empty() + && args.is_empty() + && vararg.is_none() + && kwonlyargs.is_empty() + && kwarg.is_none(); + + let maybe_comma_token = if ends_with_pos_only_argument_separator { + // `def a(b, c, /): ... ` + let mut tokens = + SimpleTokenizer::starts_at(last_node.end(), f.context().contents()) + .skip_trivia(); + + let comma = tokens.next(); + assert!(matches!(comma, Some(Token { kind: TokenKind::Comma, .. })), "The last positional only argument must be separated by a `,` from the positional only arguments separator `/` but found '{comma:?}'."); + + let slash = tokens.next(); + assert!(matches!(slash, Some(Token { kind: TokenKind::Slash, .. })), "The positional argument separator must be present for a function that has positional only arguments but found '{slash:?}'."); + + tokens.next() + } else { + first_non_trivia_token(last_node.end(), f.context().contents()) + }; + + if maybe_comma_token.map_or(false, |token| token.kind() == TokenKind::Comma) { + write!(f, [hard_line_break()])?; + } + } + + Ok(()) + }); + + let num_arguments = posonlyargs.len() + + args.len() + + usize::from(vararg.is_some()) + + kwonlyargs.len() + + usize::from(kwarg.is_some()); + + if num_arguments == 0 { + // No arguments, format any dangling comments between `()` + write!( + f, + [ + text("("), + block_indent(&dangling_node_comments(item)), + text(")") + ] + )?; + } else { + write!( + f, + [group(&format_args!( + text("("), + soft_block_indent(&group(&format_inner)), + text(")") + ))] + )?; + } + + f.context_mut().set_node_level(saved_level); + + Ok(()) + } + + fn fmt_dangling_comments(&self, _node: &Arguments, _f: &mut PyFormatter) -> FormatResult<()> { + // Handled in `fmt_fields` + Ok(()) + } +} + +struct ArgumentWithDefault<'a> { + argument: &'a Arg, + default: Option<&'a Expr>, +} + +impl Format> for ArgumentWithDefault<'_> { + fn fmt(&self, f: &mut Formatter>) -> FormatResult<()> { + write!(f, [self.argument.format()])?; + + if let Some(default) = self.default { + let space = self.argument.annotation.is_some().then_some(space()); + write!(f, [space, text("="), space, default.format()])?; + } + + Ok(()) } } diff --git a/crates/ruff_python_formatter/src/other/decorator.rs b/crates/ruff_python_formatter/src/other/decorator.rs new file mode 100644 index 0000000000000..3ebdca4e70384 --- /dev/null +++ b/crates/ruff_python_formatter/src/other/decorator.rs @@ -0,0 +1,25 @@ +use crate::expression::parentheses::Parenthesize; +use crate::prelude::*; +use crate::FormatNodeRule; +use ruff_formatter::write; +use rustpython_parser::ast::Decorator; + +#[derive(Default)] +pub struct FormatDecorator; + +impl FormatNodeRule for FormatDecorator { + fn fmt_fields(&self, item: &Decorator, f: &mut PyFormatter) -> FormatResult<()> { + let Decorator { + expression, + range: _, + } = item; + + write!( + f, + [ + text("@"), + expression.format().with_options(Parenthesize::Optional) + ] + ) + } +} diff --git a/crates/ruff_python_formatter/src/other/mod.rs b/crates/ruff_python_formatter/src/other/mod.rs index 3ca3d592d266d..b7f843d7bc2c3 100644 --- a/crates/ruff_python_formatter/src/other/mod.rs +++ b/crates/ruff_python_formatter/src/other/mod.rs @@ -2,6 +2,7 @@ pub(crate) mod alias; pub(crate) mod arg; pub(crate) mod arguments; pub(crate) mod comprehension; +pub(crate) mod decorator; pub(crate) mod excepthandler_except_handler; pub(crate) mod keyword; pub(crate) mod match_case; diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__class_blank_parentheses_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__class_blank_parentheses_py.snap index 12aa367c1f17c..301e65440e73d 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__class_blank_parentheses_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__class_blank_parentheses_py.snap @@ -36,16 +36,16 @@ class NormalClass ( ```diff --- Black +++ Ruff -@@ -1,30 +1,16 @@ +@@ -1,18 +1,10 @@ -class SimpleClassWithBlankParentheses: - pass -- +NOT_YET_IMPLEMENTED_StmtClassDef + -class ClassWithSpaceParentheses: - first_test_data = 90 - second_test_data = 100 - +- - def test_func(self): - return None +NOT_YET_IMPLEMENTED_StmtClassDef @@ -57,15 +57,14 @@ class NormalClass ( +NOT_YET_IMPLEMENTED_StmtClassDef --def public_func_with_blank_parentheses(): -- return None -+NOT_YET_IMPLEMENTED_StmtFunctionDef + def public_func_with_blank_parentheses(): +@@ -20,11 +12,7 @@ --def class_under_the_func_with_blank_parentheses(): + def class_under_the_func_with_blank_parentheses(): - class InsideFunc: - pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ NOT_YET_IMPLEMENTED_StmtClassDef -class NormalClass: @@ -87,10 +86,12 @@ NOT_YET_IMPLEMENTED_StmtClassDef NOT_YET_IMPLEMENTED_StmtClassDef -NOT_YET_IMPLEMENTED_StmtFunctionDef +def public_func_with_blank_parentheses(): + return None -NOT_YET_IMPLEMENTED_StmtFunctionDef +def class_under_the_func_with_blank_parentheses(): + NOT_YET_IMPLEMENTED_StmtClassDef NOT_YET_IMPLEMENTED_StmtClassDef diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comment_after_escaped_newline_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comment_after_escaped_newline_py.snap index 906a9362924ba..92e670eafabb9 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comment_after_escaped_newline_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comment_after_escaped_newline_py.snap @@ -22,24 +22,30 @@ def bobtwo(): \ ```diff --- Black +++ Ruff -@@ -1,6 +1,4 @@ +@@ -1,6 +1,8 @@ -def bob(): # pylint: disable=W9016 -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++def bob(): ++ # pylint: disable=W9016 + pass -def bobtwo(): # some comment here -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++def bobtwo(): ++ # some comment here + pass ``` ## Ruff Output ```py -NOT_YET_IMPLEMENTED_StmtFunctionDef +def bob(): + # pylint: disable=W9016 + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +def bobtwo(): + # some comment here + pass ``` ## Black Output diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments2_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments2_py.snap index e0d172d1c7800..44a3cffad7f79 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments2_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments2_py.snap @@ -227,7 +227,7 @@ instruction()#comment with bad spacing ] not_shareables = [ -@@ -37,129 +33,28 @@ +@@ -37,51 +33,24 @@ # builtin types and objects type, object, @@ -258,7 +258,7 @@ instruction()#comment with bad spacing # Comment before function. --def inline_comments_in_brackets_ruin_everything(): + def inline_comments_in_brackets_ruin_everything(): - if typedargslist: - parameters.children = [children[0], body, children[-1]] # (1 # )1 - parameters.children = [ @@ -282,15 +282,15 @@ instruction()#comment with bad spacing - and self._proc.poll() is None - ): - pass -- # no newline before or after -- short = [ -- # one -- 1, -- # two -- 2, -- ] -- -- # no newline after ++ NOT_YET_IMPLEMENTED_StmtIf ++ NOT_YET_IMPLEMENTED_StmtIf + # no newline before or after + short = [ + # one +@@ -91,75 +60,26 @@ + ] + + # no newline after - call( - arg1, - arg2, @@ -299,9 +299,10 @@ instruction()#comment with bad spacing -""", - arg3=True, - ) -- -- ############################################################################ -- ++ NOT_IMPLEMENTED_call() + + ############################################################################ + - call2( - # short - arg1, @@ -333,19 +334,24 @@ instruction()#comment with bad spacing - # right - if element is not None - ] -- while True: ++ NOT_IMPLEMENTED_call() ++ lcomp = [i for i in []] ++ lcomp2 = [i for i in []] ++ lcomp3 = [i for i in []] + while True: - if False: - continue - - # and round and round we go -- # and round and round we go -- -- # let's return ++ NOT_YET_IMPLEMENTED_StmtIf + # and round and round we go + + # let's return - return Node( - syms.simple_stmt, - [Node(statement, result), Leaf(token.NEWLINE, "\n")], # FIXME: \r\n? - ) -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ return NOT_IMPLEMENTED_call() -CONFIG_FILES = ( @@ -366,7 +372,7 @@ instruction()#comment with bad spacing ####################### -@@ -167,7 +62,7 @@ +@@ -167,7 +87,7 @@ ####################### @@ -430,7 +436,32 @@ NOT_YET_IMPLEMENTED_StmtIf # Comment before function. -NOT_YET_IMPLEMENTED_StmtFunctionDef +def inline_comments_in_brackets_ruin_everything(): + NOT_YET_IMPLEMENTED_StmtIf + NOT_YET_IMPLEMENTED_StmtIf + # no newline before or after + short = [ + # one + 1, + # two + 2, + ] + + # no newline after + NOT_IMPLEMENTED_call() + + ############################################################################ + + NOT_IMPLEMENTED_call() + lcomp = [i for i in []] + lcomp2 = [i for i in []] + lcomp3 = [i for i in []] + while True: + NOT_YET_IMPLEMENTED_StmtIf + # and round and round we go + + # let's return + return NOT_IMPLEMENTED_call() CONFIG_FILES = [CONFIG_FILE] + SHARED_CONFIG_FILES + USER_CONFIG_FILES # type: Final diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments3_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments3_py.snap index d0e6f55613457..32cc7618fa5d0 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments3_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments3_py.snap @@ -61,11 +61,10 @@ def func(): ```diff --- Black +++ Ruff -@@ -2,47 +2,7 @@ - +@@ -3,46 +3,13 @@ # %% --def func(): + def func(): - x = """ - a really long string - """ @@ -77,7 +76,9 @@ def func(): - # right - if element is not None - ] -- # Capture each of the exceptions in the MultiError along with each of their causes and contexts ++ x = "NOT_YET_IMPLEMENTED_STRING" ++ lcomp3 = [i for i in []] + # Capture each of the exceptions in the MultiError along with each of their causes and contexts - if isinstance(exc_value, MultiError): - embedded = [] - for exc in exc_value.exceptions: @@ -95,8 +96,9 @@ def func(): - ) - # This should be left alone (after) - ) -- -- # everything is fine if the expression isn't nested ++ NOT_YET_IMPLEMENTED_StmtIf + + # everything is fine if the expression isn't nested - traceback.TracebackException.from_exception( - exc, - limit=limit, @@ -106,7 +108,7 @@ def func(): - # shared between sub-exceptions are not omitted - _seen=set(_seen), - ) -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ NOT_IMPLEMENTED_call() # %% @@ -119,7 +121,14 @@ def func(): # %% -NOT_YET_IMPLEMENTED_StmtFunctionDef +def func(): + x = "NOT_YET_IMPLEMENTED_STRING" + lcomp3 = [i for i in []] + # Capture each of the exceptions in the MultiError along with each of their causes and contexts + NOT_YET_IMPLEMENTED_StmtIf + + # everything is fine if the expression isn't nested + NOT_IMPLEMENTED_call() # %% diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments4_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments4_py.snap index a4d31f142354d..9d741d8b926d4 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments4_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments4_py.snap @@ -107,7 +107,7 @@ def foo3(list_a, list_b): ```diff --- Black +++ Ruff -@@ -1,94 +1,14 @@ +@@ -1,94 +1,22 @@ -from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( - MyLovelyCompanyTeamProjectComponent, # NOT DRY -) @@ -169,7 +169,7 @@ def foo3(list_a, list_b): +NOT_YET_IMPLEMENTED_StmtClassDef --def foo(list_a, list_b): + def foo(list_a, list_b): - results = ( - User.query.filter(User.foo == "bar") - .filter( # Because foo. @@ -182,12 +182,12 @@ def foo3(list_a, list_b): - .with_for_update(key_share=True) - .all() - ) -- return results -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ results = NOT_IMPLEMENTED_call() + return results --def foo2(list_a, list_b): -- # Standalone comment reasonably placed. + def foo2(list_a, list_b): + # Standalone comment reasonably placed. - return ( - User.query.filter(User.foo == "bar") - .filter( @@ -195,19 +195,19 @@ def foo3(list_a, list_b): - ) - .filter(User.xyz.is_(None)) - ) -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ return NOT_IMPLEMENTED_call() --def foo3(list_a, list_b): -- return ( -- # Standalone comment but weirdly placed. + def foo3(list_a, list_b): + return ( + # Standalone comment but weirdly placed. - User.query.filter(User.foo == "bar") - .filter( - db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b)) - ) - .filter(User.xyz.is_(None)) -- ) -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ NOT_IMPLEMENTED_call() + ) ``` ## Ruff Output @@ -220,13 +220,21 @@ NOT_YET_IMPLEMENTED_StmtImportFrom NOT_YET_IMPLEMENTED_StmtClassDef -NOT_YET_IMPLEMENTED_StmtFunctionDef +def foo(list_a, list_b): + results = NOT_IMPLEMENTED_call() + return results -NOT_YET_IMPLEMENTED_StmtFunctionDef +def foo2(list_a, list_b): + # Standalone comment reasonably placed. + return NOT_IMPLEMENTED_call() -NOT_YET_IMPLEMENTED_StmtFunctionDef +def foo3(list_a, list_b): + return ( + # Standalone comment but weirdly placed. + NOT_IMPLEMENTED_call() + ) ``` ## Black Output diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments5_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments5_py.snap index 2aff58d8babe2..addd145645dbd 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments5_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments5_py.snap @@ -86,7 +86,7 @@ if __name__ == "__main__": ```diff --- Black +++ Ruff -@@ -1,61 +1,33 @@ +@@ -1,33 +1,18 @@ while True: - if something.changed: - do.stuff() # trailing comment @@ -97,72 +97,54 @@ if __name__ == "__main__": # Should this one, too? I guess so. # This one is properly standalone now. -- + -for i in range(100): - # first we do this - if i % 33 == 0: - break -- ++NOT_YET_IMPLEMENTED_StmtFor + - # then we do this - print(i) - # and finally we loop around ++NOT_YET_IMPLEMENTED_StmtWith -with open(some_temp_file) as f: - data = f.read() -+NOT_YET_IMPLEMENTED_StmtFor ++NOT_YET_IMPLEMENTED_StmtTry -try: - with open(some_other_file) as w: - w.write(data) -+NOT_YET_IMPLEMENTED_StmtWith - +- -except OSError: - print("problems") -+NOT_YET_IMPLEMENTED_StmtTry - +- -import sys +NOT_YET_IMPLEMENTED_StmtImport # leading function comment --def wat(): -- ... -- # trailing function comment -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - - # SECTION COMMENT - - +@@ -42,7 +27,7 @@ # leading 1 --@deco1 --# leading 2 + @deco1 + # leading 2 -@deco2(with_args=True) --# leading 3 --@deco3 --def decorated1(): -- ... -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - ++@NOT_IMPLEMENTED_call() + # leading 3 + @deco3 + def decorated1(): +@@ -52,7 +37,7 @@ # leading 1 --@deco1 --# leading 2 + @deco1 + # leading 2 -@deco2(with_args=True) --# leading function comment --def decorated1(): -- ... -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - - # Note: this is fixed in -@@ -65,9 +37,7 @@ - - - # This comment should be split from `some_instruction` by two lines but isn't. --def g(): -- ... -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++@NOT_IMPLEMENTED_call() + # leading function comment + def decorated1(): + ... +@@ -69,5 +54,4 @@ + ... -if __name__ == "__main__": @@ -191,18 +173,31 @@ NOT_YET_IMPLEMENTED_StmtImport # leading function comment -NOT_YET_IMPLEMENTED_StmtFunctionDef +def wat(): + ... + # trailing function comment # SECTION COMMENT # leading 1 -NOT_YET_IMPLEMENTED_StmtFunctionDef +@deco1 +# leading 2 +@NOT_IMPLEMENTED_call() +# leading 3 +@deco3 +def decorated1(): + ... # leading 1 -NOT_YET_IMPLEMENTED_StmtFunctionDef +@deco1 +# leading 2 +@NOT_IMPLEMENTED_call() +# leading function comment +def decorated1(): + ... # Note: this is fixed in @@ -212,7 +207,8 @@ some_instruction # This comment should be split from `some_instruction` by two lines but isn't. -NOT_YET_IMPLEMENTED_StmtFunctionDef +def g(): + ... NOT_YET_IMPLEMENTED_StmtIf 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 cabf5db3aef6a..3009fba804bf4 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 @@ -131,103 +131,38 @@ aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*ite ```diff --- Black +++ Ruff -@@ -1,118 +1,40 @@ +@@ -1,4 +1,4 @@ -from typing import Any, Tuple +NOT_YET_IMPLEMENTED_StmtImportFrom --def f( -- a, # type: int --): -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - - # test type comments --def f(a, b, c, d, e, f, g, h, i): -- # type: (int, int, int, int, int, int, int, int, int) -> None -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - --def f( -- a, # type: int -- b, # type: int -- c, # type: int -- d, # type: int -- e, # type: int -- f, # type: int -- g, # type: int -- h, # type: int -- i, # type: int --): -- # type: (...) -> None -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - --def f( -- arg, # type: int -- *args, # type: *Any -- default=False, # type: bool -- **kwargs, # type: **Any --): -- # type: (...) -> None -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - --def f( -- a, # type: int -- b, # type: int -- c, # type: int -- d, # type: int --): -- # type: (...) -> None -- -- element = 0 # type: int -- another_element = 1 # type: float -- another_element_with_long_name = 2 # type: int + def f( +@@ -49,15 +49,10 @@ + element = 0 # type: int + another_element = 1 # type: float + another_element_with_long_name = 2 # type: int - another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style = ( - 3 - ) # type: int - an_element_with_a_long_value = calls() or more_calls() and more() # type: bool -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ 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 -- + another_element -- + another_element_with_long_name -- + element -- + another_element -- + another_element_with_long_name -- ) # type: int -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - --def f( -- x, # not a type comment -- y, # type: int --): -- # type: (...) -> None -- pass -- -- --def f( -- x, # not a type comment --): # type: (int) -> None -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef + a = ( + element +@@ -84,35 +79,22 @@ --def func( + def func( - a=some_list[0], # type: int --): # type: () -> int ++ a=NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], # type: int + ): # type: () -> int - c = call( - 0.0123, - 0.0456, @@ -240,17 +175,20 @@ aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*ite - 0.0789, - a[-1], # type: ignore - ) -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ c = NOT_IMPLEMENTED_call() - c = call( - "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa" # type: ignore - ) ++ c = NOT_IMPLEMENTED_call() -+result = "NOT_YET_IMPLEMENTED_STRING" # aaa -result = ( # aaa - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -) ++result = "NOT_YET_IMPLEMENTED_STRING" # aaa + +-AAAAAAAAAAAAA = [AAAAAAAAAAAAA] + SHARED_AAAAAAAAAAAAA + USER_AAAAAAAAAAAAA + AAAAAAAAAAAAA # type: ignore +AAAAAAAAAAAAA = ( + [AAAAAAAAAAAAA] + + SHARED_AAAAAAAAAAAAA @@ -258,14 +196,12 @@ aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*ite + + AAAAAAAAAAAAA +) # type: ignore --AAAAAAAAAAAAA = [AAAAAAAAAAAAA] + SHARED_AAAAAAAAAAAAA + USER_AAAAAAAAAAAAA + AAAAAAAAAAAAA # type: ignore -+NOT_IMPLEMENTED_call() - -call_to_some_function_asdf( - foo, - [AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, BBBBBBBBBBBB], # type: ignore -) -- ++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] ``` @@ -276,29 +212,89 @@ aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*ite NOT_YET_IMPLEMENTED_StmtImportFrom -NOT_YET_IMPLEMENTED_StmtFunctionDef +def f( + a, # type: int +): + pass # test type comments -NOT_YET_IMPLEMENTED_StmtFunctionDef +def f(a, b, c, d, e, f, g, h, i): + # type: (int, int, int, int, int, int, int, int, int) -> None + pass + + +def f( + a, # type: int + b, # type: int + c, # type: int + d, # type: int + e, # type: int + f, # type: int + g, # type: int + h, # type: int + i, # type: int +): + # type: (...) -> None + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +def f( + arg, # type: int + *args, # type: *Any + default=False, # type: bool + **kwargs, # type: **Any +): + # type: (...) -> None + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +def f( + a, # type: int + b, # type: int + c, # type: int + d, # type: int +): + # type: (...) -> None + element = 0 # type: int + another_element = 1 # type: float + another_element_with_long_name = 2 # type: int + another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style = 3 # type: int + an_element_with_a_long_value = NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 # type: bool -NOT_YET_IMPLEMENTED_StmtFunctionDef + tup = (1, 2) # type: Tuple[int, int] + a = ( + element + + another_element + + another_element_with_long_name + + element + + another_element + + another_element_with_long_name + ) # type: int + + +def f( + x, # not a type comment + y, # type: int +): + # type: (...) -> None + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +def f( + x, # not a type comment +): # type: (int) -> None + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +def func( + a=NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key], # type: int +): # type: () -> int + c = NOT_IMPLEMENTED_call() -NOT_YET_IMPLEMENTED_StmtFunctionDef + c = NOT_IMPLEMENTED_call() result = "NOT_YET_IMPLEMENTED_STRING" # aaa diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments9_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments9_py.snap index 211492aaf4402..49e1cc324fa03 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments9_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments9_py.snap @@ -152,35 +152,7 @@ def bar(): ```diff --- Black +++ Ruff -@@ -4,8 +4,7 @@ - - - # This comment should be split from the statement above by two lines. --def function(): -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - - some = statement -@@ -14,24 +13,21 @@ - # This multiline comments section - # should be split from the statement - # above by two lines. --def function(): -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - - some = statement - - - # This comment should be split from the statement above by two lines. --async def async_function(): -- pass -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef - - - some = statement +@@ -30,8 +30,7 @@ # This comment should be split from the statement above by two lines. @@ -190,7 +162,7 @@ def bar(): some = statement -@@ -39,123 +35,55 @@ +@@ -39,17 +38,14 @@ # This should be split from the above by two lines @@ -211,54 +183,37 @@ def bar(): some = statement - - - # leading 1 --@deco1 --# leading 2 --# leading 2 extra +@@ -59,7 +55,7 @@ + @deco1 + # leading 2 + # leading 2 extra -@deco2(with_args=True) --# leading 3 --@deco3 --# leading 4 --def decorated(): -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - - some = statement - - ++@NOT_IMPLEMENTED_call() + # leading 3 + @deco3 + # leading 4 +@@ -73,7 +69,7 @@ # leading 1 --@deco1 --# leading 2 + @deco1 + # leading 2 -@deco2(with_args=True) -- --# leading 3 that already has an empty line --@deco3 --# leading 4 --def decorated_with_split_leading_comments(): -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - - some = statement - ++@NOT_IMPLEMENTED_call() + # leading 3 that already has an empty line + @deco3 +@@ -88,7 +84,7 @@ # leading 1 --@deco1 --# leading 2 + @deco1 + # leading 2 -@deco2(with_args=True) --# leading 3 --@deco3 -- --# leading 4 that already has an empty line --def decorated_with_split_leading_comments(): -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++@NOT_IMPLEMENTED_call() + # leading 3 + @deco3 + +@@ -98,41 +94,13 @@ --def main(): + def main(): - if a: - # Leading comment before inline function - def inline(): @@ -267,19 +222,20 @@ def bar(): - # Another leading comment - def another_inline(): - pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ NOT_YET_IMPLEMENTED_StmtIf - else: - # More leading comments - def inline_after_else(): - pass -- + ++NOT_YET_IMPLEMENTED_StmtIf -if a: - # Leading comment before "top-level inline" function - def top_level_quote_inline(): - pass -- + - # Another leading comment - def another_top_level_quote_inline_inline(): - pass @@ -288,9 +244,8 @@ def bar(): - # More leading comments - def top_level_quote_inline_after_else(): - pass -+NOT_YET_IMPLEMENTED_StmtIf - - +- +- -class MyClass: - # First method has no empty lines between bare class def. - # More comments. @@ -300,33 +255,6 @@ def bar(): # Regression test for https://github.com/psf/black/issues/3454. --def foo(): -- pass -- # Trailing comment that belongs to this function -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - --@decorator1 --@decorator2 # fmt: skip --def bar(): -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - - # Regression test for https://github.com/psf/black/issues/3454. --def foo(): -- pass -- # Trailing comment that belongs to this function. -- # NOTE this comment only has one empty line below, and the formatter -- # should enforce two blank lines. -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - --@decorator1 --# A standalone comment --def bar(): -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef ``` ## Ruff Output @@ -338,7 +266,8 @@ some = statement # This comment should be split from the statement above by two lines. -NOT_YET_IMPLEMENTED_StmtFunctionDef +def function(): + pass some = statement @@ -347,14 +276,16 @@ some = statement # This multiline comments section # should be split from the statement # above by two lines. -NOT_YET_IMPLEMENTED_StmtFunctionDef +def function(): + pass some = statement # This comment should be split from the statement above by two lines. -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def async_function(): + pass some = statement @@ -383,24 +314,49 @@ some = statement # leading 1 -NOT_YET_IMPLEMENTED_StmtFunctionDef +@deco1 +# leading 2 +# leading 2 extra +@NOT_IMPLEMENTED_call() +# leading 3 +@deco3 +# leading 4 +def decorated(): + pass some = statement # leading 1 -NOT_YET_IMPLEMENTED_StmtFunctionDef +@deco1 +# leading 2 +@NOT_IMPLEMENTED_call() + +# leading 3 that already has an empty line +@deco3 +# leading 4 +def decorated_with_split_leading_comments(): + pass some = statement # leading 1 -NOT_YET_IMPLEMENTED_StmtFunctionDef +@deco1 +# leading 2 +@NOT_IMPLEMENTED_call() +# leading 3 +@deco3 + +# leading 4 that already has an empty line +def decorated_with_split_leading_comments(): + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +def main(): + NOT_YET_IMPLEMENTED_StmtIf NOT_YET_IMPLEMENTED_StmtIf @@ -410,17 +366,29 @@ NOT_YET_IMPLEMENTED_StmtClassDef # Regression test for https://github.com/psf/black/issues/3454. -NOT_YET_IMPLEMENTED_StmtFunctionDef +def foo(): + pass + # Trailing comment that belongs to this function -NOT_YET_IMPLEMENTED_StmtFunctionDef +@decorator1 +@decorator2 # fmt: skip +def bar(): + pass # Regression test for https://github.com/psf/black/issues/3454. -NOT_YET_IMPLEMENTED_StmtFunctionDef +def foo(): + pass + # Trailing comment that belongs to this function. + # NOTE this comment only has one empty line below, and the formatter + # should enforce two blank lines. -NOT_YET_IMPLEMENTED_StmtFunctionDef +@decorator1 +# A standalone comment +def bar(): + pass ``` ## 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 d7403c7700f6c..cddc816cdbc83 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 @@ -32,7 +32,7 @@ def function(a:int=42): ```diff --- Black +++ Ruff -@@ -1,23 +1,11 @@ +@@ -1,23 +1,15 @@ -from .config import ( - ConfigTypeAttributes, - Int, @@ -51,15 +51,15 @@ def function(a:int=42): +square = NOT_IMPLEMENTED_call() #  type: Optional[Square] --def function(a: int = 42): + def function(a: int = 42): - """This docstring is already formatted - a - b - """ -- # There's a NBSP + 3 spaces before -- # And 4 spaces on the next line -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" + # There's a NBSP + 3 spaces before + # And 4 spaces on the next line + pass ``` ## Ruff Output @@ -75,7 +75,11 @@ result = 1 # This comment is talking about type: ignore square = NOT_IMPLEMENTED_call() #  type: Optional[Square] -NOT_YET_IMPLEMENTED_StmtFunctionDef +def function(a: int = 42): + "NOT_YET_IMPLEMENTED_STRING" + # There's a NBSP + 3 spaces before + # And 4 spaces on the next line + pass ``` ## Black Output diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments_py.snap index c211d6c77c4dc..594d47fcf3ee7 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__comments_py.snap @@ -109,7 +109,7 @@ async def wat(): ```diff --- Black +++ Ruff -@@ -4,93 +4,42 @@ +@@ -4,24 +4,15 @@ # # Has many lines. Many, many lines. # Many, many, many lines. @@ -117,50 +117,51 @@ async def wat(): - -Possibly also many, many lines. -""" -- ++"NOT_YET_IMPLEMENTED_STRING" + -import os.path -import sys -- ++NOT_YET_IMPLEMENTED_StmtImport ++NOT_YET_IMPLEMENTED_StmtImport + -import a -from b.c import X # some noqa comment -+"NOT_YET_IMPLEMENTED_STRING" ++NOT_YET_IMPLEMENTED_StmtImport ++NOT_YET_IMPLEMENTED_StmtImportFrom # some noqa comment -try: - import fast -except ImportError: - import slow as fast -+NOT_YET_IMPLEMENTED_StmtImport -+NOT_YET_IMPLEMENTED_StmtImport - -+NOT_YET_IMPLEMENTED_StmtImport -+NOT_YET_IMPLEMENTED_StmtImportFrom # some noqa comment - +- +- -# Some comment before a function. +NOT_YET_IMPLEMENTED_StmtTry y = 1 ( # some strings - y # type: ignore - ) -- -- --def function(default=None): +@@ -30,67 +21,39 @@ + + + def function(default=None): - """Docstring comes first. - - Possibly many lines. - """ -- # FIXME: Some comment about why this function is crap but still in production. ++ "NOT_YET_IMPLEMENTED_STRING" + # FIXME: Some comment about why this function is crap but still in production. - import inner_imports ++ NOT_YET_IMPLEMENTED_StmtImport - if inner_imports.are_evil(): - # Explains why we have this if. - # In great detail indeed. - x = X() - return x.method1() # type: ignore ++ NOT_YET_IMPLEMENTED_StmtIf -- # This return is also commented for some reason. -- return default -+NOT_YET_IMPLEMENTED_StmtFunctionDef + # This return is also commented for some reason. + return default # Explains why we use global state. @@ -170,7 +171,7 @@ async def wat(): # Another comment! # This time two lines. - +- -class Foo: - """Docstring for class Foo. Example from Sphinx docs.""" @@ -178,7 +179,7 @@ async def wat(): - #: Doc comment for class attribute Foo.bar. - #: It can have multiple lines. - bar = 1 -- + - flox = 1.5 #: Doc comment for Foo.flox. One line only. - - baz = 2 @@ -187,27 +188,29 @@ async def wat(): - def __init__(self): - #: Doc comment for instance attribute qux. - self.qux = 3 -+NOT_YET_IMPLEMENTED_StmtClassDef - +- - self.spam = 4 - """Docstring for instance attribute spam.""" ++NOT_YET_IMPLEMENTED_StmtClassDef + -- #'

This is pweave!

-@fast(really=True) --async def wat(): -- # This comment, for some reason \ -- # contains a trailing backslash. ++@NOT_IMPLEMENTED_call() + async def wat(): + # This comment, for some reason \ + # contains a trailing backslash. - async with X.open_async() as x: # Some more comments - result = await x.method1() -- # Comment after ending a block. ++ NOT_YET_IMPLEMENTED_StmtAsyncWith # Some more comments + # Comment after ending a block. - if result: - print("A OK", file=sys.stdout) - # Comment between things. - print() -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ NOT_YET_IMPLEMENTED_StmtIf # Some closing comments. @@ -242,7 +245,15 @@ y = 1 ) -NOT_YET_IMPLEMENTED_StmtFunctionDef +def function(default=None): + "NOT_YET_IMPLEMENTED_STRING" + # FIXME: Some comment about why this function is crap but still in production. + NOT_YET_IMPLEMENTED_StmtImport + + NOT_YET_IMPLEMENTED_StmtIf + + # This return is also commented for some reason. + return default # Explains why we use global state. @@ -259,7 +270,13 @@ NOT_YET_IMPLEMENTED_StmtClassDef #'

This is pweave!

-NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +@NOT_IMPLEMENTED_call() +async def wat(): + # This comment, for some reason \ + # contains a trailing backslash. + NOT_YET_IMPLEMENTED_StmtAsyncWith # Some more comments + # Comment after ending a block. + NOT_YET_IMPLEMENTED_StmtIf # Some closing comments. diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__docstring_preview_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__docstring_preview_py.snap index 3cb82ea680356..08eea3e67ff64 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__docstring_preview_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__docstring_preview_py.snap @@ -63,98 +63,108 @@ def single_quote_docstring_over_line_limit2(): ```diff --- Black +++ Ruff -@@ -1,48 +1,28 @@ --def docstring_almost_at_line_limit(): +@@ -1,48 +1,38 @@ + def docstring_almost_at_line_limit(): - """long docstring.................................................................""" -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" --def docstring_almost_at_line_limit_with_prefix(): + def docstring_almost_at_line_limit_with_prefix(): - f"""long docstring................................................................""" -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ NOT_YET_IMPLEMENTED_ExprJoinedStr --def mulitline_docstring_almost_at_line_limit(): + def mulitline_docstring_almost_at_line_limit(): - """long docstring................................................................. -+NOT_YET_IMPLEMENTED_StmtFunctionDef - +- - .................................................................................. - """ ++ "NOT_YET_IMPLEMENTED_STRING" -+NOT_YET_IMPLEMENTED_StmtFunctionDef --def mulitline_docstring_almost_at_line_limit_with_prefix(): + def mulitline_docstring_almost_at_line_limit_with_prefix(): - f"""long docstring................................................................ - +- - .................................................................................. - """ -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ NOT_YET_IMPLEMENTED_ExprJoinedStr --def docstring_at_line_limit(): + def docstring_at_line_limit(): - """long docstring................................................................""" -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" --def docstring_at_line_limit_with_prefix(): + def docstring_at_line_limit_with_prefix(): - f"""long docstring...............................................................""" -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ NOT_YET_IMPLEMENTED_ExprJoinedStr --def multiline_docstring_at_line_limit(): + def multiline_docstring_at_line_limit(): - """first line----------------------------------------------------------------------- - - second line----------------------------------------------------------------------""" -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" --def multiline_docstring_at_line_limit_with_prefix(): + def multiline_docstring_at_line_limit_with_prefix(): - f"""first line---------------------------------------------------------------------- - - second line----------------------------------------------------------------------""" -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ NOT_YET_IMPLEMENTED_ExprJoinedStr --def single_quote_docstring_over_line_limit(): + def single_quote_docstring_over_line_limit(): - "We do not want to put the closing quote on a new line as that is invalid (see GH-3141)." -- -- --def single_quote_docstring_over_line_limit2(): ++ "NOT_YET_IMPLEMENTED_STRING" + + + def single_quote_docstring_over_line_limit2(): - "We do not want to put the closing quote on a new line as that is invalid (see GH-3141)." -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" ``` ## Ruff Output ```py -NOT_YET_IMPLEMENTED_StmtFunctionDef +def docstring_almost_at_line_limit(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def docstring_almost_at_line_limit_with_prefix(): + NOT_YET_IMPLEMENTED_ExprJoinedStr -NOT_YET_IMPLEMENTED_StmtFunctionDef +def mulitline_docstring_almost_at_line_limit(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def mulitline_docstring_almost_at_line_limit_with_prefix(): + NOT_YET_IMPLEMENTED_ExprJoinedStr -NOT_YET_IMPLEMENTED_StmtFunctionDef +def docstring_at_line_limit(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def docstring_at_line_limit_with_prefix(): + NOT_YET_IMPLEMENTED_ExprJoinedStr -NOT_YET_IMPLEMENTED_StmtFunctionDef +def multiline_docstring_at_line_limit(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def multiline_docstring_at_line_limit_with_prefix(): + NOT_YET_IMPLEMENTED_ExprJoinedStr -NOT_YET_IMPLEMENTED_StmtFunctionDef +def single_quote_docstring_over_line_limit(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def single_quote_docstring_over_line_limit2(): + "NOT_YET_IMPLEMENTED_STRING" ``` ## Black Output diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__docstring_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__docstring_py.snap index ef8190c5d1cb1..ca085ed0883cb 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__docstring_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__docstring_py.snap @@ -234,65 +234,64 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self): ```diff --- Black +++ Ruff -@@ -1,219 +1,105 @@ +@@ -1,219 +1,149 @@ -class MyClass: - """Multiline - class docstring - """ -+NOT_YET_IMPLEMENTED_StmtClassDef - +- - def method(self): - """Multiline - method docstring - """ - pass ++NOT_YET_IMPLEMENTED_StmtClassDef -+NOT_YET_IMPLEMENTED_StmtFunctionDef --def foo(): + def foo(): - """This is a docstring with - some lines of text here - """ -- return ++ "NOT_YET_IMPLEMENTED_STRING" + return -+NOT_YET_IMPLEMENTED_StmtFunctionDef --def bar(): + def bar(): - """This is another docstring - with more lines of text - """ -- return ++ "NOT_YET_IMPLEMENTED_STRING" + return -+NOT_YET_IMPLEMENTED_StmtFunctionDef --def baz(): + def baz(): - '''"This" is a string with some - embedded "quotes"''' -- return ++ "NOT_YET_IMPLEMENTED_STRING" + return -+NOT_YET_IMPLEMENTED_StmtFunctionDef --def troz(): + def troz(): - """Indentation with tabs - is just as OK - """ -- return ++ "NOT_YET_IMPLEMENTED_STRING" + return -+NOT_YET_IMPLEMENTED_StmtFunctionDef --def zort(): + def zort(): - """Another - multiline - docstring - """ -- pass ++ "NOT_YET_IMPLEMENTED_STRING" + pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef --def poit(): + def poit(): - """ - Lorem ipsum dolor sit amet. - +- - Consectetur adipiscing elit: - - sed do eiusmod tempor incididunt ut labore - - dolore magna aliqua @@ -300,99 +299,99 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self): - - quis nostrud exercitation ullamco laboris nisi - - aliquip ex ea commodo consequat - """ -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" + pass --def under_indent(): + def under_indent(): - """ - These lines are indented in a way that does not - make sense. - """ -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" + pass --def over_indent(): + def over_indent(): - """ - This has a shallow indent - - But some lines are deeper - - And the closing quote is too deep - """ -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" + pass --def single_line(): + def single_line(): - """But with a newline after it!""" -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" + pass --def this(): + def this(): - r""" - 'hey ho' - """ -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" --def that(): + def that(): - """ "hey yah" """ -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" --def and_that(): + def and_that(): - """ - "hey yah" """ -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" --def and_this(): + def and_this(): - ''' - "hey yah"''' -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" --def multiline_whitespace(): + def multiline_whitespace(): - """ """ -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" --def oneline_whitespace(): + def oneline_whitespace(): - """ """ -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" --def empty(): + def empty(): - """""" -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" --def single_quotes(): + def single_quotes(): - "testing" -- -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" --def believe_it_or_not_this_is_in_the_py_stdlib(): + + def believe_it_or_not_this_is_in_the_py_stdlib(): - ''' - "hey yah"''' ++ "NOT_YET_IMPLEMENTED_STRING" -+NOT_YET_IMPLEMENTED_StmtFunctionDef --def ignored_docstring(): + def ignored_docstring(): - """a => \ -b""" ++ "NOT_YET_IMPLEMENTED_STRING" -+NOT_YET_IMPLEMENTED_StmtFunctionDef --def single_line_docstring_with_whitespace(): + def single_line_docstring_with_whitespace(): - """This should be stripped""" ++ "NOT_YET_IMPLEMENTED_STRING" -+NOT_YET_IMPLEMENTED_StmtFunctionDef --def docstring_with_inline_tabs_and_space_indentation(): + def docstring_with_inline_tabs_and_space_indentation(): - """hey - +- - tab separated value - tab at start of line and then a tab separated value - multiple tabs at the beginning and inline @@ -400,12 +399,12 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self): - - line ends with some tabs - """ -- -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" --def docstring_with_inline_tabs_and_tab_indentation(): -- """hey + def docstring_with_inline_tabs_and_tab_indentation(): +- """hey +- - tab separated value - tab at start of line and then a tab separated value - multiple tabs at the beginning and inline @@ -413,82 +412,83 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self): - - line ends with some tabs - """ -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" + pass --def backslash_space(): + def backslash_space(): - """\ """ -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" --def multiline_backslash_1(): + def multiline_backslash_1(): - """ - hey\there\ - \ """ -- -- --def multiline_backslash_2(): ++ "NOT_YET_IMPLEMENTED_STRING" + + + def multiline_backslash_2(): - """ - hey there \ """ -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" # Regression test for #3425 --def multiline_backslash_really_long_dont_crash(): + def multiline_backslash_really_long_dont_crash(): - """ - hey there hello guten tag hi hoow are you ola zdravstvuyte ciao como estas ca va \ """ -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" --def multiline_backslash_3(): + def multiline_backslash_3(): - """ - already escaped \\""" -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" --def my_god_its_full_of_stars_1(): + def my_god_its_full_of_stars_1(): - "I'm sorry Dave\u2001" -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" # the space below is actually a \u2001, removed in output --def my_god_its_full_of_stars_2(): + def my_god_its_full_of_stars_2(): - "I'm sorry Dave" -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" --def docstring_almost_at_line_limit(): + def docstring_almost_at_line_limit(): - """long docstring.................................................................""" -- -- --def docstring_almost_at_line_limit2(): ++ "NOT_YET_IMPLEMENTED_STRING" + + + def docstring_almost_at_line_limit2(): - """long docstring................................................................. - - .................................................................................. - """ -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" --def docstring_at_line_limit(): + def docstring_at_line_limit(): - """long docstring................................................................""" -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" --def multiline_docstring_at_line_limit(): + def multiline_docstring_at_line_limit(): - """first line----------------------------------------------------------------------- -+NOT_YET_IMPLEMENTED_StmtFunctionDef - +- - second line----------------------------------------------------------------------""" ++ "NOT_YET_IMPLEMENTED_STRING" -+NOT_YET_IMPLEMENTED_StmtFunctionDef --def stable_quote_normalization_with_immediate_inner_single_quote(self): + def stable_quote_normalization_with_immediate_inner_single_quote(self): - """' - +- - - """ -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" ``` ## Ruff Output @@ -497,108 +497,152 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self): NOT_YET_IMPLEMENTED_StmtClassDef -NOT_YET_IMPLEMENTED_StmtFunctionDef +def foo(): + "NOT_YET_IMPLEMENTED_STRING" + return -NOT_YET_IMPLEMENTED_StmtFunctionDef +def bar(): + "NOT_YET_IMPLEMENTED_STRING" + return -NOT_YET_IMPLEMENTED_StmtFunctionDef +def baz(): + "NOT_YET_IMPLEMENTED_STRING" + return -NOT_YET_IMPLEMENTED_StmtFunctionDef +def troz(): + "NOT_YET_IMPLEMENTED_STRING" + return -NOT_YET_IMPLEMENTED_StmtFunctionDef +def zort(): + "NOT_YET_IMPLEMENTED_STRING" + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +def poit(): + "NOT_YET_IMPLEMENTED_STRING" + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +def under_indent(): + "NOT_YET_IMPLEMENTED_STRING" + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +def over_indent(): + "NOT_YET_IMPLEMENTED_STRING" + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +def single_line(): + "NOT_YET_IMPLEMENTED_STRING" + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +def this(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def that(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def and_that(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def and_this(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def multiline_whitespace(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def oneline_whitespace(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def empty(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def single_quotes(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def believe_it_or_not_this_is_in_the_py_stdlib(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def ignored_docstring(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def single_line_docstring_with_whitespace(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def docstring_with_inline_tabs_and_space_indentation(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def docstring_with_inline_tabs_and_tab_indentation(): + "NOT_YET_IMPLEMENTED_STRING" + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +def backslash_space(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def multiline_backslash_1(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def multiline_backslash_2(): + "NOT_YET_IMPLEMENTED_STRING" # Regression test for #3425 -NOT_YET_IMPLEMENTED_StmtFunctionDef +def multiline_backslash_really_long_dont_crash(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def multiline_backslash_3(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def my_god_its_full_of_stars_1(): + "NOT_YET_IMPLEMENTED_STRING" # the space below is actually a \u2001, removed in output -NOT_YET_IMPLEMENTED_StmtFunctionDef +def my_god_its_full_of_stars_2(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def docstring_almost_at_line_limit(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def docstring_almost_at_line_limit2(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def docstring_at_line_limit(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def multiline_docstring_at_line_limit(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def stable_quote_normalization_with_immediate_inner_single_quote(self): + "NOT_YET_IMPLEMENTED_STRING" ``` ## Black Output 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 a00903018576f..f2f0d7ebcd3e2 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,13 +105,13 @@ def g(): ```diff --- Black +++ Ruff -@@ -1,89 +1,12 @@ +@@ -1,89 +1,45 @@ -"""Docstring.""" +"NOT_YET_IMPLEMENTED_STRING" # leading comment --def f(): + def f(): - NO = "" - SPACE = " " - DOUBLESPACE = " " @@ -124,15 +124,23 @@ def g(): - pass - if t == token.COMMENT: # another trailing comment - return DOUBLESPACE -- ++ NO = "NOT_YET_IMPLEMENTED_STRING" ++ SPACE = "NOT_YET_IMPLEMENTED_STRING" ++ DOUBLESPACE = "NOT_YET_IMPLEMENTED_STRING" + - assert p is not None, f"INTERNAL ERROR: hand-made leaf without parent: {leaf!r}" -- ++ t = leaf.NOT_IMPLEMENTED_attr ++ p = leaf.NOT_IMPLEMENTED_attr # trailing comment ++ v = leaf.NOT_IMPLEMENTED_attr + - prev = leaf.prev_sibling - if not prev: - prevp = preceding_leaf(p) - if not prevp or prevp.type in OPENING_BRACKETS: - return NO -- ++ NOT_YET_IMPLEMENTED_StmtIf ++ NOT_YET_IMPLEMENTED_StmtIf # another trailing comment + - if prevp.type == token.EQUAL: - if prevp.parent and prevp.parent.type in { - syms.typedargslist, @@ -142,7 +150,8 @@ def g(): - syms.argument, - }: - return NO -- ++ NOT_YET_IMPLEMENTED_StmtAssert + - elif prevp.type == token.DOUBLESTAR: - if prevp.parent and prevp.parent.type in { - syms.typedargslist, @@ -152,7 +161,8 @@ def g(): - syms.dictsetmaker, - }: - return NO -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ prev = leaf.NOT_IMPLEMENTED_attr ++ NOT_YET_IMPLEMENTED_StmtIf ############################################################################### @@ -160,29 +170,38 @@ def g(): ############################################################################### - --def g(): + def g(): - NO = "" - SPACE = " " - DOUBLESPACE = " " -- ++ NO = "NOT_YET_IMPLEMENTED_STRING" ++ SPACE = "NOT_YET_IMPLEMENTED_STRING" ++ DOUBLESPACE = "NOT_YET_IMPLEMENTED_STRING" + - t = leaf.type - p = leaf.parent - v = leaf.value -- -- # Comment because comments -- ++ t = leaf.NOT_IMPLEMENTED_attr ++ p = leaf.NOT_IMPLEMENTED_attr ++ v = leaf.NOT_IMPLEMENTED_attr + + # Comment because comments + - if t in ALWAYS_NO_SPACE: - pass - if t == token.COMMENT: - return DOUBLESPACE -- -- # Another comment because more comments ++ NOT_YET_IMPLEMENTED_StmtIf ++ NOT_YET_IMPLEMENTED_StmtIf + + # Another comment because more comments - assert p is not None, f"INTERNAL ERROR: hand-made leaf without parent: {leaf!r}" - - prev = leaf.prev_sibling - if not prev: - prevp = preceding_leaf(p) -- ++ NOT_YET_IMPLEMENTED_StmtAssert + - if not prevp or prevp.type in OPENING_BRACKETS: - # Start of the line or a bracketed expression. - # More than one line for the comment. @@ -197,7 +216,8 @@ def g(): - syms.argument, - }: - return NO -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ prev = leaf.NOT_IMPLEMENTED_attr ++ NOT_YET_IMPLEMENTED_StmtIf ``` ## Ruff Output @@ -207,14 +227,47 @@ def g(): # leading comment -NOT_YET_IMPLEMENTED_StmtFunctionDef +def f(): + NO = "NOT_YET_IMPLEMENTED_STRING" + SPACE = "NOT_YET_IMPLEMENTED_STRING" + DOUBLESPACE = "NOT_YET_IMPLEMENTED_STRING" + + t = leaf.NOT_IMPLEMENTED_attr + p = leaf.NOT_IMPLEMENTED_attr # trailing comment + v = leaf.NOT_IMPLEMENTED_attr + + NOT_YET_IMPLEMENTED_StmtIf + NOT_YET_IMPLEMENTED_StmtIf # another trailing comment + + NOT_YET_IMPLEMENTED_StmtAssert + + prev = leaf.NOT_IMPLEMENTED_attr + NOT_YET_IMPLEMENTED_StmtIf ############################################################################### # SECTION BECAUSE SECTIONS ############################################################################### -NOT_YET_IMPLEMENTED_StmtFunctionDef +def g(): + NO = "NOT_YET_IMPLEMENTED_STRING" + SPACE = "NOT_YET_IMPLEMENTED_STRING" + DOUBLESPACE = "NOT_YET_IMPLEMENTED_STRING" + + t = leaf.NOT_IMPLEMENTED_attr + p = leaf.NOT_IMPLEMENTED_attr + v = leaf.NOT_IMPLEMENTED_attr + + # Comment because comments + + NOT_YET_IMPLEMENTED_StmtIf + NOT_YET_IMPLEMENTED_StmtIf + + # Another comment because more comments + NOT_YET_IMPLEMENTED_StmtAssert + + prev = leaf.NOT_IMPLEMENTED_attr + NOT_YET_IMPLEMENTED_StmtIf ``` ## Black Output 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 36d363a161078..a08717b4bbcd6 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,346 +8,240 @@ +@@ -7,346 +8,245 @@ 1 1.0 1j @@ -541,6 +541,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 +558,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__) -) @@ -679,17 +679,20 @@ last_call() +mapping = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} --def gen(): + def gen(): - yield from outside_of_generator - a = yield - b = yield - c = yield -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ NOT_YET_IMPLEMENTED_ExprYieldFrom ++ a = NOT_YET_IMPLEMENTED_ExprYield ++ b = NOT_YET_IMPLEMENTED_ExprYield ++ c = NOT_YET_IMPLEMENTED_ExprYield --async def f(): + async def f(): - await some.complicated[0].call(with_args=(True or (1 is not 1))) -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ await NOT_IMPLEMENTED_call() -print(*[] or [1]) @@ -823,7 +826,7 @@ last_call() ( aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa -@@ -363,8 +258,9 @@ +@@ -363,8 +263,9 @@ bbbb >> bbbb * bbbb ( aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -1050,10 +1053,15 @@ NOT_IMPLEMENTED_call() mapping = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} -NOT_YET_IMPLEMENTED_StmtFunctionDef +def gen(): + NOT_YET_IMPLEMENTED_ExprYieldFrom + a = NOT_YET_IMPLEMENTED_ExprYield + b = NOT_YET_IMPLEMENTED_ExprYield + c = NOT_YET_IMPLEMENTED_ExprYield -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def f(): + await 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 a3d5b2e65f442..d4de723ff0251 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 @@ -53,7 +53,7 @@ def test_calculate_fades(): ```diff --- Black +++ Ruff -@@ -1,40 +1,26 @@ +@@ -1,40 +1,38 @@ -import pytest +NOT_YET_IMPLEMENTED_StmtImport @@ -67,40 +67,43 @@ def test_calculate_fades(): # Position, Volume, State, TmSt/TmEx/None, [call, [arg1...]] -@pytest.mark.parametrize('test', [ -+NOT_YET_IMPLEMENTED_StmtFunctionDef -+ -+ -+NOT_YET_IMPLEMENTED_StmtFunctionDef - +- - # Test don't manage the volume - [ - ('stuff', 'in') - ], -]) --def test_fader(test): -- pass ++@NOT_IMPLEMENTED_call() + def test_fader(test): + pass --def check_fader(test): -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ + def check_fader(test): ++ pass - pass --def verify_fader(test): + def verify_fader(test): - # misaligned comment -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ # misaligned comment + pass --def verify_fader(test): ++ + def verify_fader(test): - """Hey, ho.""" - assert test.passed() ++ "NOT_YET_IMPLEMENTED_STRING" ++ NOT_YET_IMPLEMENTED_StmtAssert ++ --def test_calculate_fades(): -- calcs = [ -- # one is zero/none + def test_calculate_fades(): + calcs = [ + # one is zero/none - (0, 4, 0, 0, 10, 0, 0, 6, 10), - (None, 4, 0, 0, 10, 0, 0, 6, 10), -- ] -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ (1, 2), ++ (1, 2), + ] # fmt: on ``` @@ -119,19 +122,31 @@ TmEx = 2 # Test data: # Position, Volume, State, TmSt/TmEx/None, [call, [arg1...]] -NOT_YET_IMPLEMENTED_StmtFunctionDef +@NOT_IMPLEMENTED_call() +def test_fader(test): + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +def check_fader(test): + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +def verify_fader(test): + # misaligned comment + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +def verify_fader(test): + "NOT_YET_IMPLEMENTED_STRING" + NOT_YET_IMPLEMENTED_StmtAssert -NOT_YET_IMPLEMENTED_StmtFunctionDef +def test_calculate_fades(): + calcs = [ + # one is zero/none + (1, 2), + (1, 2), + ] # fmt: on ``` diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff4_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff4_py.snap index 6deb07e8166d9..9fd0b0b4b4dc3 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff4_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff4_py.snap @@ -26,16 +26,16 @@ def f(): pass ```diff --- Black +++ Ruff -@@ -1,20 +1,5 @@ +@@ -1,20 +1,10 @@ # fmt: off -@test([ - 1, 2, - 3, 4, -]) --# fmt: on --def f(): -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++@NOT_IMPLEMENTED_call() + # fmt: on + def f(): + pass -@test( @@ -46,19 +46,24 @@ def f(): pass - 4, - ] -) --def f(): -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++@NOT_IMPLEMENTED_call() + def f(): + pass ``` ## Ruff Output ```py # fmt: off -NOT_YET_IMPLEMENTED_StmtFunctionDef +@NOT_IMPLEMENTED_call() +# fmt: on +def f(): + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +@NOT_IMPLEMENTED_call() +def f(): + pass ``` ## Black Output diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff5_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff5_py.snap index cfab11e5676b3..ec7df09c26761 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff5_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtonoff5_py.snap @@ -97,7 +97,7 @@ elif unformatted: ```diff --- Black +++ Ruff -@@ -1,87 +1,29 @@ +@@ -1,87 +1,33 @@ # Regression test for https://github.com/psf/black/issues/3129. -setup( - entry_points={ @@ -127,18 +127,18 @@ elif unformatted: # Regression test for https://github.com/psf/black/issues/3026. --def test_func(): -- # yapf: disable + def test_func(): + # yapf: disable - if unformatted( args ): - return True - # yapf: enable - elif b: - return True -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ NOT_YET_IMPLEMENTED_StmtIf + + return False -- return False -- # Regression test for https://github.com/psf/black/issues/2567. -if True: - # fmt: off @@ -161,14 +161,14 @@ elif unformatted: - ) : - # fmt: on - print ( "This won't be formatted" ) -- -- elif param[0:4] in ("ZZZZ",): -- print ( "This won't be formatted either" ) -- -- print("This will be formatted") +NOT_YET_IMPLEMENTED_StmtClassDef +- elif param[0:4] in ("ZZZZ",): +- print ( "This won't be formatted either" ) +- print("This will be formatted") +- +- # Regression test for https://github.com/psf/black/issues/2985. -class Named(t.Protocol): - # fmt: off @@ -180,10 +180,10 @@ elif unformatted: -class Factory(t.Protocol): - def this_will_be_formatted(self, **kwargs) -> Named: - ... +- +- # fmt: on +NOT_YET_IMPLEMENTED_StmtClassDef -- # fmt: on -- # Regression test for https://github.com/psf/black/issues/3436. -if x: @@ -207,7 +207,11 @@ NOT_IMPLEMENTED_call() # Regression test for https://github.com/psf/black/issues/3026. -NOT_YET_IMPLEMENTED_StmtFunctionDef +def test_func(): + # yapf: disable + NOT_YET_IMPLEMENTED_StmtIf + + return False # Regression test for https://github.com/psf/black/issues/2567. 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 b21f49a135cc9..7e6b71b7ad183 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 @@ -199,7 +199,7 @@ d={'a':1, ```diff --- Black +++ Ruff -@@ -1,224 +1,72 @@ +@@ -1,16 +1,14 @@ #!/usr/bin/env python3 -import asyncio -import sys @@ -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, @@ -222,10 +222,10 @@ d={'a':1, # Comment 1 # Comment 2 - +@@ -18,109 +16,109 @@ # fmt: off --def func_no_args(): + def func_no_args(): - a; b; c - if True: raise RuntimeError - if False: ... @@ -234,7 +234,17 @@ d={'a':1, - continue - exec('new-style exec', {}, {}) - return None --async def coroutine(arg, exec=False): ++ a ++ b ++ c ++ NOT_YET_IMPLEMENTED_StmtIf ++ NOT_YET_IMPLEMENTED_StmtIf ++ NOT_YET_IMPLEMENTED_StmtFor ++ NOT_IMPLEMENTED_call() ++ return None ++ ++ + async def coroutine(arg, exec=False): - 'Single-line docstring. Multiline is harder to reformat.' - async with some_connection() as conn: - await conn.do_what_i_mean('SELECT bobby, tables FROM xkcd', timeout=2) @@ -246,47 +256,75 @@ d={'a':1, -) -def function_signature_stress_test(number:int,no_annotation=None,text:str='default',* ,debug:bool=False,**kwargs) -> str: - return text[number:-1] --# fmt: on --def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""): -- offset = attr.ib(default=attr.Factory(lambda: _r.uniform(1, 2))) -- assert task._cancel_stack[: len(old_stack)] == old_stack -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" ++ NOT_YET_IMPLEMENTED_StmtAsyncWith ++ await NOT_IMPLEMENTED_call() + + -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++@asyncio.NOT_IMPLEMENTED_attr ++@NOT_IMPLEMENTED_call() ++def function_signature_stress_test( ++ number: int, ++ no_annotation=None, ++ text: str = "NOT_YET_IMPLEMENTED_STRING", ++ debug: bool = False, ++ **kwargs, ++) -> str: ++ return NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] + - -+NOT_YET_IMPLEMENTED_StmtFunctionDef - --def spaces_types( -- a: int = 1, ++ + # fmt: on +-def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""): +- offset = attr.ib(default=attr.Factory(lambda: _r.uniform(1, 2))) +- assert task._cancel_stack[: len(old_stack)] == old_stack ++def spaces( ++ a=1, ++ b=(1, 2), ++ c=[], ++ d={NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value}, ++ e=True, ++ f=NOT_YET_IMPLEMENTED_ExprUnaryOp, ++ g=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false, ++ h="NOT_YET_IMPLEMENTED_STRING", ++ i="NOT_YET_IMPLEMENTED_STRING", ++): ++ offset = NOT_IMPLEMENTED_call() ++ NOT_YET_IMPLEMENTED_StmtAssert + + + def spaces_types( + a: int = 1, - b: tuple = (), -- c: list = [], ++ b: tuple = (1, 2), + c: list = [], - d: dict = {}, -- e: bool = True, ++ d: dict = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value}, + e: bool = True, - 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", + ): + ... -+# fmt: on -+NOT_YET_IMPLEMENTED_StmtFunctionDef -def spaces2(result=_core.Value(None)): -- ... ++def spaces2(result=NOT_IMPLEMENTED_call()): + ... -+NOT_YET_IMPLEMENTED_StmtFunctionDef -something = { - # fmt: off - key: 'value', -} ++something = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} -+NOT_YET_IMPLEMENTED_StmtFunctionDef --def subscriptlist(): + def subscriptlist(): - atom[ - # fmt: off - 'some big and', @@ -295,81 +333,90 @@ d={'a':1, - goes + here, - andhere, - ] ++ NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] -+something = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} --def import_as_names(): -- # fmt: off + def import_as_names(): + # fmt: off - from hello import a, b - 'unformatted' -- # fmt: on ++ NOT_YET_IMPLEMENTED_StmtImportFrom ++ "NOT_YET_IMPLEMENTED_STRING" + # fmt: on -+NOT_YET_IMPLEMENTED_StmtFunctionDef --def testlist_star_expr(): -- # fmt: off + def testlist_star_expr(): + # fmt: off - a , b = *hello - 'unformatted' -- # fmt: on ++ (1, 2) = NOT_YET_IMPLEMENTED_ExprStarred ++ "NOT_YET_IMPLEMENTED_STRING" + # fmt: on -+NOT_YET_IMPLEMENTED_StmtFunctionDef --def yield_expr(): -- # fmt: off + def yield_expr(): + # fmt: off - yield hello - 'unformatted' -- # fmt: on ++ NOT_YET_IMPLEMENTED_ExprYield ++ "NOT_YET_IMPLEMENTED_STRING" + # fmt: on - "formatted" -- # fmt: off ++ "NOT_YET_IMPLEMENTED_STRING" + # fmt: off - ( yield hello ) - 'unformatted' -- # fmt: on ++ (NOT_YET_IMPLEMENTED_ExprYield) ++ "NOT_YET_IMPLEMENTED_STRING" + # fmt: on -+NOT_YET_IMPLEMENTED_StmtFunctionDef --def example(session): -- # fmt: off + def example(session): + # fmt: off - 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() -- # fmt: on ++ result = NOT_IMPLEMENTED_call() + # fmt: on -+NOT_YET_IMPLEMENTED_StmtFunctionDef --def off_and_on_without_data(): + def off_and_on_without_data(): - """All comments here are technically on the same prefix. - +- - The comments between will be formatted. This is a known limitation. - """ -- # fmt: off -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" + # fmt: off -- # hey, that won't work - -- # fmt: on -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef + # hey, that won't work +@@ -130,13 +128,15 @@ --def on_and_off_broken(): + def on_and_off_broken(): - """Another known limitation.""" -- # fmt: on -- # fmt: off ++ "NOT_YET_IMPLEMENTED_STRING" + # fmt: on + # fmt: off - this=should.not_be.formatted() - and_=indeed . it is not formatted - because . the . handling . inside . generate_ignored_nodes() - now . considers . multiple . fmt . directives . within . one . prefix -- # fmt: on -- # fmt: off -- # ...but comments still get reformatted even though they should not be -- # fmt: on -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - --def long_lines(): ++ this = NOT_IMPLEMENTED_call() ++ and_ = NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right ++ NOT_IMPLEMENTED_call() ++ ( ++ now.NOT_IMPLEMENTED_attr.NOT_IMPLEMENTED_attr.NOT_IMPLEMENTED_attr.NOT_IMPLEMENTED_attr.NOT_IMPLEMENTED_attr.NOT_IMPLEMENTED_attr.NOT_IMPLEMENTED_attr ++ ) + # fmt: on + # fmt: off + # ...but comments still get reformatted even though they should not be +@@ -144,81 +144,18 @@ + + + def long_lines(): - if True: - typedargslist.extend( - gen_annotated_params( @@ -408,13 +455,15 @@ d={'a':1, - re.MULTILINE|re.VERBOSE - # fmt: on - ) -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ NOT_YET_IMPLEMENTED_StmtIf ++ _type_comment_re = NOT_IMPLEMENTED_call() --def single_literal_yapf_disable(): + 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_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" ++ BAZ = {(1, 2), (1, 2), (1, 2)} # yapf: disable -cfg.rule( @@ -476,53 +525,142 @@ NOT_YET_IMPLEMENTED_ExprJoinedStr # fmt: off -NOT_YET_IMPLEMENTED_StmtFunctionDef +def func_no_args(): + a + b + c + NOT_YET_IMPLEMENTED_StmtIf + NOT_YET_IMPLEMENTED_StmtIf + NOT_YET_IMPLEMENTED_StmtFor + NOT_IMPLEMENTED_call() + return None -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def coroutine(arg, exec=False): + "NOT_YET_IMPLEMENTED_STRING" + NOT_YET_IMPLEMENTED_StmtAsyncWith + await NOT_IMPLEMENTED_call() -NOT_YET_IMPLEMENTED_StmtFunctionDef +@asyncio.NOT_IMPLEMENTED_attr +@NOT_IMPLEMENTED_call() +def function_signature_stress_test( + number: int, + no_annotation=None, + text: str = "NOT_YET_IMPLEMENTED_STRING", + debug: bool = False, + **kwargs, +) -> str: + return NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] # fmt: on -NOT_YET_IMPLEMENTED_StmtFunctionDef +def spaces( + a=1, + b=(1, 2), + c=[], + d={NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value}, + e=True, + f=NOT_YET_IMPLEMENTED_ExprUnaryOp, + g=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false, + h="NOT_YET_IMPLEMENTED_STRING", + i="NOT_YET_IMPLEMENTED_STRING", +): + offset = NOT_IMPLEMENTED_call() + NOT_YET_IMPLEMENTED_StmtAssert -NOT_YET_IMPLEMENTED_StmtFunctionDef +def spaces_types( + a: int = 1, + b: tuple = (1, 2), + c: list = [], + d: dict = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value}, + e: bool = True, + 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", +): + ... -NOT_YET_IMPLEMENTED_StmtFunctionDef +def spaces2(result=NOT_IMPLEMENTED_call()): + ... something = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} -NOT_YET_IMPLEMENTED_StmtFunctionDef +def subscriptlist(): + NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] -NOT_YET_IMPLEMENTED_StmtFunctionDef +def import_as_names(): + # fmt: off + NOT_YET_IMPLEMENTED_StmtImportFrom + "NOT_YET_IMPLEMENTED_STRING" + # fmt: on -NOT_YET_IMPLEMENTED_StmtFunctionDef +def testlist_star_expr(): + # fmt: off + (1, 2) = NOT_YET_IMPLEMENTED_ExprStarred + "NOT_YET_IMPLEMENTED_STRING" + # fmt: on -NOT_YET_IMPLEMENTED_StmtFunctionDef +def yield_expr(): + # fmt: off + NOT_YET_IMPLEMENTED_ExprYield + "NOT_YET_IMPLEMENTED_STRING" + # fmt: on + "NOT_YET_IMPLEMENTED_STRING" + # fmt: off + (NOT_YET_IMPLEMENTED_ExprYield) + "NOT_YET_IMPLEMENTED_STRING" + # fmt: on -NOT_YET_IMPLEMENTED_StmtFunctionDef +def example(session): + # fmt: off + result = NOT_IMPLEMENTED_call() + # fmt: on + + +def off_and_on_without_data(): + "NOT_YET_IMPLEMENTED_STRING" + # fmt: off + # hey, that won't work -NOT_YET_IMPLEMENTED_StmtFunctionDef + # fmt: on + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +def on_and_off_broken(): + "NOT_YET_IMPLEMENTED_STRING" + # fmt: on + # fmt: off + this = NOT_IMPLEMENTED_call() + and_ = NOT_IMPLEMENTED_left < NOT_IMPLEMENTED_right + NOT_IMPLEMENTED_call() + ( + now.NOT_IMPLEMENTED_attr.NOT_IMPLEMENTED_attr.NOT_IMPLEMENTED_attr.NOT_IMPLEMENTED_attr.NOT_IMPLEMENTED_attr.NOT_IMPLEMENTED_attr.NOT_IMPLEMENTED_attr + ) + # fmt: on + # fmt: off + # ...but comments still get reformatted even though they should not be + # fmt: on -NOT_YET_IMPLEMENTED_StmtFunctionDef +def long_lines(): + NOT_YET_IMPLEMENTED_StmtIf + _type_comment_re = NOT_IMPLEMENTED_call() -NOT_YET_IMPLEMENTED_StmtFunctionDef +def single_literal_yapf_disable(): + "NOT_YET_IMPLEMENTED_STRING" + BAZ = {(1, 2), (1, 2), (1, 2)} # yapf: disable NOT_IMPLEMENTED_call() diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip8_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip8_py.snap index 0fcef6b3496e1..1b9c54b04853a 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip8_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__fmtskip8_py.snap @@ -75,20 +75,23 @@ async def test_async_with(): ```diff --- Black +++ Ruff -@@ -1,62 +1,33 @@ +@@ -1,62 +1,40 @@ # Make sure a leading comment is not removed. -def some_func( unformatted, args ): # fmt: skip - print("I am some_func") -- return 0 -- # Make sure this comment is not removed. -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++def some_func(unformatted, args): # fmt: skip ++ NOT_IMPLEMENTED_call() + return 0 + # Make sure this comment is not removed. # Make sure a leading comment is not removed. -async def some_async_func( unformatted, args): # fmt: skip - print("I am some_async_func") - await asyncio.sleep(1) -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++async def some_async_func(unformatted, args): # fmt: skip ++ NOT_IMPLEMENTED_call() ++ await NOT_IMPLEMENTED_call() # Make sure a leading comment is not removed. @@ -96,13 +99,13 @@ async def test_async_with(): - def some_method( self, unformatted, args ): # fmt: skip - print("I am some_method") - return 0 -+NOT_YET_IMPLEMENTED_StmtClassDef - +- - async def some_async_method( self, unformatted, args ): # fmt: skip - print("I am some_async_method") - await asyncio.sleep(1) ++NOT_YET_IMPLEMENTED_StmtClassDef + -- # Make sure a leading comment is not removed. -if unformatted_call( args ): # fmt: skip - print("First branch") @@ -125,10 +128,10 @@ async def test_async_with(): +NOT_YET_IMPLEMENTED_StmtFor # fmt: skip --async def test_async_for(): + async def test_async_for(): - async for i in some_async_iter( unformatted, args ): # fmt: skip - print("Do something") -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ NOT_YET_IMPLEMENTED_StmtAsyncFor # fmt: skip -try : # fmt: skip @@ -145,21 +148,26 @@ async def test_async_with(): +NOT_YET_IMPLEMENTED_StmtWith # fmt: skip --async def test_async_with(): + async def test_async_with(): - async with give_me_async_context( unformatted, args ): # fmt: skip - print("Do something") -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ NOT_YET_IMPLEMENTED_StmtAsyncWith # fmt: skip ``` ## Ruff Output ```py # Make sure a leading comment is not removed. -NOT_YET_IMPLEMENTED_StmtFunctionDef +def some_func(unformatted, args): # fmt: skip + NOT_IMPLEMENTED_call() + return 0 + # Make sure this comment is not removed. # Make sure a leading comment is not removed. -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def some_async_func(unformatted, args): # fmt: skip + NOT_IMPLEMENTED_call() + await NOT_IMPLEMENTED_call() # Make sure a leading comment is not removed. @@ -177,7 +185,8 @@ while NOT_IMPLEMENTED_call(): # fmt: skip NOT_YET_IMPLEMENTED_StmtFor # fmt: skip -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def test_async_for(): + NOT_YET_IMPLEMENTED_StmtAsyncFor # fmt: skip NOT_YET_IMPLEMENTED_StmtTry @@ -186,7 +195,8 @@ NOT_YET_IMPLEMENTED_StmtTry NOT_YET_IMPLEMENTED_StmtWith # fmt: skip -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def test_async_with(): + NOT_YET_IMPLEMENTED_StmtAsyncWith # fmt: skip ``` ## Black Output diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function2_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function2_py.snap index 7222c21c5e187..d4b5749cd38f0 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function2_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__function2_py.snap @@ -66,11 +66,10 @@ with hmm_but_this_should_get_two_preceding_newlines(): ```diff --- Black +++ Ruff -@@ -1,65 +1,12 @@ --def f( -- a, -- **kwargs, --) -> A: +@@ -2,64 +2,27 @@ + a, + **kwargs, + ) -> A: - with cache_dir(): - if something: - result = CliRunner().invoke( @@ -82,19 +81,24 @@ with hmm_but_this_should_get_two_preceding_newlines(): - very_long_argument_name2=-very.long.value.for_the_argument, - **kwargs, - ) -- -- --def g(): ++ NOT_YET_IMPLEMENTED_StmtWith ++ NOT_IMPLEMENTED_call() # negate top ++ return NOT_IMPLEMENTED_call() + + + def g(): - "Docstring." -- -- def inner(): -- pass -- ++ "NOT_YET_IMPLEMENTED_STRING" + + def inner(): + pass + - print("Inner defs should breathe a little.") -- -- --def h(): -- def inner(): ++ NOT_IMPLEMENTED_call() + + + def h(): + def inner(): - pass - - print("Inner defs should breathe a little.") @@ -104,36 +108,34 @@ with hmm_but_this_should_get_two_preceding_newlines(): - import termios - - def i_should_be_followed_by_only_one_newline(): -- pass -- + pass + -elif os.name == "nt": - try: - import msvcrt -- ++ NOT_IMPLEMENTED_call() + - def i_should_be_followed_by_only_one_newline(): - pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef - except ImportError: ++NOT_YET_IMPLEMENTED_StmtIf - def i_should_be_followed_by_only_one_newline(): - pass - -elif False: -+NOT_YET_IMPLEMENTED_StmtFunctionDef - +- - class IHopeYouAreHavingALovelyDay: - def __call__(self): - print("i_should_be_followed_by_only_one_newline") - +- -else: -+NOT_YET_IMPLEMENTED_StmtFunctionDef - +- - def foo(): - pass - -+NOT_YET_IMPLEMENTED_StmtIf - +- +- -with hmm_but_this_should_get_two_preceding_newlines(): - pass +NOT_YET_IMPLEMENTED_StmtWith @@ -142,13 +144,29 @@ with hmm_but_this_should_get_two_preceding_newlines(): ## Ruff Output ```py -NOT_YET_IMPLEMENTED_StmtFunctionDef +def f( + a, + **kwargs, +) -> A: + NOT_YET_IMPLEMENTED_StmtWith + NOT_IMPLEMENTED_call() # negate top + return NOT_IMPLEMENTED_call() + + +def g(): + "NOT_YET_IMPLEMENTED_STRING" + + def inner(): + pass + NOT_IMPLEMENTED_call() -NOT_YET_IMPLEMENTED_StmtFunctionDef +def h(): + def inner(): + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef + NOT_IMPLEMENTED_call() NOT_YET_IMPLEMENTED_StmtIf 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 97bb06f0cdcc7..4990f6f531fd4 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 @@ -108,7 +108,7 @@ def __await__(): return (yield) ```diff --- Black +++ Ruff -@@ -1,148 +1,41 @@ +@@ -1,148 +1,94 @@ #!/usr/bin/env python3 -import asyncio -import sys @@ -125,10 +125,10 @@ def __await__(): return (yield) -f"trigger 3.6 mode" - --def func_no_args(): -- a -- b -- c + def func_no_args(): + a + b + c - if True: - raise RuntimeError - if False: @@ -137,59 +137,85 @@ def __await__(): return (yield) - print(i) - continue - exec("new-style exec", {}, {}) -- return None -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ NOT_YET_IMPLEMENTED_StmtIf ++ NOT_YET_IMPLEMENTED_StmtIf ++ NOT_YET_IMPLEMENTED_StmtFor ++ NOT_IMPLEMENTED_call() + return None --async def coroutine(arg, exec=False): + async def coroutine(arg, exec=False): - "Single-line docstring. Multiline is harder to reformat." - async with some_connection() as conn: - await conn.do_what_i_mean("SELECT bobby, tables FROM xkcd", timeout=2) - await asyncio.sleep(1) -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" ++ NOT_YET_IMPLEMENTED_StmtAsyncWith ++ await NOT_IMPLEMENTED_call() -@asyncio.coroutine -@some_decorator(with_args=True, many_args=[1, 2, 3]) --def function_signature_stress_test( -- number: int, -- no_annotation=None, ++@asyncio.NOT_IMPLEMENTED_attr ++@NOT_IMPLEMENTED_call() + def function_signature_stress_test( + number: int, + no_annotation=None, - text: str = "default", - *, -- debug: bool = False, -- **kwargs, --) -> str: ++ text: str = "NOT_YET_IMPLEMENTED_STRING", + debug: bool = False, + **kwargs, + ) -> str: - return text[number:-1] -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ return NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] -def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""): - offset = attr.ib(default=attr.Factory(lambda: _r.uniform(10000, 200000))) - assert task._cancel_stack[: len(old_stack)] == old_stack -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++def spaces( ++ a=1, ++ b=(1, 2), ++ c=[], ++ d={NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value}, ++ e=True, ++ f=NOT_YET_IMPLEMENTED_ExprUnaryOp, ++ g=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false, ++ h="NOT_YET_IMPLEMENTED_STRING", ++ i="NOT_YET_IMPLEMENTED_STRING", ++): ++ offset = NOT_IMPLEMENTED_call() ++ NOT_YET_IMPLEMENTED_StmtAssert --def spaces_types( -- a: int = 1, + def spaces_types( + a: int = 1, - b: tuple = (), -- c: list = [], ++ b: tuple = (1, 2), + c: list = [], - d: dict = {}, -- e: bool = True, ++ d: dict = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value}, + e: bool = True, - f: int = -1, - g: int = 1 if False else 2, - h: str = "", - i: str = r"", --): -- ... -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ 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", + ): + ... -def spaces2(result=_core.Value(None)): - assert fut is self._read_fut, (fut, self._read_fut) -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++def spaces2(result=NOT_IMPLEMENTED_call()): ++ NOT_YET_IMPLEMENTED_StmtAssert --def example(session): + def example(session): - result = ( - session.query(models.Customer.id) - .filter( @@ -199,10 +225,10 @@ def __await__(): return (yield) - .order_by(models.Customer.id.asc()) - .all() - ) -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ result = NOT_IMPLEMENTED_call() --def long_lines(): + def long_lines(): - if True: - typedargslist.extend( - gen_annotated_params( @@ -243,23 +269,24 @@ def __await__(): return (yield) - """, - re.MULTILINE | re.VERBOSE, - ) -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ NOT_YET_IMPLEMENTED_StmtIf ++ _type_comment_re = NOT_IMPLEMENTED_call() --def trailing_comma(): + def trailing_comma(): - mapping = { - A: 0.25 * (10.0 / 12), - B: 0.1 * (10.0 / 12), - C: 0.1 * (10.0 / 12), - D: 0.1 * (10.0 / 12), - } -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ mapping = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} --def f( -- a, -- **kwargs, --) -> A: + def f( + a, + **kwargs, + ) -> A: - return ( - yield from A( - very_long_argument_name1=very_long_value_for_the_argument, @@ -267,12 +294,12 @@ def __await__(): return (yield) - **kwargs, - ) - ) -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ return NOT_YET_IMPLEMENTED_ExprYieldFrom --def __await__(): + def __await__(): - return (yield) -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ return NOT_YET_IMPLEMENTED_ExprYield ``` ## Ruff Output @@ -288,37 +315,90 @@ NOT_YET_IMPLEMENTED_StmtImportFrom NOT_YET_IMPLEMENTED_ExprJoinedStr -NOT_YET_IMPLEMENTED_StmtFunctionDef - - -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +def func_no_args(): + a + b + c + NOT_YET_IMPLEMENTED_StmtIf + NOT_YET_IMPLEMENTED_StmtIf + NOT_YET_IMPLEMENTED_StmtFor + NOT_IMPLEMENTED_call() + return None -NOT_YET_IMPLEMENTED_StmtFunctionDef +async def coroutine(arg, exec=False): + "NOT_YET_IMPLEMENTED_STRING" + NOT_YET_IMPLEMENTED_StmtAsyncWith + await NOT_IMPLEMENTED_call() -NOT_YET_IMPLEMENTED_StmtFunctionDef +@asyncio.NOT_IMPLEMENTED_attr +@NOT_IMPLEMENTED_call() +def function_signature_stress_test( + number: int, + no_annotation=None, + text: str = "NOT_YET_IMPLEMENTED_STRING", + debug: bool = False, + **kwargs, +) -> str: + return NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] + + +def spaces( + a=1, + b=(1, 2), + c=[], + d={NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value}, + e=True, + f=NOT_YET_IMPLEMENTED_ExprUnaryOp, + g=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false, + h="NOT_YET_IMPLEMENTED_STRING", + i="NOT_YET_IMPLEMENTED_STRING", +): + offset = NOT_IMPLEMENTED_call() + NOT_YET_IMPLEMENTED_StmtAssert -NOT_YET_IMPLEMENTED_StmtFunctionDef +def spaces_types( + a: int = 1, + b: tuple = (1, 2), + c: list = [], + d: dict = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value}, + e: bool = True, + 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", +): + ... -NOT_YET_IMPLEMENTED_StmtFunctionDef +def spaces2(result=NOT_IMPLEMENTED_call()): + NOT_YET_IMPLEMENTED_StmtAssert -NOT_YET_IMPLEMENTED_StmtFunctionDef +def example(session): + result = NOT_IMPLEMENTED_call() -NOT_YET_IMPLEMENTED_StmtFunctionDef +def long_lines(): + NOT_YET_IMPLEMENTED_StmtIf + _type_comment_re = NOT_IMPLEMENTED_call() -NOT_YET_IMPLEMENTED_StmtFunctionDef +def trailing_comma(): + mapping = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} -NOT_YET_IMPLEMENTED_StmtFunctionDef +def f( + a, + **kwargs, +) -> A: + return NOT_YET_IMPLEMENTED_ExprYieldFrom -NOT_YET_IMPLEMENTED_StmtFunctionDef +def __await__(): + return NOT_YET_IMPLEMENTED_ExprYield ``` ## Black Output 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 03fd9abc72a92..9850280e89c53 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,21 +74,22 @@ some_module.some_function( ```diff --- Black +++ Ruff -@@ -1,114 +1,31 @@ --def f( -- a, --): +@@ -1,69 +1,29 @@ + def f( + a, + ): - d = { - "key": "value", - } - tup = (1,) -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ d = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} ++ tup = (1, 2) --def f2( -- a, -- b, --): + def f2( + a, + b, + ): - d = { - "key": "value", - "key2": "value2", @@ -97,12 +98,13 @@ some_module.some_function( - 1, - 2, - ) -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ d = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} ++ tup = (1, 2) --def f( -- a: int = 1, --): + def f( + a: int = 1, + ): - call( - arg={ - "explode": "this", @@ -129,7 +131,10 @@ some_module.some_function( - }["a"] - ): - pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ NOT_IMPLEMENTED_call() ++ NOT_IMPLEMENTED_call() ++ x = NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] ++ NOT_YET_IMPLEMENTED_StmtIf -def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> ( @@ -144,23 +149,13 @@ some_module.some_function( - } - } - } -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key]: ++ json = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} # The type annotation shouldn't get a trailing comma since that would change its type. - # Relevant bug report: https://github.com/psf/black/issues/2381. --def some_function_with_a_really_long_name() -> ( -- returning_a_deeply_nested_import_of_a_type_i_suppose --): -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - --def some_method_with_a_really_long_name( -- very_long_parameter_so_yeah: str, another_long_parameter: int --) -> another_case_of_returning_a_deeply_nested_import_of_a_type_i_suppose_cause_why_not: -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef +@@ -80,35 +40,16 @@ + pass -def func() -> ( @@ -168,8 +163,8 @@ some_module.some_function( - this_shouldn_t_get_a_trailing_comma_too - ) -): -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++def func() -> NOT_IMPLEMENTED_call(): + pass -def func() -> ( @@ -177,8 +172,8 @@ some_module.some_function( - this_shouldn_t_get_a_trailing_comma_too - ) -): -- pass -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++def func() -> NOT_IMPLEMENTED_call(): + pass # Make sure inner one-element tuple won't explode @@ -204,30 +199,54 @@ some_module.some_function( ## Ruff Output ```py -NOT_YET_IMPLEMENTED_StmtFunctionDef +def f( + a, +): + d = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} + tup = (1, 2) -NOT_YET_IMPLEMENTED_StmtFunctionDef +def f2( + a, + b, +): + d = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} + tup = (1, 2) -NOT_YET_IMPLEMENTED_StmtFunctionDef +def f( + a: int = 1, +): + NOT_IMPLEMENTED_call() + NOT_IMPLEMENTED_call() + x = NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] + NOT_YET_IMPLEMENTED_StmtIf -NOT_YET_IMPLEMENTED_StmtFunctionDef +def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key]: + json = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} # The type annotation shouldn't get a trailing comma since that would change its type. # Relevant bug report: https://github.com/psf/black/issues/2381. -NOT_YET_IMPLEMENTED_StmtFunctionDef +def some_function_with_a_really_long_name() -> ( + returning_a_deeply_nested_import_of_a_type_i_suppose +): + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +def some_method_with_a_really_long_name( + very_long_parameter_so_yeah: str, another_long_parameter: int +) -> another_case_of_returning_a_deeply_nested_import_of_a_type_i_suppose_cause_why_not: + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +def func() -> NOT_IMPLEMENTED_call(): + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef +def func() -> NOT_IMPLEMENTED_call(): + pass # Make sure inner one-element tuple won't explode 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 c3eb10be9893f..56b3a0ef5a8ab 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,21 +76,12 @@ return np.divide( ```diff --- Black +++ Ruff -@@ -1,63 +1,51 @@ --def function(**kwargs): -- t = a**2 + b**3 -- return t**2 -+NOT_YET_IMPLEMENTED_StmtFunctionDef +@@ -8,56 +8,48 @@ --def function_replace_spaces(**kwargs): -- t = a**2 + b**3 + c**4 -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - --def function_dont_replace_spaces(): + def function_dont_replace_spaces(): - {**a, **b, **c} -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} -a = 5**~4 @@ -184,13 +175,17 @@ return np.divide( ## Ruff Output ```py -NOT_YET_IMPLEMENTED_StmtFunctionDef +def function(**kwargs): + t = a**2 + b**3 + return t**2 -NOT_YET_IMPLEMENTED_StmtFunctionDef +def function_replace_spaces(**kwargs): + t = a**2 + b**3 + c**4 -NOT_YET_IMPLEMENTED_StmtFunctionDef +def function_dont_replace_spaces(): + {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value} a = 5**NOT_YET_IMPLEMENTED_ExprUnaryOp diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_await_parens_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_await_parens_py.snap index 2d1804fc958a1..7923c03bb5410 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_await_parens_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_await_parens_py.snap @@ -94,51 +94,58 @@ async def main(): ```diff --- Black +++ Ruff -@@ -1,93 +1,60 @@ +@@ -1,66 +1,57 @@ -import asyncio +NOT_YET_IMPLEMENTED_StmtImport # Control example --async def main(): + async def main(): - await asyncio.sleep(1) -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ await NOT_IMPLEMENTED_call() # Remove brackets for short coroutine/task --async def main(): + async def main(): - await asyncio.sleep(1) -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ await (NOT_IMPLEMENTED_call()) --async def main(): + async def main(): - await asyncio.sleep(1) -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ await (NOT_IMPLEMENTED_call()) --async def main(): + async def main(): - await asyncio.sleep(1) -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ await (NOT_IMPLEMENTED_call()) # Check comments --async def main(): + async def main(): - await asyncio.sleep(1) # Hello -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ ( ++ await # Hello ++ NOT_IMPLEMENTED_call() ++ ) --async def main(): + async def main(): - await asyncio.sleep(1) # Hello -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ ( ++ await ( ++ NOT_IMPLEMENTED_call() # Hello ++ ) ++ ) --async def main(): + async def main(): - await asyncio.sleep(1) # Hello -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ await (NOT_IMPLEMENTED_call()) # Hello # Long lines --async def main(): + async def main(): - await asyncio.gather( - asyncio.sleep(1), - asyncio.sleep(1), @@ -148,11 +155,11 @@ async def main(): - asyncio.sleep(1), - asyncio.sleep(1), - ) -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ await NOT_IMPLEMENTED_call() # Same as above but with magic trailing comma in function --async def main(): + async def main(): - await asyncio.gather( - asyncio.sleep(1), - asyncio.sleep(1), @@ -162,50 +169,46 @@ async def main(): - asyncio.sleep(1), - asyncio.sleep(1), - ) -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ await NOT_IMPLEMENTED_call() # Cr@zY Br@ck3Tz --async def main(): + async def main(): - await black(1) -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ await (NOT_IMPLEMENTED_call()) # Keep brackets around non power operations and nested awaits --async def main(): -- await (set_of_tasks | other_set) -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +@@ -69,7 +60,7 @@ --async def main(): + async def main(): - await (await asyncio.sleep(1)) -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ await (await NOT_IMPLEMENTED_call()) # It's awaits all the way down... --async def main(): -- await (await x) -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +@@ -78,16 +69,16 @@ --async def main(): + async def main(): - await (yield x) -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ await (NOT_YET_IMPLEMENTED_ExprYield) --async def main(): + async def main(): - await (await asyncio.sleep(1)) -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ await (await (NOT_IMPLEMENTED_call())) --async def main(): + async def main(): - await (await (await (await (await asyncio.sleep(1))))) -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ await (await (await (await (await (NOT_IMPLEMENTED_call()))))) --async def main(): + async def main(): - await (yield) -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ await (NOT_YET_IMPLEMENTED_ExprYield) ``` ## Ruff Output @@ -215,62 +218,86 @@ NOT_YET_IMPLEMENTED_StmtImport # Control example -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def main(): + await NOT_IMPLEMENTED_call() # Remove brackets for short coroutine/task -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def main(): + await (NOT_IMPLEMENTED_call()) -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def main(): + await (NOT_IMPLEMENTED_call()) -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def main(): + await (NOT_IMPLEMENTED_call()) # Check comments -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def main(): + ( + await # Hello + NOT_IMPLEMENTED_call() + ) -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def main(): + ( + await ( + NOT_IMPLEMENTED_call() # Hello + ) + ) -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def main(): + await (NOT_IMPLEMENTED_call()) # Hello # Long lines -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def main(): + await NOT_IMPLEMENTED_call() # Same as above but with magic trailing comma in function -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def main(): + await NOT_IMPLEMENTED_call() # Cr@zY Br@ck3Tz -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def main(): + await (NOT_IMPLEMENTED_call()) # Keep brackets around non power operations and nested awaits -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def main(): + await (set_of_tasks | other_set) -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def main(): + await (await NOT_IMPLEMENTED_call()) # It's awaits all the way down... -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def main(): + await (await x) -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def main(): + await (NOT_YET_IMPLEMENTED_ExprYield) -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def main(): + await (await (NOT_IMPLEMENTED_call())) -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def main(): + await (await (await (await (await (NOT_IMPLEMENTED_call()))))) -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def main(): + await (NOT_YET_IMPLEMENTED_ExprYield) ``` ## Black Output diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_newline_after_code_block_open_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_newline_after_code_block_open_py.snap index b0d01240b13b2..6bf44926b125a 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_newline_after_code_block_open_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__remove_newline_after_code_block_open_py.snap @@ -121,40 +121,40 @@ with open("/path/to/file.txt", mode="r") as read_file: ```diff --- Black +++ Ruff -@@ -1,78 +1,56 @@ +@@ -1,78 +1,64 @@ -import random +NOT_YET_IMPLEMENTED_StmtImport --def foo1(): + def foo1(): - print("The newline above me should be deleted!") -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ NOT_IMPLEMENTED_call() --def foo2(): + def foo2(): - print("All the newlines above me should be deleted!") -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ NOT_IMPLEMENTED_call() --def foo3(): + def foo3(): - print("No newline above me!") -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ NOT_IMPLEMENTED_call() - print("There is a newline above me, and that's OK!") ++ NOT_IMPLEMENTED_call() -+NOT_YET_IMPLEMENTED_StmtFunctionDef --def foo4(): -- # There is a comment here + def foo4(): + # There is a comment here - print("The newline above me should not be deleted!") -+NOT_YET_IMPLEMENTED_StmtClassDef ++ NOT_IMPLEMENTED_call() -class Foo: - def bar(self): - print("The newline above me should be deleted!") -+NOT_YET_IMPLEMENTED_StmtFor ++NOT_YET_IMPLEMENTED_StmtClassDef -for i in range(5): @@ -170,8 +170,9 @@ with open("/path/to/file.txt", mode="r") as read_file: -for i in range(5): - for j in range(7): - print(f"{i}) The lines above me should be removed!") -- -- ++NOT_YET_IMPLEMENTED_StmtFor + + -if random.randint(0, 3) == 0: - print("The new line above me is about to be removed!") +NOT_YET_IMPLEMENTED_StmtIf @@ -226,16 +227,24 @@ with open("/path/to/file.txt", mode="r") as read_file: NOT_YET_IMPLEMENTED_StmtImport -NOT_YET_IMPLEMENTED_StmtFunctionDef +def foo1(): + NOT_IMPLEMENTED_call() -NOT_YET_IMPLEMENTED_StmtFunctionDef +def foo2(): + NOT_IMPLEMENTED_call() -NOT_YET_IMPLEMENTED_StmtFunctionDef +def foo3(): + NOT_IMPLEMENTED_call() + NOT_IMPLEMENTED_call() -NOT_YET_IMPLEMENTED_StmtFunctionDef + +def foo4(): + # There is a comment here + + NOT_IMPLEMENTED_call() NOT_YET_IMPLEMENTED_StmtClassDef 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 3802fc4b75d09..5e1e16cd2ebc1 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 @@ -68,7 +68,7 @@ def example8(): ```diff --- Black +++ Ruff -@@ -1,85 +1,37 @@ +@@ -1,24 +1,16 @@ x = 1 x = 1.2 @@ -78,8 +78,8 @@ def example8(): +data = NOT_IMPLEMENTED_call() --async def show_status(): -- while True: + async def show_status(): + while True: - try: - if report_host: - data = ( @@ -87,54 +87,47 @@ def example8(): - ).encode() - except Exception as e: - pass -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ NOT_YET_IMPLEMENTED_StmtTry --def example(): + def example(): - return "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ return "NOT_YET_IMPLEMENTED_STRING" --def example1(): -- return 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111 -+NOT_YET_IMPLEMENTED_StmtFunctionDef + def example1(): +@@ -30,15 +22,11 @@ --def example1point5(): -- return 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111 -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - --def example2(): + def example2(): - return ( - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - ) -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ return "NOT_YET_IMPLEMENTED_STRING" --def example3(): + def example3(): - return ( - 1111111111111111111111111111111111111111111111111111111111111111111111111111111 - ) -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ return 1111111111111111111111111111111111111111111111111111111111111111111111111111111 --def example4(): -- return True -+NOT_YET_IMPLEMENTED_StmtFunctionDef + def example4(): +@@ -46,39 +34,15 @@ --def example5(): + def example5(): - return () -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ return (1, 2) --def example6(): + def example6(): - return {a: a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]} -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ return {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} --def example7(): + def example7(): - return { - a: a - for a in [ @@ -160,12 +153,10 @@ def example8(): - 20000000000000000000, - ] - } -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ return {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} --def example8(): -- return None -+NOT_YET_IMPLEMENTED_StmtFunctionDef + def example8(): ``` ## Ruff Output @@ -177,37 +168,49 @@ x = 1.2 data = NOT_IMPLEMENTED_call() -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def show_status(): + while True: + NOT_YET_IMPLEMENTED_StmtTry -NOT_YET_IMPLEMENTED_StmtFunctionDef +def example(): + return "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def example1(): + return 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111 -NOT_YET_IMPLEMENTED_StmtFunctionDef +def example1point5(): + return 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111 -NOT_YET_IMPLEMENTED_StmtFunctionDef +def example2(): + return "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def example3(): + return 1111111111111111111111111111111111111111111111111111111111111111111111111111111 -NOT_YET_IMPLEMENTED_StmtFunctionDef +def example4(): + return True -NOT_YET_IMPLEMENTED_StmtFunctionDef +def example5(): + return (1, 2) -NOT_YET_IMPLEMENTED_StmtFunctionDef +def example6(): + return {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} -NOT_YET_IMPLEMENTED_StmtFunctionDef +def example7(): + return {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} -NOT_YET_IMPLEMENTED_StmtFunctionDef +def example8(): + return None ``` ## Black Output diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__return_annotation_brackets_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__return_annotation_brackets_py.snap index b5fb72b427638..404098c4317aa 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__return_annotation_brackets_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__return_annotation_brackets_py.snap @@ -101,123 +101,35 @@ def foo() -> tuple[int, int, int,]: ```diff --- Black +++ Ruff -@@ -1,120 +1,65 @@ - # Control --def double(a: int) -> int: -- return 2 * a -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - - # Remove the brackets --def double(a: int) -> int: -- return 2 * a -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - - # Some newline variations --def double(a: int) -> int: -- return 2 * a -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - --def double(a: int) -> int: -- return 2 * a -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - --def double(a: int) -> int: -- return 2 * a -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - - # Don't lose the comments --def double(a: int) -> int: # Hello -- return 2 * a -+NOT_YET_IMPLEMENTED_StmtFunctionDef +@@ -26,7 +26,9 @@ + return 2 * a -def double(a: int) -> int: # Hello -- return 2 * a -+NOT_YET_IMPLEMENTED_StmtFunctionDef - ++def double(a: int) -> ( ++ int # Hello ++): + return 2 * a - # Really long annotations --def foo() -> ( -- intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds --): -- return 2 -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - --def foo() -> ( -- intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds --): -- return 2 -+NOT_YET_IMPLEMENTED_StmtFunctionDef - --def foo() -> ( -- intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds -- | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds --): -- return 2 -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - --def foo( -- a: int, -- b: int, -- c: int, +@@ -54,7 +56,9 @@ + a: int, + b: int, + c: int, -) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds: -- return 2 -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - --def foo( -- a: int, -- b: int, -- c: int, --) -> ( -- intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds -- | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds --): -- return 2 -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - - # Split args but no need to split return --def foo( -- a: int, -- b: int, -- c: int, --) -> int: -- return 2 -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - - # Deeply nested brackets - # with *interesting* spacing --def double(a: int) -> int: -- return 2 * a -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++) -> ( ++ intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds ++): + return 2 --def double(a: int) -> int: -- return 2 * a -+NOT_YET_IMPLEMENTED_StmtFunctionDef - - --def foo() -> ( -- intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds --): -- return 2 -+NOT_YET_IMPLEMENTED_StmtFunctionDef +@@ -95,26 +99,14 @@ # Return type with commas -def foo() -> tuple[int, int, int]: -- return 2 -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++def foo() -> NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key]: + return 2 -def foo() -> ( @@ -227,8 +139,8 @@ def foo() -> tuple[int, int, int,]: - loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, - ] -): -- return 2 -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++def foo() -> NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key]: + return 2 # Magic trailing comma example @@ -239,78 +151,125 @@ def foo() -> tuple[int, int, int,]: - int, - ] -): -- return 2 -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++def foo() -> NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key]: + return 2 ``` ## Ruff Output ```py # Control -NOT_YET_IMPLEMENTED_StmtFunctionDef +def double(a: int) -> int: + return 2 * a # Remove the brackets -NOT_YET_IMPLEMENTED_StmtFunctionDef +def double(a: int) -> int: + return 2 * a # Some newline variations -NOT_YET_IMPLEMENTED_StmtFunctionDef +def double(a: int) -> int: + return 2 * a -NOT_YET_IMPLEMENTED_StmtFunctionDef +def double(a: int) -> int: + return 2 * a -NOT_YET_IMPLEMENTED_StmtFunctionDef +def double(a: int) -> int: + return 2 * a # Don't lose the comments -NOT_YET_IMPLEMENTED_StmtFunctionDef +def double(a: int) -> int: # Hello + return 2 * a -NOT_YET_IMPLEMENTED_StmtFunctionDef +def double(a: int) -> ( + int # Hello +): + return 2 * a # Really long annotations -NOT_YET_IMPLEMENTED_StmtFunctionDef +def foo() -> ( + intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds +): + return 2 -NOT_YET_IMPLEMENTED_StmtFunctionDef +def foo() -> ( + intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds +): + return 2 -NOT_YET_IMPLEMENTED_StmtFunctionDef +def foo() -> ( + intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds + | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds +): + return 2 -NOT_YET_IMPLEMENTED_StmtFunctionDef +def foo( + a: int, + b: int, + c: int, +) -> ( + intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds +): + return 2 -NOT_YET_IMPLEMENTED_StmtFunctionDef +def foo( + a: int, + b: int, + c: int, +) -> ( + intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds + | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds +): + return 2 # Split args but no need to split return -NOT_YET_IMPLEMENTED_StmtFunctionDef +def foo( + a: int, + b: int, + c: int, +) -> int: + return 2 # Deeply nested brackets # with *interesting* spacing -NOT_YET_IMPLEMENTED_StmtFunctionDef +def double(a: int) -> int: + return 2 * a -NOT_YET_IMPLEMENTED_StmtFunctionDef +def double(a: int) -> int: + return 2 * a -NOT_YET_IMPLEMENTED_StmtFunctionDef +def foo() -> ( + intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds +): + return 2 # Return type with commas -NOT_YET_IMPLEMENTED_StmtFunctionDef +def foo() -> NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key]: + return 2 -NOT_YET_IMPLEMENTED_StmtFunctionDef +def foo() -> NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key]: + return 2 # Magic trailing comma example -NOT_YET_IMPLEMENTED_StmtFunctionDef +def foo() -> NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key]: + return 2 ``` ## Black Output 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 3fae804e2dec6..6dc17b505b5ae 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,37 @@ +@@ -1,59 +1,38 @@ -slice[a.b : c.d] -slice[d :: d + 1] -slice[d + 1 :: d] @@ -117,9 +117,9 @@ x[ +NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] --async def f(): + async def f(): - slice[await x : [i async for i in arange(42)] : 42] -+NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef ++ NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] # These are from PEP-8: @@ -191,7 +191,8 @@ NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] -NOT_YET_IMPLEMENTED_StmtAsyncFunctionDef +async def f(): + NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] # These are from PEP-8: 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 72a298611219a..eb5b0bf26b062 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,16 @@ +@@ -1,20 +1,18 @@ #!/usr/bin/env python3 -name = "Łukasz" @@ -53,16 +53,16 @@ def docstring_multiline(): +(1, 2) --def docstring_singleline(): + def docstring_singleline(): - R"""2020 was one hell of a year. The good news is that we were able to""" -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" --def docstring_multiline(): + def docstring_multiline(): - R""" - clear out all of the issues opened in that time :p - """ -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ "NOT_YET_IMPLEMENTED_STRING" ``` ## Ruff Output @@ -80,10 +80,12 @@ name = "NOT_YET_IMPLEMENTED_STRING" (1, 2) -NOT_YET_IMPLEMENTED_StmtFunctionDef +def docstring_singleline(): + "NOT_YET_IMPLEMENTED_STRING" -NOT_YET_IMPLEMENTED_StmtFunctionDef +def docstring_multiline(): + "NOT_YET_IMPLEMENTED_STRING" ``` ## Black Output 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 fcc9f5767e32d..0aee58f5ca4e3 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__torture_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__black_test__torture_py.snap @@ -42,7 +42,7 @@ assert ( ```diff --- Black +++ Ruff -@@ -1,58 +1,21 @@ +@@ -1,58 +1,22 @@ importA ( - () @@ -79,7 +79,7 @@ assert ( +NOT_YET_IMPLEMENTED_StmtClassDef --def test(self, othr): + def test(self, othr): - return 1 == 2 and ( - name, - description, @@ -99,7 +99,7 @@ assert ( - othr.meta_data, - othr.schedule, - ) -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ return NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 -assert a_function( @@ -129,7 +129,8 @@ importA NOT_YET_IMPLEMENTED_StmtClassDef -NOT_YET_IMPLEMENTED_StmtFunctionDef +def test(self, othr): + return NOT_IMPLEMENTED_bool_op1 and NOT_IMPLEMENTED_bool_op2 NOT_YET_IMPLEMENTED_StmtAssert 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 5f7947985b589..d1a1d68ab9bc9 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,20 @@ +@@ -1,50 +1,21 @@ -zero( - one, -).two( @@ -79,14 +79,14 @@ assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx( # Example from https://github.com/psf/black/issues/3229 --def refresh_token(self, device_family, refresh_token, api_key): + def refresh_token(self, device_family, refresh_token, api_key): - return self.orchestration.refresh_token( - data={ - "refreshToken": refresh_token, - }, - api_key=api_key, - )["extensions"]["sdk"]["token"] -+NOT_YET_IMPLEMENTED_StmtFunctionDef ++ return NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] # Edge case where a bug in a working-in-progress version of @@ -120,7 +120,8 @@ NOT_IMPLEMENTED_call() # Example from https://github.com/psf/black/issues/3229 -NOT_YET_IMPLEMENTED_StmtFunctionDef +def refresh_token(self, device_family, refresh_token, api_key): + return NOT_IMPLEMENTED_value[NOT_IMPLEMENTED_key] # Edge case where a bug in a working-in-progress version of diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__statement__function_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__statement__function_py.snap new file mode 100644 index 0000000000000..3d448396f60da --- /dev/null +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__statement__function_py.snap @@ -0,0 +1,182 @@ +--- +source: crates/ruff_python_formatter/src/lib.rs +expression: snapshot +--- +## Input +```py +# Dangling comments +def test( + # comment + + # another + +): ... + + +# Argument empty line spacing +def test( + # comment + a, + + # another + + b, +): ... + + +### Different function argument wrappings + +def single_line(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccccccccc): + pass + +def arguments_on_their_own_line(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccc, ddddddddddddd, eeeeeee): + pass + +def argument_per_line(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccccccccc, ddddddddddddd, eeeeeeeeeeeeeeee, ffffffffffff): + pass + +def last_pos_only_trailing_comma(a, b, /,): + pass + +def last_pos_no_trailing_comma(a, b, /): + pass + + +def varg_with_leading_comments( + a, b, + # comment + *args +): ... + +def kwarg_with_leading_comments( + a, b, + # comment + **kwargs +): ... + +def argument_with_long_default( + a, + b = ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc + [ + dddddddddddddddddddd, eeeeeeeeeeeeeeeeeeee, ffffffffffffffffffffffff + ], + h = [] +): ... + + +def argument_with_long_type_annotation( + a, + b: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy | zzzzzzzzzzzzzzzzzzz = [0, 1, 2, 3], + h = [] +): ... + + +def test(): ... + +# Comment +def with_leading_comment(): ... +``` + + + +## Output +```py +# Dangling comments +def test( + # comment + # another +): + ... + + +# Argument empty line spacing +def test( + # comment + a, + # another + b, +): + ... + + +### Different function argument wrappings + +def single_line(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccccccccc): + pass + + +def arguments_on_their_own_line( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, ccccccccccc, ddddddddddddd, eeeeeee +): + pass + + +def argument_per_line( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, + bbbbbbbbbbbbbbb, + ccccccccccccccccc, + ddddddddddddd, + eeeeeeeeeeeeeeee, + ffffffffffff, +): + pass + + +def last_pos_only_trailing_comma( + a, + b, + /, +): + pass + + +def last_pos_no_trailing_comma(a, b, /): + pass + + +def varg_with_leading_comments( + a, + b, + # comment + *args, +): + ... + + +def kwarg_with_leading_comments( + a, + b, + # comment + **kwargs, +): + ... + + +def argument_with_long_default( + a, + b=ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc + + [dddddddddddddddddddd, eeeeeeeeeeeeeeeeeeee, ffffffffffffffffffffffff], + h=[], +): + ... + + +def argument_with_long_type_annotation( + a, + b: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + | yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy + | zzzzzzzzzzzzzzzzzzz = [0, 1, 2, 3], + h=[], +): + ... + + +def test(): + ... + + +# Comment +def with_leading_comment(): + ... +``` + + diff --git a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__statement__stmt_assign_py.snap b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__statement__stmt_assign_py.snap index 206324b160cf0..b4237a40c768b 100644 --- a/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__statement__stmt_assign_py.snap +++ b/crates/ruff_python_formatter/src/snapshots/ruff_python_formatter__tests__ruff_test__statement__stmt_assign_py.snap @@ -21,17 +21,13 @@ a = asdf = fjhalsdljfalflaflapamsakjsdhflakjdslfjhalsdljfalflaflapamsakjsdhflakj ## Output ```py # break left hand side -a1akjdshflkjahdslkfjlasfdahjlfds = bakjdshflkjahdslkfjlasfdahjlfds = cakjdshflkjahdslkfjlasfdahjlfds = kjaödkjaföjfahlfdalfhaöfaöfhaöfha = fkjaödkjaföjfahlfdalfhaöfaöfhaöfha = g = ( - 3 -) +a1akjdshflkjahdslkfjlasfdahjlfds = bakjdshflkjahdslkfjlasfdahjlfds = cakjdshflkjahdslkfjlasfdahjlfds = kjaödkjaföjfahlfdalfhaöfaöfhaöfha = fkjaödkjaföjfahlfdalfhaöfaöfhaöfha = g = 3 # join left hand side a2 = (b2) = 2 # Break the last element -a = asdf = fjhalsdljfalflaflapamsakjsdhflakjdslfjhalsdljfalflaflapamsakjsdhflakjdslfjhalsdljfal = ( - 1 -) +a = asdf = fjhalsdljfalflaflapamsakjsdhflakjdslfjhalsdljfalflaflapamsakjsdhflakjdslfjhalsdljfal = 1 ``` diff --git a/crates/ruff_python_formatter/src/statement/stmt_async_function_def.rs b/crates/ruff_python_formatter/src/statement/stmt_async_function_def.rs index c81a5f0eaa7df..a0e28aa381d33 100644 --- a/crates/ruff_python_formatter/src/statement/stmt_async_function_def.rs +++ b/crates/ruff_python_formatter/src/statement/stmt_async_function_def.rs @@ -1,5 +1,6 @@ -use crate::{not_yet_implemented, FormatNodeRule, PyFormatter}; -use ruff_formatter::{write, Buffer, FormatResult}; +use crate::prelude::*; +use crate::FormatNodeRule; +use ruff_python_ast::function::AnyFunctionDefinition; use rustpython_parser::ast::StmtAsyncFunctionDef; #[derive(Default)] @@ -7,6 +8,15 @@ pub struct FormatStmtAsyncFunctionDef; impl FormatNodeRule for FormatStmtAsyncFunctionDef { fn fmt_fields(&self, item: &StmtAsyncFunctionDef, f: &mut PyFormatter) -> FormatResult<()> { - write!(f, [not_yet_implemented(item)]) + AnyFunctionDefinition::from(item).format().fmt(f) + } + + fn fmt_dangling_comments( + &self, + _node: &StmtAsyncFunctionDef, + _f: &mut PyFormatter, + ) -> FormatResult<()> { + // Handled by `AnyFunctionDef` + Ok(()) } } diff --git a/crates/ruff_python_formatter/src/statement/stmt_function_def.rs b/crates/ruff_python_formatter/src/statement/stmt_function_def.rs index e39f24f2ac2f8..ed48d4820deda 100644 --- a/crates/ruff_python_formatter/src/statement/stmt_function_def.rs +++ b/crates/ruff_python_formatter/src/statement/stmt_function_def.rs @@ -1,12 +1,141 @@ -use crate::{not_yet_implemented, FormatNodeRule, PyFormatter}; -use ruff_formatter::{write, Buffer, FormatResult}; -use rustpython_parser::ast::StmtFunctionDef; +use crate::comments::{leading_comments, trailing_comments}; +use crate::context::NodeLevel; +use crate::expression::parentheses::Parenthesize; +use crate::prelude::*; +use crate::trivia::{lines_after, skip_trailing_trivia}; +use crate::FormatNodeRule; +use ruff_formatter::{write, FormatOwnedWithRule, FormatRefWithRule}; +use ruff_python_ast::function::AnyFunctionDefinition; +use rustpython_parser::ast::{Ranged, StmtFunctionDef}; #[derive(Default)] pub struct FormatStmtFunctionDef; impl FormatNodeRule for FormatStmtFunctionDef { fn fmt_fields(&self, item: &StmtFunctionDef, f: &mut PyFormatter) -> FormatResult<()> { - write!(f, [not_yet_implemented(item)]) + AnyFunctionDefinition::from(item).format().fmt(f) + } + + fn fmt_dangling_comments( + &self, + _node: &StmtFunctionDef, + _f: &mut PyFormatter, + ) -> FormatResult<()> { + // Handled by `AnyFunctionDef` + Ok(()) + } +} + +#[derive(Default)] +pub struct FormatAnyFunctionDef; + +impl FormatRule, PyFormatContext<'_>> for FormatAnyFunctionDef { + fn fmt( + &self, + item: &AnyFunctionDefinition<'_>, + f: &mut Formatter>, + ) -> FormatResult<()> { + let comments = f.context().comments().clone(); + + let dangling_comments = comments.dangling_comments(item.into()); + let trailing_definition_comments_start = + dangling_comments.partition_point(|comment| comment.position().is_own_line()); + + let (leading_function_definition_comments, trailing_definition_comments) = + dangling_comments.split_at(trailing_definition_comments_start); + + if let Some(last_decorator) = item.decorators().last() { + f.join_nodes(NodeLevel::CompoundStatement) + .nodes(item.decorators()) + .finish()?; + + if leading_function_definition_comments.is_empty() { + write!(f, [hard_line_break()])?; + } else { + // Write any leading function comments (between last decorator and function header) + // while maintaining the right amount of empty lines between the comment + // and the last decorator. + let decorator_end = + skip_trailing_trivia(last_decorator.end(), f.context().contents()); + + let leading_line = if lines_after(decorator_end, f.context().contents()) <= 1 { + hard_line_break() + } else { + empty_line() + }; + + write!( + f, + [ + leading_line, + leading_comments(leading_function_definition_comments) + ] + )?; + } + } + + if item.is_async() { + write!(f, [text("async"), space()])?; + } + + let name = item.name(); + + write!( + f, + [ + text("def"), + space(), + dynamic_text(name.as_str(), None), + item.arguments().format(), + ] + )?; + + if let Some(return_annotation) = item.returns() { + write!( + f, + [ + space(), + text("->"), + space(), + return_annotation + .format() + .with_options(Parenthesize::IfBreaks) + ] + )?; + } + + write!( + f, + [ + text(":"), + trailing_comments(trailing_definition_comments), + block_indent(&item.body().format()) + ] + ) + } +} + +impl<'def, 'ast> AsFormat> for AnyFunctionDefinition<'def> { + type Format<'a> = FormatRefWithRule< + 'a, + AnyFunctionDefinition<'def>, + FormatAnyFunctionDef, + PyFormatContext<'ast>, + > where Self: 'a; + + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new(self, FormatAnyFunctionDef::default()) + } +} + +impl<'def, 'ast> IntoFormat> for AnyFunctionDefinition<'def> { + type Format = FormatOwnedWithRule< + AnyFunctionDefinition<'def>, + FormatAnyFunctionDef, + PyFormatContext<'ast>, + >; + + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new(self, FormatAnyFunctionDef) } } diff --git a/crates/ruff_python_formatter/src/statement/suite.rs b/crates/ruff_python_formatter/src/statement/suite.rs index d80bb55803794..23b98f179895a 100644 --- a/crates/ruff_python_formatter/src/statement/suite.rs +++ b/crates/ruff_python_formatter/src/statement/suite.rs @@ -188,7 +188,7 @@ mod tests { use crate::comments::Comments; use crate::prelude::*; use crate::statement::suite::SuiteLevel; - use ruff_formatter::{format, SimpleFormatOptions}; + use ruff_formatter::{format, IndentStyle, SimpleFormatOptions}; use rustpython_parser::ast::Suite; use rustpython_parser::Parse; @@ -216,8 +216,14 @@ def trailing_func(): let statements = Suite::parse(source, "test.py").unwrap(); - let context = - PyFormatContext::new(SimpleFormatOptions::default(), source, Comments::default()); + let context = PyFormatContext::new( + SimpleFormatOptions { + indent_style: IndentStyle::Space(4), + ..SimpleFormatOptions::default() + }, + source, + Comments::default(), + ); let test_formatter = format_with(|f: &mut PyFormatter| statements.format().with_options(level).fmt(f)); @@ -252,10 +258,13 @@ NOT_YET_IMPLEMENTED_StmtClassDef trailing_statement = 1 -NOT_YET_IMPLEMENTED_StmtFunctionDef +def func(): + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef"# +def trailing_func(): + pass +"# ); } @@ -278,9 +287,12 @@ NOT_YET_IMPLEMENTED_StmtClassDef trailing_statement = 1 -NOT_YET_IMPLEMENTED_StmtFunctionDef +def func(): + pass -NOT_YET_IMPLEMENTED_StmtFunctionDef"# +def trailing_func(): + pass +"# ); } }