Skip to content

Commit

Permalink
Deprecate aliases pointing to the legacy implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
aaugustin committed Sep 21, 2024
1 parent 6e9fa23 commit b84ac8d
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 99 deletions.
3 changes: 2 additions & 1 deletion docs/howto/upgrade.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ For context, the ``websockets`` package is structured as follows:
* The new implementation is found in the ``websockets.asyncio`` package.
* The original implementation was moved to the ``websockets.legacy`` package.
* The ``websockets`` package provides aliases for convenience. They were
switched to the new implementation in version 14.0.
switched to the new implementation in version 14.0 or deprecated when there
isn't an equivalent API.
* The ``websockets.client`` and ``websockets.server`` packages provide aliases
for backwards-compatibility with earlier versions of websockets. They will
be deprecated together with the original implementation.
Expand Down
7 changes: 7 additions & 0 deletions docs/project/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ Backwards-incompatible changes
If you're using any of them, then you must follow the :doc:`upgrade guide
<../howto/upgrade>` immediately.

.. admonition:: The new :mod:`asyncio` implementation is now deprecated.
:class: caution

Aliases for deprecated API were removed from ``__all__``. As a consequence,
they cannot be imported with ``from websockets import *`` anymore. The same
applies to other modules providing aliases.

.. _13.1:

13.1
Expand Down
63 changes: 18 additions & 45 deletions src/websockets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,6 @@
"ProtocolError",
"SecurityError",
"WebSocketException",
"WebSocketProtocolError",
# .legacy.auth
"BasicAuthWebSocketServerProtocol",
"basic_auth_protocol_factory",
# .legacy.client
"WebSocketClientProtocol",
# .legacy.exceptions
"AbortHandshake",
"InvalidMessage",
"InvalidStatusCode",
"RedirectHandshake",
# .legacy.protocol
"WebSocketCommonProtocol",
# .legacy.server
"WebSocketServer",
"WebSocketServerProtocol",
# .server
"ServerProtocol",
# .typing
Expand Down Expand Up @@ -99,21 +83,7 @@
ProtocolError,
SecurityError,
WebSocketException,
WebSocketProtocolError,
)
from .legacy.auth import (
BasicAuthWebSocketServerProtocol,
basic_auth_protocol_factory,
)
from .legacy.client import WebSocketClientProtocol
from .legacy.exceptions import (
AbortHandshake,
InvalidMessage,
InvalidStatusCode,
RedirectHandshake,
)
from .legacy.protocol import WebSocketCommonProtocol
from .legacy.server import WebSocketServer, WebSocketServerProtocol
from .server import ServerProtocol
from .typing import (
Data,
Expand All @@ -132,6 +102,7 @@
"connect": ".asyncio.client",
"unix_connect": ".asyncio.client",
# .asyncio.server
"basic_auth": ".asyncio.server",
"broadcast": ".asyncio.server",
"serve": ".asyncio.server",
"unix_serve": ".asyncio.server",
Expand Down Expand Up @@ -164,21 +135,6 @@
"SecurityError": ".exceptions",
"WebSocketException": ".exceptions",
"WebSocketProtocolError": ".exceptions",
# .legacy.auth
"BasicAuthWebSocketServerProtocol": ".legacy.auth",
"basic_auth_protocol_factory": ".legacy.auth",
# .legacy.client
"WebSocketClientProtocol": ".legacy.client",
# .legacy.exceptions
"AbortHandshake": ".legacy.exceptions",
"InvalidMessage": ".legacy.exceptions",
"InvalidStatusCode": ".legacy.exceptions",
"RedirectHandshake": ".legacy.exceptions",
# .legacy.protocol
"WebSocketCommonProtocol": ".legacy.protocol",
# .legacy.server
"WebSocketServer": ".legacy.server",
"WebSocketServerProtocol": ".legacy.server",
# .server
"ServerProtocol": ".server",
# .typing
Expand All @@ -196,5 +152,22 @@
"handshake": ".legacy",
"parse_uri": ".uri",
"WebSocketURI": ".uri",
# deprecated in 14.0
# .legacy.auth
"BasicAuthWebSocketServerProtocol": ".legacy.auth",
"basic_auth_protocol_factory": ".legacy.auth",
# .legacy.client
"WebSocketClientProtocol": ".legacy.client",
# .legacy.exceptions
"AbortHandshake": ".legacy.exceptions",
"InvalidMessage": ".legacy.exceptions",
"InvalidStatusCode": ".legacy.exceptions",
"RedirectHandshake": ".legacy.exceptions",
"WebSocketProtocolError": ".legacy.exceptions",
# .legacy.protocol
"WebSocketCommonProtocol": ".legacy.protocol",
# .legacy.server
"WebSocketServer": ".legacy.server",
"WebSocketServerProtocol": ".legacy.server",
},
)
10 changes: 8 additions & 2 deletions src/websockets/auth.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
from __future__ import annotations

# See #940 for why lazy_import isn't used here for backwards compatibility.
# See #1400 for why listing compatibility imports in __all__ helps PyCharm.
import warnings

from .legacy.auth import *
from .legacy.auth import __all__ # noqa: F401


warnings.warn( # deprecated in 14.0
"websockets.auth is deprecated",
DeprecationWarning,
)
20 changes: 13 additions & 7 deletions src/websockets/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
parse_upgrade,
)
from .http11 import Request, Response
from .imports import lazy_import
from .protocol import CLIENT, CONNECTING, OPEN, Protocol, State
from .typing import (
ConnectionOption,
Expand All @@ -40,13 +41,7 @@
from .utils import accept_key, generate_key


# See #940 for why lazy_import isn't used here for backwards compatibility.
# See #1400 for why listing compatibility imports in __all__ helps PyCharm.
from .legacy.client import * # isort:skip # noqa: I001
from .legacy.client import __all__ as legacy__all__


__all__ = ["ClientProtocol"] + legacy__all__
__all__ = ["ClientProtocol"]


class ClientProtocol(Protocol):
Expand Down Expand Up @@ -392,3 +387,14 @@ def backoff(
delay *= factor
while True:
yield max_delay


lazy_import(
globals(),
deprecated_aliases={
# deprecated in 14.0
"WebSocketClientProtocol": ".legacy.client",
"connect": ".legacy.client",
"unix_connect": ".legacy.client",
},
)
41 changes: 13 additions & 28 deletions src/websockets/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@

from __future__ import annotations

import typing
import warnings

from .imports import lazy_import
Expand All @@ -45,9 +44,7 @@
"InvalidURI",
"InvalidHandshake",
"SecurityError",
"InvalidMessage",
"InvalidStatus",
"InvalidStatusCode",
"InvalidHeader",
"InvalidHeaderFormat",
"InvalidHeaderValue",
Expand All @@ -57,10 +54,7 @@
"DuplicateParameter",
"InvalidParameterName",
"InvalidParameterValue",
"AbortHandshake",
"RedirectHandshake",
"ProtocolError",
"WebSocketProtocolError",
"PayloadTooBig",
"InvalidState",
"ConcurrencyError",
Expand Down Expand Up @@ -366,27 +360,18 @@ class ConcurrencyError(WebSocketException, RuntimeError):
"""


# When type checking, import non-deprecated aliases eagerly. Else, import on demand.
if typing.TYPE_CHECKING:
from .legacy.exceptions import (
AbortHandshake,
InvalidMessage,
InvalidStatusCode,
RedirectHandshake,
)

WebSocketProtocolError = ProtocolError
else:
lazy_import(
globals(),
aliases={
"AbortHandshake": ".legacy.exceptions",
"InvalidMessage": ".legacy.exceptions",
"InvalidStatusCode": ".legacy.exceptions",
"RedirectHandshake": ".legacy.exceptions",
"WebSocketProtocolError": ".legacy.exceptions",
},
)

# At the bottom to break import cycles created by type annotations.
from . import frames, http11 # noqa: E402


lazy_import(
globals(),
deprecated_aliases={
# deprecated in 14.0
"AbortHandshake": ".legacy.exceptions",
"InvalidMessage": ".legacy.exceptions",
"InvalidStatusCode": ".legacy.exceptions",
"RedirectHandshake": ".legacy.exceptions",
"WebSocketProtocolError": ".legacy.exceptions",
},
)
22 changes: 15 additions & 7 deletions src/websockets/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
parse_upgrade,
)
from .http11 import Request, Response
from .imports import lazy_import
from .protocol import CONNECTING, OPEN, SERVER, Protocol, State
from .typing import (
ConnectionOption,
Expand All @@ -40,13 +41,7 @@
from .utils import accept_key


# See #940 for why lazy_import isn't used here for backwards compatibility.
# See #1400 for why listing compatibility imports in __all__ helps PyCharm.
from .legacy.server import * # isort:skip # noqa: I001
from .legacy.server import __all__ as legacy__all__


__all__ = ["ServerProtocol"] + legacy__all__
__all__ = ["ServerProtocol"]


class ServerProtocol(Protocol):
Expand Down Expand Up @@ -586,3 +581,16 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
DeprecationWarning,
)
super().__init__(*args, **kwargs)


lazy_import(
globals(),
deprecated_aliases={
# deprecated in 14.0
"WebSocketServer": ".legacy.server",
"WebSocketServerProtocol": ".legacy.server",
"broadcast": ".legacy.server",
"serve": ".legacy.server",
"unix_serve": ".legacy.server",
},
)
2 changes: 1 addition & 1 deletion tests/legacy/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
import unittest
import urllib.error

from websockets.exceptions import InvalidStatusCode
from websockets.headers import build_authorization_basic
from websockets.legacy.auth import *
from websockets.legacy.auth import is_credentials
from websockets.legacy.exceptions import InvalidStatusCode

from .test_client_server import ClientServerTestsMixin, with_client, with_server
from .utils import AsyncioTestCase
Expand Down
2 changes: 1 addition & 1 deletion tests/legacy/test_client_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
ConnectionClosed,
InvalidHandshake,
InvalidHeader,
InvalidStatusCode,
NegotiationError,
)
from websockets.extensions.permessage_deflate import (
Expand All @@ -32,6 +31,7 @@
from websockets.frames import CloseCode
from websockets.http11 import USER_AGENT
from websockets.legacy.client import *
from websockets.legacy.exceptions import InvalidStatusCode
from websockets.legacy.handshake import build_response
from websockets.legacy.http import read_response
from websockets.legacy.server import *
Expand Down
30 changes: 23 additions & 7 deletions tests/test_exports.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,46 @@
import unittest

import websockets
import websockets.auth
import websockets.asyncio.client
import websockets.asyncio.server
import websockets.client
import websockets.datastructures
import websockets.exceptions
import websockets.legacy.protocol
import websockets.server
import websockets.typing
import websockets.uri


combined_exports = (
websockets.auth.__all__
[]
+ websockets.asyncio.client.__all__
+ websockets.asyncio.server.__all__
+ websockets.client.__all__
+ websockets.datastructures.__all__
+ websockets.exceptions.__all__
+ websockets.legacy.protocol.__all__
+ websockets.server.__all__
+ websockets.typing.__all__
)

# These API are intentionally not re-exported by the top-level module.
missing_reexports = [
# websockets.asyncio.client
"ClientConnection",
# websockets.asyncio.server
"ServerConnection",
"Server",
]


class ExportsTests(unittest.TestCase):
def test_top_level_module_reexports_all_submodule_exports(self):
self.assertEqual(set(combined_exports), set(websockets.__all__))
def test_top_level_module_reexports_submodule_exports(self):
self.assertEqual(
set(combined_exports),
set(websockets.__all__ + missing_reexports),
)

def test_submodule_exports_are_globally_unique(self):
self.assertEqual(len(set(combined_exports)), len(combined_exports))
self.assertEqual(
len(set(combined_exports)),
len(combined_exports),
)

0 comments on commit b84ac8d

Please sign in to comment.