Skip to content
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

DM-48576: Suppress some client warnings for async generators #460

Merged
merged 2 commits into from
Jan 24, 2025

Conversation

rra
Copy link
Member

@rra rra commented Jan 24, 2025

Python 3.13 adds a new warning when the aclose method of an async generator is not called explicitly. Async generators should ideally be explicitly shut down with aclose when they are no longer in use. Fix typing in some cases where async generators were returned but typed as async iterators (which don't require aclose), and close more generators explicitly. Include some async iterators from third party libraries that are actually generators, which requires working around the typing and some future-proofing for API changes.

Ignore the remaining warning that's internal to httpx-sse and can't be fixed at the client level.

Python 3.13 adds a new warning when the `aclose` method of an async
generator is not called explicitly. Async generators should ideally be
explicitly shut down with `aclose` when they are no longer in use.
Fix typing in some cases where async generators were returned but
typed as async iterators (which don't require `aclose`), and close more
generators explicitly. Include some async iterators from third party
libraries that are actually generators, which requires working around
the typing and some future-proofing for API changes.

Ignore the remaining warning that's internal to httpx-sse and can't
be fixed at the client level.
Comment on lines +41 to +42
async with aclosing(progress):
async with asyncio.timeout(30):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious if the aclosing has to be outside the timeout, or if it doesn't matter.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't matter. It will close the generator in the finally block when exited by the exception raised by asyncio.timeout either way.

# therefore is supposed to be explicitly closed with alcose()
# after break, unlike a true iterator. Handle this case to suppress
# warnings in Python 3.13.
with suppress(AttributeError):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have to handle AttributeErrors here (and elsewhere), instead of using aclosing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because the upstream typing says that they're returning an async iterator, but it's actually an async generator. Async iterators don't have aclose methods, and they could replace the generator with an iterator at any time and not break the interface guarantee. So we have to allow for the possibility that aclose doesn't exist, because it really is an iterator.

I've now refactored this into a helper function (which we could lift into Safir if we wanted to pursue this elsewhere) and added a bunch more documentation to make this clearer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohhhhhhh that's to suppress the case where aclose isn't there. I mistakenly thought it was to catch an AttributeError from the contents of aclose. This makes total sense.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, yeah, the suppress might be a bit too broadly scoped. I didn't think about that. I suppose I should actually use getattr just to be safer?

@rra rra force-pushed the tickets/DM-48576 branch from 8490502 to b95d1fb Compare January 24, 2025 18:38
Move the code in the Nublado client to close upstream library async
iterators that are actually generators into an `_aclosing_iter` helper
class with the same interface as `contextlib.aclosing`. Use that class
documentation to more thoroughly document why we're taking this
approach.
@rra rra force-pushed the tickets/DM-48576 branch from b95d1fb to 775a6e5 Compare January 24, 2025 18:44
@rra rra merged commit 3a374fb into main Jan 24, 2025
11 checks passed
@rra rra deleted the tickets/DM-48576 branch January 24, 2025 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants