Skip to content

coverage seems to cause coroutines to skip over exeption handlers on 3.12 #1635

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
graingert opened this issue May 31, 2023 · 7 comments
Closed
Labels
bug Something isn't working

Comments

@graingert
Copy link
Contributor

graingert commented May 31, 2023

urllib3/urllib3#3049 (comment)

Describe the bug
when running on 3.12b1 and coverage 7.2.7 (with C extension) coverage seems to cause coroutines to skip over exeption handlers

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? 3.12b1
  2. What version of coverage.py shows the problem? The output of coverage debug sys is helpful. 7.2.7
  3. What versions of what packages do you have installed? The output of pip freeze is helpful.
  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. Python 3.12 Support urllib3/urllib3#3049 (comment)

input:

import asyncio

async def inner():
    loop = asyncio.get_running_loop()
    fut = loop.create_future()
    loop.call_later(0.1, fut.set_exception, Exception())
    try:
        await fut
    except Exception:
        print("good")

async def main():
    await inner()

asyncio.run(main())

Expected behavior

 graingert@conscientious  ~/projects/urllib3   py3-12-debug ± ./.nox/test-3-12/bin/coverage run -m demo
Traceback (most recent call last):
  File "/home/graingert/projects/urllib3/demo.py", line 15, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.12/asyncio/runners.py", line 194, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/asyncio/base_events.py", line 664, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/home/graingert/projects/urllib3/demo.py", line 13, in main
    await inner()
Exception
 ✘  graingert@conscientious  ~/projects/urllib3   py3-12-debug ± vim demo.py 
 graingert@conscientious  ~/projects/urllib3   py3-12-debug ± ./.nox/test-3-12/bin/python -m demo
good

Additional context
Add any other context about the problem here.

@graingert graingert added bug Something isn't working needs triage labels May 31, 2023
@graingert
Copy link
Contributor Author

graingert commented May 31, 2023

eliminating asyncio:

import types

@types.coroutine
def _async_yield(v):
    return (yield v)

async def inner():
    try:
        await _async_yield(None)
    except Exception:
        print("good")
    return "good2"

async def main():
    return await inner()

def run(coro):
    coro.send(None)
    try:
        coro.throw(Exception)
    except StopIteration as e:
        print(e.value)


run(main())
 graingert@conscientious  ~/projects/urllib3   py3-12-debug ± ./.nox/test-3-12/bin/coverage run -m demo
Traceback (most recent call last):
  File "/home/graingert/projects/urllib3/demo.py", line 25, in <module>
    run(main())
  File "/home/graingert/projects/urllib3/demo.py", line 20, in run
    coro.throw(Exception)
  File "/home/graingert/projects/urllib3/demo.py", line 15, in main
    return await inner()
           ^^^^^^^^^^^^^
Exception
 ✘  graingert@conscientious  ~/projects/urllib3   py3-12-debug ± ./.nox/test-3-12/bin/python -m demo      
good
good2

@graingert
Copy link
Contributor Author

same with a plain generator:

def inner():
    try:
        yield None
    except Exception:
        print("good")
    return "good2"

def main():
    return (yield from inner())

def run(coro):
    coro.send(None)
    try:
        coro.throw(Exception)
    except StopIteration as e:
        print(e.value)


run(main())
 graingert@conscientious  ~/projects/urllib3   py3-12-debug ± ./.nox/test-3-12/bin/coverage run -m demo
Traceback (most recent call last):
  File "/home/graingert/projects/urllib3/demo.py", line 19, in <module>
    run(main())
  File "/home/graingert/projects/urllib3/demo.py", line 14, in run
    coro.throw(Exception)
  File "/home/graingert/projects/urllib3/demo.py", line 9, in main
    return (yield from inner())
            ^^^^^^^^^^^^^^^^^^
Exception
 ✘  graingert@conscientious  ~/projects/urllib3   py3-12-debug ± ./.nox/test-3-12/bin/python -m demo      
good
good2

@sethmlarson
Copy link

I'm also able to reproduce this on Ubuntu w/ Python 3.12.0-beta1:

(venv) $ python --version
Python 3.12.0b1

(venv) $ python -m pip freeze
coverage==7.2.7

(venv) $ coverage run -m demo
Traceback (most recent call last):
  File "/tmp/demo.py", line 19, in <module>
    run(main())
  File "/tmp/demo.py", line 14, in run
    coro.throw(Exception)
  File "/tmp/demo.py", line 9, in main
    return (yield from inner())
            ^^^^^^^^^^^^^^^^^^
Exception

(venv) $ python -m demo
good
good2

@graingert
Copy link
Contributor Author

same issue using a manually written Inner generator:

class Inner:
    def send(self, v):
        return None

    def __iter__(self):
        return self

    def __next__(self):
        return self.send(None)

    def throw(self, *exc_info):
        raise StopIteration("good")


def main():
    return (yield from Inner())

def run(coro):
    coro.send(None)
    try:
        coro.throw(Exception)
    except StopIteration as e:
        print(e.value)


run(main())

@graingert
Copy link
Contributor Author

eliminating coverage:

./.nox/test-3-12/bin/python -m trace --count -C . demo.py
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/usr/lib/python3.12/trace.py", line 741, in <module>
    main()
  File "/usr/lib/python3.12/trace.py", line 729, in main
    t.runctx(code, globs, globs)
  File "/usr/lib/python3.12/trace.py", line 451, in runctx
    exec(cmd, globals, locals)
  File "demo.py", line 26, in <module>
    run(main())
  File "demo.py", line 21, in run
    coro.throw(Exception)
  File "demo.py", line 16, in main
    return (yield from Inner())
            ^^^^^^^^^^^^^^^^^^
Exception

@pquentin
Copy link

pquentin commented Jun 2, 2023

This turned out to be a CPython issue, so I think this can be safely closed.

@graingert
Copy link
Contributor Author

graingert commented Jun 2, 2023

Closed, there's a CPython fix proposed already!

python/cpython#105162

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants