You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Regression: unittest.IsolatedAsyncioTestCase in 3.11 is too picky about what it will run with the event loop #101486
In previous versions, _callMaybeAsync(self, func, /, *args, **kwargs) would run result = func(*args, **kwargs) and then run the result with the event loop if inspect.isawaitable(result) returned True. In 3.11 inspect.iscoroutinefunction(func) is checked ahead of time instead, resulting in a warning about a coroutine not being awaited after trying to run func(*args, **kwargs) synchronously. This prevents using anything other than an async def-defined coroutine for test methods or cleanup functions1, the latter of which may not be defined in local code. This can be worked around by wrapping any known awaitable in a dummy async def _wrapper(aw): return await aw, but that's rather inconvenient and not a pleasant UX.
I have a "fix" for this that I don't consider to be viable that I'll nevertheless attach as a draft PR for discussion. It gives the behavior I would prefer to see in unittest and passes all existing tests, but relies on an ugly hack in asyncio to defeat the non-reentrancy of contextvars.Context.run. Ideally, either Context.run would allow recursive calls (by not running the entrance and exit routines if the context is already entered?), or would expose the underlying ctx_entered flag to allow LBYL when calling Context.run. I don't have a great understanding of contextvars, so I'm not sure how any of these options might break things or if there's a better option that's obvious to someone who knows what's going on here :)
Yeah, there's now an inspect.markcoroutinefunction decorator that you can use to make a sync function that returns something async appear async to whoever calls inspect.iscoroutinefunction on it.
Unfortunately there seems a lot of use of this outside the stdlib so a full rewrite will probably break other people's dependencies (no matter how brittle) on the current implementation. There's some documentation but I'm not sure how much people just depend on what happens to work and will get disappointed if we change anything. :-(
The associated PR is closed and 3.11 is in security fixes only; the docs state that addAsyncCleanup only accept coroutines, is there anything to do here or should we close it now @zware ?
The PR was never considered to be a reasonable fix, I've long since worked around the issue and forgotten how, and nobody else seems to have complained, so I'll give up and live with whatever my workaround was :)
Activity
kumaraditya303 commentedon Feb 3, 2023
Honestly, this whole thing needs a rewrite with a better design which relies less on the event loop details but I don't know how feasible that is.
IIRC there were some recent changes to
inspect.iscoroutinefunctionwhich might make this easier, @gvanrossum?gvanrossum commentedon Feb 3, 2023
Yeah, there's now an
inspect.markcoroutinefunctiondecorator that you can use to make a sync function that returns something async appear async to whoever callsinspect.iscoroutinefunctionon it.Unfortunately there seems a lot of use of this outside the stdlib so a full rewrite will probably break other people's dependencies (no matter how brittle) on the current implementation. There's some documentation but I'm not sure how much people just depend on what happens to work and will get disappointed if we change anything. :-(
kumaraditya303 commentedon Jul 4, 2025
The associated PR is closed and 3.11 is in security fixes only; the docs state that addAsyncCleanup only accept coroutines, is there anything to do here or should we close it now @zware ?
zware commentedon Jul 5, 2025
The PR was never considered to be a reasonable fix, I've long since worked around the issue and forgotten how, and nobody else seems to have complained, so I'll give up and live with whatever my workaround was :)