Skip to content

Commit

Permalink
Fix long case blocks not split into multiple lines (#4024)
Browse files Browse the repository at this point in the history
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
  • Loading branch information
rdrll and JelleZijlstra committed Nov 7, 2023
1 parent 46be1f8 commit 50ed622
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 21 deletions.
2 changes: 2 additions & 0 deletions CHANGES.md
Expand Up @@ -25,6 +25,8 @@
indented less (#3964)
- Multiline list and dict unpacking as the sole argument to a function is now also
indented less (#3992)
- Fix a bug where long `case` blocks were not split into multiple lines. Also enable
general trailing comma rules on `case` blocks (#4024)
- Keep requiring two empty lines between module-level docstring and first function or
class definition. (#4028)

Expand Down
24 changes: 23 additions & 1 deletion src/black/linegen.py
Expand Up @@ -1229,7 +1229,7 @@ def normalize_prefix(leaf: Leaf, *, inside_brackets: bool) -> None:
leaf.prefix = ""


def normalize_invisible_parens(
def normalize_invisible_parens( # noqa: C901
node: Node, parens_after: Set[str], *, mode: Mode, features: Collection[Feature]
) -> None:
"""Make existing optional parentheses invisible or create new ones.
Expand Down Expand Up @@ -1260,6 +1260,17 @@ def normalize_invisible_parens(
child, parens_after=parens_after, mode=mode, features=features
)

# Fixes a bug where invisible parens are not properly wrapped around
# case blocks.
if (
isinstance(child, Node)
and child.type == syms.case_block
and Preview.long_case_block_line_splitting in mode
):
normalize_invisible_parens(
child, parens_after={"case"}, mode=mode, features=features
)

# Add parentheses around long tuple unpacking in assignments.
if (
index == 0
Expand Down Expand Up @@ -1305,6 +1316,17 @@ def normalize_invisible_parens(
# invisible parentheses to work more precisely.
continue

elif (
isinstance(child, Leaf)
and child.next_sibling is not None
and child.next_sibling.type == token.COLON
and child.value == "case"
and Preview.long_case_block_line_splitting in mode
):
# A special patch for "case case:" scenario, the second occurrence
# of case will be not parsed as a Python keyword.
break

elif not (isinstance(child, Leaf) and is_multiline_string(child)):
wrap_in_parentheses(node, child, visible=False)

Expand Down
1 change: 1 addition & 0 deletions src/black/mode.py
Expand Up @@ -193,6 +193,7 @@ class Preview(Enum):
hug_parens_with_braces_and_square_brackets = auto()
allow_empty_first_line_before_new_block_or_comment = auto()
single_line_format_skip_with_multiple_comments = auto()
long_case_block_line_splitting = auto()


class Deprecated(UserWarning):
Expand Down
22 changes: 2 additions & 20 deletions tests/data/cases/pattern_matching_extras.py
Expand Up @@ -30,22 +30,6 @@ def func(match: case, case: match) -> case:
...


match maybe, multiple:
case perhaps, 5:
pass
case perhaps, 6,:
pass


match more := (than, one), indeed,:
case _, (5, 6):
pass
case [[5], (6)], [7],:
pass
case _:
pass


match a, *b, c:
case [*_]:
assert "seq" == _
Expand All @@ -67,12 +51,12 @@ def func(match: case, case: match) -> case:
),
):
pass

case [a as match]:
pass

case case:
pass
case something:
pass


match match:
Expand All @@ -98,10 +82,8 @@ def func(match: case, case: match) -> case:
match something:
case 1 as a:
pass

case 2 as b, 3 as c:
pass

case 4 as d, (5 as e), (6 | 7 as g), *h:
pass

Expand Down
34 changes: 34 additions & 0 deletions tests/data/cases/preview_pattern_matching_long.py
@@ -0,0 +1,34 @@
# flags: --preview --minimum-version=3.10
match x:
case "abcd" | "abcd" | "abcd" :
pass
case "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd" | "abcd":
pass
case xxxxxxxxxxxxxxxxxxxxxxx:
pass

# output

match x:
case "abcd" | "abcd" | "abcd":
pass
case (
"abcd"
| "abcd"
| "abcd"
| "abcd"
| "abcd"
| "abcd"
| "abcd"
| "abcd"
| "abcd"
| "abcd"
| "abcd"
| "abcd"
| "abcd"
| "abcd"
| "abcd"
):
pass
case xxxxxxxxxxxxxxxxxxxxxxx:
pass
39 changes: 39 additions & 0 deletions tests/data/cases/preview_pattern_matching_trailing_comma.py
@@ -0,0 +1,39 @@
# flags: --preview --minimum-version=3.10
match maybe, multiple:
case perhaps, 5:
pass
case perhaps, 6,:
pass


match more := (than, one), indeed,:
case _, (5, 6):
pass
case [[5], (6)], [7],:
pass
case _:
pass


# output

match maybe, multiple:
case perhaps, 5:
pass
case (
perhaps,
6,
):
pass


match more := (than, one), indeed,:
case _, (5, 6):
pass
case (
[[5], (6)],
[7],
):
pass
case _:
pass

0 comments on commit 50ed622

Please sign in to comment.