Chapter 6 · practice
The websockets Library, Without asyncio
Install and Pin websockets
Your Chapter 5 echo service works: the hand-built client and the hand-built server agree on every ws_handshake.py, ws_frames.py and loopback_demo.py, and a mistake made the same way on both sides cancels out, as a 16-bit length written
This chapter brings in the websockets library, written to the same RFC 6455 by other people. First it tests your code; from Lesson 2 on, it takes over the plumbing.
The project tree holds the course’s finished versions of loopback_demo.py, ws_frames.py and ws_handshake.py, so the chapter starts from known files whatever your own Chapter 5 code looked like; nothing in this chapter edits them. You write echo_library.py from Lesson 2 on, and Run starts library_demo.py in the editor lessons.
Which version is here
This lesson has a
python -c "import websockets; print(websockets.__version__)"
It should print 17.4, the version this course was checked against and the one the site’s sandbox has. That copy is installed for the sandbox’s Python, so every later lesson can import websockets without installing anything.
Pin it
requirements.txt already holds one line, pytest==9.1.1. Open the file in the Project tab, or with nano requirements.txt in the shell as in Python in Practice, and add the library below it, so the file reads:
pytest==9.1.1
websockets==17.4
The == pins the exact version. Libraries change between releases: some pip install -r requirements.txt then gives you the library this chapter uses.
Why write websockets==17.4 rather than websockets?
Install it where you can see it
Now prove the file is enough to rebuild the environment. Make a fresh
python -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
echo $?
.venv/bin/python -m pip freeze
pip reads both lines and installs from the course’s mirror, and echo $? prints its exit status, 0 when the install worked. On the site, the status was 0 and pip freeze listed pytest and the packages pytest needs, and the line websockets==17.4. Then ask the new environment which version it got:
.venv/bin/python -c "import websockets; print(websockets.__version__)"
Locally it printed 17.4, the same version the sandbox’s own Python should report.
If the install fails instead, pip prints an error, echo $? prints a status other than 0, and pip freeze shows no
The site never saves .venv. Generated directories are left out when your project is saved, as Python in Practice showed, so the environment you just built is gone in the next lesson. Later lessons use the copy installed for the sandbox’s Python, which is the same version. The pin is for your own machine, and for anyone who installs this project after you.
You open the next lesson. Is your .venv still there?
The library meets your server
Open interop.py and read it; every wait in it is bounded. It starts the Chapter 5 server, loopback_demo.serve_clients, on a thread for one client on 127.0.0.1 connect(...) from websockets.sync.client, sends one text and one binary message and reads each echo, sends a with block, which closes the connection. Lesson 3 has you write a client like it. Run it:
python interop.py
A run of these files on the site printed this. PORT stands for the port number the system picked; yours will differ:
interop: the Chapter 5 server is listening on 127.0.0.1:PORT
library client: the handshake succeeded
library client: echo 'hello from the websockets library'
library client: echo b'\x00\x01\x02'
library client: ping answered: True
library client: closed the connection
Chapter 5 server: [{'messages': 2, 'code': 1000}]
interop: server thread still running: False
Read it line by line. The check_upgrade answered with a 101 carrying the accept accept_value computed, and the library checked that value the way your check_accept_response does. The two echoes are printed with repr, which writes a value the way Python source would: quotes around a str, a b before bytes. So the library masked a text frame and a binary frame, the Chapter 5 server unmasked and decoded them, and the echoes came back as text and as binary. The ping was answered: the library sent a ping carrying b"interop", server_reply answered with a pong carrying the same bytes, and the wait returned True within its 2 seconds. Leaving the block sent close 1000, and the server’s own report shows it echoed that close: two messages, code 1000. Last, the server thread had finished.
To see your own Chapter 5 code in this run, copy the course’s file aside with cp loopback_demo.py course_loopback_demo.py, paste yours over loopback_demo.py, and run python interop.py again. Nothing checks that run; afterwards put the course’s version back with cp course_loopback_demo.py loopback_demo.py, because later lessons use it.
You run interop.py: the websockets library's client connects to your Chapter 5 server, completes the handshake, gets back a text echo and a binary echo, gets a pong for its ping, and closes with 1000. What does that run show?
Check your work
Press Check my work. It reads requirements.txt and nothing else: exactly one websockets line, websockets==17.4, with the pytest==9.1.1 line still there; comments and blank lines are fine. It does not look at .venv, which is not saved, or at the interop run.
The library has talked to your server and agreed with it. In the next lesson the roles turn around: your Chapter 5 server becomes a library server, a handler of a few lines.
Task
Pin the library in requirements.txt: add the line websockets==17.4 and keep the line pytest==9.1.1.
Then, in the
python -c "import websockets; print(websockets.__version__)"to see the sandbox’s own version;python -m venv .venvand.venv/bin/python -m pip install -r requirements.txtto install from the course’s mirror;.venv/bin/python -m pip freezeand look forwebsockets==17.4;python interop.pyto watch the library’s client talk to the Chapter 5 server.
Press Check my work when the pin is in the file. The check reads requirements.txt only: it expects exactly one line naming websockets==17.4, with no >= or ~= and not only in a comment, and it expects pytest==9.1.1 to still be there. Comments, blank lines and the order of the two lines are up to you. The check does not look at .venv, which the site does not save, or at what interop.py printed.