Skip to content

Exclude the case line when an irrefutable case body is excluded - #2269

Merged
nedbat merged 3 commits into
coveragepy:mainfrom
yhuikzdtguioaert:fix/1563-exclude-case-body
Aug 30, 2026
Merged

nedbat merged 3 commits into
coveragepy:mainfrom
yhuikzdtguioaert:fix/1563-exclude-case-body

Conversation

@yhuikzdtguioaert

Copy link
Copy Markdown
Contributor

The problem

Excluding the body of a case clause doesn't propagate to the case line, so
the case line is still reported as missing (or as a partial branch under
--branch). This is inconsistent with if/else, where excluding the else:
body makes the else: line disappear from the report.

Reproducer from the issue, with exclude_lines = assert False$:

match 1:
    case 1:
        print("all is well")
    case _:            # still reported as uncovered
        assert False   # excluded

Root cause

An irrefutable case (a wildcard case _:, or a bare capture like
case other:, with no guard) is the match equivalent of an else clause.
Unlike else:, though, the case line is a real statement with its own arc,
so excluding only its body left the case line behind as a missing statement /
partial branch.

The fix

In PythonParser._raw_parse, while walking the AST, if a case is irrefutable
and its entire body is excluded, the case line is added to the excluded set
too. This mirrors the existing handling that carries exclusions from a
decorator/signature onto a function or class body.

The wildcard detection that AstArcAnalyzer._handle__Match already performed is
factored out into a small _case_is_irrefutable() helper that both places now
share.

Refutable cases such as case 2: are deliberately left alone: their case
line stays reported when the body is excluded, the same way an elif line does.

Tests

  • tests/test_parser.py: three unit tests covering an irrefutable case _:, a
    bare-capture case other:, and a case whose body is only partly excluded
    (which must not be excluded).
  • tests/test_coverage.py: an end-to-end test in branch mode checking that the
    wildcard is excluded while a refutable case 2: with an excluded body is
    still reported as missing.
$ python -m pytest tests/test_parser.py tests/test_coverage.py tests/test_arcs.py
287 passed, 1 skipped

ruff format --check, ruff check, and mypy --strict are clean on the
changed files; pylint reports only a pre-existing unrelated TODO.

Fixes #1563.

yhuikzdtguioaert and others added 3 commits August 18, 2026 17:52
When the whole body of an irrefutable `case` (like `case _:` or a bare
capture) is excluded, exclude the `case` line too, the same way an
excluded `else:` body makes the `else:` line disappear. Previously the
`case` line was left behind and reported as a missing statement (or a
partial branch under `--branch`).

Refutable cases such as `case 2:` are unaffected and still reported when
their body is excluded, matching how an `elif` line behaves.

Closes coveragepy#1563.
@nedbat
nedbat merged commit 33553b3 into coveragepy:main Aug 30, 2026
67 of 68 checks passed
@nedbat

nedbat commented Sep 13, 2026

Copy link
Copy Markdown
Member

This is now released as part of coverage 7.16.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Exclusion of body doesn't propagate to case block

2 participants