-
Notifications
You must be signed in to change notification settings - Fork 138
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
pytest fixture that uses TaskGroup fails to teardown when pytest-asyncio is installed #74
Comments
Indeed the thought of But are you not aware that anyio comes with its own pytest plugin? There's a whole section in the documentation dedicated to that. This is also mentioned in the (very brief) README. |
Yeah it's a pretty special situation actually — in
FYI the fix in #75 provides a test that was initially failing in the case I reported (
I am aware of this — I actually use the plugin extensively in |
Hey,
First, I wanted to thank you @agronholm for this very well crafted library. I decided to use
anyio
in asgi-lifespan, mostly to validate the idea of distributing packages built on top ofanyio
, and see how they perform in non-primarily-anyio
environments.In the context of HTTPX though and this issue in particular: encode/httpx#350, I came across an tricky bug that occurs when
pytest-asyncio
is installed along withanyio
.(Off topic: this setup is very likely to occur for users that use asyncio as well as a library that uses
anyio
under the hood (e.g. someone building an asyncio-based ASGI web app and usingasgi-lifespan
as well). Which makes me thinkperhapspytest-anyio
should be a thing?)Anyway, here's the bug:
I have this setup:
If you run
$ pytest tests.py
, the test will fail during teardown:The print statements in there are mine — it shows that the task group's cancel scope is trying to remove the host task from its set of tasks, but it's not there, leading to a
KeyError
when calling.remove()
.I looked at what exactly
pytest-asyncio
is doing for async fixtures, and here's what it looks like (code):So indeed,
host_task
inCancelScope.__aenter__()
andCancelScope.__aexit__()
doesn't refer to the same coroutine. In one case it'ssetup()
, in the other it'sasync_finalizer()
. This explains theKeyError
— we never addedasync_finalizer()
toself._tasks
in the first place.I tried to bypass the issue using:
But this resulted in teardown hanging indefinitely, because of this part in
TaskGroup.__aexit__()
:Since we're not removing finished tasks from
self.cancel_scope._tasks
(e.g.setup()
in this case), this loops indefinitely. I managed to fix it using:Not sure this won't break anything else, so I'll happily open a PR with this change to see how it performs against the test suite. 👍
The text was updated successfully, but these errors were encountered: