[Async-sig] Optional async method and best practices

Dima Tisnek dimaqq at gmail.com
Wed Jul 12 06:34:53 EDT 2017


Hi Laurent,

I'm still a dilettante, so take my comments with a grain of salt:

1. Target Python 3.6 only.
    (i.e. drop 3.5; look at 3.7 obv, but you want users now)
    (i.e. forget `yield from`, none will remember/get it next year)
    (if 2.7 or 3.3 must be supported, provide synch package)
2. Use futures (unless it's a stream)
3. Shield liberally
4. Provide context managers

Naive user code might look like that:

req = lib.request(...)
await req.ready()  # optional
return await req.json()["something"]

That's sane and pretty similar to
http://aiohttp.readthedocs.io/en/stable/client.html thus your users
will get it :)

A more advanced use will be `[async] with lib.request(...) as r: await r.json()`
(you probably want `async with` unless you can ensure synchronous
timely termination)

Personally I'd prefer `ready` and `json` without parentheses, but it
seems I'm in a minority.


Cheers,
d.




On 12 July 2017 at 00:26, Laurent Mazuel via Async-sig
<async-sig at python.org> wrote:
> Hello,
>
> I’m working currently with Brett Cannon to bring asyncio support to our SDK. We wanted to check with you one of the scenario, since we got a loooong discussion on it together 😊. And we want to do it using the best reasonable practice with your opinion.
>
> We have an api that is clearly async and will gain a lot to be converted to asyncio. However, it's a two-step operation. Operation 1 asks for the creation of a resource and is not async, operation 2 is *optional* and wait for completion of this creation (with nightmare threads currently and I removed a lot of code moving to asyncio - happiness). There is perfectly legit scenarios where operation 2 is not needed and avoid it is better, but it has to be prepared at the same time of operation 1. Current code looks like this:
>
>     sync_poller = client.create(**parameters)
>     obj = sync_poller.resource() # Get the initial resource information, but the object is not actually created yet.
>     obj = sync_poller.result() # OPTIONAL. This is a blocking call with thread, if you want to wait for actual creation and get updated metadatas
>
> My first prototype was to split and return a tuple (resource, coroutine):
>
>     obj, optional_poller = client.create(**parameters)
>     obj = await optional_poller # OPTIONAL
>
> But I got a warning if I decide to do not use this poller, RuntimeWarning: coroutine 'foo' was never awaited
>
> I was surprised honestly that I can't do that, since I feel like I'm not leaking anything. I didn't run the operation, so there is no wasted resource at my knowledge. But I remember wasting time because of a forgotten "yield from", so I guess it's fair 😊. But I would be curious to understand what I did badly.
>
> I found 2 solutions to avoid the warning, and I currently prefer solution 2:
> 1- Return a function to call, and not a coroutine. The "await" statement becomes:
>
>    obj = await optional_poller()
>
> 2- Return my initial object with an async method. This allows me to write (something finally close to the current code):
>
>     async_poller = client.create(**parameters)
>     obj = async_poller.resource() # Get the initial resource information, but the object is not actually created yet.
>     obj = await async_poller.result() # OPTIONAL
>
> My async_poller object being something like:
>
>     class PollerOperation:
>          async def result(self):
>               ...async version of previous sync result()...
>
> So the questions are:
> - Does this seem a correct pattern?
> - Is there a simple way to achieve something like this:
>
>     obj = await async_poller
>
> meaning, I can win the "result()" syntax and directly "await" on the object and get the result from magic function. I tried by subclassing some ABC coroutine/awaitable, but wasn't able to find a correct syntax. I'm not even sure this makes sense and respects the zen of Python 😊
>
> If it helps, I'm willing to use 3.5 as minimal requirement to get async behavior.
>
> Thank you!!
>
> Laurent
> _______________________________________________
> Async-sig mailing list
> Async-sig at python.org
> https://mail.python.org/mailman/listinfo/async-sig
> Code of Conduct: https://www.python.org/psf/codeofconduct/


More information about the Async-sig mailing list