Skip to content

Stop counting the try/else line when a with statement raises - #2301

Merged
nedbat merged 17 commits into
coveragepy:mainfrom
DITlieD:fix-try-else-with-reraise
Sep 26, 2026
Merged

nedbat merged 17 commits into
coveragepy:mainfrom
DITlieD:fix-try-else-with-reraise

Conversation

@DITlieD

@DITlieD DITlieD commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

On Python 3.14, branch coverage reported the else body of a try as executed when the body was a with that raised. The example in #2289 is a with contextlib.ExitStack() that raises SystemExit. The else line that raises RuntimeError never runs, but the report showed 100%.

sys.monitoring delivers the not-taken POP_JUMP_IF_TRUE in the with exception handler, and the destination is RERAISE. BranchArcResolver then walked past that RERAISE into the swallowed-exception path, which jumps to the else line. RERAISE does not fall through, so the walk now stops there and that arc is not recorded.

tests/test_arcs.py::WithTest::test_bug_2289 runs the example from #2289 and expects the else line (raise RuntimeError) to be missing.

Fixes #2289

On Python 3.14 the not-taken with handler was walked into the following
jump and the else line was reported as covered.

Co-authored-by: Cursor <[email protected]>
@nedbat

nedbat commented Sep 24, 2026

Copy link
Copy Markdown
Member

Thanks, but it looks like PyPy needs some adjustment: https://github.com/coveragepy/coveragepy/actions/runs/36057278907/job/107827357129 Let me know if you want help with it.

@DITlieD

DITlieD commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

PyPy counted the try/else line because a line event fired while the opcode was PUSH_EXC_INFO. Commit 3aab736 returns before that line is recorded. The test file is unchanged.

Local check on that commit:
python -m pytest -o addopts= tests/test_arcs.py::WithTest::test_bug_2289

CPython and PyPy both passed that test locally. This note does not say the GitHub checks have finished.

@nedbat

nedbat commented Sep 26, 2026

Copy link
Copy Markdown
Member

Thanks. tests/test_push_exc_info.py seemed like too deep a test of too many internal details, and it's not needed to verify the fix. Unless I've missed something?

@nedbat

nedbat commented Sep 26, 2026

Copy link
Copy Markdown
Member

Hmm, now we seem not to be hitting this branch:

            if op in NO_FALL_THROUGH:
                return None

but that was the fix, and we have a test, so what is missing?

@nedbat

nedbat commented Sep 26, 2026

Copy link
Copy Markdown
Member

Oh, derp. That code is called from the tracer, so it's not covered

@nedbat
nedbat merged commit 8ad7236 into coveragepy:main Sep 26, 2026
71 of 72 checks passed
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.

try-else + with + branch = true with sysmon results in false negative

2 participants