GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — bpo-29679: Implement @contextlib.asynccontextmanager by JelleZijlstra · Pull Request #360 · python/cpython Conversation
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
Member
Author
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
JelleZijlstra
added a commit
to JelleZijlstra/cpython
that referenced
this pull request
Contributor
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
ncoghlan
requested changes
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. General concept and approach looks good to me, just some specific feedback on particular aspects of the implementation and test layout.
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactions
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ContextDecorator is designed to work with So I'd suggest moving the ContextDecorator inheritance and the
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactions
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right, my implementation didn't actually work as a decorator. (Although it's because ContextDecorator uses We could add a separate
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactions
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I actually consider making _GeneratorContextManager inherit from ContextDecorator a design error on my part (that's why _recreate_cm is still a private API: https://bugs.python.org/issue11647#msg161113 ) So simply not supporting an equivalent for async context managers is entirely fine by me :)
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactions
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactions
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer for other implementations to be able to readily test the rest of contextlib without requiring a working asyncio implementation, so it would be good to split these new tests out to a separate
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactions
Member
Author
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
ncoghlan
approved these changes
Contributor
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
Member
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
Contributor
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
Member
Author
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
Member
Author
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
ncoghlan
requested changes
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Noted several lines from the diff coverage report that the new test cases should really be hitting. The other uncovered lines all step from Feel free to ask for more info if it isn't clear how to craft a test case that covers the commented on lines.
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactions
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Diff coverage shows a missing test case for this line.
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactions
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing test case here as well.
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactions
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| except RuntimeError as exc: | ||
| if exc is value: | ||
| return False | ||
| if exc.__cause__ is value: |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Huh, this (and its counterpart in _GeneratorContextManager) is buggy, since it isn't checking that value was the appropriate kind of exception to start with: http://bugs.python.org/issue29692
Don't fix the synchronous version in this PR, but do add a test case for the async version that hits this line (throw StopAsyncIteration from inside an async with statement and then catch it again outside), and also one that chains some other exception type with RuntimeError and make sure that still gets chained correctly.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| raise | ||
| except: | ||
| if sys.exc_info()[1] is not value: | ||
| raise |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Hitting this line means adding a test case that replaces the thrown in exception with an entirely unrelated one that is neither StopAsyncIteration nor RuntimeError
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| def _async_test(func): | ||
| """Decorator to turn an async function into a test case.""" | ||
| def wrapper(*args, **kwargs): | ||
| loop = asyncio.new_event_loop() |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
You need to close the loop (1), and make sure it's the default loop (2).
Please rewrite to:
loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) try: loop.run_until_complete(coro) finally: loop.close() asyncio.set_event_loop(None)
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
|
||
| def _async_test(func): | ||
| """Decorator to turn an async function into a test case.""" | ||
| def wrapper(*args, **kwargs): |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Also, I know it's just a test, but please add @functools.wraps(func)
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Please add a wraps decorator.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| .. decorator:: asynccontextmanager | ||
|
|
||
| Similar to :func:`~contextlib.contextmanager`, but works with | ||
| :term:`coroutines <coroutine>`. |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
"works with coroutine" isn't really descriptive. I'd rephrase to something akin to "but creates asynchronous context managers".
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| class _GeneratorContextManager(ContextDecorator, AbstractContextManager): | ||
| """Helper for @contextmanager decorator.""" | ||
| class _GeneratorContextManagerBase: | ||
| """Shared functionality for the @contextmanager and @asynccontextmanager |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
First line of docstring must be a single sentence. Just make it
"""Shared functionality for the @contextmanager and @asynccontextmanager."""
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Thanks! Fixed the comment. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
If you'd like, you can add a note to Docs/whatsnew/3.7.rst about the addition, otherwise I'll add it when I update Misc/NEWS prior to merging :) |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| This function is a :term:`decorator` that can be used to define a factory | ||
| function for :keyword:`async with` statement asynchronous context managers, | ||
| without needing to create a class or separate :meth:`__aenter__` and | ||
| :meth:`__aexit__` methods. |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I'd add that the decorator expects to be applied to asynchronous generator functions.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| when they are :mod:`copied <copy>` or :mod:`pickled <pickle>`. | ||
| (Contributed by Serhiy Storchaka in :issue:`20804`.) | ||
|
|
||
| xmlrpc.server |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I'd leave reordering out of this PR. It should be done in a separate commit.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I've left another couple of comments in the review. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
LGTM. FWIW I'm really glad the tests didn't expose any bugs in asynchronous generators :)
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Created the same package that implements asynccontextmanager decorator on these weekends, and wanted to push it into python. And here it is! Any thoughts in which python release this will be included? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Correct. @ncoghlan do you want me to merge this PR? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
@1st1 Go ahead, thanks :) For folks interested in 3.5 and 3.6 support, I opened an issue against contextlib2 to discuss the options for handling that: jazzband/contextlib2#12 |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Not sure what happened to the Appveyor build, the failures don't look related to contextlib. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Is there anything blocking this from being merged? There were a few merge conflicts already. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I'll merge it when it passes the checks. Thanks! |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Thanks! |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
@JelleZijlstra |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Yes, sounds good. I can do that. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Implements: - python/typing#438 - python/cpython#360 python/cpython#1412, which adds contextlib.AbstractAsyncContextManager, has not yet been merged.
) Implements: - python/typing#438 - python/cpython#360 Note that python/cpython#1412, which adds contextlib.AbstractAsyncContextManager, has not yet been merged.
#360) * Remove 'Automerge-Triggered-By' text when removing the automerge label * Add more tests * Add test case for the scenario that the trailer text does not exist
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.