mirror of
https://github.com/python/cpython.git
synced 2025-11-02 03:01:58 +00:00
bpo-41229: Update docs for explicit aclose()-required cases and add contextlib.aclosing() method (GH-21545)
This is a PR to:
* Add `contextlib.aclosing` which ia analogous to `contextlib.closing` but for async-generators with an explicit test case for [bpo-41229]()
* Update the docs to describe when we need explicit `aclose()` invocation.
which are motivated by the following issues, articles, and examples:
* [bpo-41229]()
* https://github.com/njsmith/async_generator
* https://vorpus.org/blog/some-thoughts-on-asynchronous-api-design-in-a-post-asyncawait-world/#cleanup-in-generators-and-async-generators
* https://www.python.org/dev/peps/pep-0533/
* ef7bf0cea7/src/aiotools/context.py (L152)
Particuarly regarding [PEP-533](https://www.python.org/dev/peps/pep-0533/), its acceptance (`__aiterclose__()`) would make this little addition of `contextlib.aclosing()` unnecessary for most use cases, but until then this could serve as a good counterpart and analogy to `contextlib.closing()`. The same applies for `contextlib.closing` with `__iterclose__()`.
Also, still there are other use cases, e.g., when working with non-generator objects with `aclose()` methods.
This commit is contained in:
parent
e9208f0e74
commit
6e8dcdaaa4
5 changed files with 133 additions and 4 deletions
|
|
@ -154,6 +154,39 @@ Functions and classes provided:
|
|||
``page.close()`` will be called when the :keyword:`with` block is exited.
|
||||
|
||||
|
||||
.. class:: aclosing(thing)
|
||||
|
||||
Return an async context manager that calls the ``aclose()`` method of *thing*
|
||||
upon completion of the block. This is basically equivalent to::
|
||||
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
@asynccontextmanager
|
||||
async def aclosing(thing):
|
||||
try:
|
||||
yield thing
|
||||
finally:
|
||||
await thing.aclose()
|
||||
|
||||
Significantly, ``aclosing()`` supports deterministic cleanup of async
|
||||
generators when they happen to exit early by :keyword:`break` or an
|
||||
exception. For example::
|
||||
|
||||
from contextlib import aclosing
|
||||
|
||||
async with aclosing(my_generator()) as values:
|
||||
async for value in values:
|
||||
if value == 42:
|
||||
break
|
||||
|
||||
This pattern ensures that the generator's async exit code is executed in
|
||||
the same context as its iterations (so that exceptions and context
|
||||
variables work as expected, and the exit code isn't run after the
|
||||
lifetime of some task it depends on).
|
||||
|
||||
.. versionadded:: 3.10
|
||||
|
||||
|
||||
.. _simplifying-support-for-single-optional-context-managers:
|
||||
|
||||
.. function:: nullcontext(enter_result=None)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue