-
-
Notifications
You must be signed in to change notification settings - Fork 2
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
add async119: yield in contextmanager in async generator #238
Conversation
No, that's not a false alarm: import contextlib, itertools, trio
resource_id = itertools.count()
@contextlib.contextmanager
def hold_some_resource():
n = next(resource_id)
print(f"acquire {n=}")
try:
yield
finally:
print(f"release {n=}")
async def loop_with_resource():
with hold_some_resource():
yield
yield
@trio.run
async def main():
for n in range(3):
async for _ in loop_with_resource():
if n == 0:
break
and this can still happen with a single un-looped yield, depending on how it's called (ie if you create the generator but never iterate it, or iterate into the context but not out) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor comments, but looks great overall - merge when ready!
flake8_async/visitors/visitors.py
Outdated
# Decision point: the error could point to the method, or context manager, | ||
# or the yield. | ||
self.error(node) | ||
# only warn once per method (?) | ||
self.unsafe_function = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think warning on each yield which is inside a context manager would be best; each one is a separate chance of problems.
I'm confused, your example seems to show that it is a false alarm, and that's also my understanding. |
The issue is that the release of 0 is delayed until the end, no? If we remove the break from inside the loop we get
which seems like sensible behaviour.
|
…nstead of nodes since we don't need to warn on them or refer to them. Warn on each yield, add test case for that.
Cleanup being delayed until the destructor is called is potentially surprising, but I'm not sure I'd call it a bug? To me, the really big problem is when cleanup doesn't happen at all because the cleanup code cannot await in the destructor, and I was expecting that to be the case we focus on.
At a guess, I suspect this will be due to cleanup being done on refcount decrement for one but only in the garbage collector on the other — perhaps putting a |
Yeah, if the generator is not iterated to completion then This is why https://peps.python.org/pep-0533/ exists, and why I'm speaking about it at the language summit next month! |
See #211
@alicederyn
The issue is somewhat confusing at times to parse out what discussing pertains to async119 vs async102 vs hypotheticals, but I think this is what was settled upon.
I think this is a false positive with current implementation
i.e. the contextmanager is sync (and there are no awaits after the contextmanager?). Resolving that wouldn't be terribly complicated so I'll implement that if somebody confirms my understanding.
I didn't put much energy in formatting the entry in the readme, as that is on its way out. The links in the docs would probably be much cleaner with intersphinx or something, but leaving that for a different PR.