From cf75971656d9a04faa1b5aeaeb776da3567b8041 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 5 Oct 2021 15:37:44 -0700 Subject: add support for match statement (#630) --- pyflakes/checker.py | 14 +++++++- pyflakes/test/test_match.py | 83 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 pyflakes/test/test_match.py diff --git a/pyflakes/checker.py b/pyflakes/checker.py index 135ad33..6fafe89 100644 --- a/pyflakes/checker.py +++ b/pyflakes/checker.py @@ -275,7 +275,8 @@ def iter_child_nodes(node, omit=None, _fields_order=_FieldsOrder()): yield field elif isinstance(field, list): for item in field: - yield item + if isinstance(item, ast.AST): + yield item def convert_to_value(item): @@ -691,6 +692,8 @@ def getNodeName(node): return node.id if hasattr(node, 'name'): # an ExceptHandler node return node.name + if hasattr(node, 'rest'): # a MatchMapping node + return node.rest TYPING_MODULES = frozenset(('typing', 'typing_extensions')) @@ -2378,3 +2381,12 @@ class Checker(object): left = right self.handleChildren(node) + + MATCH = MATCH_CASE = MATCHCLASS = MATCHOR = MATCHSEQUENCE = handleChildren + MATCHSINGLETON = MATCHVALUE = handleChildren + + def _match_target(self, node): + self.handleNodeStore(node) + self.handleChildren(node) + + MATCHAS = MATCHMAPPING = MATCHSTAR = _match_target diff --git a/pyflakes/test/test_match.py b/pyflakes/test/test_match.py new file mode 100644 index 0000000..89826e3 --- /dev/null +++ b/pyflakes/test/test_match.py @@ -0,0 +1,83 @@ +from sys import version_info + +from pyflakes.test.harness import TestCase, skipIf + + +@skipIf(version_info < (3, 10), "Python >= 3.10 only") +class TestMatch(TestCase): + def test_match_bindings(self): + self.flakes(''' + def f(): + x = 1 + match x: + case 1 as y: + print(f'matched as {y}') + ''') + self.flakes(''' + def f(): + x = [1, 2, 3] + match x: + case [1, y, 3]: + print(f'matched {y}') + ''') + self.flakes(''' + def f(): + x = {'foo': 1} + match x: + case {'foo': y}: + print(f'matched {y}') + ''') + + def test_match_pattern_matched_class(self): + self.flakes(''' + from a import B + + match 1: + case B(x=1) as y: + print(f'matched {y}') + ''') + self.flakes(''' + from a import B + + match 1: + case B(a, x=z) as y: + print(f'matched {y} {a} {z}') + ''') + + def test_match_placeholder(self): + self.flakes(''' + def f(): + match 1: + case _: + print('catchall!') + ''') + + def test_match_singleton(self): + self.flakes(''' + match 1: + case True: + print('true') + ''') + + def test_match_or_pattern(self): + self.flakes(''' + match 1: + case 1 | 2: + print('one or two') + ''') + + def test_match_star(self): + self.flakes(''' + x = [1, 2, 3] + match x: + case [1, *y]: + print(f'captured: {y}') + ''') + + def test_match_double_star(self): + self.flakes(''' + x = {'foo': 'bar', 'baz': 'womp'} + match x: + case {'foo': k1, **rest}: + print(f'{k1=} {rest=}') + ''') -- cgit v1.2.1