Skip to content

Commit 44ccee1

Browse files
committed
Drop Python 3.8.
It is EOL at the end of October.
1 parent 37c7f65 commit 44ccee1

32 files changed

+76
-129
lines changed

.github/workflows/tests.yml

-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ jobs:
5555
strategy:
5656
matrix:
5757
python:
58-
- "3.8"
5958
- "3.9"
6059
- "3.10"
6160
- "3.11"

docs/howto/django.rst

+1-2
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,7 @@ authentication fails, it closes the connection and exits.
121121
When we call an API that makes a database query such as ``get_user()``, we
122122
wrap the call in :func:`~asyncio.to_thread`. Indeed, the Django ORM doesn't
123123
support asynchronous I/O. It would block the event loop if it didn't run in a
124-
separate thread. :func:`~asyncio.to_thread` is available since Python 3.9. In
125-
earlier versions, use :meth:`~asyncio.loop.run_in_executor` instead.
124+
separate thread.
126125

127126
Finally, we start a server with :func:`~websockets.asyncio.server.serve`.
128127

docs/intro/index.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Getting started
66
Requirements
77
------------
88

9-
websockets requires Python ≥ 3.8.
9+
websockets requires Python ≥ 3.9.
1010

1111
.. admonition:: Use the most recent Python release
1212
:class: tip

docs/project/changelog.rst

+9-5
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ notice.
3232

3333
*In development*
3434

35+
Backwards-incompatible changes
36+
..............................
37+
38+
.. admonition:: websockets 14.0 requires Python ≥ 3.9.
39+
:class: tip
40+
41+
websockets 13.1 is the last version supporting Python 3.8.
42+
43+
3544
.. _13.1:
3645

3746
13.1
@@ -106,11 +115,6 @@ Bug fixes
106115
Backwards-incompatible changes
107116
..............................
108117

109-
.. admonition:: websockets 13.0 requires Python ≥ 3.8.
110-
:class: tip
111-
112-
websockets 12.0 is the last version supporting Python 3.7.
113-
114118
.. admonition:: Receiving the request path in the second parameter of connection
115119
handlers is deprecated.
116120
:class: note

