From 75b2067c0f0c6e0bdbf896b9092eda75f315e328 Mon Sep 17 00:00:00 2001 From: SoulSniper1212 Date: Mon, 10 Nov 2025 22:28:09 -0500 Subject: [PATCH 1/2] feat: add SimplifiableIfMatchViolation for single-case matches Signed-off-by: SoulSniper1212 --- .../test_simplified_match_conditions.py | 109 ++++++++++++++++++ .../violations/consistency.py | 40 +++++++ .../visitors/ast/conditions.py | 13 ++- 3 files changed, 161 insertions(+), 1 deletion(-) diff --git a/tests/test_visitors/test_ast/test_conditions/test_simplified_match_conditions.py b/tests/test_visitors/test_ast/test_conditions/test_simplified_match_conditions.py index f7efa69de..88ad54a1f 100644 --- a/tests/test_visitors/test_ast/test_conditions/test_simplified_match_conditions.py +++ b/tests/test_visitors/test_ast/test_conditions/test_simplified_match_conditions.py @@ -1,6 +1,7 @@ import pytest from wemake_python_styleguide.violations.consistency import ( + SimplifiableIfMatchViolation, SimplifiableMatchViolation, ) from wemake_python_styleguide.visitors.ast.conditions import ( @@ -187,3 +188,111 @@ def test_not_simplifiable_match_templates( visitor = SimplifiableMatchVisitor(default_options, tree=tree) visitor.run() assert_errors(visitor, []) + + +# New tests for single-case matches: + +# Wrong (single case): +single_case_match = """ +match x: + case {0}: + do_something() +""" + +single_case_with_as_binding_match = """ +match x: + case {0} as y: + do_something() +""" + +# Correct (not single case or has guards): +multi_case_match = """ +match x: + case 1: + do_something() + case 2: + do_something_else() +""" + +single_case_with_guard = """ +match x: + case y if y > 0: + do_something() +""" + +wildcard_case = """ +match x: + case _: + do_something() +""" + +pattern_with_complex_structure = """ +match x: + case [a, b]: + do_something() +""" + +pattern_with_class_args = """ +match x: + case SomeClass(a): + do_something() +""" + + +@pytest.mark.parametrize( + 'code', + [ + '1', + 'True', + 'None', + '"string"', + 'ns.CONST', + 'State.ACCEPTED', + ], +) +def test_single_case_match( + code, + assert_errors, + parse_ast_tree, + default_options, +): + """Test that single-case matches raise a violation.""" + tree = parse_ast_tree(single_case_match.format(code)) + visitor = SimplifiableMatchVisitor(default_options, tree=tree) + visitor.run() + assert_errors(visitor, [SimplifiableIfMatchViolation]) + + +def test_single_case_with_as_binding( + assert_errors, + parse_ast_tree, + default_options, +): + """Test that single-case matches with as-binding raise a violation.""" + tree = parse_ast_tree(single_case_with_as_binding_match.format('1')) + visitor = SimplifiableMatchVisitor(default_options, tree=tree) + visitor.run() + assert_errors(visitor, [SimplifiableIfMatchViolation]) + + +@pytest.mark.parametrize( + 'template', + [ + multi_case_match, + single_case_with_guard, + wildcard_case, + pattern_with_complex_structure, + pattern_with_class_args, + ], +) +def test_not_single_case_match( + template, + assert_errors, + parse_ast_tree, + default_options, +): + """Test that non-single-case matches do not raise the single-case violation.""" + tree = parse_ast_tree(template) + visitor = SimplifiableMatchVisitor(default_options, tree=tree) + visitor.run() + assert_errors(visitor, []) diff --git a/wemake_python_styleguide/violations/consistency.py b/wemake_python_styleguide/violations/consistency.py index dc0ac8a6f..108e4a748 100644 --- a/wemake_python_styleguide/violations/consistency.py +++ b/wemake_python_styleguide/violations/consistency.py @@ -2460,3 +2460,43 @@ class SimplifiableMatchViolation(ASTViolation): 'Found simplifiable `match` statement that can be just `if`' ) code = 365 + + +@final +class SimplifiableIfMatchViolation(ASTViolation): + """ + Single-case ``match`` statements can be simplified to ``if`` statements. + + Reasoning: + Using ``match`` for a single case is unnecessarily complex compared to a + simple ``if`` condition. The intent is clear, and using ``if`` reduces + nesting and cognitive load. + + Solution: + Replace single-case ``match ... case`` statements with ``if``. + + When is this violation is raised? + - When there is exactly one ``case`` statement + - When the pattern is simple (literal, constant, enum, etc.) + - When no guard (``if`` ...) is used + - When no wildcard pattern is used + + Example:: + + # Correct: + if x == 1: + do_something() + + # Wrong: + match x: + case 1: + do_something() + + .. versionadded:: 1.10.0 + + """ + + error_template = ( + 'Found single-case `match` statement that can be simplified to `if`' + ) + code = 366 diff --git a/wemake_python_styleguide/visitors/ast/conditions.py b/wemake_python_styleguide/visitors/ast/conditions.py index 0487facd0..0c97b35bc 100644 --- a/wemake_python_styleguide/visitors/ast/conditions.py +++ b/wemake_python_styleguide/visitors/ast/conditions.py @@ -208,7 +208,18 @@ def visit_Match(self, node: ast.Match) -> None: def _check_simplifiable_match(self, node: ast.Match) -> None: cases = node.cases - if len(cases) == 2: + + # Check for single-case matches with no guard + if len(cases) == 1: + case = cases[0] + # Check if there's no guard condition + if case.guard is None: + # Check if the pattern is simple (literal, constant, enum, etc.) + if pattern_matching.is_simple_pattern(case.pattern): + self.add_violation(consistency.SimplifiableIfMatchViolation(node)) + + # Check for two-case matches with wildcard (existing logic) + elif len(cases) == 2: first, second = cases if not pattern_matching.is_wildcard_pattern(second): From 9ae86532eb963ffeb3802b157d7cd7fab9107038 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 03:28:33 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks --- wemake_python_styleguide/violations/consistency.py | 4 ++-- wemake_python_styleguide/visitors/ast/conditions.py | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/wemake_python_styleguide/violations/consistency.py b/wemake_python_styleguide/violations/consistency.py index 108e4a748..f21a011a2 100644 --- a/wemake_python_styleguide/violations/consistency.py +++ b/wemake_python_styleguide/violations/consistency.py @@ -2468,8 +2468,8 @@ class SimplifiableIfMatchViolation(ASTViolation): Single-case ``match`` statements can be simplified to ``if`` statements. Reasoning: - Using ``match`` for a single case is unnecessarily complex compared to a - simple ``if`` condition. The intent is clear, and using ``if`` reduces + Using ``match`` for a single case is unnecessarily complex compared to a + simple ``if`` condition. The intent is clear, and using ``if`` reduces nesting and cognitive load. Solution: diff --git a/wemake_python_styleguide/visitors/ast/conditions.py b/wemake_python_styleguide/visitors/ast/conditions.py index 0c97b35bc..aff89c738 100644 --- a/wemake_python_styleguide/visitors/ast/conditions.py +++ b/wemake_python_styleguide/visitors/ast/conditions.py @@ -208,7 +208,7 @@ def visit_Match(self, node: ast.Match) -> None: def _check_simplifiable_match(self, node: ast.Match) -> None: cases = node.cases - + # Check for single-case matches with no guard if len(cases) == 1: case = cases[0] @@ -216,8 +216,10 @@ def _check_simplifiable_match(self, node: ast.Match) -> None: if case.guard is None: # Check if the pattern is simple (literal, constant, enum, etc.) if pattern_matching.is_simple_pattern(case.pattern): - self.add_violation(consistency.SimplifiableIfMatchViolation(node)) - + self.add_violation( + consistency.SimplifiableIfMatchViolation(node) + ) + # Check for two-case matches with wildcard (existing logic) elif len(cases) == 2: first, second = cases