diff --git a/peps/pep-0828.rst b/peps/pep-0828.rst index a335167a292..3cbddd3efd1 100644 --- a/peps/pep-0828.rst +++ b/peps/pep-0828.rst @@ -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 + + + 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):