On Tue, Jul 11, 2017 at 3:26 PM, Laurent Mazuel via Async-sig <async-sig@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 advice would be to - think how you'd write the API if it were synchronous, and then do exactly that, except marking the blocking functions/methods as async - pretend that the only allowed syntax for using await or coroutines is 'await fn(...)', and treat the 'await obj' syntax as something that only exists for compatibility with legacy code that uses explicit Future/Deferred objects. One of Python's famous design principles is "there should be one (and preferably only one) obvious way to do it". The word "obvious" there is important -- because programming is so flexible, and Python in particular is so flexible, there generally are tons and tons of ways to do anything in Python. Like, if you want to make an http request, that could be a function call, `requests.get(url)`. Or you could have a class that does the request when you access some property, `Request(url).doit`. Or you could have a class whose `__str__` method does the request, and you monkeypatch a StringIO in place of sys.stdout and use print, like `sys.stdout = io.StringIO(); print(Request(url), end=""); body = sys.stdout.getvalue()`. Why not, the computer doesn't care! These are all equally compliant with the Python language specification. Fortunately, we have some strong conventions about these things, and most of these options would never even occur to most people. *Of course* the obvious way to make an HTTP request is to call a function. The other options are ridiculous. And that makes life much easier, because we don't need to stop every time we implement some trivial function and be like "hmm, what if I did this using monkeypatching and two metaclasses? Would that be a good idea?", and it means that when you use a new library you (mostly) don't have to worry that they're secretly using monkeypatching and metaclasses to implement some trivial functionality, etc. Yay conventions. But *un*fortunately, async in Python is so new and shiny that we currently have all this flexibility, but we don't have conventions yet, so people try all kinds of wacky stuff and no-one's sure what to recommend. There's lots of ways to do it, but no-one knows which one is obvious. The nice thing about my rules above is that they give you one obvious way to do it, and minimize the delta between sync and async code. You already know how functions and synchronous APIs work, your users already know how functions and synchronous APIs work, all you need to add is some 'async' and 'await' keywords and you're good to go. I think forcing users to know what "coroutine objects" are before they can write async I/O code ā or even deal with the word "coroutine" at all ā is like forcing users to understand the nuances of metaclass property lookup and the historical mess around nb_add/sq_concat before they can use a+b to add two numbers. Obviously in both cases it's important that the full details are available for those who want to dig into it, but you shouldn't need that just to make some HTTP requests. tl;dr: Treat async functions as a kind of function with a funny calling convention. -n -- Nathaniel J. Smith -- https://vorpus.org _______________________________________________ Async-sig mailing list Async-sig@python.org https://mail.python.org/mailman/listinfo/async-sig Code of Conduct: https://www.python.org/psf/codeofconduct/