diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4a00bf8fc..ed52ddd80 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,7 +56,7 @@ jobs: with: platforms: all - name: Build wheels - uses: pypa/cibuildwheel@v2.16.2 + uses: pypa/cibuildwheel@v2.20.0 env: BUILD_EXTENSION: yes - name: Save wheels diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 15a45bdfb..b9172b7fb 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -62,6 +62,7 @@ jobs: - "3.10" - "3.11" - "3.12" + - "3.13" - "pypy-3.9" - "pypy-3.10" is_main: @@ -78,6 +79,7 @@ jobs: uses: actions/setup-python@v5 with: python-version: ${{ matrix.python }} + allow-prereleases: true - name: Install tox run: pip install tox - name: Run tests diff --git a/docs/faq/misc.rst b/docs/faq/misc.rst index ee5ad2372..0e74a784f 100644 --- a/docs/faq/misc.rst +++ b/docs/faq/misc.rst @@ -3,6 +3,9 @@ Miscellaneous .. currentmodule:: websockets +.. Remove this question when dropping Python < 3.13, which provides natively +.. a good error message in this case. + Why do I get the error: ``module 'websockets' has no attribute '...'``? ....................................................................... diff --git a/docs/project/changelog.rst b/docs/project/changelog.rst index 8143e3483..00b055dd1 100644 --- a/docs/project/changelog.rst +++ b/docs/project/changelog.rst @@ -71,7 +71,7 @@ New features See :func:`websockets.asyncio.client.connect` and :func:`websockets.asyncio.server.serve` for details. -* Validated compatibility with Python 3.12. +* Validated compatibility with Python 3.12 and 3.13. * Added :doc:`environment variables <../reference/variables>` to configure debug logs, the ``Server`` and ``User-Agent`` headers, as well as security limits. diff --git a/pyproject.toml b/pyproject.toml index de8acd6a3..c1d34c90b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ] dynamic = ["version", "readme"] diff --git a/src/websockets/asyncio/connection.py b/src/websockets/asyncio/connection.py index 152c6789e..4f44d798c 100644 --- a/src/websockets/asyncio/connection.py +++ b/src/websockets/asyncio/connection.py @@ -564,8 +564,7 @@ async def ping(self, data: Data | None = None) -> Awaitable[None]: pong_waiter = self.loop.create_future() # The event loop's default clock is time.monotonic(). Its resolution - # is a bit low on Windows (~16ms). We cannot use time.perf_counter() - # because it doesn't count time elapsed while the process sleeps. + # is a bit low on Windows (~16ms). This is improved in Python 3.13. ping_timestamp = self.loop.time() self.pong_waiters[data] = (pong_waiter, ping_timestamp) self.protocol.send_ping(data) diff --git a/tox.ini b/tox.ini index 1edcfe261..16d9c9f16 100644 --- a/tox.ini +++ b/tox.ini @@ -5,6 +5,7 @@ env_list = py310 py311 py312 + py313 coverage black ruff