Skip to content

fix: dynamic_context for @staticmethod and @classmethod tests (issue 1923) - #2297

Merged
nedbat merged 3 commits into
coveragepy:mainfrom
glaziermag:fix/dynctx-staticmethod
Sep 26, 2026
Merged

nedbat merged 3 commits into
coveragepy:mainfrom
glaziermag:fix/dynctx-staticmethod

Conversation

@glaziermag

Copy link
Copy Markdown
Contributor

Closes #1923.

qualname_from_frame() finds a test method through its self argument or, failing that, through the module globals. A @staticmethod or @classmethod test satisfies neither, so it returned None and the test ran under no context. With the issue's example on main (08fbc32), CoverageData.measured_contexts() is ['', 'test_foo.TestFoo.test_foo_instance']: the static and class method tests are missing.

The fix falls back to the code object's co_qualname (Python 3.11+), only for real function frames (CO_OPTIMIZED) so a class body with a test-like name still returns None (test_bug_829), and not for nested functions, which keep their old behavior. The same run then reports all three contexts. On 3.10 nothing changes and the new tests are skipped.

Your nedbat/bug1923-dynctx-staticmethod branch returned the bare co_qualname; that is what fails test_bug_829, and it also drops the module prefix. This version keeps every existing test passing.

Tests: two QualnameTest cases and one end-to-end DynamicContextTest case. All three fail on main and pass with the fix. Fork CI on this SHA: Tests https://github.com/glaziermag/coveragepy/actions/runs/35817084448, Quality https://github.com/glaziermag/coveragepy/actions/runs/35817082251.

Written with Claude Code (Fable 5.1); I ran the reproduction and tests above myself.

glaziermag and others added 3 commits September 22, 2026 21:07
`qualname_from_frame()` found a test method through its `self` argument
or through the module globals, so `@staticmethod` and `@classmethod`
tests got no context under `dynamic_context = test_function`.  Use the
code object's `co_qualname` (Python 3.11+) when neither lookup works,
but only for real function frames, so a class body with a test-like
name (test_bug_829) is still ignored.  Closes coveragepy#1923.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Resolve the CHANGES.rst conflict by keeping both Unreleased entries.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
@nedbat

nedbat commented Sep 26, 2026

Copy link
Copy Markdown
Member

Why do we need CO_OPTIMIZED?

@nedbat
nedbat merged commit a3e969f into coveragepy:main Sep 26, 2026
72 checks passed
@glaziermag

Copy link
Copy Markdown
Contributor Author

Thanks for the merge and the PYVERSIONS comment. On CO_OPTIMIZED: without it a module-level class test_something: body has co_qualname == "test_something" and no <locals>, so the class body would get a context named mod.test_something while it runs at import. The flag is set only on function code objects, which is the cheapest way to tell a function frame from a class body. Happy to send a follow-up dropping it if you'd rather have the simpler code.

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.

dynamic_context is not set for tests which are static or class methods

2 participants