Skip to content

Commit 75b2067

Browse files
author
SoulSniper1212
committed
feat: add SimplifiableIfMatchViolation for single-case matches
Signed-off-by: SoulSniper1212 <[email protected]>
1 parent 613fbd1 commit 75b2067

File tree

3 files changed

+161
-1
lines changed

3 files changed

+161
-1
lines changed

tests/test_visitors/test_ast/test_conditions/test_simplified_match_conditions.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import pytest
22

33
from wemake_python_styleguide.violations.consistency import (
4+
SimplifiableIfMatchViolation,
45
SimplifiableMatchViolation,
56
)
67
from wemake_python_styleguide.visitors.ast.conditions import (
@@ -187,3 +188,111 @@ def test_not_simplifiable_match_templates(
187188
visitor = SimplifiableMatchVisitor(default_options, tree=tree)
188189
visitor.run()
189190
assert_errors(visitor, [])
191+
192+
193+
# New tests for single-case matches:
194+
195+
# Wrong (single case):
196+
single_case_match = """
197+
match x:
198+
case {0}:
199+
do_something()
200+
"""
201+
202+
single_case_with_as_binding_match = """
203+
match x:
204+
case {0} as y:
205+
do_something()
206+
"""
207+
208+
# Correct (not single case or has guards):
209+
multi_case_match = """
210+
match x:
211+
case 1:
212+
do_something()
213+
case 2:
214+
do_something_else()
215+
"""
216+
217+
single_case_with_guard = """
218+
match x:
219+
case y if y > 0:
220+
do_something()
221+
"""
222+
223+
wildcard_case = """
224+
match x:
225+
case _:
226+
do_something()
227+
"""
228+
229+
pattern_with_complex_structure = """
230+
match x:
231+
case [a, b]:
232+
do_something()
233+
"""
234+
235+
pattern_with_class_args = """
236+
match x:
237+
case SomeClass(a):
238+
do_something()
239+
"""
240+
241+
242+
@pytest.mark.parametrize(
243+
'code',
244+
[
245+
'1',
246+
'True',
247+
'None',
248+
'"string"',
249+
'ns.CONST',
250+
'State.ACCEPTED',
251+
],
252+
)
253+
def test_single_case_match(
254+
code,
255+
assert_errors,
256+
parse_ast_tree,
257+
default_options,
258+
):
259+
"""Test that single-case matches raise a violation."""
260+
tree = parse_ast_tree(single_case_match.format(code))
261+
visitor = SimplifiableMatchVisitor(default_options, tree=tree)
262+
visitor.run()
263+
assert_errors(visitor, [SimplifiableIfMatchViolation])
264+
265+
266+
def test_single_case_with_as_binding(
267+
assert_errors,
268+
parse_ast_tree,
269+
default_options,
270+
):
271+
"""Test that single-case matches with as-binding raise a violation."""
272+
tree = parse_ast_tree(single_case_with_as_binding_match.format('1'))
273+
visitor = SimplifiableMatchVisitor(default_options, tree=tree)
274+
visitor.run()
275+
assert_errors(visitor, [SimplifiableIfMatchViolation])
276+
277+
278+
@pytest.mark.parametrize(
279+
'template',
280+
[
281+
multi_case_match,
282+
single_case_with_guard,
283+
wildcard_case,
284+
pattern_with_complex_structure,
285+
pattern_with_class_args,
286+
],
287+
)
288+
def test_not_single_case_match(
289+
template,
290+
assert_errors,
291+
parse_ast_tree,
292+
default_options,
293+
):
294+
"""Test that non-single-case matches do not raise the single-case violation."""
295+
tree = parse_ast_tree(template)
296+
visitor = SimplifiableMatchVisitor(default_options, tree=tree)
297+
visitor.run()
298+
assert_errors(visitor, [])

wemake_python_styleguide/violations/consistency.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2460,3 +2460,43 @@ class SimplifiableMatchViolation(ASTViolation):
24602460
'Found simplifiable `match` statement that can be just `if`'
24612461
)
24622462
code = 365
2463+
2464+
2465+
@final
2466+
class SimplifiableIfMatchViolation(ASTViolation):
2467+
"""
2468+
Single-case ``match`` statements can be simplified to ``if`` statements.
2469+
2470+
Reasoning:
2471+
Using ``match`` for a single case is unnecessarily complex compared to a
2472+
simple ``if`` condition. The intent is clear, and using ``if`` reduces
2473+
nesting and cognitive load.
2474+
2475+
Solution:
2476+
Replace single-case ``match ... case`` statements with ``if``.
2477+
2478+
When is this violation is raised?
2479+
- When there is exactly one ``case`` statement
2480+
- When the pattern is simple (literal, constant, enum, etc.)
2481+
- When no guard (``if`` ...) is used
2482+
- When no wildcard pattern is used
2483+
2484+
Example::
2485+
2486+
# Correct:
2487+
if x == 1:
2488+
do_something()
2489+
2490+
# Wrong:
2491+
match x:
2492+
case 1:
2493+
do_something()
2494+
2495+
.. versionadded:: 1.10.0
2496+
2497+
"""
2498+
2499+
error_template = (
2500+
'Found single-case `match` statement that can be simplified to `if`'
2501+
)
2502+
code = 366

wemake_python_styleguide/visitors/ast/conditions.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,18 @@ def visit_Match(self, node: ast.Match) -> None:
208208

209209
def _check_simplifiable_match(self, node: ast.Match) -> None:
210210
cases = node.cases
211-
if len(cases) == 2:
211+
212+
# Check for single-case matches with no guard
213+
if len(cases) == 1:
214+
case = cases[0]
215+
# Check if there's no guard condition
216+
if case.guard is None:
217+
# Check if the pattern is simple (literal, constant, enum, etc.)
218+
if pattern_matching.is_simple_pattern(case.pattern):
219+
self.add_violation(consistency.SimplifiableIfMatchViolation(node))
220+
221+
# Check for two-case matches with wildcard (existing logic)
222+
elif len(cases) == 2:
212223
first, second = cases
213224

214225
if not pattern_matching.is_wildcard_pattern(second):

0 commit comments

Comments
 (0)