Skip to content

Commit a78b554

Browse files
committed
Document legacy implementation in websockets.legacy.
Until now it was documented directly in the websockets package. Also update most examples to use the new asyncio implementation. Some drive-by documentation improvements too.
1 parent 60381d2 commit a78b554

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+951
-902
lines changed

compliance/test_client.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1+
import asyncio
12
import json
23
import logging
34
import urllib.parse
45

5-
import asyncio
6-
import websockets
6+
from websockets.asyncio.client import connect
77

88

99
logging.basicConfig(level=logging.WARNING)
@@ -18,21 +18,21 @@
1818

1919
async def get_case_count(server):
2020
uri = f"{server}/getCaseCount"
21-
async with websockets.connect(uri) as ws:
21+
async with connect(uri) as ws:
2222
msg = ws.recv()
2323
return json.loads(msg)
2424

2525

2626
async def run_case(server, case, agent):
2727
uri = f"{server}/runCase?case={case}&agent={agent}"
28-
async with websockets.connect(uri, max_size=2 ** 25, max_queue=1) as ws:
28+
async with connect(uri, max_size=2 ** 25, max_queue=1) as ws:
2929
async for msg in ws:
3030
await ws.send(msg)
3131

3232

3333
async def update_reports(server, agent):
3434
uri = f"{server}/updateReports?agent={agent}"
35-
async with websockets.connect(uri):
35+
async with connect(uri):
3636
pass
3737

3838

compliance/test_server.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
import asyncio
12
import logging
23

3-
import asyncio
4-
import websockets
4+
from websockets.asyncio.server import serve
55

66

77
logging.basicConfig(level=logging.WARNING)
@@ -19,7 +19,7 @@ async def echo(ws):
1919

2020

2121
async def main():
22-
with websockets.serve(echo, HOST, PORT, max_size=2 ** 25, max_queue=1):
22+
with serve(echo, HOST, PORT, max_size=2 ** 25, max_queue=1):
2323
try:
2424
await asyncio.get_running_loop().create_future() # run forever
2525
except KeyboardInterrupt:

docs/conf.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,20 @@
3636
# topics/design.rst discusses undocumented APIs
3737
("py:meth", "client.WebSocketClientProtocol.handshake"),
3838
("py:meth", "server.WebSocketServerProtocol.handshake"),
39-
("py:attr", "legacy.protocol.WebSocketCommonProtocol.is_client"),
40-
("py:attr", "legacy.protocol.WebSocketCommonProtocol.messages"),
41-
("py:meth", "legacy.protocol.WebSocketCommonProtocol.close_connection"),
42-
("py:attr", "legacy.protocol.WebSocketCommonProtocol.close_connection_task"),
43-
("py:meth", "legacy.protocol.WebSocketCommonProtocol.keepalive_ping"),
44-
("py:attr", "legacy.protocol.WebSocketCommonProtocol.keepalive_ping_task"),
45-
("py:meth", "legacy.protocol.WebSocketCommonProtocol.transfer_data"),
46-
("py:attr", "legacy.protocol.WebSocketCommonProtocol.transfer_data_task"),
47-
("py:meth", "legacy.protocol.WebSocketCommonProtocol.connection_open"),
48-
("py:meth", "legacy.protocol.WebSocketCommonProtocol.ensure_open"),
49-
("py:meth", "legacy.protocol.WebSocketCommonProtocol.fail_connection"),
50-
("py:meth", "legacy.protocol.WebSocketCommonProtocol.connection_lost"),
51-
("py:meth", "legacy.protocol.WebSocketCommonProtocol.read_message"),
52-
("py:meth", "legacy.protocol.WebSocketCommonProtocol.write_frame"),
39+
("py:attr", "protocol.WebSocketCommonProtocol.is_client"),
40+
("py:attr", "protocol.WebSocketCommonProtocol.messages"),
41+
("py:meth", "protocol.WebSocketCommonProtocol.close_connection"),
42+
("py:attr", "protocol.WebSocketCommonProtocol.close_connection_task"),
43+
("py:meth", "protocol.WebSocketCommonProtocol.keepalive_ping"),
44+
("py:attr", "protocol.WebSocketCommonProtocol.keepalive_ping_task"),
45+
("py:meth", "protocol.WebSocketCommonProtocol.transfer_data"),
46+
("py:attr", "protocol.WebSocketCommonProtocol.transfer_data_task"),
47+
("py:meth", "protocol.WebSocketCommonProtocol.connection_open"),
48+
("py:meth", "protocol.WebSocketCommonProtocol.ensure_open"),
49+
("py:meth", "protocol.WebSocketCommonProtocol.fail_connection"),
50+
("py:meth", "protocol.WebSocketCommonProtocol.connection_lost"),
51+
("py:meth", "protocol.WebSocketCommonProtocol.read_message"),
52+
("py:meth", "protocol.WebSocketCommonProtocol.write_frame"),
5353
]
5454

5555
# Add any Sphinx extension module names here, as strings. They can be

docs/faq/asyncio.rst

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
Using asyncio
22
=============
33

4-
.. currentmodule:: websockets
4+
.. currentmodule:: websockets.asyncio.connection
5+
6+
.. admonition:: This FAQ is written for the new :mod:`asyncio` implementation.
7+
:class: hint
8+
9+
Answers are also valid for the legacy :mod:`asyncio` implementation.
510

611
How do I run two coroutines in parallel?
712
----------------------------------------
813

914
You must start two tasks, which the event loop will run concurrently. You can
1015
achieve this with :func:`asyncio.gather` or :func:`asyncio.create_task`.
1116

12-
Keep track of the tasks and make sure they terminate or you cancel them when
13-
the connection terminates.
17+
Keep track of the tasks and make sure that they terminate or that you cancel
18+
them when the connection terminates.
1419

1520
Why does my program never receive any messages?
1621
-----------------------------------------------
@@ -22,13 +27,12 @@ Putting an ``await`` statement in a ``for`` or a ``while`` loop isn't enough
2227
to yield control. Awaiting a coroutine may yield control, but there's no
2328
guarantee that it will.
2429

25-
For example, :meth:`~legacy.protocol.WebSocketCommonProtocol.send` only yields
26-
control when send buffers are full, which never happens in most practical
27-
cases.
30+
For example, :meth:`~Connection.send` only yields control when send buffers are
31+
full, which never happens in most practical cases.
2832

29-
If you run a loop that contains only synchronous operations and
30-
a :meth:`~legacy.protocol.WebSocketCommonProtocol.send` call, you must yield
31-
control explicitly with :func:`asyncio.sleep`::
33+
If you run a loop that contains only synchronous operations and a
34+
:meth:`~Connection.send` call, you must yield control explicitly with
35+
:func:`asyncio.sleep`::
3236

3337
async def producer(websocket):
3438
message = generate_next_message()
@@ -46,24 +50,26 @@ See `issue 867`_.
4650
Why am I having problems with threads?
4751
--------------------------------------
4852

49-
If you choose websockets' default implementation based on :mod:`asyncio`, then
50-
you shouldn't use threads. Indeed, choosing :mod:`asyncio` to handle concurrency
51-
is mutually exclusive with :mod:`threading`.
53+
If you choose websockets' :mod:`asyncio` implementation, then you shouldn't use
54+
threads. Indeed, choosing :mod:`asyncio` to handle concurrency is mutually
55+
exclusive with :mod:`threading`.
5256

5357
If you believe that you need to run websockets in a thread and some logic in
5458
another thread, you should run that logic in a :class:`~asyncio.Task` instead.
55-
If it blocks the event loop, :meth:`~asyncio.loop.run_in_executor` will help.
5659

57-
This question is really about :mod:`asyncio`. Please review the advice about
58-
:ref:`asyncio-multithreading` in the Python documentation.
60+
If it has to run in another thread because it would block the event loop,
61+
:func:`~asyncio.to_thread` or :meth:`~asyncio.loop.run_in_executor` is the way
62+
to go.
63+
64+
Please review the advice about :ref:`asyncio-multithreading` in the Python
65+
documentation.
5966

6067
Why does my simple program misbehave mysteriously?
6168
--------------------------------------------------
6269

6370
You are using :func:`time.sleep` instead of :func:`asyncio.sleep`, which
6471
blocks the event loop and prevents asyncio from operating normally.
6572

66-
This may lead to messages getting send but not received, to connection
67-
timeouts, and to unexpected results of shotgun debugging e.g. adding an
68-
unnecessary call to :meth:`~legacy.protocol.WebSocketCommonProtocol.send`
69-
makes the program functional.
73+
This may lead to messages getting send but not received, to connection timeouts,
74+
and to unexpected results of shotgun debugging e.g. adding an unnecessary call
75+
to a coroutine makes the program functional.

docs/faq/client.rst

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
Client
22
======
33

4-
.. currentmodule:: websockets
4+
.. currentmodule:: websockets.asyncio.client
5+
6+
.. admonition:: This FAQ is written for the new :mod:`asyncio` implementation.
7+
:class: hint
8+
9+
Answers are also valid for the legacy :mod:`asyncio` implementation.
10+
11+
They translate to the :mod:`threading` implementation by removing ``await``
12+
and ``async`` keywords and by using a :class:`~threading.Thread` instead of
13+
a :class:`~asyncio.Task` for concurrent execution.
514

