Skip to content

Commit

Permalink
Basic match statement support (#291)
Browse files Browse the repository at this point in the history
  • Loading branch information
kreathon authored Sep 18, 2022
1 parent e3d2da3 commit f060795
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
* Basic `match` statement support (kreathon, #276).

# 2.5 (2022-07-03)

* Mark imports in `__all__` as used (kreathon, #172, #282).
Expand Down
101 changes: 101 additions & 0 deletions tests/test_scavenging.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import sys

import pytest

from . import check, v

assert v # Silence pyflakes.
Expand Down Expand Up @@ -759,3 +761,102 @@ def foo(a, b, c, d=3):
check(v.used_names, ["foo", "a", "b", "c", "d"])
check(v.unused_vars, [])
check(v.unused_funcs, [])


@pytest.mark.skipif(
sys.version_info < (3, 10), reason="requires python3.10 or higher"
)
def test_match_class_simple(v):
v.scan(
"""\
from dataclasses import dataclass
@dataclass
class X:
a: int
b: int
c: int
u: int
x = input()
match x:
case X(a=0):
print("a")
case X(b=0, c=0):
print("b c")
"""
)
check(v.defined_classes, ["X"])
check(v.defined_vars, ["a", "b", "c", "u", "x"])

check(v.unused_classes, [])
check(v.unused_vars, ["u"])


@pytest.mark.skipif(
sys.version_info < (3, 10), reason="requires python3.10 or higher"
)
def test_match_class_embedded(v):
v.scan(
"""\
from dataclasses import dataclass
@dataclass
class X:
a: int
b: int
c: int
d: int
e: int
u: int
x = input()
match x:
case X(a=1) | X(b=0):
print("Or")
case [X(c=1), X(d=0)]:
print("Sequence")
case {"k": X(e=1)}:
print("Mapping")
"""
)
check(v.defined_classes, ["X"])
check(v.defined_vars, ["a", "b", "c", "d", "e", "u", "x"])

check(v.unused_classes, [])
check(v.unused_vars, ["u"])


@pytest.mark.skipif(
sys.version_info < (3, 10), reason="requires python3.10 or higher"
)
def test_match_enum(v):
v.scan(
"""\
from enum import Enum
class Color(Enum):
RED = 0
YELLOW = 1
GREEN = 2
BLUE = 3
color = input()
match color:
case Color.RED:
print("Real danger!")
case Color.YELLOW | Color.GREEN:
print("No danger!")
"""
)
check(v.defined_classes, ["Color"])
check(v.defined_vars, ["RED", "YELLOW", "GREEN", "BLUE", "color"])

check(v.unused_classes, [])
check(v.unused_vars, ["BLUE"])
4 changes: 4 additions & 0 deletions vulture/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,10 @@ def visit_Assign(self, node):
def visit_While(self, node):
self._handle_conditional_node(node, "while")

def visit_MatchClass(self, node):
for kwd_attr in node.kwd_attrs:
self.used_names.add(kwd_attr)

def visit(self, node):
method = "visit_" + node.__class__.__name__
visitor = getattr(self, method, None)
Expand Down
1 change: 1 addition & 0 deletions vulture/whitelists/ast_whitelist.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
whitelist_node_visitor.visit_Lambda
whitelist_node_visitor.visit_List
whitelist_node_visitor.visit_ListComp
whitelist_node_visitor.visit_MatchClass
whitelist_node_visitor.visit_Module
whitelist_node_visitor.visit_Name
whitelist_node_visitor.visit_NameConstant
Expand Down

0 comments on commit f060795

Please sign in to comment.