From 205d2348560671d07939a59c8ab89eecc7992421 Mon Sep 17 00:00:00 2001 From: Harutaka Kawamura Date: Thu, 24 Aug 2023 10:58:05 +0900 Subject: [PATCH] Format `PatternMatchStar` (#6653) --- .../test/fixtures/ruff/statement/match.py | 38 ++++++- .../src/comments/placement.rs | 15 +++ .../src/pattern/pattern_match_star.rs | 33 +++++-- ...y@py_310__pattern_matching_complex.py.snap | 43 ++------ ...ty@py_310__pattern_matching_extras.py.snap | 36 ++----- ...ty@py_310__pattern_matching_simple.py.snap | 22 +---- .../snapshots/format@statement__match.py.snap | 99 ++++++++++++++++++- 7 files changed, 194 insertions(+), 92 deletions(-) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/match.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/match.py index 7f4b6a956a510..8b45e6a9ffb6d 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/match.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/match.py @@ -237,7 +237,6 @@ def foo(): ]: pass - match foo: case 1: y = 0 @@ -263,3 +262,40 @@ def foo(): # comment ): y = 1 + +match foo: + case [1, 2, *rest]: + pass + case [1, 2, *_]: + pass + case [*rest, 1, 2]: + pass + case [*_, 1, 2]: + pass + case [ + 1, + 2, + *rest, + ]: + pass + case [1, 2, * # comment + rest]: + pass + case [1, 2, * # comment + _]: + pass + case [* # comment + rest, 1, 2]: + pass + case [* # comment + _, 1, 2]: + pass + case [* # end of line + # own line + _, 1, 2]: + pass + case [* # end of line + # own line + _, 1, 2]: + pass + diff --git a/crates/ruff_python_formatter/src/comments/placement.rs b/crates/ruff_python_formatter/src/comments/placement.rs index 49d4534131ca4..56a9c35e843ab 100644 --- a/crates/ruff_python_formatter/src/comments/placement.rs +++ b/crates/ruff_python_formatter/src/comments/placement.rs @@ -206,6 +206,7 @@ fn handle_enclosed_comment<'a>( } AnyNodeRef::WithItem(_) => handle_with_item_comment(comment, locator), AnyNodeRef::PatternMatchAs(_) => handle_pattern_match_as_comment(comment, locator), + AnyNodeRef::PatternMatchStar(_) => handle_pattern_match_star_comment(comment), AnyNodeRef::StmtFunctionDef(_) => handle_leading_function_with_decorators_comment(comment), AnyNodeRef::StmtClassDef(class_def) => { handle_leading_class_with_decorators_comment(comment, class_def) @@ -1187,6 +1188,20 @@ fn handle_pattern_match_as_comment<'a>( } } +/// Handles dangling comments between the `*` token and identifier of a pattern match star: +/// +/// ```python +/// case [ +/// ..., +/// * # dangling end of line comment +/// # dangling end of line comment +/// rest, +/// ]: ... +/// ``` +fn handle_pattern_match_star_comment(comment: DecoratedComment) -> CommentPlacement { + CommentPlacement::dangling(comment.enclosing_node(), comment) +} + /// Handles comments around the `:=` token in a named expression (walrus operator). /// /// For example, here, `# 1` and `# 2` will be marked as dangling comments on the named expression, diff --git a/crates/ruff_python_formatter/src/pattern/pattern_match_star.rs b/crates/ruff_python_formatter/src/pattern/pattern_match_star.rs index 613586752e914..7ee3dbffb8643 100644 --- a/crates/ruff_python_formatter/src/pattern/pattern_match_star.rs +++ b/crates/ruff_python_formatter/src/pattern/pattern_match_star.rs @@ -1,19 +1,34 @@ -use ruff_formatter::{write, Buffer, FormatResult}; +use ruff_formatter::{prelude::text, write, Buffer, FormatResult}; use ruff_python_ast::PatternMatchStar; -use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter}; +use crate::comments::{dangling_comments, SourceComment}; +use crate::AsFormat; +use crate::{FormatNodeRule, PyFormatter}; #[derive(Default)] pub struct FormatPatternMatchStar; impl FormatNodeRule for FormatPatternMatchStar { fn fmt_fields(&self, item: &PatternMatchStar, f: &mut PyFormatter) -> FormatResult<()> { - write!( - f, - [not_yet_implemented_custom_text( - "*NOT_YET_IMPLEMENTED_PatternMatchStar", - item - )] - ) + let PatternMatchStar { name, .. } = item; + + let comments = f.context().comments().clone(); + let dangling = comments.dangling(item); + + write!(f, [text("*"), dangling_comments(dangling)])?; + + match name { + Some(name) => write!(f, [name.format()]), + None => write!(f, [text("_")]), + } + } + + fn fmt_dangling_comments( + &self, + _dangling_comments: &[SourceComment], + _f: &mut PyFormatter, + ) -> FormatResult<()> { + // Handled by `fmt_fields` + Ok(()) } } diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_complex.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_complex.py.snap index 69fa19f8de895..9aad3c54d377e 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_complex.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_complex.py.snap @@ -179,8 +179,7 @@ match x: y = 0 # case black_check_sequence_then_mapping match x: -- case [*_]: -+ case [*NOT_YET_IMPLEMENTED_PatternMatchStar]: + case [*_]: return "seq" - case {}: + case {"NOT_YET_IMPLEMENTED_PatternMatchMapping": _, 2: _}: @@ -204,7 +203,7 @@ match x: x = True # case black_test_patma_154 match x: -@@ -54,15 +54,15 @@ +@@ -54,11 +54,11 @@ y = 0 # case black_test_patma_134 match x: @@ -219,12 +218,7 @@ match x: y = 2 # case black_test_patma_185 match Seq(): -- case [*_]: -+ case [*NOT_YET_IMPLEMENTED_PatternMatchStar]: - y = 0 - # case black_test_patma_063 - match x: -@@ -72,11 +72,11 @@ +@@ -72,7 +72,7 @@ y = 1 # case black_test_patma_248 match x: @@ -233,26 +227,7 @@ match x: y = bar # case black_test_patma_019 match (0, 1, 2): -- case [0, 1, *x, 2]: -+ case [0, 1, *NOT_YET_IMPLEMENTED_PatternMatchStar, 2]: - y = 0 - # case black_test_patma_052 - match x: -@@ -88,7 +88,7 @@ - y = 2 - # case black_test_patma_191 - match w: -- case [x, y, *_]: -+ case [x, y, *NOT_YET_IMPLEMENTED_PatternMatchStar]: - z = 0 - # case black_test_patma_110 - match x: -@@ -128,17 +128,17 @@ - y = 0 - # case black_test_patma_189 - match w: -- case [x, y, *rest]: -+ case [x, y, *NOT_YET_IMPLEMENTED_PatternMatchStar]: +@@ -132,13 +132,13 @@ z = 0 # case black_test_patma_042 match x: @@ -300,7 +275,7 @@ match x: y = 0 # case black_check_sequence_then_mapping match x: - case [*NOT_YET_IMPLEMENTED_PatternMatchStar]: + case [*_]: return "seq" case {"NOT_YET_IMPLEMENTED_PatternMatchMapping": _, 2: _}: return "map" @@ -338,7 +313,7 @@ match x: y = 2 # case black_test_patma_185 match Seq(): - case [*NOT_YET_IMPLEMENTED_PatternMatchStar]: + case [*_]: y = 0 # case black_test_patma_063 match x: @@ -352,7 +327,7 @@ match x: y = bar # case black_test_patma_019 match (0, 1, 2): - case [0, 1, *NOT_YET_IMPLEMENTED_PatternMatchStar, 2]: + case [0, 1, *x, 2]: y = 0 # case black_test_patma_052 match x: @@ -364,7 +339,7 @@ match x: y = 2 # case black_test_patma_191 match w: - case [x, y, *NOT_YET_IMPLEMENTED_PatternMatchStar]: + case [x, y, *_]: z = 0 # case black_test_patma_110 match x: @@ -404,7 +379,7 @@ match x: y = 0 # case black_test_patma_189 match w: - case [x, y, *NOT_YET_IMPLEMENTED_PatternMatchStar]: + case [x, y, *rest]: z = 0 # case black_test_patma_042 match x: diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_extras.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_extras.py.snap index bbb9c5c8246ca..1292cd47eb2f1 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_extras.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_extras.py.snap @@ -161,7 +161,7 @@ match bar1: ... case another: ... -@@ -32,23 +32,32 @@ +@@ -32,14 +32,23 @@ match maybe, multiple: case perhaps, 5: pass @@ -188,11 +188,9 @@ match bar1: pass case _: pass - - +@@ -48,7 +57,7 @@ match a, *b, c: -- case [*_]: -+ case [*NOT_YET_IMPLEMENTED_PatternMatchStar]: + case [*_]: assert "seq" == _ - case {}: + case {"NOT_YET_IMPLEMENTED_PatternMatchMapping": _, 2: _}: @@ -213,13 +211,7 @@ match bar1: pass case [a as match]: -@@ -80,17 +84,14 @@ - - - match a, *b(), c: -- case d, *f, g: -+ case d, *NOT_YET_IMPLEMENTED_PatternMatchStar, g: - pass +@@ -85,12 +89,9 @@ match something: @@ -234,17 +226,12 @@ match bar1: pass -@@ -101,19 +102,22 @@ +@@ -101,19 +102,17 @@ case 2 as b, 3 as c: pass - case 4 as d, (5 as e), (6 | 7 as g), *h: -+ case ( -+ 4 as d, -+ 5 as e, -+ NOT_YET_IMPLEMENTED_PatternMatchOf | (y) as g, -+ *NOT_YET_IMPLEMENTED_PatternMatchStar, -+ ): ++ case 4 as d, 5 as e, NOT_YET_IMPLEMENTED_PatternMatchOf | (y) as g, *h: pass @@ -324,7 +311,7 @@ match ( match a, *b, c: - case [*NOT_YET_IMPLEMENTED_PatternMatchStar]: + case [*_]: assert "seq" == _ case {"NOT_YET_IMPLEMENTED_PatternMatchMapping": _, 2: _}: assert "map" == b @@ -353,7 +340,7 @@ match match: match a, *b(), c: - case d, *NOT_YET_IMPLEMENTED_PatternMatchStar, g: + case d, *f, g: pass @@ -371,12 +358,7 @@ match something: case 2 as b, 3 as c: pass - case ( - 4 as d, - 5 as e, - NOT_YET_IMPLEMENTED_PatternMatchOf | (y) as g, - *NOT_YET_IMPLEMENTED_PatternMatchStar, - ): + case 4 as d, 5 as e, NOT_YET_IMPLEMENTED_PatternMatchOf | (y) as g, *h: pass diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_simple.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_simple.py.snap index d370a429178ba..81ca3e9dc6580 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_simple.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_simple.py.snap @@ -104,23 +104,7 @@ def where_is(point): ```diff --- Black +++ Ruff -@@ -23,7 +23,7 @@ - # The rest of your commands go here - - match command.split(): -- case ["drop", *objects]: -+ case ["drop", *NOT_YET_IMPLEMENTED_PatternMatchStar]: - for obj in objects: - character.drop(obj, current_room) - # The rest of your commands go here -@@ -33,24 +33,24 @@ - pass - case ["go", direction]: - print("Going:", direction) -- case ["drop", *objects]: -+ case ["drop", *NOT_YET_IMPLEMENTED_PatternMatchStar]: - print("Dropping: ", *objects) - case _: +@@ -39,18 +39,18 @@ print(f"Sorry, I couldn't understand {command!r}") match command.split(): @@ -217,7 +201,7 @@ match command.split(): # The rest of your commands go here match command.split(): - case ["drop", *NOT_YET_IMPLEMENTED_PatternMatchStar]: + case ["drop", *objects]: for obj in objects: character.drop(obj, current_room) # The rest of your commands go here @@ -227,7 +211,7 @@ match command.split(): pass case ["go", direction]: print("Going:", direction) - case ["drop", *NOT_YET_IMPLEMENTED_PatternMatchStar]: + case ["drop", *objects]: print("Dropping: ", *objects) case _: print(f"Sorry, I couldn't understand {command!r}") diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__match.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__match.py.snap index 8cca7405d3e02..b3edf1348c154 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@statement__match.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__match.py.snap @@ -243,7 +243,6 @@ match foo: ]: pass - match foo: case 1: y = 0 @@ -269,6 +268,43 @@ match foo: # comment ): y = 1 + +match foo: + case [1, 2, *rest]: + pass + case [1, 2, *_]: + pass + case [*rest, 1, 2]: + pass + case [*_, 1, 2]: + pass + case [ + 1, + 2, + *rest, + ]: + pass + case [1, 2, * # comment + rest]: + pass + case [1, 2, * # comment + _]: + pass + case [* # comment + rest, 1, 2]: + pass + case [* # comment + _, 1, 2]: + pass + case [* # end of line + # own line + _, 1, 2]: + pass + case [* # end of line + # own line + _, 1, 2]: + pass + ``` ## Output @@ -506,7 +542,6 @@ match foo: ]: pass - match foo: case 1: y = 0 @@ -532,6 +567,66 @@ match foo: # comment ): y = 1 + +match foo: + case [1, 2, *rest]: + pass + case [1, 2, *_]: + pass + case [*rest, 1, 2]: + pass + case [*_, 1, 2]: + pass + case [ + 1, + 2, + *rest, + ]: + pass + case [ + 1, + 2, + * # comment + rest, + ]: + pass + case [ + 1, + 2, + * # comment + _, + ]: + pass + case [ + * # comment + rest, + 1, + 2, + ]: + pass + case [ + * # comment + _, + 1, + 2, + ]: + pass + case [ + * # end of line + # own line + _, + 1, + 2, + ]: + pass + case [ + * # end of line + # own line + _, + 1, + 2, + ]: + pass ```