615
Why does the client close the connection prematurely?
716
-----------------------------------------------------
@@ -22,46 +31,47 @@ change it to::
2231
How do I access HTTP headers?
2332
-----------------------------
2433

25-
Once the connection is established, HTTP headers are available in
26-
:attr:`~client.WebSocketClientProtocol.request_headers` and
27-
:attr:`~client.WebSocketClientProtocol.response_headers`.
34+
Once the connection is established, HTTP headers are available in the
35+
:attr:`~ClientConnection.request` and :attr:`~ClientConnection.response`
36+
objects::
37+
38+
async with connect(...) as websocket:
39+
websocket.request.headers
40+
websocket.response.headers
2841

2942
How do I set HTTP headers?
3043
--------------------------
3144

3245
To set the ``Origin``, ``Sec-WebSocket-Extensions``, or
3346
``Sec-WebSocket-Protocol`` headers in the WebSocket handshake request, use the
34-
``origin``, ``extensions``, or ``subprotocols`` arguments of
35-
:func:`~client.connect`.
47+
``origin``, ``extensions``, or ``subprotocols`` arguments of :func:`~connect`.
3648

3749
To override the ``User-Agent`` header, use the ``user_agent_header`` argument.
3850
Set it to :obj:`None` to remove the header.
3951

4052
To set other HTTP headers, for example the ``Authorization`` header, use the
41-
``extra_headers`` argument::
53+
``additional_headers`` argument::
4254

43-
async with connect(..., extra_headers={"Authorization": ...}) as websocket:
55+
async with connect(..., additional_headers={"Authorization": ...}) as websocket:
4456
...
4557

46-
In the :mod:`threading` API, this argument is named ``additional_headers``::
47-
48-
with connect(..., additional_headers={"Authorization": ...}) as websocket:
49-
...
58+
In the legacy :mod:`asyncio` API, this argument is named ``extra_headers``.
5059

5160
How do I force the IP address that the client connects to?
5261
----------------------------------------------------------
5362

54-
Use the ``host`` argument of :meth:`~asyncio.loop.create_connection`::
63+
Use the ``host`` argument :func:`~connect`::
5564

56-
await websockets.connect("ws://example.com", host="192.168.0.1")
65+
async with connect(..., host="192.168.0.1") as websocket:
66+
...
5767

58-
:func:`~client.connect` accepts the same arguments as
59-
:meth:`~asyncio.loop.create_connection`.
68+
:func:`~connect` accepts the same arguments as
69+
:meth:`~asyncio.loop.create_connection` and passes them through.
6070

6171
How do I close a connection?
6272
----------------------------
6373

64-
The easiest is to use :func:`~client.connect` as a context manager::
74+
The easiest is to use :func:`~connect` as a context manager::
6575

6676
async with connect(...) as websocket:
6777
...
@@ -71,9 +81,17 @@ The connection is closed when exiting the context manager.
7181
How do I reconnect when the connection drops?
7282
---------------------------------------------
7383

74-
Use :func:`~client.connect` as an asynchronous iterator::
84+
.. admonition:: This feature is only supported by the legacy :mod:`asyncio`
85+
implementation.
86+
:class: warning
87+
88+
It will be added to the new :mod:`asyncio` implementation soon.
89+
90+
Use :func:`~websockets.legacy.client.connect` as an asynchronous iterator::
91+
92+
from websockets.legacy.client import connect
7593

76-
async for websocket in websockets.connect(...):
94+
async for websocket in connect(...):
7795
try:
7896
...
7997
except websockets.ConnectionClosed:
@@ -90,12 +108,12 @@ You can close the connection.
90108
Here's an example that terminates cleanly when it receives SIGTERM on Unix:
91109

92110
.. literalinclude:: ../../example/faq/shutdown_client.py
93-
:emphasize-lines: 10-13
111+
:emphasize-lines: 11-13
94112

95113
How do I disable TLS/SSL certificate verification?
96114
--------------------------------------------------
97115

98116
Look at the ``ssl`` argument of :meth:`~asyncio.loop.create_connection`.
99117

100-
:func:`~client.connect` accepts the same arguments as
101-
:meth:`~asyncio.loop.create_connection`.
118+
:func:`~connect` accepts the same arguments as
119+
:meth:`~asyncio.loop.create_connection` and passes them through.

0 commit comments

Comments
 (0)