Skip to content

Add trio implementation #1628

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ tests:
python -m unittest

coverage:
coverage run --source src/websockets,tests -m unittest
coverage run --source src/websockets,tests -m unittest tests/trio/test_server.py
coverage html
coverage report --show-missing --fail-under=100

maxi_cov:
python tests/maxi_cov.py
Expand Down
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
"sesame": ("https://django-sesame.readthedocs.io/en/stable/", None),
"trio": ("https://trio.readthedocs.io/en/stable/", None),
"werkzeug": ("https://werkzeug.palletsprojects.com/en/stable/", None),
}

Expand Down
8 changes: 8 additions & 0 deletions docs/project/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ Backwards-incompatible changes
New features
............

.. admonition:: websockets 16.0 introduces a :mod:`trio` implementation.
:class: important

It is an alternative to the :mod:`asyncio` implementation.

See :func:`websockets.trio.client.connect` and
:func:`websockets.trio.server.serve` for details.

* Validated compatibility with Python 3.14.

Improvements
Expand Down
257 changes: 129 additions & 128 deletions docs/reference/features.rst

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions docs/reference/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ This alternative implementation can be a good choice for clients.
sync/server
sync/client

:mod:`trio`
------------

This is another option for servers that handle many clients concurrently.

.. toctree::
:titlesonly:

trio/server
trio/client

`Sans-I/O`_
-----------

Expand Down
66 changes: 66 additions & 0 deletions docs/reference/trio/client.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
Client (:mod:`trio`)
=======================

.. automodule:: websockets.trio.client

.. Opening a connection
.. --------------------

.. .. autofunction:: connect
.. :async:

.. .. autofunction:: unix_connect
.. :async:

.. .. autofunction:: process_exception

.. Using a connection
.. ------------------

.. .. autoclass:: ClientConnection

.. .. automethod:: __aiter__

.. .. automethod:: recv

.. .. automethod:: recv_streaming

.. .. automethod:: send

.. .. automethod:: close

.. .. automethod:: wait_closed

.. .. automethod:: ping

.. .. automethod:: pong

.. WebSocket connection objects also provide these attributes:

.. .. autoattribute:: id

.. .. autoattribute:: logger

.. .. autoproperty:: local_address

.. .. autoproperty:: remote_address

.. .. autoattribute:: latency

.. .. autoproperty:: state

.. The following attributes are available after the opening handshake,
.. once the WebSocket connection is open:

.. .. autoattribute:: request

.. .. autoattribute:: response

.. .. autoproperty:: subprotocol

.. The following attributes are available after the closing handshake,
.. once the WebSocket connection is closed:

.. .. autoproperty:: close_code

.. .. autoproperty:: close_reason
58 changes: 58 additions & 0 deletions docs/reference/trio/common.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
:orphan:

Both sides (:mod:`trio`)
===========================

.. automodule:: websockets.trio.connection

.. autoclass:: Connection

.. automethod:: __aiter__

.. automethod:: recv

.. automethod:: receive

.. automethod:: recv_streaming

.. automethod:: send

.. automethod:: close

.. automethod:: aclose

.. automethod:: wait_closed

.. automethod:: ping

.. automethod:: pong

WebSocket connection objects also provide these attributes:

.. autoattribute:: id

.. autoattribute:: logger

.. autoproperty:: local_address

.. autoproperty:: remote_address

.. autoattribute:: latency

.. autoproperty:: state

The following attributes are available after the opening handshake,
once the WebSocket connection is open:

.. autoattribute:: request

.. autoattribute:: response

.. autoproperty:: subprotocol

The following attributes are available after the closing handshake,
once the WebSocket connection is closed:

.. autoproperty:: close_code

.. autoproperty:: close_reason
110 changes: 110 additions & 0 deletions docs/reference/trio/server.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
Server (:mod:`trio`)
=======================

.. automodule:: websockets.trio.server

.. Creating a server
.. -----------------

.. .. autofunction:: serve
.. :async:

.. .. autofunction:: unix_serve
.. :async:

.. Routing connections
.. -------------------

.. .. automodule:: websockets.trio.router

.. .. autofunction:: route
.. :async:

.. .. autofunction:: unix_route
.. :async:

.. .. autoclass:: Router

.. .. currentmodule:: websockets.trio.server

.. Running a server
.. ----------------

.. .. autoclass:: Server

.. .. autoattribute:: connections

.. .. automethod:: close

.. .. automethod:: wait_closed

.. .. automethod:: get_loop

.. .. automethod:: is_serving

.. .. automethod:: start_serving

.. .. automethod:: serve_forever

.. .. autoattribute:: sockets

.. Using a connection
.. ------------------

.. .. autoclass:: ServerConnection

.. .. automethod:: __aiter__

.. .. automethod:: recv

.. .. automethod:: recv_streaming

.. .. automethod:: send

.. .. automethod:: close

.. .. automethod:: wait_closed

.. .. automethod:: ping

.. .. automethod:: pong

.. .. automethod:: respond

.. WebSocket connection objects also provide these attributes:

.. .. autoattribute:: id

.. .. autoattribute:: logger

.. .. autoproperty:: local_address

.. .. autoproperty:: remote_address

.. .. autoattribute:: latency

.. .. autoproperty:: state

.. The following attributes are available after the opening handshake,
.. once the WebSocket connection is open:

.. .. autoattribute:: request

.. .. autoattribute:: response

.. .. autoproperty:: subprotocol

.. The following attributes are available after the closing handshake,
.. once the WebSocket connection is closed:

.. .. autoproperty:: close_code

.. .. autoproperty:: close_reason

.. HTTP Basic Authentication
.. -------------------------

.. websockets supports HTTP Basic Authentication according to
.. :rfc:`7235` and :rfc:`7617`.

.. .. autofunction:: basic_auth
4 changes: 2 additions & 2 deletions docs/topics/keepalive.rst
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ measured during the last exchange of Ping and Pong frames::
Alternatively, you can measure the latency at any time by calling
:attr:`~asyncio.connection.Connection.ping` and awaiting its result::

pong_waiter = await websocket.ping()
latency = await pong_waiter
pong_received = await websocket.ping()
latency = await pong_received

Latency between a client and a server may increase for two reasons:

Expand Down
22 changes: 22 additions & 0 deletions example/trio/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env python

"""Client example using the trio API."""

import trio

from websockets.trio.client import connect


async def hello():
async with connect("ws://localhost:8765") as websocket:
name = input("What's your name? ")

await websocket.send(name)
print(f">>> {name}")

greeting = await websocket.recv()
print(f"<<< {greeting}")


if __name__ == "__main__":
trio.run(hello)
15 changes: 15 additions & 0 deletions example/trio/echo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env python

"""Echo server using the trio API."""

import trio
from websockets.trio.server import serve


async def echo(websocket):
async for message in websocket:
await websocket.send(message)


if __name__ == "__main__":
trio.run(serve, echo, 8765)
17 changes: 17 additions & 0 deletions example/trio/hello.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env python

"""Client using the trio API."""

import trio
from websockets.trio.client import connect


async def hello():
async with connect("ws://localhost:8765") as websocket:
await websocket.send("Hello world!")
message = await websocket.recv()
print(message)


if __name__ == "__main__":
trio.run(hello)
20 changes: 20 additions & 0 deletions example/trio/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env python

"""Server example using the trio API."""

import trio
from websockets.trio.server import serve


async def hello(websocket):
name = await websocket.recv()
print(f"<<< {name}")

greeting = f"Hello {name}!"

await websocket.send(greeting)
print(f">>> {greeting}")


if __name__ == "__main__":
trio.run(serve, hello, 8765)
Loading
Loading