pyproject.toml

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
55
[project]
66
name = "websockets"
77
description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
8-
requires-python = ">=3.8"
8+
requires-python = ">=3.9"
99
license = { text = "BSD-3-Clause" }
1010
authors = [
1111
{ name = "Aymeric Augustin", email = "aymeric.augustin@m4x.org" },
@@ -19,7 +19,6 @@ classifiers = [
1919
"Operating System :: OS Independent",
2020
"Programming Language :: Python",
2121
"Programming Language :: Python :: 3",
22-
"Programming Language :: Python :: 3.8",
2322
"Programming Language :: Python :: 3.9",
2423
"Programming Language :: Python :: 3.10",
2524
"Programming Language :: Python :: 3.11",

src/websockets/asyncio/client.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
import logging
55
import os
66
import urllib.parse
7+
from collections.abc import AsyncIterator, Generator, Sequence
78
from types import TracebackType
8-
from typing import Any, AsyncIterator, Callable, Generator, Sequence
9+
from typing import Any, Callable
910

1011
from ..client import ClientProtocol, backoff
1112
from ..datastructures import HeadersLike
@@ -492,7 +493,7 @@ async def __aexit__(
492493
# async for ... in connect(...):
493494

494495
async def __aiter__(self) -> AsyncIterator[ClientConnection]:
495-
delays: Generator[float, None, None] | None = None
496+
delays: Generator[float] | None = None
496497
while True:
497498
try:
498499
async with self as protocol:

src/websockets/asyncio/connection.py

+2-9
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,9 @@
88
import struct
99
import sys
1010
import uuid
11+
from collections.abc import AsyncIterable, AsyncIterator, Awaitable, Iterable, Mapping
1112
from types import TracebackType
12-
from typing import (
13-
Any,
14-
AsyncIterable,
15-
AsyncIterator,
16-
Awaitable,
17-
Iterable,
18-
Mapping,
19-
cast,
20-
)
13+
from typing import Any, cast
2114

2215
from ..exceptions import (
2316
ConcurrencyError,

src/websockets/asyncio/messages.py

+2-8
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,8 @@
33
import asyncio
44
import codecs
55
import collections
6-
from typing import (
7-
Any,
8-
AsyncIterator,
9-
Callable,
10-
Generic,
11-
Iterable,
12-
TypeVar,
13-
)
6+
from collections.abc import AsyncIterator, Iterable
7+
from typing import Any, Callable, Generic, TypeVar
148

159
from ..exceptions import ConcurrencyError
1610
from ..frames import OP_BINARY, OP_CONT, OP_TEXT, Frame

src/websockets/asyncio/server.py

+4-12
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,9 @@
66
import logging
77
import socket
88
import sys
9+
from collections.abc import Awaitable, Generator, Iterable, Sequence
910
from types import TracebackType
10-
from typing import (
11-
Any,
12-
Awaitable,
13-
Callable,
14-
Generator,
15-
Iterable,
16-
Sequence,
17-
Tuple,
18-
cast,
19-
)
11+
from typing import Any, Callable, cast
2012

2113
from ..exceptions import InvalidHeader
2214
from ..extensions.base import ServerExtensionFactory
@@ -905,9 +897,9 @@ def basic_auth(
905897

906898
if credentials is not None:
907899
if is_credentials(credentials):
908-
credentials_list = [cast(Tuple[str, str], credentials)]
900+
credentials_list = [cast(tuple[str, str], credentials)]
909901
elif isinstance(credentials, Iterable):
910-
credentials_list = list(cast(Iterable[Tuple[str, str]], credentials))
902+
credentials_list = list(cast(Iterable[tuple[str, str]], credentials))
911903
if not all(is_credentials(item) for item in credentials_list):
912904
raise TypeError(f"invalid credentials argument: {credentials}")
913905
else:

src/websockets/client.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import os
44
import random
55
import warnings
6-
from typing import Any, Generator, Sequence
6+
from collections.abc import Generator, Sequence
7+
from typing import Any
78

89
from .datastructures import Headers, MultipleValuesError
910
from .exceptions import (
@@ -313,7 +314,7 @@ def send_request(self, request: Request) -> None:
313314

314315
self.writes.append(request.serialize())
315316

316-
def parse(self) -> Generator[None, None, None]:
317+
def parse(self) -> Generator[None]:
317318
if self.state is CONNECTING:
318319
try:
319320
response = yield from Response.parse(
@@ -374,7 +375,7 @@ def backoff(
374375
min_delay: float = BACKOFF_MIN_DELAY,
375376
max_delay: float = BACKOFF_MAX_DELAY,
376377
factor: float = BACKOFF_FACTOR,
377-
) -> Generator[float, None, None]:
378+
) -> Generator[float]:
378379
"""
379380
Generate a series of backoff delays between reconnection attempts.
380381

src/websockets/datastructures.py

+3-12
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
11
from __future__ import annotations
22

3-
from typing import (
4-
Any,
5-
Iterable,
6-
Iterator,
7-
Mapping,
8-
MutableMapping,
9-
Protocol,
10-
Tuple,
11-
Union,
12-
)
3+
from collections.abc import Iterable, Iterator, Mapping, MutableMapping
4+
from typing import Any, Protocol, Union
135

146

157
__all__ = ["Headers", "HeadersLike", "MultipleValuesError"]
@@ -179,8 +171,7 @@ def __getitem__(self, key: str) -> str: ...
179171
HeadersLike = Union[
180172
Headers,
181173
Mapping[str, str],
182-
# Change to tuple[str, str] when dropping Python < 3.9.
183-
Iterable[Tuple[str, str]],
174+
Iterable[tuple[str, str]],
184175
SupportsKeysAndGetItem,
185176
]
186177
"""

src/websockets/extensions/base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from __future__ import annotations
22

3-
from typing import Sequence
3+
from collections.abc import Sequence
44

55
from ..frames import Frame
66
from ..typing import ExtensionName, ExtensionParameter

src/websockets/extensions/permessage_deflate.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
import dataclasses
44
import zlib
5-
from typing import Any, Sequence
5+
from collections.abc import Sequence
6+
from typing import Any
67

78
from .. import frames
89
from ..exceptions import (

src/websockets/frames.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
import os
77
import secrets
88
import struct
9-
from typing import Callable, Generator, Sequence
9+
from collections.abc import Generator, Sequence
10+
from typing import Callable
1011

1112
from .exceptions import PayloadTooBig, ProtocolError
1213

src/websockets/headers.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
import binascii
55
import ipaddress
66
import re
7-
from typing import Callable, Sequence, TypeVar, cast
7+
from collections.abc import Sequence
8+
from typing import Callable, TypeVar, cast
89

910
from .exceptions import InvalidHeaderFormat, InvalidHeaderValue
1011
from .typing import (

src/websockets/http11.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
import re
66
import sys
77
import warnings
8-
from typing import Callable, Generator
8+
from collections.abc import Generator
9+
from typing import Callable
910

1011
from .datastructures import Headers
1112
from .exceptions import SecurityError

src/websockets/imports.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from __future__ import annotations
22

33
import warnings
4-
from typing import Any, Iterable
4+
from collections.abc import Iterable
5+
from typing import Any
56

67

78
__all__ = ["lazy_import"]

src/websockets/legacy/auth.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import functools
44
import hmac
55
import http
6-
from typing import Any, Awaitable, Callable, Iterable, Tuple, cast
6+
from collections.abc import Awaitable, Iterable
7+
from typing import Any, Callable, cast
78

89
from ..datastructures import Headers
910
from ..exceptions import InvalidHeader
@@ -13,8 +14,7 @@
1314

1415
__all__ = ["BasicAuthWebSocketServerProtocol", "basic_auth_protocol_factory"]
1516

16-
# Change to tuple[str, str] when dropping Python < 3.9.
17-
Credentials = Tuple[str, str]
17+
Credentials = tuple[str, str]
1818

1919

2020
def is_credentials(value: Any) -> bool:

src/websockets/legacy/client.py

+2-8
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,9 @@
77
import random
88
import urllib.parse
99
import warnings
10+
from collections.abc import AsyncIterator, Generator, Sequence
1011
from types import TracebackType
11-
from typing import (
12-
Any,
13-
AsyncIterator,
14-
Callable,
15-
Generator,
16-
Sequence,
17-
cast,
18-
)
12+
from typing import Any, Callable, cast
1913

2014
from ..asyncio.compatibility import asyncio_timeout
2115
from ..datastructures import Headers, HeadersLike

src/websockets/legacy/framing.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from __future__ import annotations
22

33
import struct
4-
from typing import Any, Awaitable, Callable, NamedTuple, Sequence
4+
from collections.abc import Awaitable, Sequence
5+
from typing import Any, Callable, NamedTuple
56

67
from .. import extensions, frames
78
from ..exceptions import PayloadTooBig, ProtocolError

src/websockets/legacy/protocol.py

+2-11
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,8 @@
1111
import time
1212
import uuid
1313
import warnings
14-
from typing import (
15-
Any,
16-
AsyncIterable,
17-
AsyncIterator,
18-
Awaitable,
19-
Callable,
20-
Deque,
21-
Iterable,
22-
Mapping,
23-
cast,
24-
)
14+
from collections.abc import AsyncIterable, AsyncIterator, Awaitable, Iterable, Mapping
15+
from typing import Any, Callable, Deque, cast
2516

2617
from ..asyncio.compatibility import asyncio_timeout
2718
from ..datastructures import Headers

src/websockets/legacy/server.py

+3-13
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,9 @@
88
import logging
99
import socket
1010
import warnings
11+
from collections.abc import Awaitable, Generator, Iterable, Sequence
1112
from types import TracebackType
12-
from typing import (
13-
Any,
14-
Awaitable,
15-
Callable,
16-
Generator,
17-
Iterable,
18-
Sequence,
19-
Tuple,
20-
Union,
21-
cast,
22-
)
13+
from typing import Any, Callable, Union, cast
2314

2415
from ..asyncio.compatibility import asyncio_timeout
2516
from ..datastructures import Headers, HeadersLike, MultipleValuesError
@@ -59,8 +50,7 @@
5950
# Change to HeadersLike | ... when dropping Python < 3.10.
6051
HeadersLikeOrCallable = Union[HeadersLike, Callable[[str, Headers], HeadersLike]]
6152

62-
# Change to tuple[...] when dropping Python < 3.9.
63-
HTTPResponse = Tuple[StatusLike, HeadersLike, bytes]
53+
HTTPResponse = tuple[StatusLike, HeadersLike, bytes]
6454

6555

6656
class WebSocketServerProtocol(WebSocketCommonProtocol):

0 commit comments

Comments
 (0)