Skip to content

Branch coverage missing in async for loop w/ break, inside try... finally (CPython 3.14.0b4) #1999

@vytas7

Description

@vytas7

Describe the bug
When an async for loop contains a conditional break from the loop, and the whole loop is inside a try.. finally block (the except clause may also be present), it manifests as missing branch coverage under CPython 3.14.0b4. The branch is correctly covered under CPython 3.12.x.

This bug is very similar to #1324 (affects CPython 3.10), so I used almost the same file to reproduce. However, the loop now needs to be inside a try.. finally block to trigger.

To Reproduce
How can we reproduce the problem? Please be specific. Don't link to a failing CI job. Answer the questions below:

  1. What version of Python are you using?
    CPython 3.14.0b4

  2. What version of coverage.py shows the problem? The output of coverage debug sys is helpful.
    coverage_version: 7.9.2

  3. What versions of what packages do you have installed? The output of pip freeze is helpful.
    Only coverage==7.9.2.

  4. What code shows the problem? Give us a specific commit of a specific repo that we can check out. If you've already worked around the problem, please provide a commit before that fix.

import asyncio


class CoverMe:
    def __init__(self, number):
        self._number = number

    async def _async_range(self):
        for n in range(self._number):
            yield n

    async def do_something(self):
        accumulated = 0

        try:
            async for n in self._async_range():
                accumulated += n
                if accumulated > 10:
                    break

        finally:
            print('Whoa, finally done.')

        return accumulated


async def main():
    print(await CoverMe(1).do_something())
    print(await CoverMe(3).do_something())
    print(await CoverMe(10).do_something())


if __name__ == '__main__':
    asyncio.run(main())
  1. What commands should we run to reproduce the problem? Be specific. Include everything, even git clone, pip install, and so on. Explain like we're five!
    Configure branch coverage. (See Branch coverage missing in async for loop w/ break (CPython 3.10.2) #1324 for .coveragerc.)
    Then
$ coverage erase && coverage run example.py && coverage report
Whoa, finally done.
0
Whoa, finally done.
3
Whoa, finally done.
15
Name       Stmts   Miss Branch BrPart  Cover   Missing
------------------------------------------------------
cover.py      22      0      8      2    93%   16->22, 33->exit
------------------------------------------------------
TOTAL         22      0      8      2    93%

Expected behavior
The same run on CPython 3.12:

Name         Stmts   Miss Branch BrPart  Cover   Missing
--------------------------------------------------------
example.py      22      0      8      1    97%   33->exit
--------------------------------------------------------
TOTAL           22      0      8      1    97%

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfixed

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions