Skip to content

Commit 7f435c1

Browse files
- fixed bugs in 'match' wildcard detection, for when a wildcard is
included OR'ed with other cases (absurd) or with a guard. Thanks to Ned Batchelder;
1 parent 594c319 commit 7f435c1

File tree

3 files changed

+55
-3
lines changed

3 files changed

+55
-3
lines changed

src/slipcover/branch.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,11 @@ def visit_Match(self, node: ast.Match) -> ast.Match:
8787
for case in node.cases:
8888
case.body = self._mark_branch(node.lineno, case.body[0].lineno) + case.body
8989

90-
has_wildcard = isinstance(node.cases[-1].pattern, ast.MatchAs) and \
91-
node.cases[-1].pattern.pattern is None
90+
last_pattern = case.pattern # case is node.cases[-1]
91+
while isinstance(last_pattern, ast.MatchOr):
92+
last_pattern = last_pattern.patterns[-1]
9293

94+
has_wildcard = case.guard is None and isinstance(last_pattern, ast.MatchAs) and last_pattern.pattern is None
9395
if not has_wildcard:
9496
to_line = node.next_node.lineno if node.next_node else 0 # exit
9597
node.cases.append(ast.match_case(ast.MatchAs(),

src/slipcover/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "1.0.14"
1+
__version__ = "1.0.15"

tests/test_branch.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,22 @@ def test_match_case_with_false_guard():
547547
assert [(3,7)] == g[br.BRANCH_NAME]
548548

549549

550+
@pytest.mark.skipif(PYTHON_VERSION < (3,10), reason="New in 3.10")
551+
def test_match_case_with_guard_isnt_wildcard():
552+
t = ast_parse("""
553+
def fun(v):
554+
match v:
555+
case _ if v > 0:
556+
print("not default")
557+
""")
558+
559+
560+
t = br.preinstrument(t)
561+
check_locations(t)
562+
code = compile(t, "foo", "exec")
563+
assert [(2,0), (2,4)] == get_branches(code)
564+
565+
550566
@pytest.mark.skipif(PYTHON_VERSION < (3,10), reason="New in 3.10")
551567
def test_match_branch_to_exit():
552568
t = ast_parse("""
@@ -693,6 +709,39 @@ def test_branch_after_case_with_next():
693709
assert [(2,4), (4,9)] == g[br.BRANCH_NAME]
694710

695711

712+
@pytest.mark.skipif(PYTHON_VERSION < (3,10), reason="New in 3.10")
713+
def test_match_wildcard_in_match_or():
714+
# Thanks to Ned Batchelder for this test case
715+
t = ast_parse(f"""
716+
def absurd(x):
717+
match x:
718+
case (3 | 99 | (999 | _)):
719+
print("default")
720+
absurd(5)
721+
""")
722+
723+
t = br.preinstrument(t)
724+
check_locations(t)
725+
code = compile(t, "foo", "exec")
726+
assert [(2,4)] == get_branches(code)
727+
728+
729+
@pytest.mark.skipif(PYTHON_VERSION < (3,10), reason="New in 3.10")
730+
def test_match_capture():
731+
t = ast_parse(f"""
732+
def capture(x):
733+
match x:
734+
case y:
735+
print("default")
736+
capture(5)
737+
""")
738+
739+
t = br.preinstrument(t)
740+
check_locations(t)
741+
code = compile(t, "foo", "exec")
742+
assert [(2,4)] == get_branches(code)
743+
744+
696745
@pytest.mark.parametrize("star", ['', '*'] if PYTHON_VERSION >= (3,11) else [''])
697746
def test_try_except(star):
698747
t = ast_parse(f"""
@@ -781,3 +830,4 @@ def foo(x):
781830
check_locations(t)
782831
code = compile(t, "foo", "exec")
783832
assert [(4,5), (4,10), (7,8), (7,13), (10,11), (10,13)] == get_branches(code)
833+

0 commit comments

Comments
 (0)