<div dir="ltr">Thanks for the thorough rundown, Nathaniel. I started to get an idea of the required shape only by looking at CPython code like you suggest. I wanted to create an awaitable compatible with asyncio and trio that could be awaited more than once unlike a coroutine, and not runner-specific like a Future or Deferred. Are coroutines the only common awaitable the various async libraries are going to have for now?<div><br></div><div>I'll take Python documentation suggestions up with other channels.</div><div>- Justin</div></div><br><div class="gmail_quote"><div dir="ltr">On Wed, Nov 7, 2018 at 11:27 PM Nathaniel Smith <<a href="mailto:njs@pobox.com">njs@pobox.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">"Awaitable" is a language-level concept. To actually use awaitables,<br>
you also need a coroutine runner library, and each library defines<br>
additional restrictions on the awaitables it works with. So e.g. when<br>
using asyncio as your coroutine runner, asyncio expects your<br>
awaitables to follow particular rules about what values they yield,<br>
what kinds of values they can handle being sent/thrown back in, etc.<br>
Different async libraries use different rules here.<br>
<br>
Asyncio's rules aren't documented, I guess because it's such a<br>
low-level thing that anyone who really needs to know is expected to<br>
read the source :-). (In particular asyncio/futures.py and<br>
asyncio/tasks.py.) But it's basically: the object returned by<br>
__await__ has to implement the generator interface (which is a<br>
superset of the iterator interface), the objects yielded by your<br>
iterator have to implement the Future interface, and then you're<br>
resumed either by sending back None when the Future completes, or else<br>
by having an exception thrown in.<br>
<br>
-n<br>
<br>
On Wed, Nov 7, 2018 at 8:24 PM, Justin Turner Arthur<br>
<<a href="mailto:justinarthur@gmail.com" target="_blank">justinarthur@gmail.com</a>> wrote:<br>
> I'm trying to figure out if our documentation on the new awaitable concept<br>
> in Python 3.6+ is correct. It seems to imply that if an object's __await__<br>
> method returns an iterator, the object is awaitable. However, just returning<br>
> an iterator doesn't seem to work with await in a coroutine or with the<br>
> asyncio selector loop's run_until_complete method.<br>
><br>
> If the awaitable is not a coroutine or future, it looks like we wrap it in a<br>
> coroutine using sub-generator delegation, and therefore have to have an<br>
> iterator that fits a very specific shape for the coroutine step process that<br>
> isn't documented anywhere I could find. Am I missing something?<br>
><br>
> If the definition of an awaitable is more than just an __await__ iterator,<br>
> we may need to expand the documentation as well as the abstract base class.<br>
><br>
> Here's what I tried in making a synchronous awaitable that resolves to the<br>
> int 42:<br>
> class MyAwaitable(Awaitable):<br>
>     def __await__(self):<br>
>         return iter((42,))<br>
> # RuntimeError: Task got bad yield: 42<br>
><br>
> class MyAwaitable(Awaitable):<br>
>     def __await__(self):<br>
>         yield 42<br>
> # RuntimeError: Task got bad yield: 42<br>
><br>
> class MyAwaitable(Awaitable):<br>
>     def __await__(self):<br>
>         return (i for i in (42,))<br>
> # RuntimeError: Task got bad yield: 42<br>
><br>
> class MyAwaitable(Awaitable):<br>
>     def __await__(self):<br>
>         return self<br>
>     def __next__(self):<br>
>         return 42<br>
> # RuntimeError: Task got bad yield: 42'''<br>
><br>
> class MyAwaitable(Awaitable):<br>
>     def __await__(self):<br>
>         return iter(asyncio.coroutine(lambda: 42)())<br>
> # TypeError: __await__() returned a coroutine<br>
><br>
> class MyAwaitable(Awaitable):<br>
>     def __await__(self):<br>
>         yield from asyncio.coroutine(lambda: 42)()<br>
> # None<br>
><br>
> class MyAwaitable(Awaitable):<br>
>     def __await__(self):<br>
>         return (yield from asyncio.coroutine(lambda: 42)())<br>
> # 42<br>
><br>
> async def await_things():<br>
>     print(await MyAwaitable())<br>
><br>
> asyncio.get_event_loop().run_until_complete(await_things())<br>
><br>
><br>
> _______________________________________________<br>
> Python-Dev mailing list<br>
> <a href="mailto:Python-Dev@python.org" target="_blank">Python-Dev@python.org</a><br>
> <a href="https://mail.python.org/mailman/listinfo/python-dev" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-dev</a><br>
> Unsubscribe:<br>
> <a href="https://mail.python.org/mailman/options/python-dev/njs%40pobox.com" rel="noreferrer" target="_blank">https://mail.python.org/mailman/options/python-dev/njs%40pobox.com</a><br>
><br>
<br>
<br>
<br>
-- <br>
Nathaniel J. Smith -- <a href="https://vorpus.org" rel="noreferrer" target="_blank">https://vorpus.org</a><br>
</blockquote></div>