Doc rework to use the async/await syntax.
This commit is contained in:
		@@ -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 <http://docs.python.org/3.4/library/asyncio-task.html#coroutines>`__ are (on a certain level) quite similar to Twisted inline callbacks. Here is the code corresponding to our example above:
 | 
			
		||||
`Asyncio Coroutines <http://docs.python.org/3.5/library/asyncio-task.html#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.
 | 
			
		||||
 
 | 
			
		||||
@@ -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::
 | 
			
		||||
 
 | 
			
		||||
@@ -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.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user