From 4cd97d47dfde0a0997aa5fc4037c30c99cdbd967 Mon Sep 17 00:00:00 2001 From: Nicolas Di Pietro Date: Sun, 10 Jul 2016 15:42:15 +0200 Subject: [PATCH] Doc rework to use the async/await syntax. --- docs/asynchronous-programming.rst | 20 ++++++-------- docs/wamp/programming.rst | 46 ++++++++++++------------------- docs/work/programming.rst | 16 +++++------ 3 files changed, 35 insertions(+), 47 deletions(-) diff --git a/docs/asynchronous-programming.rst b/docs/asynchronous-programming.rst index 06e33b4e..28fa6977 100644 --- a/docs/asynchronous-programming.rst +++ b/docs/asynchronous-programming.rst @@ -272,7 +272,7 @@ Have a look at the highlighted lines - here is what we do: .. note:: - The reason ``returnValue`` is necessary goes deep into implementation details of Twisted and Python. In short: co-routines in Python 2 with Twisted are simulated using exceptions. Only Python 3.3+ has gotten native support for co-routines using the new yield from statement. + The reason ``returnValue`` is necessary goes deep into implementation details of Twisted and Python. In short: co-routines in Python 2 with Twisted are simulated using exceptions. Only Python 3.3+ has gotten native support for co-routines using the new yield from statement, Python 3.5+ use await statement and it is the new recommended method. In above, we are using a little helper :func:`autobahn.twisted.util.sleep` for sleeping "inline". The helper is really trivial: @@ -298,7 +298,7 @@ Asyncio Futures and Coroutines On the other hand, asyncio futures are quite different from Twisted Deferreds. One difference is that they have no built-in machinery for chaining. -`Asyncio Coroutines `__ are (on a certain level) quite similar to Twisted inline callbacks. Here is the code corresponding to our example above: +`Asyncio Coroutines `__ are (on a certain level) quite similar to Twisted inline callbacks. Here is the code corresponding to our example above: ------- @@ -355,19 +355,17 @@ Now, when converted to ``asyncio.coroutine``, the code becomes: .. code-block:: python :linenos: - :emphasize-lines: 3,5,6 + :emphasize-lines: 3,4,5 import asyncio - @asyncio.coroutine - def slow_square(x): - yield from asyncio.sleep(1) + async def slow_square(x): + await asyncio.sleep(1) return x * x - @asyncio.coroutine - def test(): - res = yield from slow_square(3) + async def test(): + res = await slow_square(3) print(res) loop = asyncio.get_event_loop() @@ -375,9 +373,9 @@ Now, when converted to ``asyncio.coroutine``, the code becomes: The main differences (on surface) are: -1. The use of the decorator ``@asyncio.coroutine`` (line 3) in asyncio versus ``@defer.inlineCallbacks`` with Twisted +1. The declaration of the function with ``async`` keyword (line 3) in asyncio versus the decorator ``@defer.inlineCallbacks`` with Twisted 2. The use of ``defer.returnValue`` in Twisted for returning values whereas in asyncio, you can use plain returns (line 6) -3. The use of ``yield from`` in asyncio, versus plain ``yield`` in Twisted (line 5) +3. The use of ``await`` in asyncio, versus ``yield`` in Twisted (line 5) 4. The auxiliary code to get the event loop started and stopped Most of the examples that follow will show code for both Twisted and asyncio, unless the conversion is trivial. diff --git a/docs/wamp/programming.rst b/docs/wamp/programming.rst index 66642697..c4ddc57f 100644 --- a/docs/wamp/programming.rst +++ b/docs/wamp/programming.rst @@ -144,18 +144,16 @@ Here are quick templates for you to copy/paste for creating and running a WAMP c **asyncio**: .. code-block:: python - :emphasize-lines: 2 + :emphasize-lines: 1 - from asyncio import coroutine from autobahn.asyncio.wamp import ApplicationSession, ApplicationRunner class MyComponent(ApplicationSession): - @coroutine - def onJoin(self, details): + async def onJoin(self, details): print("session joined") # can do subscribes, registers here e.g.: - # yield from self.subscribe(...) - # yield from self.register(...) + # await self.subscribe(...) + # await self.register(...) if __name__ == '__main__': runner = ApplicationRunner(url=u"ws://localhost:8080/ws", realm=u"realm1") @@ -248,21 +246,19 @@ Using **asyncio**, the example looks like this: .. code-block:: python :linenos: - :emphasize-lines: 13 + :emphasize-lines: 11 from autobahn.asyncio.wamp import ApplicationSession - from asyncio import coroutine class MyComponent(ApplicationSession): - @coroutine - def onJoin(self, details): + async def onJoin(self, details): print("session ready") def add2(x, y): return x + y try: - yield from self.register(add2, u'com.myapp.add2') + await self.register(add2, u'com.myapp.add2') print("procedure registered") except Exception as e: print("could not register procedure: {0}".format(e)) @@ -270,8 +266,8 @@ Using **asyncio**, the example looks like this: The differences compared with the Twisted variant are: * the ``import`` of ``ApplicationSession`` -* the use of ``@coroutine`` to decorate co-routines -* the use of ``yield from`` instead of ``yield`` +* the use of ``async`` keyword to declare co-routines +* the use of ``await`` instead of ``yield`` .. _calling-procedures: @@ -306,19 +302,17 @@ And here is the same done on **asyncio** .. code-block:: python :linenos: - :emphasize-lines: 11 + :emphasize-lines: 9 from autobahn.asyncio.wamp import ApplicationSession - from asyncio import coroutine class MyComponent(ApplicationSession): - @coroutine - def onJoin(self, details): + async def onJoin(self, details): print("session ready") try: - res = yield from self.call(u'com.myapp.add2', 2, 3) + res = await self.call(u'com.myapp.add2', 2, 3) print("call result: {}".format(res)) except Exception as e: print("call error: {0}".format(e)) @@ -383,22 +377,20 @@ The corresponding **asyncio** code looks like this .. code-block:: python :linenos: - :emphasize-lines: 14 + :emphasize-lines: 12 from autobahn.asyncio.wamp import ApplicationSession - from asyncio import coroutine class MyComponent(ApplicationSession): - @coroutine - def onJoin(self, details): + async def onJoin(self, details): print("session ready") def oncounter(count): print("event received: {0}", count) try: - yield from self.subscribe(oncounter, u'com.myapp.oncounter') + await self.subscribe(oncounter, u'com.myapp.oncounter') print("subscribed to topic") except Exception as e: print("could not subscribe to topic: {0}".format(e)) @@ -441,23 +433,21 @@ The corresponding **asyncio** code looks like this .. code-block:: python :linenos: - :emphasize-lines: 13 + :emphasize-lines: 11 from autobahn.asyncio.wamp import ApplicationSession from asyncio import sleep - from asyncio import coroutine class MyComponent(ApplicationSession): - @coroutine - def onJoin(self, details): + async def onJoin(self, details): print("session ready") counter = 0 while True: self.publish(u'com.myapp.oncounter', counter) counter += 1 - yield from sleep(1) + await sleep(1) .. tip:: diff --git a/docs/work/programming.rst b/docs/work/programming.rst index d813d0cd..c2a62b29 100644 --- a/docs/work/programming.rst +++ b/docs/work/programming.rst @@ -15,7 +15,7 @@ For example, here is how you call a remote procedure that takes no arguments and print(now) -This is using `yield`, which assumes the context in that you run this code is a *co-routine* (something decorated with `defer.inlineDeferred` in Twisted or `asyncio.coroutine` in asyncio). +This is using `yield`, which assumes the context in that you run this code is a *co-routine* (something decorated with `defer.inlineDeferred` in Twisted or declared with `async def` in asyncio). The same call using plain Twisted Deferreds would look like: @@ -183,7 +183,7 @@ The direct asyncio equivalent of above would be: import functools - def print_sales(product, future): + async def print_sales(product, future): sales = future.result() print("Sales {}: {}".format(product, sales)) @@ -192,7 +192,7 @@ The direct asyncio equivalent of above would be: f = session.call("com.myapp.sales_by_product", product) f.add_done_callback(functools.partial(print_sales, product)) fl.append(f) - yield from asyncio.gather(*fl) + await asyncio.gather(*fl) > Note: Part of the verbosity stems from the fact that, different from Twisted's `addCallback`, asyncio's `add_done_callback` sadly does not take and forward `args` and `kwargs` to the callback added. > @@ -201,12 +201,12 @@ However, there is a better way, if we restructure the code a litte: .. code-block:: python - def get_and_print_sales(product): - sales = yield from session.call("com.myapp.sales_by_product", product) + async def get_and_print_sales(product): + sales = await session.call("com.myapp.sales_by_product", product) print("Sales {}: {}".format(product, sales)) tasks = [get_and_print_sales(product) for product in ["product2", "product3", "product5"]] - yield from asyncio.wait(tasks) + await asyncio.wait(tasks) Calls with complex results .......................... @@ -248,7 +248,7 @@ Using asyncio coroutines (`asyncio.coroutine`): .. code-block:: python try: - res = yield from session.call("com.calculator.sqrt", -1) + res = await session.call("com.calculator.sqrt", -1) except ApplicationError as err: print("Error: {}".format(err)) else: @@ -480,7 +480,7 @@ In asyncio, use .. code-block:: python - registrations = yield from asyncio.gather(*session.register(calc)) + registrations = await asyncio.gather(*session.register(calc)) to yield a list of registrations.