-
-
Notifications
You must be signed in to change notification settings - Fork 4
Description
The issue is considered to be a follow up of discussion at #238.
-
The rules page states ( https://flake8-async.readthedocs.io/en/stable/rules.html#async119 ):
yield
in context manager in async generator is unsafe, the cleanup may be delayed untilawait
is no longer allowedBut the rule is triggered for sync context managers too. But sync CMs can't have any
await
s inside. So the description is confusing.FTR, error message displayed by
flake8
is:Yield in contextmanager in async generator might not trigger cleanup. Use
@asynccontextmanager
or refactor. -
As per comments in original pull request, there are basically two distinct issues / leves of concern mixed into the issue:
a. Generator cleanup may be performed by garbage collector and may not be performed promptly.
b. Generator cleanup may be performed in context where coroutine runner is not available andawait
s are doomed to be skipped/raise errors.IMO these two cases should be split into distinct error because case a is less severe than case b. It may be desired to "ignore" them independently. Moreover as demonstrated by snippet in my comment, case a applies to purely sync code with sync generators/sync context managers. So maybe such rule should be pushed towards more generic linters, i.e.
flake8
on its own. -
Back to statement that generator cleanup may run in context where coroutine runner is not available. As per my understanding it should not happen with asyncio due to shutdown asyncgens machinery. Well, at least if
asyncio.run
is used. It would be nice to have a demonstrating snippet and clarify conditions under which it could happen (i.e. use trio, use pypy, etc.). So we have reproducible example everyone could check and developers may decide if they should bother for their case. Snippets posted by Zac and me on original pull request discussion both demonstrate case a, but not case b. In case issue only applies to non-asyncio libraries, the rule could be adjusted like it was done with ASYNC102. -
Last but not least. In my code base I have snippets like:
from contextlib import suppress async def iterate(): with suppress(SomeError): yield yield
I think the snippet is perfectly safe (even omitting my other concerns), because implementation of
suppress.__exit__
only inspects exception in case it was thrown and do nothing otherwise. However it seems there is no way to instruct flake8-async about it other then adding "noqa" directives. There is--transform-async-generator-decorators
but it's too broad for my case because it marks overall generator as safe, but not exact context manager used inside generator.