Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 35.2k
bpo-40816 Add AsyncContextDecorator class#20516
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
db99d4a7d1243a20aeef8858a98f1922773dcaa6205e6cec7a5fd929a1735c581df65c1293c871bace39File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -126,6 +126,31 @@ Functions and classes provided: | ||
| .. versionadded:: 3.7 | ||
| Context managers defined with :func:`asynccontextmanager` can be used | ||
| either as decorators or with :keyword:`async with` statements:: | ||
| import time | ||
| async def timeit(): | ||
| now = time.monotonic() | ||
| try: | ||
| yield | ||
| finally: | ||
| print(f'it took {time.monotonic() - now}s to run') | ||
| @timeit() | ||
| async def main(): | ||
| # ... async code ... | ||
| When used as a decorator, a new generator instance is implicitly created on | ||
| each function call. This allows the otherwise "one-shot" context managers | ||
| created by :func:`asynccontextmanager` to meet the requirement that context | ||
| managers support multiple invocations in order to be used as decorators. | ||
| .. versionchanged:: 3.10 | ||
| Async context managers created with :func:`asynccontextmanager` can | ||
| be used as decorators. | ||
| .. function:: closing(thing) | ||
| @@ -351,6 +376,43 @@ Functions and classes provided: | ||
| .. versionadded:: 3.2 | ||
| .. class:: AsyncContextManager | ||
| Similar as ContextManger only for async | ||
heckad marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| Example of ``ContextDecorator``:: | ||
| from asyncio import run | ||
| from contextlib import AsyncContextDecorator | ||
| class mycontext(AsyncContextDecorator): | ||
| async def __aenter__(self): | ||
| print('Starting') | ||
| return self | ||
| async def __aexit__(self, *exc): | ||
| print('Finishing') | ||
| return False | ||
| >>> @mycontext() | ||
| ... async def function(): | ||
| ... print('The bit in the middle') | ||
| ... | ||
| >>> run(function()) | ||
| Starting | ||
| The bit in the middle | ||
| Finishing | ||
| >>> async def function(): | ||
| ... async with mycontext(): | ||
| ... print('The bit in the middle') | ||
| ... | ||
| >>> run(function()) | ||
| Starting | ||
| The bit in the middle | ||
| Finishing | ||
| .. class:: ExitStack() | ||
| A context manager that is designed to make it easy to programmatically | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -278,6 +278,33 @@ async def woohoo(self, func, args, kwds): | ||
| async with woohoo(self=11, func=22, args=33, kwds=44) as target: | ||
| self.assertEqual(target, (11, 22, 33, 44)) | ||
| @_async_test | ||
| async def test_recursive(self): | ||
heckad marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| depth = 0 | ||
heckad marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| ncols = 0 | ||
| @asynccontextmanager | ||
| async def woohoo(): | ||
| nonlocal ncols | ||
| ncols += 1 | ||
| nonlocal depth | ||
| before = depth | ||
| depth += 1 | ||
heckad marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| yield | ||
| depth -= 1 | ||
| self.assertEqual(depth, before) | ||
| @woohoo() | ||
| async def recursive(): | ||
| if depth < 10: | ||
| await recursive() | ||
| await recursive() | ||
| self.assertEqual(ncols, 10) | ||
| self.assertEqual(depth, 0) | ||
heckad marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| class TestAsyncExitStack(TestBaseExitStack, unittest.TestCase): | ||
| class SyncAsyncExitStack(AsyncExitStack): | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Add AsyncContextDecorator to contextlib to support async context manager as a decorator. |
Uh oh!
There was an error while loading. Please reload this page.