mirror of
https://github.com/python/cpython.git
synced 2025-11-01 10:45:30 +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
|
|
@ -643,6 +643,16 @@ after resuming depends on the method which resumed the execution. If
|
|||
:meth:`~agen.asend` is used, then the result will be the value passed in to
|
||||
that method.
|
||||
|
||||
If an asynchronous generator happens to exit early by :keyword:`break`, the caller
|
||||
task being cancelled, or other exceptions, the generator's async cleanup code
|
||||
will run and possibly raise exceptions or access context variables in an
|
||||
unexpected context--perhaps after the lifetime of tasks it depends, or
|
||||
during the event loop shutdown when the async-generator garbage collection hook
|
||||
is called.
|
||||
To prevent this, the caller must explicitly close the async generator by calling
|
||||
:meth:`~agen.aclose` method to finalize the generator and ultimately detach it
|
||||
from the event loop.
|
||||
|
||||
In an asynchronous generator function, yield expressions are allowed anywhere
|
||||
in a :keyword:`try` construct. However, if an asynchronous generator is not
|
||||
resumed before it is finalized (by reaching a zero reference count or by
|
||||
|
|
@ -654,9 +664,9 @@ generator-iterator's :meth:`~agen.aclose` method and run the resulting
|
|||
coroutine object, thus allowing any pending :keyword:`!finally` clauses
|
||||
to execute.
|
||||
|
||||
To take care of finalization, an event loop should define
|
||||
a *finalizer* function which takes an asynchronous generator-iterator
|
||||
and presumably calls :meth:`~agen.aclose` and executes the coroutine.
|
||||
To take care of finalization upon event loop termination, an event loop should
|
||||
define a *finalizer* function which takes an asynchronous generator-iterator and
|
||||
presumably calls :meth:`~agen.aclose` and executes the coroutine.
|
||||
This *finalizer* may be registered by calling :func:`sys.set_asyncgen_hooks`.
|
||||
When first iterated over, an asynchronous generator-iterator will store the
|
||||
registered *finalizer* to be called upon finalization. For a reference example
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue