From 94f5f18ddbe3bd39fa7ff59b861dceb67e1cf6e0 Mon Sep 17 00:00:00 2001 From: Harutaka Kawamura Date: Wed, 23 Aug 2023 09:44:33 +0900 Subject: [PATCH] Format `PatternMatchSequence` (#6676) --- .../test/fixtures/ruff/statement/match.py | 28 +++++ .../src/pattern/pattern_match_sequence.rs | 52 +++++++-- ...y@py_310__pattern_matching_complex.py.snap | 88 ++++++++------- ...ty@py_310__pattern_matching_extras.py.snap | 100 ++++++++++++------ ...y@py_310__pattern_matching_generic.py.snap | 12 +-- ...ty@py_310__pattern_matching_simple.py.snap | 99 ++++++++++------- .../snapshots/format@fmt_skip__match.py.snap | 17 +-- ..._opening_parentheses_comment_empty.py.snap | 3 +- .../snapshots/format@statement__match.py.snap | 97 ++++++++++++++++- 9 files changed, 353 insertions(+), 143 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 518d081904..4f9d61e2b3 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 @@ -172,6 +172,7 @@ match x: case (a as b) as c: pass + match pattern_singleton: case ( # leading 1 @@ -187,3 +188,30 @@ match pattern_singleton: ... case False: ... + + +match foo: + case "a", "b": + pass + case "a", "b",: + pass + case ("a", "b"): + pass + case ["a", "b"]: + pass + case (["a", "b"]): + pass + + +match foo: + case [ # leading +# leading + # leading + # leading + "a", # trailing +# trailing + # trailing + # trailing + "b", + ]: + pass diff --git a/crates/ruff_python_formatter/src/pattern/pattern_match_sequence.rs b/crates/ruff_python_formatter/src/pattern/pattern_match_sequence.rs index 53599d14f8..19db6f6953 100644 --- a/crates/ruff_python_formatter/src/pattern/pattern_match_sequence.rs +++ b/crates/ruff_python_formatter/src/pattern/pattern_match_sequence.rs @@ -1,19 +1,53 @@ -use ruff_formatter::{write, Buffer, FormatResult}; +use ruff_formatter::prelude::format_with; +use ruff_formatter::{Format, FormatResult}; use ruff_python_ast::PatternMatchSequence; -use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter}; +use crate::builders::PyFormatterExtensions; +use crate::expression::parentheses::{empty_parenthesized, optional_parentheses, parenthesized}; +use crate::{FormatNodeRule, PyFormatter}; #[derive(Default)] pub struct FormatPatternMatchSequence; +#[derive(Debug)] +enum SequenceType { + Tuple, + TupleNoParens, + List, +} + impl FormatNodeRule for FormatPatternMatchSequence { fn fmt_fields(&self, item: &PatternMatchSequence, f: &mut PyFormatter) -> FormatResult<()> { - write!( - f, - [not_yet_implemented_custom_text( - "[NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]", - item - )] - ) + let PatternMatchSequence { patterns, range } = item; + let sequence_type = match &f.context().source()[*range].chars().next() { + Some('(') => SequenceType::Tuple, + Some('[') => SequenceType::List, + _ => SequenceType::TupleNoParens, + }; + let comments = f.context().comments().clone(); + let dangling = comments.dangling(item); + if patterns.is_empty() { + return match sequence_type { + SequenceType::Tuple => empty_parenthesized("(", dangling, ")").fmt(f), + SequenceType::List => empty_parenthesized("[", dangling, "]").fmt(f), + SequenceType::TupleNoParens => { + unreachable!("If empty, it should be either tuple or list") + } + }; + } + let items = format_with(|f| { + f.join_comma_separated(range.end()) + .nodes(patterns.iter()) + .finish() + }); + match sequence_type { + SequenceType::Tuple => parenthesized("(", &items, ")") + .with_dangling_comments(dangling) + .fmt(f), + SequenceType::List => parenthesized("[", &items, "]") + .with_dangling_comments(dangling) + .fmt(f), + SequenceType::TupleNoParens => optional_parentheses(&items).fmt(f), + } } } 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 0bfe67727a..ac54cdd462 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 @@ -156,7 +156,7 @@ match x: ```diff --- Black +++ Ruff -@@ -2,105 +2,105 @@ +@@ -2,97 +2,108 @@ # case black_test_patma_098 match x: @@ -189,7 +189,7 @@ match x: # case black_check_sequence_then_mapping match x: - case [*_]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case [*NOT_YET_IMPLEMENTED_PatternMatchStar]: return "seq" - case {}: + case {"NOT_YET_IMPLEMENTED_PatternMatchMapping": _, 2: _}: @@ -202,8 +202,7 @@ match x: - case {0: [1, 2, {}] | True} | {1: [[]]} | {0: [1, 2, {}]} | [] | "X" | {}: + case NOT_YET_IMPLEMENTED_PatternMatchOf | (y): y = 1 -- case []: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case []: y = 2 # case black_test_patma_107 match x: @@ -239,7 +238,7 @@ match x: # case black_test_patma_185 match Seq(): - case [*_]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case [*NOT_YET_IMPLEMENTED_PatternMatchStar]: y = 0 # case black_test_patma_063 match x: @@ -257,23 +256,34 @@ match x: # case black_test_patma_019 match (0, 1, 2): - case [0, 1, *x, 2]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case [ ++ "NOT_YET_IMPLEMENTED_PatternMatchValue", ++ "NOT_YET_IMPLEMENTED_PatternMatchValue", ++ *NOT_YET_IMPLEMENTED_PatternMatchStar, ++ "NOT_YET_IMPLEMENTED_PatternMatchValue", ++ ]: y = 0 # case black_test_patma_052 match x: - case [0]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case ["NOT_YET_IMPLEMENTED_PatternMatchValue"]: y = 0 - case [1, 0] if (x := x[:0]): -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2] if (x := x[:0]): ++ case [ ++ "NOT_YET_IMPLEMENTED_PatternMatchValue", ++ "NOT_YET_IMPLEMENTED_PatternMatchValue", ++ ] if (x := x[:0]): y = 1 - case [1, 0]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case [ ++ "NOT_YET_IMPLEMENTED_PatternMatchValue", ++ "NOT_YET_IMPLEMENTED_PatternMatchValue", ++ ]: y = 2 # case black_test_patma_191 match w: - case [x, y, *_]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case [x, y, *NOT_YET_IMPLEMENTED_PatternMatchStar]: z = 0 # case black_test_patma_110 match x: @@ -282,8 +292,7 @@ match x: y = 0 # case black_test_patma_151 match (x,): -- case [y]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: +@@ -100,7 +111,7 @@ z = 0 # case black_test_patma_114 match x: @@ -292,7 +301,7 @@ match x: y = 0 # case black_test_patma_232 match x: -@@ -108,7 +108,7 @@ +@@ -108,7 +119,7 @@ y = 0 # case black_test_patma_058 match x: @@ -301,27 +310,24 @@ match x: y = 0 # case black_test_patma_233 match x: -@@ -116,11 +116,11 @@ - y = 0 - # case black_test_patma_078 +@@ -118,9 +129,9 @@ match x: -- case []: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case []: y = 0 - case [""]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case ["NOT_YET_IMPLEMENTED_PatternMatchValue"]: y = 1 - case "": + case "NOT_YET_IMPLEMENTED_PatternMatchValue": y = 2 # case black_test_patma_156 match x: -@@ -128,17 +128,17 @@ +@@ -128,17 +139,17 @@ y = 0 # case black_test_patma_189 match w: - case [x, y, *rest]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case [x, y, *NOT_YET_IMPLEMENTED_PatternMatchStar]: z = 0 # case black_test_patma_042 match x: @@ -336,8 +342,7 @@ match x: - case {0: [1, 2, {}] | False} | {1: [[]]} | {0: [1, 2, {}]} | [] | "X" | {}: + case NOT_YET_IMPLEMENTED_PatternMatchOf | (y): y = 1 -- case []: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case []: y = 2 ``` @@ -370,7 +375,7 @@ match x: y = 0 # case black_check_sequence_then_mapping match x: - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [*NOT_YET_IMPLEMENTED_PatternMatchStar]: return "seq" case {"NOT_YET_IMPLEMENTED_PatternMatchMapping": _, 2: _}: return "map" @@ -380,7 +385,7 @@ match x: y = 0 case NOT_YET_IMPLEMENTED_PatternMatchOf | (y): y = 1 - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case []: y = 2 # case black_test_patma_107 match x: @@ -408,7 +413,7 @@ match x: y = 2 # case black_test_patma_185 match Seq(): - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [*NOT_YET_IMPLEMENTED_PatternMatchStar]: y = 0 # case black_test_patma_063 match x: @@ -422,19 +427,30 @@ match x: y = bar # case black_test_patma_019 match (0, 1, 2): - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [ + "NOT_YET_IMPLEMENTED_PatternMatchValue", + "NOT_YET_IMPLEMENTED_PatternMatchValue", + *NOT_YET_IMPLEMENTED_PatternMatchStar, + "NOT_YET_IMPLEMENTED_PatternMatchValue", + ]: y = 0 # case black_test_patma_052 match x: - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case ["NOT_YET_IMPLEMENTED_PatternMatchValue"]: y = 0 - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2] if (x := x[:0]): + case [ + "NOT_YET_IMPLEMENTED_PatternMatchValue", + "NOT_YET_IMPLEMENTED_PatternMatchValue", + ] if (x := x[:0]): y = 1 - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [ + "NOT_YET_IMPLEMENTED_PatternMatchValue", + "NOT_YET_IMPLEMENTED_PatternMatchValue", + ]: y = 2 # case black_test_patma_191 match w: - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [x, y, *NOT_YET_IMPLEMENTED_PatternMatchStar]: z = 0 # case black_test_patma_110 match x: @@ -442,7 +458,7 @@ match x: y = 0 # case black_test_patma_151 match (x,): - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [y]: z = 0 # case black_test_patma_114 match x: @@ -462,9 +478,9 @@ match x: y = 0 # case black_test_patma_078 match x: - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case []: y = 0 - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case ["NOT_YET_IMPLEMENTED_PatternMatchValue"]: y = 1 case "NOT_YET_IMPLEMENTED_PatternMatchValue": y = 2 @@ -474,7 +490,7 @@ match x: y = 0 # case black_test_patma_189 match w: - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [x, y, *NOT_YET_IMPLEMENTED_PatternMatchStar]: z = 0 # case black_test_patma_042 match x: @@ -486,7 +502,7 @@ match x: y = 0 case NOT_YET_IMPLEMENTED_PatternMatchOf | (y): y = 1 - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case []: y = 2 ``` 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 8bcbd65ca1..15a9b8b33b 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 @@ -131,15 +131,9 @@ match bar1: ```diff --- Black +++ Ruff -@@ -1,13 +1,13 @@ - import match - - match something: -- case [a as b]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: +@@ -5,9 +5,9 @@ print(b) -- case [a as b, c, d, e as f]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [a as b, c, d, e as f]: print(f) - case Point(a as b): + case NOT_YET_IMPLEMENTED_PatternMatchClass(0, 0): @@ -158,7 +152,7 @@ match bar1: pass case match: pass -@@ -23,32 +23,35 @@ +@@ -23,32 +23,47 @@ def func(match: case, case: match) -> case: match Something(): @@ -171,10 +165,13 @@ match bar1: match maybe, multiple: - case perhaps, 5: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case perhaps, "NOT_YET_IMPLEMENTED_PatternMatchValue": pass - case perhaps, 6,: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case ( ++ perhaps, ++ "NOT_YET_IMPLEMENTED_PatternMatchValue", ++ ): pass @@ -184,10 +181,19 @@ match bar1: + more := (than, one), + indeed, +): -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case _, ( ++ "NOT_YET_IMPLEMENTED_PatternMatchValue", ++ "NOT_YET_IMPLEMENTED_PatternMatchValue", ++ ): pass - case [[5], (6)], [7],: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case [ ++ [ ++ ["NOT_YET_IMPLEMENTED_PatternMatchValue"], ++ "NOT_YET_IMPLEMENTED_PatternMatchValue", ++ ], ++ ["NOT_YET_IMPLEMENTED_PatternMatchValue"], ++ ]: pass case _: pass @@ -195,14 +201,14 @@ match bar1: match a, *b, c: - case [*_]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case [*NOT_YET_IMPLEMENTED_PatternMatchStar]: assert "seq" == _ - case {}: + case {"NOT_YET_IMPLEMENTED_PatternMatchMapping": _, 2: _}: assert "map" == b -@@ -59,15 +62,10 @@ +@@ -59,12 +74,7 @@ ), case, ): @@ -215,17 +221,13 @@ match bar1: + case NOT_YET_IMPLEMENTED_PatternMatchClass(0, 0): pass -- case [a as match]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: - pass - - case case: -@@ -80,40 +78,35 @@ + case [a as match]: +@@ -80,40 +90,43 @@ match a, *b(), c: - case d, *f, g: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case d, *NOT_YET_IMPLEMENTED_PatternMatchStar, g: pass @@ -247,11 +249,19 @@ match bar1: pass - case 2 as b, 3 as c: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case ( ++ "NOT_YET_IMPLEMENTED_PatternMatchValue" as b, ++ "NOT_YET_IMPLEMENTED_PatternMatchValue" as c, ++ ): pass - case 4 as d, (5 as e), (6 | 7 as g), *h: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case ( ++ "NOT_YET_IMPLEMENTED_PatternMatchValue" as d, ++ "NOT_YET_IMPLEMENTED_PatternMatchValue" as e, ++ NOT_YET_IMPLEMENTED_PatternMatchOf | (y) as g, ++ *NOT_YET_IMPLEMENTED_PatternMatchStar, ++ ): pass @@ -277,9 +287,9 @@ match bar1: import match match something: - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [a as b]: print(b) - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [a as b, c, d, e as f]: print(f) case NOT_YET_IMPLEMENTED_PatternMatchClass(0, 0): print(b) @@ -306,9 +316,12 @@ def func(match: case, case: match) -> case: match maybe, multiple: - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case perhaps, "NOT_YET_IMPLEMENTED_PatternMatchValue": pass - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case ( + perhaps, + "NOT_YET_IMPLEMENTED_PatternMatchValue", + ): pass @@ -316,16 +329,25 @@ match ( more := (than, one), indeed, ): - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case _, ( + "NOT_YET_IMPLEMENTED_PatternMatchValue", + "NOT_YET_IMPLEMENTED_PatternMatchValue", + ): pass - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [ + [ + ["NOT_YET_IMPLEMENTED_PatternMatchValue"], + "NOT_YET_IMPLEMENTED_PatternMatchValue", + ], + ["NOT_YET_IMPLEMENTED_PatternMatchValue"], + ]: pass case _: pass match a, *b, c: - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [*NOT_YET_IMPLEMENTED_PatternMatchStar]: assert "seq" == _ case {"NOT_YET_IMPLEMENTED_PatternMatchMapping": _, 2: _}: assert "map" == b @@ -341,7 +363,7 @@ match match( case NOT_YET_IMPLEMENTED_PatternMatchClass(0, 0): pass - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [a as match]: pass case case: @@ -354,7 +376,7 @@ match match: match a, *b(), c: - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case d, *NOT_YET_IMPLEMENTED_PatternMatchStar, g: pass @@ -369,10 +391,18 @@ match something: case "NOT_YET_IMPLEMENTED_PatternMatchValue" as a: pass - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case ( + "NOT_YET_IMPLEMENTED_PatternMatchValue" as b, + "NOT_YET_IMPLEMENTED_PatternMatchValue" as c, + ): pass - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case ( + "NOT_YET_IMPLEMENTED_PatternMatchValue" as d, + "NOT_YET_IMPLEMENTED_PatternMatchValue" as e, + NOT_YET_IMPLEMENTED_PatternMatchOf | (y) as g, + *NOT_YET_IMPLEMENTED_PatternMatchStar, + ): pass diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_generic.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_generic.py.snap index d7e3f09879..a262921af9 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_generic.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@py_310__pattern_matching_generic.py.snap @@ -128,7 +128,7 @@ with match() as match: y = 0 self.assertIs(x, False) self.assertEqual(y, 0) -@@ -73,14 +73,14 @@ +@@ -73,7 +73,7 @@ x = 0 y = None match x: @@ -137,14 +137,6 @@ with match() as match: y = 0 self.assertEqual(x, 0) self.assertIs(y, None) - - x = range(3) - match x: -- case [y, case as x, z]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: - w = 0 - - # At least one of the above branches must have been taken, because every Python ``` ## Ruff Output @@ -232,7 +224,7 @@ def get_grammars(target_versions: Set[TargetVersion]) -> List[Grammar]: x = range(3) match x: - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [y, case as x, z]: w = 0 # At least one of the above branches must have been taken, because every Python 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 bf02fd3fe4..cb7b0acf4e 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,54 +104,47 @@ def where_is(point): ```diff --- Black +++ Ruff -@@ -1,92 +1,92 @@ - # Cases sampled from PEP 636 examples - - match command.split(): -- case [action, obj]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: - ... # interpret action, obj - - match command.split(): -- case [action]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: - ... # interpret single-verb action -- case [action, obj]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: +@@ -11,82 +11,97 @@ ... # interpret action, obj match command.split(): - case ["quit"]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case ["NOT_YET_IMPLEMENTED_PatternMatchValue"]: print("Goodbye!") quit_game() - case ["look"]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case ["NOT_YET_IMPLEMENTED_PatternMatchValue"]: current_room.describe() - case ["get", obj]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case ["NOT_YET_IMPLEMENTED_PatternMatchValue", obj]: character.get(obj, current_room) - case ["go", direction]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case ["NOT_YET_IMPLEMENTED_PatternMatchValue", direction]: current_room = current_room.neighbor(direction) # The rest of your commands go here match command.split(): - case ["drop", *objects]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case [ ++ "NOT_YET_IMPLEMENTED_PatternMatchValue", ++ *NOT_YET_IMPLEMENTED_PatternMatchStar, ++ ]: for obj in objects: character.drop(obj, current_room) # The rest of your commands go here match command.split(): - case ["quit"]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case ["NOT_YET_IMPLEMENTED_PatternMatchValue"]: pass - case ["go", direction]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case ["NOT_YET_IMPLEMENTED_PatternMatchValue", direction]: print("Going:", direction) - case ["drop", *objects]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case [ ++ "NOT_YET_IMPLEMENTED_PatternMatchValue", ++ *NOT_YET_IMPLEMENTED_PatternMatchStar, ++ ]: print("Dropping: ", *objects) case _: print(f"Sorry, I couldn't understand {command!r}") @@ -166,21 +159,30 @@ def where_is(point): match command.split(): - case ["go", ("north" | "south" | "east" | "west")]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case [ ++ "NOT_YET_IMPLEMENTED_PatternMatchValue", ++ NOT_YET_IMPLEMENTED_PatternMatchOf | (y), ++ ]: current_room = current_room.neighbor(...) # how do I know which direction to go? match command.split(): - case ["go", ("north" | "south" | "east" | "west") as direction]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case [ ++ "NOT_YET_IMPLEMENTED_PatternMatchValue", ++ NOT_YET_IMPLEMENTED_PatternMatchOf | (y) as direction, ++ ]: current_room = current_room.neighbor(direction) match command.split(): - case ["go", direction] if direction in current_room.exits: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2] if direction in current_room.exits: ++ case [ ++ "NOT_YET_IMPLEMENTED_PatternMatchValue", ++ direction, ++ ] if direction in current_room.exits: current_room = current_room.neighbor(direction) - case ["go", _]: -+ case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: ++ case ["NOT_YET_IMPLEMENTED_PatternMatchValue", _]: print("Sorry, you can't go that way") match event.get(): @@ -232,39 +234,45 @@ def where_is(point): # Cases sampled from PEP 636 examples match command.split(): - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [action, obj]: ... # interpret action, obj match command.split(): - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [action]: ... # interpret single-verb action - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [action, obj]: ... # interpret action, obj match command.split(): - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case ["NOT_YET_IMPLEMENTED_PatternMatchValue"]: print("Goodbye!") quit_game() - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case ["NOT_YET_IMPLEMENTED_PatternMatchValue"]: current_room.describe() - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case ["NOT_YET_IMPLEMENTED_PatternMatchValue", obj]: character.get(obj, current_room) - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case ["NOT_YET_IMPLEMENTED_PatternMatchValue", direction]: current_room = current_room.neighbor(direction) # The rest of your commands go here match command.split(): - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [ + "NOT_YET_IMPLEMENTED_PatternMatchValue", + *NOT_YET_IMPLEMENTED_PatternMatchStar, + ]: for obj in objects: character.drop(obj, current_room) # The rest of your commands go here match command.split(): - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case ["NOT_YET_IMPLEMENTED_PatternMatchValue"]: pass - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case ["NOT_YET_IMPLEMENTED_PatternMatchValue", direction]: print("Going:", direction) - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [ + "NOT_YET_IMPLEMENTED_PatternMatchValue", + *NOT_YET_IMPLEMENTED_PatternMatchStar, + ]: print("Dropping: ", *objects) case _: print(f"Sorry, I couldn't understand {command!r}") @@ -276,18 +284,27 @@ match command.split(): ... # Code for picking up the given object match command.split(): - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [ + "NOT_YET_IMPLEMENTED_PatternMatchValue", + NOT_YET_IMPLEMENTED_PatternMatchOf | (y), + ]: current_room = current_room.neighbor(...) # how do I know which direction to go? match command.split(): - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [ + "NOT_YET_IMPLEMENTED_PatternMatchValue", + NOT_YET_IMPLEMENTED_PatternMatchOf | (y) as direction, + ]: current_room = current_room.neighbor(direction) match command.split(): - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2] if direction in current_room.exits: + case [ + "NOT_YET_IMPLEMENTED_PatternMatchValue", + direction, + ] if direction in current_room.exits: current_room = current_room.neighbor(direction) - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case ["NOT_YET_IMPLEMENTED_PatternMatchValue", _]: print("Sorry, you can't go that way") match event.get(): diff --git a/crates/ruff_python_formatter/tests/snapshots/format@fmt_skip__match.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@fmt_skip__match.py.snap index 39466e5247..977a4d3d44 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@fmt_skip__match.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@fmt_skip__match.py.snap @@ -97,11 +97,11 @@ def http_error(status): match point: case (0, 0): # fmt: skip print("Origin") - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case ("NOT_YET_IMPLEMENTED_PatternMatchValue", y): print(f"Y={y}") - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case (x, "NOT_YET_IMPLEMENTED_PatternMatchValue"): print(f"X={x}") - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case (x, y): print(f"X={x}, Y={y}") case _: raise ValueError("Not a point") @@ -127,15 +127,18 @@ def location(point): match points: - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case []: print("No points in the list.") case [ Point(0, 0) ]: # fmt: skip print("The origin is the only point in the list.") - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [NOT_YET_IMPLEMENTED_PatternMatchClass(0, 0)]: print(f"A single point {x}, {y} is in the list.") - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [ + NOT_YET_IMPLEMENTED_PatternMatchClass(0, 0), + NOT_YET_IMPLEMENTED_PatternMatchClass(0, 0), + ]: print(f"Two points on the Y axis at {y1}, {y2} are in the list.") case _: print("Something else is found in the list.") @@ -148,7 +151,7 @@ match test_variable: 40 ): # fmt: skip print("A warning has been received.") - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case ("NOT_YET_IMPLEMENTED_PatternMatchValue", code, _): print(f"An error {code} occurred.") diff --git a/crates/ruff_python_formatter/tests/snapshots/format@parentheses__opening_parentheses_comment_empty.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@parentheses__opening_parentheses_comment_empty.py.snap index 69ba4add15..7f619ec37f 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@parentheses__opening_parentheses_comment_empty.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@parentheses__opening_parentheses_comment_empty.py.snap @@ -142,7 +142,8 @@ match ( # d 2 case d2: pass match d3: - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case ( # d 3 + ): pass while ( # d 4 ): 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 b014065718..8a643aca9b 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 @@ -178,6 +178,7 @@ match x: case (a as b) as c: pass + match pattern_singleton: case ( # leading 1 @@ -193,6 +194,33 @@ match pattern_singleton: ... case False: ... + + +match foo: + case "a", "b": + pass + case "a", "b",: + pass + case ("a", "b"): + pass + case ["a", "b"]: + pass + case (["a", "b"]): + pass + + +match foo: + case [ # leading +# leading + # leading + # leading + "a", # trailing +# trailing + # trailing + # trailing + "b", + ]: + pass ``` ## Output @@ -226,13 +254,21 @@ match [ # comment second, third, ]: # another comment - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [ + "NOT_YET_IMPLEMENTED_PatternMatchValue", + "NOT_YET_IMPLEMENTED_PatternMatchValue", + "NOT_YET_IMPLEMENTED_PatternMatchValue", + ]: pass match ( # comment "a b c" ).split(): # another comment - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [ + "NOT_YET_IMPLEMENTED_PatternMatchValue", + "NOT_YET_IMPLEMENTED_PatternMatchValue", + "NOT_YET_IMPLEMENTED_PatternMatchValue", + ]: pass @@ -240,7 +276,11 @@ match ( # comment # let's go yield foo ): # another comment - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2]: + case [ + "NOT_YET_IMPLEMENTED_PatternMatchValue", + "NOT_YET_IMPLEMENTED_PatternMatchValue", + "NOT_YET_IMPLEMENTED_PatternMatchValue", + ]: pass @@ -268,7 +308,10 @@ match newlines: case "NOT_YET_IMPLEMENTED_PatternMatchValue" if foo == 2: # second pass - case [NOT_YET_IMPLEMENTED_PatternMatchSequence, 2] if (foo := 1): # third + case ( + "NOT_YET_IMPLEMENTED_PatternMatchValue", + "NOT_YET_IMPLEMENTED_PatternMatchValue", + ) if (foo := 1): # third pass case "NOT_YET_IMPLEMENTED_PatternMatchValue": @@ -360,6 +403,7 @@ match x: case (a as b) as c: pass + match pattern_singleton: case ( # leading 1 @@ -375,6 +419,51 @@ match pattern_singleton: ... case False: ... + + +match foo: + case ( + "NOT_YET_IMPLEMENTED_PatternMatchValue", + "NOT_YET_IMPLEMENTED_PatternMatchValue", + ): + pass + case ( + "NOT_YET_IMPLEMENTED_PatternMatchValue", + "NOT_YET_IMPLEMENTED_PatternMatchValue", + ): + pass + case ( + "NOT_YET_IMPLEMENTED_PatternMatchValue", + "NOT_YET_IMPLEMENTED_PatternMatchValue", + ): + pass + case [ + "NOT_YET_IMPLEMENTED_PatternMatchValue", + "NOT_YET_IMPLEMENTED_PatternMatchValue", + ]: + pass + case ( + [ + "NOT_YET_IMPLEMENTED_PatternMatchValue", + "NOT_YET_IMPLEMENTED_PatternMatchValue", + ] + ): + pass + + +match foo: + case [ + # leading + # leading + # leading + # leading + "NOT_YET_IMPLEMENTED_PatternMatchValue", # trailing + # trailing + # trailing + # trailing + "NOT_YET_IMPLEMENTED_PatternMatchValue", + ]: + pass ```