Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 37 additions & 6 deletions peps/pep-0828.rst
Original file line number Diff line number Diff line change
Expand Up @@ -379,16 +379,47 @@ asynchronous generator methods: :meth:`~agen.asend` to :meth:`~generator.send`,
:meth:`~agen.athrow` to :meth:`~generator.throw`, and :meth:`~agen.aclose`
to :meth:`~generator.close`.

For example, asynchronous exceptions could be injected into synchronous
generators:
It's trivial for anyone that needs to delegate to a subgenerator to write
the wrapper class to upgrade a synchronous :class:`~collections.abc.Iterable`
or :class:`~collections.abc.Generator` to an
async one before calling ``async yield from``.

.. code-block:: python

class AsAsyncIterator:
def __init__(self, wrapped):
self._wrapped = iter(wrapped)

def __aiter__(self):
return self

async def __anext__(self):
try:
return self._wrapped.__next__()
except StopIteration as e:
raise StopAsyncIteration(e.value) from e
Comment thread
ZeroIntensity marked this conversation as resolved.


class AsAsyncGenerator(AsAsyncIterator):
async def asend(self, value):
try:
return self._wrapped.send(value)
except StopIteration as e:
raise StopAsyncIteration(e.value) from e

async def athrow(self, exc):
try:
return self._wrapped.throw(exc)
except StopIteration as e:
raise StopAsyncIteration(e.value) from e

async def aclose(self):
return self._wrapped.close()


async def agen():
async with asyncio.timeout(3):
# If the timeout fails, then an asyncio.TimeoutError would be raised
# in a *synchronous* generator!
yield from subgen()
async yield from AsAsyncIterator([1, 2, 3])
async yield from AsAsyncGenerator(subgen())


To quote Brandt Bucher (paraphrased):
Expand Down
Loading