Skip to content

Commit

Permalink
Update docs to async / await syntax.
Browse files Browse the repository at this point in the history
Fix #88.
  • Loading branch information
aaugustin committed Dec 25, 2015
1 parent 00f0b53 commit 4f16e25
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 29 deletions.
8 changes: 5 additions & 3 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ Changelog
``None`` when the connection was closed. This required checking the return
value of every call::

message = yield from websocket.recv()
message = await websocket.recv()
if message is None:
return

Now it raises a :exc:`~websockets.exceptions.ConnectionClosed` exception
instead. This is more Pythonic. The previous code can be simplified to::

message = yield from websocket.recv()
message = await websocket.recv()

When implementing a server, which is the more popular use case, there's no
strong reason to handle such exceptions. Let them bubble up, terminate the
Expand All @@ -42,6 +42,8 @@ Also:
* :func:`~websockets.client.connect` can be used as an asynchronous context
manager on Python ≥ 3.5.

* Updated documentation with ``await`` and ``async`` syntax from Python 3.5.

* :meth:`~websockets.protocol.WebSocketCommonProtocol.ping` and
:meth:`~websockets.protocol.WebSocketCommonProtocol.pong` supports
data passed as :class:`str` in addition to :class:`bytes`.
Expand Down Expand Up @@ -142,7 +144,7 @@ Also:

you must now write::

yield from websocket.send(message)
await websocket.send(message)

Also:

Expand Down
63 changes: 45 additions & 18 deletions docs/intro.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
Getting started
===============

.. warning::

This documentation is written for Python ≥ 3.5. If you're using Python 3.4
or 3.3, you will have to :ref:`adapt the code samples <python-lt-35>`.

Basic example
-------------

Expand Down Expand Up @@ -54,11 +59,10 @@ Consumer

For receiving messages and passing them to a ``consumer`` coroutine::

@asyncio.coroutine
def handler(websocket, path):
async def handler(websocket, path):
while True:
message = yield from websocket.recv()
yield from consumer(message)
message = await websocket.recv()
await consumer(message)

:meth:`~websockets.protocol.WebSocketCommonProtocol.recv` raises a
:exc:`~websockets.exceptions.ConnectionClosed` exception when the client
Expand All @@ -69,11 +73,10 @@ Producer

For getting messages from a ``producer`` coroutine and sending them::

@asyncio.coroutine
def handler(websocket, path):
async def handler(websocket, path):
while True:
message = yield from producer()
yield from websocket.send(message)
message = await producer()
await websocket.send(message)

:meth:`~websockets.protocol.WebSocketCommonProtocol.send` raises a
:exc:`~websockets.exceptions.ConnectionClosed` exception when the client
Expand All @@ -87,24 +90,23 @@ messages on the same connection.

::

@asyncio.coroutine
def handler(websocket, path):
async def handler(websocket, path):
while True:
listener_task = asyncio.ensure_future(websocket.recv())
producer_task = asyncio.ensure_future(producer())
done, pending = yield from asyncio.wait(
done, pending = await asyncio.wait(
[listener_task, producer_task],
return_when=asyncio.FIRST_COMPLETED)

if listener_task in done:
message = listener_task.result()
yield from consumer(message)
await consumer(message)
else:
listener_task.cancel()

if producer_task in done:
message = producer_task.result()
yield from websocket.send(message)
await websocket.send(message)
else:
producer_task.cancel()

Expand All @@ -121,16 +123,14 @@ register clients when they connect and unregister them when they disconnect.

connected = set()

@asyncio.coroutine
def handler(websocket, path):
async def handler(websocket, path):
global connected
# Register.
connected.add(websocket)
try:
# Implement logic here.
yield from asyncio.wait(
[ws.send("Hello!") for ws in connected])
yield from asyncio.sleep(10)
await asyncio.wait([ws.send("Hello!") for ws in connected])
await asyncio.sleep(10)
finally:
# Unregister.
connected.remove(websocket)
Expand All @@ -148,3 +148,30 @@ You don't have to worry about performing the opening or the closing handshake,
answering pings, or any other behavior required by the specification.

``websockets`` handles all this under the hood so you don't have to.

.. _python-lt-35:

Python < 3.5
------------

This documentation uses the ``await`` and ``async`` syntax introduced in
Python 3.5.

If you're using Python 3.4 or 3.3, you must substitute::

async def ...

with::

@asyncio.coroutine
def ...

and::

await ...

with::

yield from ...

Otherwise you will encounter a :exc:`SyntaxError`.
7 changes: 3 additions & 4 deletions example/sendtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@
import random
import websockets

@asyncio.coroutine
def time(websocket, path):
async def time(websocket, path):
while True:
now = datetime.datetime.utcnow().isoformat() + 'Z'
yield from websocket.send(now)
yield from asyncio.sleep(random.random() * 3)
await websocket.send(now)
await asyncio.sleep(random.random() * 3)

start_server = websockets.serve(time, '127.0.0.1', 5678)

Expand Down
7 changes: 3 additions & 4 deletions example/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
import asyncio
import websockets

@asyncio.coroutine
def hello(websocket, path):
name = yield from websocket.recv()
async def hello(websocket, path):
name = await websocket.recv()
print("< {}".format(name))
greeting = "Hello {}!".format(name)

yield from websocket.send(greeting)
await websocket.send(greeting)
print("> {}".format(greeting))

start_server = websockets.serve(hello, 'localhost', 8765)
Expand Down

0 comments on commit 4f16e25

Please sign in to comment.